forked from Minki/linux
SCSI for-linus on 20141208
This patch is the usual mix of driver updates (srp, ipr, scsi_debug, NCR5380, fnic, 53c974, ses, wd719x, hpsa, megaraid_sas). Of those, wd7a9x is new and 53c974 is a rewrite of the old tmscsim driver and the extensive work by Finn Thain rewrites all the NCR5380 based drivers. There's also extensive infrastructure updates: a new logging infrastructure for sense information and a rewrite of the tagged command queue API and an assortment of minor updates. Signed-off-by: James Bottomley <JBottomley@Parallels.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABAgAGBQJUhgazAAoJEDeqqVYsXL0MxIYH/2wCs9sne5cfDTjfufLJDdu1 WLoJgNMxv+14OukknJfG2Kk1WlHgLRM5+TVWIGiG0mmjXuFyShzIqEOHKTDWqxnE tBH4wLi/+XYqZAmAeim4/2zhvf+cUVVlIu01VERR5uwaBWYM8BeLSwjdnAAvEEwb iV74p1WV6frXo4guADplgtkjD0YxI4MTUZ1figRMlLO6WLFFyQ+95UfY8jFs+eQv zk63y7Mm7dQNd57/Wl3i89lw0kqlaJSZNl8Ovj1axy4rDYzT1wXhY8mEwD8fI8Ym wahldjFE5vXgj0NpO3tB3Z+UDP2YmQduMyzTxkPNnrEPKiOCsnQo42XR6vb92cQ= =Y+DU -----END PGP SIGNATURE----- Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi Pull SCSI updates from James Bottomley: "This patch is the usual mix of driver updates (srp, ipr, scsi_debug, NCR5380, fnic, 53c974, ses, wd719x, hpsa, megaraid_sas). Of those, wd7a9x is new and 53c974 is a rewrite of the old tmscsim driver and the extensive work by Finn Thain rewrites all the NCR5380 based drivers. There's also extensive infrastructure updates: a new logging infrastructure for sense information and a rewrite of the tagged command queue API and an assortment of minor updates" * tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (183 commits) scsi: set fmt to NULL scsi_extd_sense_format() by default libsas: remove task_collector mode wd719x: remove dma_cache_sync call scsi_debug: add Report supported opcodes+tmfs; Compare and write scsi_debug: change SCSI command parser to table driven scsi_debug: add Capacity Changed Unit Attention scsi_debug: append inject error flags onto scsi_cmnd object scsi_debug: pinpoint invalid field in sense data wd719x: Add firmware documentation wd719x: Introduce Western Digital WD7193/7197/7296 PCI SCSI card driver eeprom-93cx6: Add (read-only) support for 8-bit mode esas2r: fix an oversight in setting return value esas2r: fix an error path in esas2r_ioctl_handler esas2r: fir error handling in do_fm_api scsi: add SPC-3 command definitions scsi: rename SERVICE_ACTION_IN to SERVICE_ACTION_IN_16 scsi: remove scsi_driver owner field scsi: move scsi_dispatch_cmd to scsi_lib.c scsi: stop passing a gfp_mask argument down the command setup path scsi: remove scsi_next_command ...
This commit is contained in:
commit
f3f62a38ce
@ -55,12 +55,12 @@ Description: Interface for making ib_srp connect to a new target.
|
||||
only safe with partial memory descriptor list support enabled
|
||||
(allow_ext_sg=1).
|
||||
* comp_vector, a number in the range 0..n-1 specifying the
|
||||
MSI-X completion vector. Some HCA's allocate multiple (n)
|
||||
MSI-X vectors per HCA port. If the IRQ affinity masks of
|
||||
these interrupts have been configured such that each MSI-X
|
||||
interrupt is handled by a different CPU then the comp_vector
|
||||
parameter can be used to spread the SRP completion workload
|
||||
over multiple CPU's.
|
||||
MSI-X completion vector of the first RDMA channel. Some
|
||||
HCA's allocate multiple (n) MSI-X vectors per HCA port. If
|
||||
the IRQ affinity masks of these interrupts have been
|
||||
configured such that each MSI-X interrupt is handled by a
|
||||
different CPU then the comp_vector parameter can be used to
|
||||
spread the SRP completion workload over multiple CPU's.
|
||||
* tl_retry_count, a number in the range 2..7 specifying the
|
||||
IB RC retry count.
|
||||
* queue_size, the maximum number of commands that the
|
||||
@ -88,6 +88,13 @@ Description: Whether ib_srp is allowed to include a partial memory
|
||||
descriptor list in an SRP_CMD when communicating with an SRP
|
||||
target.
|
||||
|
||||
What: /sys/class/scsi_host/host<n>/ch_count
|
||||
Date: April 1, 2015
|
||||
KernelVersion: 3.19
|
||||
Contact: linux-rdma@vger.kernel.org
|
||||
Description: Number of RDMA channels used for communication with the SRP
|
||||
target.
|
||||
|
||||
What: /sys/class/scsi_host/host<n>/cmd_sg_entries
|
||||
Date: May 19, 2011
|
||||
KernelVersion: 2.6.39
|
||||
@ -95,6 +102,12 @@ Contact: linux-rdma@vger.kernel.org
|
||||
Description: Maximum number of data buffer descriptors that may be sent to
|
||||
the target in a single SRP_CMD request.
|
||||
|
||||
What: /sys/class/scsi_host/host<n>/comp_vector
|
||||
Date: September 2, 2013
|
||||
KernelVersion: 3.11
|
||||
Contact: linux-rdma@vger.kernel.org
|
||||
Description: Completion vector used for the first RDMA channel.
|
||||
|
||||
What: /sys/class/scsi_host/host<n>/dgid
|
||||
Date: June 17, 2006
|
||||
KernelVersion: 2.6.17
|
||||
|
@ -827,10 +827,6 @@ but in the event of any barrier requests in the tag queue we need to ensure
|
||||
that requests are restarted in the order they were queue. This may happen
|
||||
if the driver needs to use blk_queue_invalidate_tags().
|
||||
|
||||
Tagging also defines a new request flag, REQ_QUEUED. This is set whenever
|
||||
a request is currently tagged. You should not use this flag directly,
|
||||
blk_rq_tagged(rq) is the portable way to do so.
|
||||
|
||||
3.3 I/O Submission
|
||||
|
||||
The routine submit_bio() is used to submit a single io. Higher level i/o
|
||||
|
@ -226,9 +226,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha)
|
||||
my_ha->sas_ha.lldd_dev_found = my_dev_found;
|
||||
my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
|
||||
|
||||
my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1)
|
||||
|
||||
my_ha->sas_ha.lldd_queue_size = ha_can_queue;
|
||||
my_ha->sas_ha.lldd_execute_task = my_execute_task;
|
||||
|
||||
my_ha->sas_ha.lldd_abort_task = my_abort_task;
|
||||
@ -247,28 +244,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha)
|
||||
return sas_register_ha(&my_ha->sas_ha);
|
||||
}
|
||||
|
||||
(1) This is normally a LLDD parameter, something of the
|
||||
lines of a task collector. What it tells the SAS Layer is
|
||||
whether the SAS layer should run in Direct Mode (default:
|
||||
value 0 or 1) or Task Collector Mode (value greater than 1).
|
||||
|
||||
In Direct Mode, the SAS Layer calls Execute Task as soon as
|
||||
it has a command to send to the SDS, _and_ this is a single
|
||||
command, i.e. not linked.
|
||||
|
||||
Some hardware (e.g. aic94xx) has the capability to DMA more
|
||||
than one task at a time (interrupt) from host memory. Task
|
||||
Collector Mode is an optional feature for HAs which support
|
||||
this in their hardware. (Again, it is completely optional
|
||||
even if your hardware supports it.)
|
||||
|
||||
In Task Collector Mode, the SAS Layer would do _natural_
|
||||
coalescing of tasks and at the appropriate moment it would
|
||||
call your driver to DMA more than one task in a single HA
|
||||
interrupt. DMBS may want to use this by insmod/modprobe
|
||||
setting the lldd_max_execute_num to something greater than
|
||||
1.
|
||||
|
||||
(2) SAS 1.1 does not define I_T Nexus Reset TMF.
|
||||
|
||||
Events
|
||||
@ -325,71 +300,22 @@ PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
|
||||
|
||||
The Execute Command SCSI RPC:
|
||||
|
||||
int (*lldd_execute_task)(struct sas_task *, int num,
|
||||
unsigned long gfp_flags);
|
||||
int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
|
||||
|
||||
Used to queue a task to the SAS LLDD. @task is the tasks to
|
||||
be executed. @num should be the number of tasks being
|
||||
queued at this function call (they are linked listed via
|
||||
task::list), @gfp_mask should be the gfp_mask defining the
|
||||
context of the caller.
|
||||
Used to queue a task to the SAS LLDD. @task is the task to be executed.
|
||||
@gfp_mask is the gfp_mask defining the context of the caller.
|
||||
|
||||
This function should implement the Execute Command SCSI RPC,
|
||||
or if you're sending a SCSI Task as linked commands, you
|
||||
should also use this function.
|
||||
|
||||
That is, when lldd_execute_task() is called, the command(s)
|
||||
That is, when lldd_execute_task() is called, the command
|
||||
go out on the transport *immediately*. There is *no*
|
||||
queuing of any sort and at any level in a SAS LLDD.
|
||||
|
||||
The use of task::list is two-fold, one for linked commands,
|
||||
the other discussed below.
|
||||
|
||||
It is possible to queue up more than one task at a time, by
|
||||
initializing the list element of struct sas_task, and
|
||||
passing the number of tasks enlisted in this manner in num.
|
||||
|
||||
Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
|
||||
0, the task(s) were queued.
|
||||
|
||||
If you want to pass num > 1, then either
|
||||
A) you're the only caller of this function and keep track
|
||||
of what you've queued to the LLDD, or
|
||||
B) you know what you're doing and have a strategy of
|
||||
retrying.
|
||||
|
||||
As opposed to queuing one task at a time (function call),
|
||||
batch queuing of tasks, by having num > 1, greatly
|
||||
simplifies LLDD code, sequencer code, and _hardware design_,
|
||||
and has some performance advantages in certain situations
|
||||
(DBMS).
|
||||
|
||||
The LLDD advertises if it can take more than one command at
|
||||
a time at lldd_execute_task(), by setting the
|
||||
lldd_max_execute_num parameter (controlled by "collector"
|
||||
module parameter in aic94xx SAS LLDD).
|
||||
|
||||
You should leave this to the default 1, unless you know what
|
||||
you're doing.
|
||||
|
||||
This is a function of the LLDD, to which the SAS layer can
|
||||
cater to.
|
||||
|
||||
int lldd_queue_size
|
||||
The host adapter's queue size. This is the maximum
|
||||
number of commands the lldd can have pending to domain
|
||||
devices on behalf of all upper layers submitting through
|
||||
lldd_execute_task().
|
||||
|
||||
You really want to set this to something (much) larger than
|
||||
1.
|
||||
|
||||
This _really_ has absolutely nothing to do with queuing.
|
||||
There is no queuing in SAS LLDDs.
|
||||
|
||||
struct sas_task {
|
||||
dev -- the device this task is destined to
|
||||
list -- must be initialized (INIT_LIST_HEAD)
|
||||
task_proto -- _one_ of enum sas_proto
|
||||
scatter -- pointer to scatter gather list array
|
||||
num_scatter -- number of elements in scatter
|
||||
|
@ -149,7 +149,7 @@ scsi_add_host() ---->
|
||||
scsi_scan_host() -------+
|
||||
|
|
||||
slave_alloc()
|
||||
slave_configure() --> scsi_adjust_queue_depth()
|
||||
slave_configure() --> scsi_change_queue_depth()
|
||||
|
|
||||
slave_alloc()
|
||||
slave_configure()
|
||||
@ -159,7 +159,7 @@ scsi_scan_host() -------+
|
||||
------------------------------------------------------------
|
||||
|
||||
If the LLD wants to adjust the default queue settings, it can invoke
|
||||
scsi_adjust_queue_depth() in its slave_configure() routine.
|
||||
scsi_change_queue_depth() in its slave_configure() routine.
|
||||
|
||||
*** For scsi devices that the mid level tries to scan but do not
|
||||
respond, a slave_alloc(), slave_destroy() pair is called.
|
||||
@ -203,7 +203,7 @@ LLD mid level LLD
|
||||
scsi_add_device() ------+
|
||||
|
|
||||
slave_alloc()
|
||||
slave_configure() [--> scsi_adjust_queue_depth()]
|
||||
slave_configure() [--> scsi_change_queue_depth()]
|
||||
------------------------------------------------------------
|
||||
|
||||
In a similar fashion, an LLD may become aware that a SCSI device has been
|
||||
@ -261,7 +261,7 @@ init_this_scsi_driver() ----+
|
||||
| scsi_register()
|
||||
|
|
||||
slave_alloc()
|
||||
slave_configure() --> scsi_adjust_queue_depth()
|
||||
slave_configure() --> scsi_change_queue_depth()
|
||||
slave_alloc() ***
|
||||
slave_destroy() ***
|
||||
|
|
||||
@ -271,9 +271,9 @@ init_this_scsi_driver() ----+
|
||||
slave_destroy() ***
|
||||
------------------------------------------------------------
|
||||
|
||||
The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and
|
||||
"cmd_per_lun" for that host as the queue length. These settings can be
|
||||
overridden by a slave_configure() supplied by the LLD.
|
||||
The mid level invokes scsi_change_queue_depth() with "cmd_per_lun" for that
|
||||
host as the queue length. These settings can be overridden by a
|
||||
slave_configure() supplied by the LLD.
|
||||
|
||||
*** For scsi devices that the mid level tries to scan but do not
|
||||
respond, a slave_alloc(), slave_destroy() pair is called.
|
||||
@ -366,13 +366,11 @@ is initialized. The functions below are listed alphabetically and their
|
||||
names all start with "scsi_".
|
||||
|
||||
Summary:
|
||||
scsi_activate_tcq - turn on tag command queueing
|
||||
scsi_add_device - creates new scsi device (lu) instance
|
||||
scsi_add_host - perform sysfs registration and set up transport class
|
||||
scsi_adjust_queue_depth - change the queue depth on a SCSI device
|
||||
scsi_change_queue_depth - change the queue depth on a SCSI device
|
||||
scsi_bios_ptable - return copy of block device's partition table
|
||||
scsi_block_requests - prevent further commands being queued to given host
|
||||
scsi_deactivate_tcq - turn off tag command queueing
|
||||
scsi_host_alloc - return a new scsi_host instance whose refcount==1
|
||||
scsi_host_get - increments Scsi_Host instance's refcount
|
||||
scsi_host_put - decrements Scsi_Host instance's refcount (free if 0)
|
||||
@ -389,24 +387,6 @@ Summary:
|
||||
|
||||
Details:
|
||||
|
||||
/**
|
||||
* scsi_activate_tcq - turn on tag command queueing ("ordered" task attribute)
|
||||
* @sdev: device to turn on TCQ for
|
||||
* @depth: queue depth
|
||||
*
|
||||
* Returns nothing
|
||||
*
|
||||
* Might block: no
|
||||
*
|
||||
* Notes: Eventually, it is hoped depth would be the maximum depth
|
||||
* the device could cope with and the real queue depth
|
||||
* would be adjustable from 0 to depth.
|
||||
*
|
||||
* Defined (inline) in: include/scsi/scsi_tcq.h
|
||||
**/
|
||||
void scsi_activate_tcq(struct scsi_device *sdev, int depth)
|
||||
|
||||
|
||||
/**
|
||||
* scsi_add_device - creates new scsi device (lu) instance
|
||||
* @shost: pointer to scsi host instance
|
||||
@ -456,11 +436,8 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
|
||||
|
||||
|
||||
/**
|
||||
* scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device
|
||||
* scsi_change_queue_depth - allow LLD to change queue depth on a SCSI device
|
||||
* @sdev: pointer to SCSI device to change queue depth on
|
||||
* @tagged: 0 - no tagged queuing
|
||||
* MSG_SIMPLE_TAG - simple tagged queuing
|
||||
* MSG_ORDERED_TAG - ordered tagged queuing
|
||||
* @tags Number of tags allowed if tagged queuing enabled,
|
||||
* or number of commands the LLD can queue up
|
||||
* in non-tagged mode (as per cmd_per_lun).
|
||||
@ -471,15 +448,12 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
|
||||
*
|
||||
* Notes: Can be invoked any time on a SCSI device controlled by this
|
||||
* LLD. [Specifically during and after slave_configure() and prior to
|
||||
* slave_destroy().] Can safely be invoked from interrupt code. Actual
|
||||
* queue depth change may be delayed until the next command is being
|
||||
* processed. See also scsi_activate_tcq() and scsi_deactivate_tcq().
|
||||
* slave_destroy().] Can safely be invoked from interrupt code.
|
||||
*
|
||||
* Defined in: drivers/scsi/scsi.c [see source code for more notes]
|
||||
*
|
||||
**/
|
||||
void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged,
|
||||
int tags)
|
||||
int scsi_change_queue_depth(struct scsi_device *sdev, int tags)
|
||||
|
||||
|
||||
/**
|
||||
@ -514,20 +488,6 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
|
||||
void scsi_block_requests(struct Scsi_Host * shost)
|
||||
|
||||
|
||||
/**
|
||||
* scsi_deactivate_tcq - turn off tag command queueing
|
||||
* @sdev: device to turn off TCQ for
|
||||
* @depth: queue depth (stored in sdev)
|
||||
*
|
||||
* Returns nothing
|
||||
*
|
||||
* Might block: no
|
||||
*
|
||||
* Defined (inline) in: include/scsi/scsi_tcq.h
|
||||
**/
|
||||
void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
|
||||
|
||||
|
||||
/**
|
||||
* scsi_host_alloc - create a scsi host adapter instance and perform basic
|
||||
* initialization.
|
||||
@ -1254,7 +1214,7 @@ of interest:
|
||||
for disk firmware uploads.
|
||||
cmd_per_lun - maximum number of commands that can be queued on devices
|
||||
controlled by the host. Overridden by LLD calls to
|
||||
scsi_adjust_queue_depth().
|
||||
scsi_change_queue_depth().
|
||||
unchecked_isa_dma - 1=>only use bottom 16 MB of ram (ISA DMA addressing
|
||||
restriction), 0=>can use full 32 bit (or better) DMA
|
||||
address space
|
||||
@ -1294,7 +1254,7 @@ struct scsi_cmnd
|
||||
Instances of this structure convey SCSI commands to the LLD and responses
|
||||
back to the mid level. The SCSI mid level will ensure that no more SCSI
|
||||
commands become queued against the LLD than are indicated by
|
||||
scsi_adjust_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will
|
||||
scsi_change_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will
|
||||
be at least one instance of struct scsi_cmnd available for each SCSI device.
|
||||
Members of interest:
|
||||
cmnd - array containing SCSI command
|
||||
|
@ -506,9 +506,11 @@ user does not request data that far.)
|
||||
|
||||
DEBUGGING HINTS
|
||||
|
||||
To enable debugging messages, edit st.c and #define DEBUG 1. As seen
|
||||
above, debugging can be switched off with an ioctl if debugging is
|
||||
compiled into the driver. The debugging output is not voluminous.
|
||||
Debugging code is now compiled in by default but debugging is turned off
|
||||
with the kernel module parameter debug_flag defaulting to 0. Debugging
|
||||
can still be switched on and off with an ioctl. To enable debug at
|
||||
module load time add debug_flag=1 to the module load options, the
|
||||
debugging output is not voluminous.
|
||||
|
||||
If the tape seems to hang, I would be very interested to hear where
|
||||
the driver is waiting. With the command 'ps -l' you can see the state
|
||||
|
21
Documentation/scsi/wd719x.txt
Normal file
21
Documentation/scsi/wd719x.txt
Normal file
@ -0,0 +1,21 @@
|
||||
Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards
|
||||
---------------------------------------------------------------
|
||||
|
||||
The card requires firmware that can be cut out of the Windows NT driver that
|
||||
can be downloaded from WD at:
|
||||
http://support.wdc.com/product/download.asp?groupid=801&sid=27&lang=en
|
||||
|
||||
There is no license anywhere in the file or on the page - so the firmware
|
||||
probably cannot be added to linux-firmware.
|
||||
|
||||
This script downloads and extracts the firmware, creating wd719x-risc.bin and
|
||||
d719x-wcs.bin files. Put them in /lib/firmware/.
|
||||
|
||||
#!/bin/sh
|
||||
wget http://support.wdc.com/download/archive/pciscsi.exe
|
||||
lha xi pciscsi.exe pci-scsi.exe
|
||||
lha xi pci-scsi.exe nt/wd7296a.sys
|
||||
rm pci-scsi.exe
|
||||
dd if=wd7296a.sys of=wd719x-risc.bin bs=1 skip=5760 count=14336
|
||||
dd if=wd7296a.sys of=wd719x-wcs.bin bs=1 skip=20096 count=514
|
||||
rm wd7296a.sys
|
17
MAINTAINERS
17
MAINTAINERS
@ -2862,11 +2862,10 @@ F: Documentation/networking/dmfe.txt
|
||||
F: drivers/net/ethernet/dec/tulip/dmfe.c
|
||||
|
||||
DC390/AM53C974 SCSI driver
|
||||
M: Kurt Garloff <garloff@suse.de>
|
||||
W: http://www.garloff.de/kurt/linux/dc390/
|
||||
M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/scsi/tmscsim.*
|
||||
F: drivers/scsi/am53c974.c
|
||||
|
||||
DC395x SCSI driver
|
||||
M: Oliver Neukum <oliver@neukum.org>
|
||||
@ -5991,10 +5990,13 @@ W: http://linuxtv.org
|
||||
S: Odd Fixes
|
||||
F: drivers/media/parport/pms*
|
||||
|
||||
MEGARAID SCSI DRIVERS
|
||||
M: Neela Syam Kolli <megaraidlinux@lsi.com>
|
||||
MEGARAID SCSI/SAS DRIVERS
|
||||
M: Kashyap Desai <kashyap.desai@avagotech.com>
|
||||
M: Sumit Saxena <sumit.saxena@avagotech.com>
|
||||
M: Uday Lingala <uday.lingala@avagotech.com>
|
||||
L: megaraidlinux.pdl@avagotech.com
|
||||
L: linux-scsi@vger.kernel.org
|
||||
W: http://megaraid.lsilogic.com
|
||||
W: http://www.lsi.com
|
||||
S: Maintained
|
||||
F: Documentation/scsi/megaraid.txt
|
||||
F: drivers/scsi/megaraid.*
|
||||
@ -6305,7 +6307,6 @@ F: drivers/scsi/g_NCR5380.*
|
||||
F: drivers/scsi/g_NCR5380_mmio.c
|
||||
F: drivers/scsi/mac_scsi.*
|
||||
F: drivers/scsi/pas16.*
|
||||
F: drivers/scsi/sun3_NCR5380.c
|
||||
F: drivers/scsi/sun3_scsi.*
|
||||
F: drivers/scsi/sun3_scsi_vme.c
|
||||
F: drivers/scsi/t128.*
|
||||
|
@ -858,6 +858,24 @@ static struct platform_device *atari_netusbee_devices[] __initdata = {
|
||||
};
|
||||
#endif /* CONFIG_ATARI_ETHERNEC */
|
||||
|
||||
#ifdef CONFIG_ATARI_SCSI
|
||||
static const struct resource atari_scsi_st_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_MFP_FSCSI,
|
||||
.end = IRQ_MFP_FSCSI,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource atari_scsi_tt_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_TT_MFP_SCSI,
|
||||
.end = IRQ_TT_MFP_SCSI,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
int __init atari_platform_init(void)
|
||||
{
|
||||
int rv = 0;
|
||||
@ -892,6 +910,15 @@ int __init atari_platform_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ATARI_SCSI
|
||||
if (ATARIHW_PRESENT(ST_SCSI))
|
||||
platform_device_register_simple("atari_scsi", -1,
|
||||
atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc));
|
||||
else if (ATARIHW_PRESENT(TT_SCSI))
|
||||
platform_device_register_simple("atari_scsi", -1,
|
||||
atari_scsi_tt_rsrc, ARRAY_SIZE(atari_scsi_tt_rsrc));
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,31 @@ static irqreturn_t stdma_int (int irq, void *dummy);
|
||||
/************************* End of Prototypes **************************/
|
||||
|
||||
|
||||
/**
|
||||
* stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
|
||||
* @handler: interrupt handler to use after acquisition
|
||||
*
|
||||
* Returns !0 if lock was acquired; otherwise 0.
|
||||
*/
|
||||
|
||||
int stdma_try_lock(irq_handler_t handler, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (stdma_locked) {
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stdma_locked = 1;
|
||||
stdma_isr = handler;
|
||||
stdma_isr_data = data;
|
||||
local_irq_restore(flags);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_try_lock);
|
||||
|
||||
|
||||
/*
|
||||
* Function: void stdma_lock( isrfunc isr, void *data )
|
||||
@ -78,19 +103,10 @@ static irqreturn_t stdma_int (int irq, void *dummy);
|
||||
|
||||
void stdma_lock(irq_handler_t handler, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags); /* protect lock */
|
||||
|
||||
/* Since the DMA is used for file system purposes, we
|
||||
have to sleep uninterruptible (there may be locked
|
||||
buffers) */
|
||||
wait_event(stdma_wait, !stdma_locked);
|
||||
|
||||
stdma_locked = 1;
|
||||
stdma_isr = handler;
|
||||
stdma_isr_data = data;
|
||||
local_irq_restore(flags);
|
||||
wait_event(stdma_wait, stdma_try_lock(handler, data));
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_lock);
|
||||
|
||||
@ -122,22 +138,25 @@ void stdma_release(void)
|
||||
EXPORT_SYMBOL(stdma_release);
|
||||
|
||||
|
||||
/*
|
||||
* Function: int stdma_others_waiting( void )
|
||||
*
|
||||
* Purpose: Check if someone waits for the ST-DMA lock.
|
||||
*
|
||||
* Inputs: none
|
||||
*
|
||||
* Returns: 0 if no one is waiting, != 0 otherwise
|
||||
/**
|
||||
* stdma_is_locked_by - allow lock holder to check whether it needs to release.
|
||||
* @handler: interrupt handler previously used to acquire lock.
|
||||
*
|
||||
* Returns !0 if locked for the given handler; 0 otherwise.
|
||||
*/
|
||||
|
||||
int stdma_others_waiting(void)
|
||||
int stdma_is_locked_by(irq_handler_t handler)
|
||||
{
|
||||
return waitqueue_active(&stdma_wait);
|
||||
unsigned long flags;
|
||||
int result;
|
||||
|
||||
local_irq_save(flags);
|
||||
result = stdma_locked && (stdma_isr == handler);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(stdma_others_waiting);
|
||||
EXPORT_SYMBOL(stdma_is_locked_by);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
/***************************** Prototypes *****************************/
|
||||
|
||||
int stdma_try_lock(irq_handler_t, void *);
|
||||
void stdma_lock(irq_handler_t handler, void *data);
|
||||
void stdma_release( void );
|
||||
int stdma_others_waiting( void );
|
||||
int stdma_islocked( void );
|
||||
void *stdma_locked_by( void );
|
||||
int stdma_is_locked_by(irq_handler_t);
|
||||
void stdma_init( void );
|
||||
|
||||
/************************* End of Prototypes **************************/
|
||||
|
@ -53,6 +53,10 @@ struct mac_model
|
||||
#define MAC_SCSI_QUADRA 2
|
||||
#define MAC_SCSI_QUADRA2 3
|
||||
#define MAC_SCSI_QUADRA3 4
|
||||
#define MAC_SCSI_IIFX 5
|
||||
#define MAC_SCSI_DUO 6
|
||||
#define MAC_SCSI_CCL 7
|
||||
#define MAC_SCSI_LATE 8
|
||||
|
||||
#define MAC_IDE_NONE 0
|
||||
#define MAC_IDE_QUADRA 1
|
||||
|
@ -278,7 +278,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "IIfx",
|
||||
.adb_type = MAC_ADB_IOP,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_IIFX,
|
||||
.scc_type = MAC_SCC_IOP,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_IOP,
|
||||
@ -329,7 +329,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "Color Classic",
|
||||
.adb_type = MAC_ADB_CUDA,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_CCL,
|
||||
.scc_type = MAC_SCC_II,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -338,7 +338,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "Color Classic II",
|
||||
.adb_type = MAC_ADB_CUDA,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_CCL,
|
||||
.scc_type = MAC_SCC_II,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -526,7 +526,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "Performa 520",
|
||||
.adb_type = MAC_ADB_CUDA,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_CCL,
|
||||
.scc_type = MAC_SCC_II,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -535,7 +535,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "Performa 550",
|
||||
.adb_type = MAC_ADB_CUDA,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_CCL,
|
||||
.scc_type = MAC_SCC_II,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -567,7 +567,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "TV",
|
||||
.adb_type = MAC_ADB_CUDA,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_CCL,
|
||||
.scc_type = MAC_SCC_II,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -712,7 +712,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook 190",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_QUADRA,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_LATE,
|
||||
.ide_type = MAC_IDE_BABOON,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
@ -722,7 +722,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook 520",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_QUADRA,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_LATE,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.ether_type = MAC_ETHER_SONIC,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
@ -740,7 +740,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 210",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -749,7 +749,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 230",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -758,7 +758,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 250",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -767,7 +767,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 270c",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -776,7 +776,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 280",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -785,7 +785,7 @@ static struct mac_model mac_data_table[] = {
|
||||
.name = "PowerBook Duo 280c",
|
||||
.adb_type = MAC_ADB_PB2,
|
||||
.via_type = MAC_VIA_IICI,
|
||||
.scsi_type = MAC_SCSI_OLD,
|
||||
.scsi_type = MAC_SCSI_DUO,
|
||||
.scc_type = MAC_SCC_QUADRA,
|
||||
.nubus_type = MAC_NUBUS,
|
||||
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
|
||||
@ -929,6 +929,70 @@ static struct platform_device swim_pdev = {
|
||||
.resource = &swim_rsrc,
|
||||
};
|
||||
|
||||
static const struct resource mac_scsi_iifx_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_MAC_SCSI,
|
||||
.end = IRQ_MAC_SCSI,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50008000,
|
||||
.end = 0x50009FFF,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource mac_scsi_duo_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0xFEE02000,
|
||||
.end = 0xFEE03FFF,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource mac_scsi_old_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_MAC_SCSI,
|
||||
.end = IRQ_MAC_SCSI,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50010000,
|
||||
.end = 0x50011FFF,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50006000,
|
||||
.end = 0x50007FFF,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource mac_scsi_late_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_MAC_SCSI,
|
||||
.end = IRQ_MAC_SCSI,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50010000,
|
||||
.end = 0x50011FFF,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct resource mac_scsi_ccl_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = IRQ_MAC_SCSI,
|
||||
.end = IRQ_MAC_SCSI,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50F10000,
|
||||
.end = 0x50F11FFF,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x50F06000,
|
||||
.end = 0x50F07FFF,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device esp_0_pdev = {
|
||||
.name = "mac_esp",
|
||||
.id = 0,
|
||||
@ -1000,6 +1064,60 @@ int __init mac_platform_init(void)
|
||||
(macintosh_config->ident == MAC_MODEL_Q950))
|
||||
platform_device_register(&esp_1_pdev);
|
||||
break;
|
||||
case MAC_SCSI_IIFX:
|
||||
/* Addresses from The Guide to Mac Family Hardware.
|
||||
* $5000 8000 - $5000 9FFF: SCSI DMA
|
||||
* $5000 C000 - $5000 DFFF: Alternate SCSI (DMA)
|
||||
* $5000 E000 - $5000 FFFF: Alternate SCSI (Hsk)
|
||||
* The SCSI DMA custom IC embeds the 53C80 core. mac_scsi does
|
||||
* not make use of its DMA or hardware handshaking logic.
|
||||
*/
|
||||
platform_device_register_simple("mac_scsi", 0,
|
||||
mac_scsi_iifx_rsrc, ARRAY_SIZE(mac_scsi_iifx_rsrc));
|
||||
break;
|
||||
case MAC_SCSI_DUO:
|
||||
/* Addresses from the Duo Dock II Developer Note.
|
||||
* $FEE0 2000 - $FEE0 3FFF: normal mode
|
||||
* $FEE0 4000 - $FEE0 5FFF: pseudo DMA without /DRQ
|
||||
* $FEE0 6000 - $FEE0 7FFF: pseudo DMA with /DRQ
|
||||
* The NetBSD code indicates that both 5380 chips share
|
||||
* an IRQ (?) which would need careful handling (see mac_esp).
|
||||
*/
|
||||
platform_device_register_simple("mac_scsi", 1,
|
||||
mac_scsi_duo_rsrc, ARRAY_SIZE(mac_scsi_duo_rsrc));
|
||||
/* fall through */
|
||||
case MAC_SCSI_OLD:
|
||||
/* Addresses from Developer Notes for Duo System,
|
||||
* PowerBook 180 & 160, 140 & 170, Macintosh IIsi
|
||||
* and also from The Guide to Mac Family Hardware for
|
||||
* SE/30, II, IIx, IIcx, IIci.
|
||||
* $5000 6000 - $5000 7FFF: pseudo-DMA with /DRQ
|
||||
* $5001 0000 - $5001 1FFF: normal mode
|
||||
* $5001 2000 - $5001 3FFF: pseudo-DMA without /DRQ
|
||||
* GMFH says that $5000 0000 - $50FF FFFF "wraps
|
||||
* $5000 0000 - $5001 FFFF eight times" (!)
|
||||
* mess.org says IIci and Color Classic do not alias
|
||||
* I/O address space.
|
||||
*/
|
||||
platform_device_register_simple("mac_scsi", 0,
|
||||
mac_scsi_old_rsrc, ARRAY_SIZE(mac_scsi_old_rsrc));
|
||||
break;
|
||||
case MAC_SCSI_LATE:
|
||||
/* PDMA logic in 68040 PowerBooks is somehow different to
|
||||
* '030 models. It's probably more like Quadras (see mac_esp).
|
||||
*/
|
||||
platform_device_register_simple("mac_scsi", 0,
|
||||
mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc));
|
||||
break;
|
||||
case MAC_SCSI_CCL:
|
||||
/* Addresses from the Color Classic Developer Note.
|
||||
* $50F0 6000 - $50F0 7FFF: SCSI handshake
|
||||
* $50F1 0000 - $50F1 1FFF: SCSI
|
||||
* $50F1 2000 - $50F1 3FFF: SCSI DMA
|
||||
*/
|
||||
platform_device_register_simple("mac_scsi", 0,
|
||||
mac_scsi_ccl_rsrc, ARRAY_SIZE(mac_scsi_ccl_rsrc));
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/oplib.h>
|
||||
#include <asm/setup.h>
|
||||
@ -27,6 +28,7 @@
|
||||
#include <asm/sun3mmu.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/machines.h>
|
||||
#include <asm/idprom.h>
|
||||
#include <asm/intersil.h>
|
||||
#include <asm/irq.h>
|
||||
@ -169,3 +171,61 @@ static void __init sun3_sched_init(irq_handler_t timer_routine)
|
||||
intersil_clear();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUN3_SCSI
|
||||
|
||||
static const struct resource sun3_scsi_vme_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = SUN3_VEC_VMESCSI0,
|
||||
.end = SUN3_VEC_VMESCSI0,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0xff200000,
|
||||
.end = 0xff200021,
|
||||
}, {
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = SUN3_VEC_VMESCSI1,
|
||||
.end = SUN3_VEC_VMESCSI1,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0xff204000,
|
||||
.end = 0xff204021,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Int: level 2 autovector
|
||||
* IO: type 1, base 0x00140000, 5 bits phys space: A<4..0>
|
||||
*/
|
||||
static const struct resource sun3_scsi_rsrc[] __initconst = {
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.start = 2,
|
||||
.end = 2,
|
||||
}, {
|
||||
.flags = IORESOURCE_MEM,
|
||||
.start = 0x00140000,
|
||||
.end = 0x0014001f,
|
||||
},
|
||||
};
|
||||
|
||||
int __init sun3_platform_init(void)
|
||||
{
|
||||
switch (idprom->id_machtype) {
|
||||
case SM_SUN3 | SM_3_160:
|
||||
case SM_SUN3 | SM_3_260:
|
||||
platform_device_register_simple("sun3_scsi_vme", -1,
|
||||
sun3_scsi_vme_rsrc, ARRAY_SIZE(sun3_scsi_vme_rsrc));
|
||||
break;
|
||||
case SM_SUN3 | SM_3_50:
|
||||
case SM_SUN3 | SM_3_60:
|
||||
platform_device_register_simple("sun3_scsi", -1,
|
||||
sun3_scsi_rsrc, ARRAY_SIZE(sun3_scsi_rsrc));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(sun3_platform_init);
|
||||
|
||||
#endif
|
||||
|
@ -1266,7 +1266,7 @@ void blk_requeue_request(struct request_queue *q, struct request *rq)
|
||||
blk_clear_rq_complete(rq);
|
||||
trace_block_rq_requeue(q, rq);
|
||||
|
||||
if (blk_rq_tagged(rq))
|
||||
if (rq->cmd_flags & REQ_QUEUED)
|
||||
blk_queue_end_tag(q, rq);
|
||||
|
||||
BUG_ON(blk_queued_rq(rq));
|
||||
@ -2554,7 +2554,7 @@ EXPORT_SYMBOL_GPL(blk_unprep_request);
|
||||
*/
|
||||
void blk_finish_request(struct request *req, int error)
|
||||
{
|
||||
if (blk_rq_tagged(req))
|
||||
if (req->cmd_flags & REQ_QUEUED)
|
||||
blk_queue_end_tag(req->q, req);
|
||||
|
||||
BUG_ON(blk_queued_rq(req));
|
||||
|
@ -584,6 +584,34 @@ int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_mq_unique_tag() - return a tag that is unique queue-wide
|
||||
* @rq: request for which to compute a unique tag
|
||||
*
|
||||
* The tag field in struct request is unique per hardware queue but not over
|
||||
* all hardware queues. Hence this function that returns a tag with the
|
||||
* hardware context index in the upper bits and the per hardware queue tag in
|
||||
* the lower bits.
|
||||
*
|
||||
* Note: When called for a request that is queued on a non-multiqueue request
|
||||
* queue, the hardware context index is set to zero.
|
||||
*/
|
||||
u32 blk_mq_unique_tag(struct request *rq)
|
||||
{
|
||||
struct request_queue *q = rq->q;
|
||||
struct blk_mq_hw_ctx *hctx;
|
||||
int hwq = 0;
|
||||
|
||||
if (q->mq_ops) {
|
||||
hctx = q->mq_ops->map_queue(q, rq->mq_ctx->cpu);
|
||||
hwq = hctx->queue_num;
|
||||
}
|
||||
|
||||
return (hwq << BLK_MQ_UNIQUE_TAG_BITS) |
|
||||
(rq->tag & BLK_MQ_UNIQUE_TAG_MASK);
|
||||
}
|
||||
EXPORT_SYMBOL(blk_mq_unique_tag);
|
||||
|
||||
ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
|
||||
{
|
||||
char *orig_page = page;
|
||||
|
@ -2049,6 +2049,8 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
|
||||
*/
|
||||
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
|
||||
{
|
||||
BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS);
|
||||
|
||||
if (!set->nr_hw_queues)
|
||||
return -EINVAL;
|
||||
if (!set->queue_depth)
|
||||
|
@ -142,7 +142,7 @@ static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
|
||||
__set_bit(GPCMD_VERIFY_10, filter->read_ok);
|
||||
__set_bit(VERIFY_16, filter->read_ok);
|
||||
__set_bit(REPORT_LUNS, filter->read_ok);
|
||||
__set_bit(SERVICE_ACTION_IN, filter->read_ok);
|
||||
__set_bit(SERVICE_ACTION_IN_16, filter->read_ok);
|
||||
__set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok);
|
||||
__set_bit(MAINTENANCE_IN, filter->read_ok);
|
||||
__set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok);
|
||||
|
@ -1164,7 +1164,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
|
||||
|
||||
depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
|
||||
depth = min(ATA_MAX_QUEUE - 1, depth);
|
||||
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
|
||||
scsi_change_queue_depth(sdev, depth);
|
||||
}
|
||||
|
||||
blk_queue_flush_queueable(q, false);
|
||||
@ -1243,21 +1243,17 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
|
||||
* @ap: ATA port to which the device change the queue depth
|
||||
* @sdev: SCSI device to configure queue depth for
|
||||
* @queue_depth: new queue depth
|
||||
* @reason: calling context
|
||||
*
|
||||
* libsas and libata have different approaches for associating a sdev to
|
||||
* its ata_port.
|
||||
*
|
||||
*/
|
||||
int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
|
||||
int queue_depth, int reason)
|
||||
int queue_depth)
|
||||
{
|
||||
struct ata_device *dev;
|
||||
unsigned long flags;
|
||||
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (queue_depth < 1 || queue_depth == sdev->queue_depth)
|
||||
return sdev->queue_depth;
|
||||
|
||||
@ -1282,15 +1278,13 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
|
||||
if (sdev->queue_depth == queue_depth)
|
||||
return -EINVAL;
|
||||
|
||||
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
return scsi_change_queue_depth(sdev, queue_depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_change_queue_depth - SCSI callback for queue depth config
|
||||
* @sdev: SCSI device to configure queue depth for
|
||||
* @queue_depth: new queue depth
|
||||
* @reason: calling context
|
||||
*
|
||||
* This is libata standard hostt->change_queue_depth callback.
|
||||
* SCSI will call into this callback when user tries to set queue
|
||||
@ -1302,12 +1296,11 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
|
||||
* RETURNS:
|
||||
* Newly configured queue depth.
|
||||
*/
|
||||
int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
|
||||
int reason)
|
||||
int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
|
||||
return __ata_change_queue_depth(ap, sdev, queue_depth, reason);
|
||||
return __ata_change_queue_depth(ap, sdev, queue_depth);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3570,7 +3563,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
|
||||
break;
|
||||
|
||||
case SERVICE_ACTION_IN:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
|
||||
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
|
||||
else
|
||||
|
@ -1951,7 +1951,7 @@ static int nv_swncq_slave_config(struct scsi_device *sdev)
|
||||
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
|
||||
if (strncmp(model_num, "Maxtor", 6) == 0) {
|
||||
ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT);
|
||||
ata_scsi_change_queue_depth(sdev, 1);
|
||||
ata_dev_notice(dev, "Disabling SWNCQ mode (depth %x)\n",
|
||||
sdev->queue_depth);
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ INQUIRY_EVPD_BIT_MASK) ? 1 : 0)
|
||||
(GET_U32_FROM_CDB(cdb, READ_CAP_16_CDB_ALLOC_LENGTH_OFFSET))
|
||||
|
||||
#define IS_READ_CAP_16(cdb) \
|
||||
((cdb[0] == SERVICE_ACTION_IN && cdb[1] == SAI_READ_CAPACITY_16) ? 1 : 0)
|
||||
((cdb[0] == SERVICE_ACTION_IN_16 && cdb[1] == SAI_READ_CAPACITY_16) ? 1 : 0)
|
||||
|
||||
/* Request Sense Helper Macros */
|
||||
#define GET_REQUEST_SENSE_ALLOC_LENGTH(cdb) \
|
||||
@ -2947,7 +2947,7 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
|
||||
case READ_CAPACITY:
|
||||
retcode = nvme_trans_read_capacity(ns, hdr, cmd);
|
||||
break;
|
||||
case SERVICE_ACTION_IN:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
if (IS_READ_CAP_16(cmd))
|
||||
retcode = nvme_trans_read_capacity(ns, hdr, cmd);
|
||||
else
|
||||
|
@ -911,7 +911,7 @@ static struct scsi_host_template iscsi_iser_sht = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "iSCSI Initiator over iSER",
|
||||
.queuecommand = iscsi_queuecommand,
|
||||
.change_queue_depth = iscsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
|
||||
.max_sectors = 1024,
|
||||
.cmd_per_lun = ISER_DEF_CMD_PER_LUN,
|
||||
@ -922,6 +922,7 @@ static struct scsi_host_template iscsi_iser_sht = {
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.proc_name = "iscsi_iser",
|
||||
.this_id = -1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static struct iscsi_transport iscsi_iser_transport = {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -70,9 +70,12 @@ enum {
|
||||
|
||||
LOCAL_INV_WR_ID_MASK = 1,
|
||||
FAST_REG_WR_ID_MASK = 2,
|
||||
|
||||
SRP_LAST_WR_ID = 0xfffffffcU,
|
||||
};
|
||||
|
||||
enum srp_target_state {
|
||||
SRP_TARGET_SCANNING,
|
||||
SRP_TARGET_LIVE,
|
||||
SRP_TARGET_REMOVED,
|
||||
};
|
||||
@ -115,7 +118,6 @@ struct srp_host {
|
||||
};
|
||||
|
||||
struct srp_request {
|
||||
struct list_head list;
|
||||
struct scsi_cmnd *scmnd;
|
||||
struct srp_iu *cmd;
|
||||
union {
|
||||
@ -126,24 +128,62 @@ struct srp_request {
|
||||
struct srp_direct_buf *indirect_desc;
|
||||
dma_addr_t indirect_dma_addr;
|
||||
short nmdesc;
|
||||
short index;
|
||||
};
|
||||
|
||||
struct srp_target_port {
|
||||
/**
|
||||
* struct srp_rdma_ch
|
||||
* @comp_vector: Completion vector used by this RDMA channel.
|
||||
*/
|
||||
struct srp_rdma_ch {
|
||||
/* These are RW in the hot path, and commonly used together */
|
||||
struct list_head free_tx;
|
||||
struct list_head free_reqs;
|
||||
spinlock_t lock;
|
||||
s32 req_lim;
|
||||
|
||||
/* These are read-only in the hot path */
|
||||
struct ib_cq *send_cq ____cacheline_aligned_in_smp;
|
||||
struct srp_target_port *target ____cacheline_aligned_in_smp;
|
||||
struct ib_cq *send_cq;
|
||||
struct ib_cq *recv_cq;
|
||||
struct ib_qp *qp;
|
||||
union {
|
||||
struct ib_fmr_pool *fmr_pool;
|
||||
struct srp_fr_pool *fr_pool;
|
||||
};
|
||||
|
||||
/* Everything above this point is used in the hot path of
|
||||
* command processing. Try to keep them packed into cachelines.
|
||||
*/
|
||||
|
||||
struct completion done;
|
||||
int status;
|
||||
|
||||
struct ib_sa_path_rec path;
|
||||
struct ib_sa_query *path_query;
|
||||
int path_query_id;
|
||||
|
||||
struct ib_cm_id *cm_id;
|
||||
struct srp_iu **tx_ring;
|
||||
struct srp_iu **rx_ring;
|
||||
struct srp_request *req_ring;
|
||||
int max_ti_iu_len;
|
||||
int comp_vector;
|
||||
|
||||
struct completion tsk_mgmt_done;
|
||||
u8 tsk_mgmt_status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct srp_target_port
|
||||
* @comp_vector: Completion vector used by the first RDMA channel created for
|
||||
* this target port.
|
||||
*/
|
||||
struct srp_target_port {
|
||||
/* read and written in the hot path */
|
||||
spinlock_t lock;
|
||||
|
||||
/* read only in the hot path */
|
||||
struct srp_rdma_ch *ch;
|
||||
u32 ch_count;
|
||||
u32 lkey;
|
||||
u32 rkey;
|
||||
enum srp_target_state state;
|
||||
@ -152,10 +192,8 @@ struct srp_target_port {
|
||||
unsigned int indirect_size;
|
||||
bool allow_ext_sg;
|
||||
|
||||
/* Everything above this point is used in the hot path of
|
||||
* command processing. Try to keep them packed into cachelines.
|
||||
*/
|
||||
|
||||
/* other member variables */
|
||||
union ib_gid sgid;
|
||||
__be64 id_ext;
|
||||
__be64 ioc_guid;
|
||||
__be64 service_id;
|
||||
@ -172,34 +210,19 @@ struct srp_target_port {
|
||||
int comp_vector;
|
||||
int tl_retry_count;
|
||||
|
||||
struct ib_sa_path_rec path;
|
||||
__be16 orig_dgid[8];
|
||||
struct ib_sa_query *path_query;
|
||||
int path_query_id;
|
||||
union ib_gid orig_dgid;
|
||||
__be16 pkey;
|
||||
|
||||
u32 rq_tmo_jiffies;
|
||||
bool connected;
|
||||
|
||||
struct ib_cm_id *cm_id;
|
||||
|
||||
int max_ti_iu_len;
|
||||
|
||||
int zero_req_lim;
|
||||
|
||||
struct srp_iu **tx_ring;
|
||||
struct srp_iu **rx_ring;
|
||||
struct srp_request *req_ring;
|
||||
|
||||
struct work_struct tl_err_work;
|
||||
struct work_struct remove_work;
|
||||
|
||||
struct list_head list;
|
||||
struct completion done;
|
||||
int status;
|
||||
bool qp_in_error;
|
||||
|
||||
struct completion tsk_mgmt_done;
|
||||
u8 tsk_mgmt_status;
|
||||
};
|
||||
|
||||
struct srp_iu {
|
||||
|
@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = {
|
||||
.cmd_per_lun = 7,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = mptscsih_host_attrs,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
static int mptsas_get_linkerrors(struct sas_phy *phy)
|
||||
|
@ -2311,26 +2311,21 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
|
||||
* mptscsih_change_queue_depth - This function will set a devices queue depth
|
||||
* @sdev: per scsi_device pointer
|
||||
* @qdepth: requested queue depth
|
||||
* @reason: calling context
|
||||
*
|
||||
* Adding support for new 'change_queue_depth' api.
|
||||
*/
|
||||
int
|
||||
mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
|
||||
mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
|
||||
{
|
||||
MPT_SCSI_HOST *hd = shost_priv(sdev->host);
|
||||
VirtTarget *vtarget;
|
||||
struct scsi_target *starget;
|
||||
int max_depth;
|
||||
int tagged;
|
||||
MPT_ADAPTER *ioc = hd->ioc;
|
||||
|
||||
starget = scsi_target(sdev);
|
||||
vtarget = starget->hostdata;
|
||||
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ioc->bus_type == SPI) {
|
||||
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
|
||||
max_depth = 1;
|
||||
@ -2347,13 +2342,8 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
|
||||
|
||||
if (qdepth > max_depth)
|
||||
qdepth = max_depth;
|
||||
if (qdepth == 1)
|
||||
tagged = 0;
|
||||
else
|
||||
tagged = MSG_SIMPLE_TAG;
|
||||
|
||||
scsi_adjust_queue_depth(sdev, tagged, qdepth);
|
||||
return sdev->queue_depth;
|
||||
return scsi_change_queue_depth(sdev, qdepth);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2397,12 +2387,10 @@ mptscsih_slave_configure(struct scsi_device *sdev)
|
||||
ioc->name, vtarget->negoFlags, vtarget->maxOffset,
|
||||
vtarget->minSyncFactor));
|
||||
|
||||
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
|
||||
SCSI_QDEPTH_DEFAULT);
|
||||
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
|
||||
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||
"tagged %d, simple %d, ordered %d\n",
|
||||
ioc->name,sdev->tagged_supported, sdev->simple_tags,
|
||||
sdev->ordered_tags));
|
||||
"tagged %d, simple %d\n",
|
||||
ioc->name,sdev->tagged_supported, sdev->simple_tags));
|
||||
|
||||
blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
|
||||
|
||||
|
@ -128,8 +128,7 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F
|
||||
extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
|
||||
extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
|
||||
extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
|
||||
extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth,
|
||||
int reason);
|
||||
extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
|
||||
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
|
||||
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
|
||||
extern struct device_attribute *mptscsih_host_attrs[];
|
||||
|
@ -170,7 +170,7 @@ static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
|
||||
}
|
||||
|
||||
/**
|
||||
* eeprom_93cx6_read - Read multiple words from eeprom
|
||||
* eeprom_93cx6_read - Read a word from eeprom
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
* @word: Word index from where we should start reading
|
||||
* @data: target pointer where the information will have to be stored
|
||||
@ -234,6 +234,66 @@ void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
|
||||
|
||||
/**
|
||||
* eeprom_93cx6_readb - Read a byte from eeprom
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
* @word: Byte index from where we should start reading
|
||||
* @data: target pointer where the information will have to be stored
|
||||
*
|
||||
* This function will read a byte of the eeprom data
|
||||
* into the given data pointer.
|
||||
*/
|
||||
void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom, const u8 byte,
|
||||
u8 *data)
|
||||
{
|
||||
u16 command;
|
||||
u16 tmp;
|
||||
|
||||
/*
|
||||
* Initialize the eeprom register
|
||||
*/
|
||||
eeprom_93cx6_startup(eeprom);
|
||||
|
||||
/*
|
||||
* Select the read opcode and the byte to be read.
|
||||
*/
|
||||
command = (PCI_EEPROM_READ_OPCODE << (eeprom->width + 1)) | byte;
|
||||
eeprom_93cx6_write_bits(eeprom, command,
|
||||
PCI_EEPROM_WIDTH_OPCODE + eeprom->width + 1);
|
||||
|
||||
/*
|
||||
* Read the requested 8 bits.
|
||||
*/
|
||||
eeprom_93cx6_read_bits(eeprom, &tmp, 8);
|
||||
*data = tmp & 0xff;
|
||||
|
||||
/*
|
||||
* Cleanup eeprom register.
|
||||
*/
|
||||
eeprom_93cx6_cleanup(eeprom);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eeprom_93cx6_readb);
|
||||
|
||||
/**
|
||||
* eeprom_93cx6_multireadb - Read multiple bytes from eeprom
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
* @byte: Index from where we should start reading
|
||||
* @data: target pointer where the information will have to be stored
|
||||
* @words: Number of bytes that should be read.
|
||||
*
|
||||
* This function will read all requested bytes from the eeprom,
|
||||
* this is done by calling eeprom_93cx6_readb() multiple times.
|
||||
*/
|
||||
void eeprom_93cx6_multireadb(struct eeprom_93cx6 *eeprom, const u8 byte,
|
||||
u8 *data, const u16 bytes)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < bytes; i++)
|
||||
eeprom_93cx6_readb(eeprom, byte + i, &data[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eeprom_93cx6_multireadb);
|
||||
|
||||
/**
|
||||
* eeprom_93cx6_wren - set the write enable state
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
|
@ -187,6 +187,7 @@ void enclosure_unregister(struct enclosure_device *edev)
|
||||
EXPORT_SYMBOL_GPL(enclosure_unregister);
|
||||
|
||||
#define ENCLOSURE_NAME_SIZE 64
|
||||
#define COMPONENT_NAME_SIZE 64
|
||||
|
||||
static void enclosure_link_name(struct enclosure_component *cdev, char *name)
|
||||
{
|
||||
@ -246,6 +247,29 @@ static void enclosure_component_release(struct device *dev)
|
||||
put_device(dev->parent);
|
||||
}
|
||||
|
||||
static struct enclosure_component *
|
||||
enclosure_component_find_by_name(struct enclosure_device *edev,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
const char *cname;
|
||||
struct enclosure_component *ecomp;
|
||||
|
||||
if (!edev || !name || !name[0])
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < edev->components; i++) {
|
||||
ecomp = &edev->component[i];
|
||||
cname = dev_name(&ecomp->cdev);
|
||||
if (ecomp->number != -1 &&
|
||||
cname && cname[0] &&
|
||||
!strcmp(cname, name))
|
||||
return ecomp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct attribute_group *enclosure_component_groups[];
|
||||
|
||||
/**
|
||||
@ -269,7 +293,8 @@ enclosure_component_register(struct enclosure_device *edev,
|
||||
{
|
||||
struct enclosure_component *ecomp;
|
||||
struct device *cdev;
|
||||
int err;
|
||||
int err, i;
|
||||
char newname[COMPONENT_NAME_SIZE];
|
||||
|
||||
if (number >= edev->components)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@ -283,9 +308,20 @@ enclosure_component_register(struct enclosure_device *edev,
|
||||
ecomp->number = number;
|
||||
cdev = &ecomp->cdev;
|
||||
cdev->parent = get_device(&edev->edev);
|
||||
if (name && name[0])
|
||||
dev_set_name(cdev, "%s", name);
|
||||
else
|
||||
|
||||
if (name && name[0]) {
|
||||
/* Some hardware (e.g. enclosure in RX300 S6) has components
|
||||
* with non unique names. Registering duplicates in sysfs
|
||||
* will lead to warnings during bootup. So make the names
|
||||
* unique by appending consecutive numbers -1, -2, ... */
|
||||
i = 1;
|
||||
snprintf(newname, COMPONENT_NAME_SIZE,
|
||||
"%s", name);
|
||||
while (enclosure_component_find_by_name(edev, newname))
|
||||
snprintf(newname, COMPONENT_NAME_SIZE,
|
||||
"%s-%i", name, i++);
|
||||
dev_set_name(cdev, "%s", newname);
|
||||
} else
|
||||
dev_set_name(cdev, "%u", number);
|
||||
|
||||
cdev->release = enclosure_component_release;
|
||||
|
@ -353,9 +353,11 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
|
||||
adapter->ccw_device = ccw_device;
|
||||
|
||||
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
|
||||
INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
|
||||
INIT_DELAYED_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
|
||||
INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update);
|
||||
|
||||
adapter->next_port_scan = jiffies;
|
||||
|
||||
if (zfcp_qdio_setup(adapter))
|
||||
goto failed;
|
||||
|
||||
@ -420,7 +422,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
|
||||
{
|
||||
struct ccw_device *cdev = adapter->ccw_device;
|
||||
|
||||
cancel_work_sync(&adapter->scan_work);
|
||||
cancel_delayed_work_sync(&adapter->scan_work);
|
||||
cancel_work_sync(&adapter->stat_work);
|
||||
cancel_work_sync(&adapter->ns_up_work);
|
||||
zfcp_destroy_adapter_work_queue(adapter);
|
||||
|
@ -56,8 +56,22 @@ static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)
|
||||
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
|
||||
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
tag);
|
||||
|
||||
/*
|
||||
* We want to scan ports here, with some random backoff and without
|
||||
* rate limit. Recovery has already scheduled a port scan for us,
|
||||
* but with both random delay and rate limit. Nevertheless we get
|
||||
* what we want here by flushing the scheduled work after sleeping
|
||||
* an equivalent random time.
|
||||
* Let the port scan random delay elapse first. If recovery finishes
|
||||
* up to that point in time, that would be perfect for both recovery
|
||||
* and port scan. If not, i.e. recovery takes ages, there was no
|
||||
* point in waiting a random delay on top of the time consumed by
|
||||
* recovery.
|
||||
*/
|
||||
msleep(zfcp_fc_port_scan_backoff());
|
||||
zfcp_erp_wait(adapter);
|
||||
flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
|
||||
flush_delayed_work(&adapter->scan_work);
|
||||
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
|
||||
@ -162,11 +176,19 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
|
||||
adapter->req_no = 0;
|
||||
|
||||
zfcp_ccw_activate(cdev, 0, "ccsonl1");
|
||||
/* scan for remote ports
|
||||
either at the end of any successful adapter recovery
|
||||
or only after the adapter recovery for setting a device online */
|
||||
|
||||
/*
|
||||
* We want to scan ports here, always, with some random delay and
|
||||
* without rate limit - basically what zfcp_ccw_activate() has
|
||||
* achieved for us. Not quite! That port scan depended on
|
||||
* !no_auto_port_rescan. So let's cover the no_auto_port_rescan
|
||||
* case here to make sure a port scan is done unconditionally.
|
||||
* Since zfcp_ccw_activate() has waited the desired random time,
|
||||
* we can immediately schedule and flush a port scan for the
|
||||
* remaining cases.
|
||||
*/
|
||||
zfcp_fc_inverse_conditional_port_scan(adapter);
|
||||
flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
|
||||
flush_delayed_work(&adapter->scan_work);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
return 0;
|
||||
}
|
||||
|
@ -186,12 +186,13 @@ struct zfcp_adapter {
|
||||
struct fc_host_statistics *fc_stats;
|
||||
struct fsf_qtcb_bottom_port *stats_reset_data;
|
||||
unsigned long stats_reset;
|
||||
struct work_struct scan_work;
|
||||
struct delayed_work scan_work;
|
||||
struct work_struct ns_up_work;
|
||||
struct service_level service_level;
|
||||
struct workqueue_struct *work_queue;
|
||||
struct device_dma_parameters dma_parms;
|
||||
struct zfcp_fc_events events;
|
||||
unsigned long next_port_scan;
|
||||
};
|
||||
|
||||
struct zfcp_port {
|
||||
|
@ -821,11 +821,6 @@ static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
|
||||
return ZFCP_ERP_CONTINUES;
|
||||
}
|
||||
|
||||
static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
|
||||
{
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
|
||||
}
|
||||
|
||||
static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
|
||||
{
|
||||
struct zfcp_port *port = erp_action->port;
|
||||
@ -833,7 +828,6 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
|
||||
|
||||
switch (erp_action->step) {
|
||||
case ZFCP_ERP_STEP_UNINITIALIZED:
|
||||
zfcp_erp_port_strategy_clearstati(port);
|
||||
if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
|
||||
(status & ZFCP_STATUS_COMMON_OPEN))
|
||||
return zfcp_erp_port_forced_strategy_close(erp_action);
|
||||
@ -933,7 +927,6 @@ static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
|
||||
|
||||
switch (erp_action->step) {
|
||||
case ZFCP_ERP_STEP_UNINITIALIZED:
|
||||
zfcp_erp_port_strategy_clearstati(port);
|
||||
if (p_status & ZFCP_STATUS_COMMON_OPEN)
|
||||
return zfcp_erp_port_strategy_close(erp_action);
|
||||
break;
|
||||
|
@ -85,6 +85,7 @@ extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
|
||||
extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
|
||||
extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *);
|
||||
extern void zfcp_fc_sym_name_update(struct work_struct *);
|
||||
extern unsigned int zfcp_fc_port_scan_backoff(void);
|
||||
extern void zfcp_fc_conditional_port_scan(struct zfcp_adapter *);
|
||||
extern void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/random.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include <scsi/libfc.h>
|
||||
#include "zfcp_ext.h"
|
||||
@ -31,12 +32,54 @@ module_param_named(no_auto_port_rescan, no_auto_port_rescan, bool, 0600);
|
||||
MODULE_PARM_DESC(no_auto_port_rescan,
|
||||
"no automatic port_rescan (default off)");
|
||||
|
||||
static unsigned int port_scan_backoff = 500;
|
||||
module_param(port_scan_backoff, uint, 0600);
|
||||
MODULE_PARM_DESC(port_scan_backoff,
|
||||
"upper limit of port scan random backoff in msecs (default 500)");
|
||||
|
||||
static unsigned int port_scan_ratelimit = 60000;
|
||||
module_param(port_scan_ratelimit, uint, 0600);
|
||||
MODULE_PARM_DESC(port_scan_ratelimit,
|
||||
"minimum interval between port scans in msecs (default 60000)");
|
||||
|
||||
unsigned int zfcp_fc_port_scan_backoff(void)
|
||||
{
|
||||
if (!port_scan_backoff)
|
||||
return 0;
|
||||
return get_random_int() % port_scan_backoff;
|
||||
}
|
||||
|
||||
static void zfcp_fc_port_scan_time(struct zfcp_adapter *adapter)
|
||||
{
|
||||
unsigned long interval = msecs_to_jiffies(port_scan_ratelimit);
|
||||
unsigned long backoff = msecs_to_jiffies(zfcp_fc_port_scan_backoff());
|
||||
|
||||
adapter->next_port_scan = jiffies + interval + backoff;
|
||||
}
|
||||
|
||||
static void zfcp_fc_port_scan(struct zfcp_adapter *adapter)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
unsigned long next = adapter->next_port_scan;
|
||||
unsigned long delay = 0, max;
|
||||
|
||||
/* delay only needed within waiting period */
|
||||
if (time_before(now, next)) {
|
||||
delay = next - now;
|
||||
/* paranoia: never ever delay scans longer than specified */
|
||||
max = msecs_to_jiffies(port_scan_ratelimit + port_scan_backoff);
|
||||
delay = min(delay, max);
|
||||
}
|
||||
|
||||
queue_delayed_work(adapter->work_queue, &adapter->scan_work, delay);
|
||||
}
|
||||
|
||||
void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter)
|
||||
{
|
||||
if (no_auto_port_rescan)
|
||||
return;
|
||||
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
zfcp_fc_port_scan(adapter);
|
||||
}
|
||||
|
||||
void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter)
|
||||
@ -44,7 +87,7 @@ void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter)
|
||||
if (!no_auto_port_rescan)
|
||||
return;
|
||||
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
zfcp_fc_port_scan(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -680,12 +723,15 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_req *fc_req,
|
||||
*/
|
||||
void zfcp_fc_scan_ports(struct work_struct *work)
|
||||
{
|
||||
struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct zfcp_adapter *adapter = container_of(dw, struct zfcp_adapter,
|
||||
scan_work);
|
||||
int ret, i;
|
||||
struct zfcp_fc_req *fc_req;
|
||||
int chain, max_entries, buf_num, max_bytes;
|
||||
|
||||
zfcp_fc_port_scan_time(adapter);
|
||||
|
||||
chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS;
|
||||
buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1;
|
||||
max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE;
|
||||
|
@ -212,8 +212,6 @@ static inline
|
||||
void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi,
|
||||
u8 tm_flags)
|
||||
{
|
||||
char tag[2];
|
||||
|
||||
int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
|
||||
|
||||
if (unlikely(tm_flags)) {
|
||||
@ -221,17 +219,7 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi,
|
||||
return;
|
||||
}
|
||||
|
||||
if (scsi_populate_tag_msg(scsi, tag)) {
|
||||
switch (tag[0]) {
|
||||
case MSG_ORDERED_TAG:
|
||||
fcp->fc_pri_ta |= FCP_PTA_ORDERED;
|
||||
break;
|
||||
case MSG_SIMPLE_TAG:
|
||||
fcp->fc_pri_ta |= FCP_PTA_SIMPLE;
|
||||
break;
|
||||
};
|
||||
} else
|
||||
fcp->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
fcp->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
|
||||
if (scsi->sc_data_direction == DMA_FROM_DEVICE)
|
||||
fcp->fc_flags |= FCP_CFL_RDDATA;
|
||||
|
@ -1396,8 +1396,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
|
||||
port->handle = header->port_handle;
|
||||
atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
|
||||
ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
|
||||
ZFCP_STATUS_COMMON_ACCESS_BOXED,
|
||||
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED,
|
||||
&port->status);
|
||||
/* check whether D_ID has changed during open */
|
||||
/*
|
||||
|
@ -32,25 +32,6 @@ static bool allow_lun_scan = 1;
|
||||
module_param(allow_lun_scan, bool, 0600);
|
||||
MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs");
|
||||
|
||||
static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
|
||||
int reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case SCSI_QDEPTH_DEFAULT:
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
break;
|
||||
case SCSI_QDEPTH_QFULL:
|
||||
scsi_track_queue_full(sdev, depth);
|
||||
break;
|
||||
case SCSI_QDEPTH_RAMP_UP:
|
||||
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return sdev->queue_depth;
|
||||
}
|
||||
|
||||
static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
|
||||
{
|
||||
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||||
@ -66,9 +47,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
|
||||
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
|
||||
{
|
||||
if (sdp->tagged_supported)
|
||||
scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth);
|
||||
else
|
||||
scsi_adjust_queue_depth(sdp, 0, 1);
|
||||
scsi_change_queue_depth(sdp, default_depth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -307,7 +286,7 @@ static struct scsi_host_template zfcp_scsi_host_template = {
|
||||
.slave_alloc = zfcp_scsi_slave_alloc,
|
||||
.slave_configure = zfcp_scsi_slave_configure,
|
||||
.slave_destroy = zfcp_scsi_slave_destroy,
|
||||
.change_queue_depth = zfcp_scsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.proc_name = "zfcp",
|
||||
.can_queue = 4096,
|
||||
.this_id = -1,
|
||||
@ -322,6 +301,7 @@ static struct scsi_host_template zfcp_scsi_host_template = {
|
||||
.use_clustering = 1,
|
||||
.shost_attrs = zfcp_sysfs_shost_attrs,
|
||||
.sdev_attrs = zfcp_sysfs_sdev_attrs,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -73,9 +73,7 @@ ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n",
|
||||
ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n",
|
||||
(atomic_read(&port->status) &
|
||||
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
|
||||
ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n",
|
||||
(atomic_read(&port->status) &
|
||||
ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
|
||||
ZFCP_DEFINE_ATTR_CONST(port, access_denied, "%d\n", 0);
|
||||
|
||||
ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n",
|
||||
zfcp_unit_sdev_status(unit));
|
||||
@ -223,9 +221,13 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
|
||||
if (!adapter)
|
||||
return -ENODEV;
|
||||
|
||||
/* sync the user-space- with the kernel-invocation of scan_work */
|
||||
queue_work(adapter->work_queue, &adapter->scan_work);
|
||||
flush_work(&adapter->scan_work);
|
||||
/*
|
||||
* Users wish is our command: immediately schedule and flush a
|
||||
* worker to conduct a synchronous port scan, that is, neither
|
||||
* a random delay nor a rate limit is applied here.
|
||||
*/
|
||||
queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0);
|
||||
flush_delayed_work(&adapter->scan_work);
|
||||
zfcp_ccw_adapter_put(adapter);
|
||||
|
||||
return (ssize_t) count;
|
||||
@ -439,16 +441,15 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \
|
||||
{ \
|
||||
struct scsi_device *sdev = to_scsi_device(dev); \
|
||||
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \
|
||||
struct zfcp_port *port = zfcp_sdev->port; \
|
||||
\
|
||||
return sprintf(buf, _format, _value); \
|
||||
} \
|
||||
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
|
||||
|
||||
ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
|
||||
dev_name(&port->adapter->ccw_device->dev));
|
||||
dev_name(&zfcp_sdev->port->adapter->ccw_device->dev));
|
||||
ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
|
||||
(unsigned long long) port->wwpn);
|
||||
(unsigned long long) zfcp_sdev->port->wwpn);
|
||||
|
||||
static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
@ -460,6 +461,49 @@ static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL);
|
||||
|
||||
ZFCP_DEFINE_SCSI_ATTR(zfcp_access_denied, "%d\n",
|
||||
(atomic_read(&zfcp_sdev->status) &
|
||||
ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
|
||||
|
||||
static ssize_t zfcp_sysfs_scsi_zfcp_failed_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
unsigned int status = atomic_read(&sdev_to_zfcp(sdev)->status);
|
||||
unsigned int failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0;
|
||||
|
||||
return sprintf(buf, "%d\n", failed);
|
||||
}
|
||||
|
||||
static ssize_t zfcp_sysfs_scsi_zfcp_failed_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 0, &val) || val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
|
||||
zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
|
||||
"syufai3");
|
||||
zfcp_erp_wait(sdev_to_zfcp(sdev)->port->adapter);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(zfcp_failed, S_IWUSR | S_IRUGO,
|
||||
zfcp_sysfs_scsi_zfcp_failed_show,
|
||||
zfcp_sysfs_scsi_zfcp_failed_store);
|
||||
|
||||
ZFCP_DEFINE_SCSI_ATTR(zfcp_in_recovery, "%d\n",
|
||||
(atomic_read(&zfcp_sdev->status) &
|
||||
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
|
||||
|
||||
ZFCP_DEFINE_SCSI_ATTR(zfcp_status, "0x%08x\n",
|
||||
atomic_read(&zfcp_sdev->status));
|
||||
|
||||
struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
|
||||
&dev_attr_fcp_lun,
|
||||
&dev_attr_wwpn,
|
||||
@ -467,6 +511,10 @@ struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
|
||||
&dev_attr_read_latency,
|
||||
&dev_attr_write_latency,
|
||||
&dev_attr_cmd_latency,
|
||||
&dev_attr_zfcp_access_denied,
|
||||
&dev_attr_zfcp_failed,
|
||||
&dev_attr_zfcp_in_recovery,
|
||||
&dev_attr_zfcp_status,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -189,19 +189,6 @@ static ssize_t twa_show_stats(struct device *dev,
|
||||
return len;
|
||||
} /* End twa_show_stats() */
|
||||
|
||||
/* This function will set a devices queue depth */
|
||||
static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
|
||||
int reason)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (queue_depth > TW_Q_LENGTH-2)
|
||||
queue_depth = TW_Q_LENGTH-2;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
} /* End twa_change_queue_depth() */
|
||||
|
||||
/* Create sysfs 'stats' entry */
|
||||
static struct device_attribute twa_host_stats_attr = {
|
||||
.attr = {
|
||||
@ -2016,7 +2003,7 @@ static struct scsi_host_template driver_template = {
|
||||
.queuecommand = twa_scsi_queue,
|
||||
.eh_host_reset_handler = twa_scsi_eh_reset,
|
||||
.bios_param = twa_scsi_biosparam,
|
||||
.change_queue_depth = twa_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.can_queue = TW_Q_LENGTH-2,
|
||||
.slave_configure = twa_slave_configure,
|
||||
.this_id = -1,
|
||||
|
@ -191,19 +191,6 @@ static ssize_t twl_show_stats(struct device *dev,
|
||||
return len;
|
||||
} /* End twl_show_stats() */
|
||||
|
||||
/* This function will set a devices queue depth */
|
||||
static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth,
|
||||
int reason)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (queue_depth > TW_Q_LENGTH-2)
|
||||
queue_depth = TW_Q_LENGTH-2;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
} /* End twl_change_queue_depth() */
|
||||
|
||||
/* stats sysfs attribute initializer */
|
||||
static struct device_attribute twl_host_stats_attr = {
|
||||
.attr = {
|
||||
@ -1590,7 +1577,7 @@ static struct scsi_host_template driver_template = {
|
||||
.queuecommand = twl_scsi_queue,
|
||||
.eh_host_reset_handler = twl_scsi_eh_reset,
|
||||
.bios_param = twl_scsi_biosparam,
|
||||
.change_queue_depth = twl_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.can_queue = TW_Q_LENGTH-2,
|
||||
.slave_configure = twl_slave_configure,
|
||||
.this_id = -1,
|
||||
|
@ -523,19 +523,6 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr,
|
||||
return len;
|
||||
} /* End tw_show_stats() */
|
||||
|
||||
/* This function will set a devices queue depth */
|
||||
static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth,
|
||||
int reason)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (queue_depth > TW_Q_LENGTH-2)
|
||||
queue_depth = TW_Q_LENGTH-2;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
} /* End tw_change_queue_depth() */
|
||||
|
||||
/* Create sysfs 'stats' entry */
|
||||
static struct device_attribute tw_host_stats_attr = {
|
||||
.attr = {
|
||||
@ -2270,7 +2257,7 @@ static struct scsi_host_template driver_template = {
|
||||
.queuecommand = tw_scsi_queue,
|
||||
.eh_host_reset_handler = tw_scsi_eh_reset,
|
||||
.bios_param = tw_scsi_biosparam,
|
||||
.change_queue_depth = tw_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.can_queue = TW_Q_LENGTH-2,
|
||||
.slave_configure = tw_slave_configure,
|
||||
.this_id = -1,
|
||||
|
@ -175,7 +175,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
|
||||
STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
|
||||
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
|
||||
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
|
||||
static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth, int reason);
|
||||
static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
|
||||
static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
|
||||
|
||||
STATIC struct device_attribute *NCR_700_dev_attrs[];
|
||||
@ -327,6 +327,7 @@ NCR_700_detect(struct scsi_host_template *tpnt,
|
||||
tpnt->slave_alloc = NCR_700_slave_alloc;
|
||||
tpnt->change_queue_depth = NCR_700_change_queue_depth;
|
||||
tpnt->change_queue_type = NCR_700_change_queue_type;
|
||||
tpnt->use_blk_tags = 1;
|
||||
|
||||
if(tpnt->name == NULL)
|
||||
tpnt->name = "53c700";
|
||||
@ -592,19 +593,14 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
|
||||
hostdata->cmd = NULL;
|
||||
|
||||
if(SCp != NULL) {
|
||||
struct NCR_700_command_slot *slot =
|
||||
struct NCR_700_command_slot *slot =
|
||||
(struct NCR_700_command_slot *)SCp->host_scribble;
|
||||
|
||||
|
||||
dma_unmap_single(hostdata->dev, slot->pCmd,
|
||||
MAX_COMMAND_SIZE, DMA_TO_DEVICE);
|
||||
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
|
||||
char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
|
||||
#ifdef NCR_700_DEBUG
|
||||
printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
|
||||
SCp, SCp->cmnd[7], result);
|
||||
scsi_print_sense("53c700", SCp);
|
||||
|
||||
#endif
|
||||
dma_unmap_single(hostdata->dev, slot->dma_handle,
|
||||
SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
|
||||
/* restore the old result if the request sense was
|
||||
@ -906,8 +902,10 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata
|
||||
/* we're done negotiating */
|
||||
NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
|
||||
hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
|
||||
|
||||
SCp->device->tagged_supported = 0;
|
||||
scsi_deactivate_tcq(SCp->device, host->cmd_per_lun);
|
||||
scsi_change_queue_depth(SCp->device, host->cmd_per_lun);
|
||||
scsi_set_tag_type(SCp->device, 0);
|
||||
} else {
|
||||
shost_printk(KERN_WARNING, host,
|
||||
"(%d:%d) Unexpected REJECT Message %s\n",
|
||||
@ -1432,7 +1430,7 @@ NCR_700_start_command(struct scsi_cmnd *SCp)
|
||||
if((hostdata->tag_negotiated & (1<<scmd_id(SCp)))
|
||||
&& (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE &&
|
||||
slot->flags != NCR_700_FLAG_AUTOSENSE)) {
|
||||
count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]);
|
||||
count += spi_populate_tag_msg(&hostdata->msgout[count], SCp);
|
||||
}
|
||||
|
||||
if(hostdata->fast &&
|
||||
@ -1772,7 +1770,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
|
||||
*/
|
||||
if(NCR_700_get_depth(SCp->device) != 0
|
||||
&& (!(hostdata->tag_negotiated & (1<<scmd_id(SCp)))
|
||||
|| !blk_rq_tagged(SCp->request))) {
|
||||
|| !(SCp->flags & SCMD_TAGGED))) {
|
||||
CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n",
|
||||
NCR_700_get_depth(SCp->device));
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
@ -1800,7 +1798,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
|
||||
printk("53c700: scsi%d, command ", SCp->device->host->host_no);
|
||||
scsi_print_command(SCp);
|
||||
#endif
|
||||
if(blk_rq_tagged(SCp->request)
|
||||
if ((SCp->flags & SCMD_TAGGED)
|
||||
&& (hostdata->tag_negotiated &(1<<scmd_id(SCp))) == 0
|
||||
&& NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
|
||||
scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n");
|
||||
@ -1814,7 +1812,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
|
||||
*
|
||||
* FIXME: This will royally screw up on multiple LUN devices
|
||||
* */
|
||||
if(!blk_rq_tagged(SCp->request)
|
||||
if (!(SCp->flags & SCMD_TAGGED)
|
||||
&& (hostdata->tag_negotiated &(1<<scmd_id(SCp)))) {
|
||||
scmd_printk(KERN_INFO, SCp, "Disabling Tag Command Queuing\n");
|
||||
hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
|
||||
@ -1911,9 +1909,7 @@ NCR_700_abort(struct scsi_cmnd * SCp)
|
||||
{
|
||||
struct NCR_700_command_slot *slot;
|
||||
|
||||
scmd_printk(KERN_INFO, SCp,
|
||||
"New error handler wants to abort command\n\t");
|
||||
scsi_print_command(SCp);
|
||||
scmd_printk(KERN_INFO, SCp, "abort command\n");
|
||||
|
||||
slot = (struct NCR_700_command_slot *)SCp->host_scribble;
|
||||
|
||||
@ -2056,13 +2052,10 @@ NCR_700_slave_configure(struct scsi_device *SDp)
|
||||
|
||||
/* to do here: allocate memory; build a queue_full list */
|
||||
if(SDp->tagged_supported) {
|
||||
scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
|
||||
scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS);
|
||||
scsi_change_queue_depth(SDp, NCR_700_DEFAULT_TAGS);
|
||||
NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
|
||||
} else {
|
||||
/* initialise to default depth */
|
||||
scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
|
||||
}
|
||||
|
||||
if(hostdata->fast) {
|
||||
/* Find the correct offset and period via domain validation */
|
||||
if (!spi_initial_dv(SDp->sdev_target))
|
||||
@ -2082,16 +2075,11 @@ NCR_700_slave_destroy(struct scsi_device *SDp)
|
||||
}
|
||||
|
||||
static int
|
||||
NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason)
|
||||
NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (depth > NCR_700_MAX_TAGS)
|
||||
depth = NCR_700_MAX_TAGS;
|
||||
|
||||
scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth);
|
||||
return depth;
|
||||
return scsi_change_queue_depth(SDp, depth);
|
||||
}
|
||||
|
||||
static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
|
||||
@ -2101,8 +2089,6 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
|
||||
struct NCR_700_Host_Parameters *hostdata =
|
||||
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
|
||||
|
||||
scsi_set_tag_type(SDp, tag_type);
|
||||
|
||||
/* We have a global (per target) flag to track whether TCQ is
|
||||
* enabled, so we'll be turning it off for the entire target here.
|
||||
* our tag algorithm will fail if we mix tagged and untagged commands,
|
||||
@ -2110,15 +2096,16 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
|
||||
if (change_tag)
|
||||
scsi_target_quiesce(SDp->sdev_target);
|
||||
|
||||
scsi_set_tag_type(SDp, tag_type);
|
||||
if (!tag_type) {
|
||||
/* shift back to the default unqueued number of commands
|
||||
* (the user can still raise this) */
|
||||
scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun);
|
||||
scsi_change_queue_depth(SDp, SDp->host->cmd_per_lun);
|
||||
hostdata->tag_negotiated &= ~(1 << sdev_id(SDp));
|
||||
} else {
|
||||
/* Here, we cleared the negotiation flag above, so this
|
||||
* will force the driver to renegotiate */
|
||||
scsi_activate_tcq(SDp, SDp->queue_depth);
|
||||
scsi_change_queue_depth(SDp, SDp->queue_depth);
|
||||
if (change_tag)
|
||||
NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
|
||||
}
|
||||
|
@ -2327,12 +2327,12 @@ static int blogic_slaveconfig(struct scsi_device *dev)
|
||||
if (qdepth == 0)
|
||||
qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH;
|
||||
adapter->qdepth[tgt_id] = qdepth;
|
||||
scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, qdepth);
|
||||
scsi_change_queue_depth(dev, qdepth);
|
||||
} else {
|
||||
adapter->tagq_ok &= ~(1 << tgt_id);
|
||||
qdepth = adapter->untag_qdepth;
|
||||
adapter->qdepth[tgt_id] = qdepth;
|
||||
scsi_adjust_queue_depth(dev, 0, qdepth);
|
||||
scsi_change_queue_depth(dev, qdepth);
|
||||
}
|
||||
qdepth = 0;
|
||||
for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
|
||||
|
@ -1341,13 +1341,15 @@ config SCSI_DC395x
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called dc395x.
|
||||
|
||||
config SCSI_DC390T
|
||||
tristate "Tekram DC390(T) and Am53/79C974 SCSI support"
|
||||
config SCSI_AM53C974
|
||||
tristate "Tekram DC390(T) and Am53/79C974 SCSI support (new driver)"
|
||||
depends on PCI && SCSI
|
||||
select SCSI_SPI_ATTRS
|
||||
---help---
|
||||
This driver supports PCI SCSI host adapters based on the Am53C974A
|
||||
chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
|
||||
PCscsi/PCnet (Am53/79C974) solutions.
|
||||
This is a new implementation base on the generic esp_scsi driver.
|
||||
|
||||
Documentation can be found in <file:Documentation/scsi/tmscsim.txt>.
|
||||
|
||||
@ -1355,7 +1357,7 @@ config SCSI_DC390T
|
||||
based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tmscsim.
|
||||
module will be called am53c974.
|
||||
|
||||
config SCSI_T128
|
||||
tristate "Trantor T128/T128F/T228 SCSI support"
|
||||
@ -1451,6 +1453,14 @@ config SCSI_NSP32
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called nsp32.
|
||||
|
||||
config SCSI_WD719X
|
||||
tristate "Western Digital WD7193/7197/7296 support"
|
||||
depends on PCI && SCSI
|
||||
select EEPROM_93CX6
|
||||
---help---
|
||||
This is a driver for Western Digital WD7193, WD7197 and WD7296 PCI
|
||||
SCSI controllers (based on WD33C296A chip).
|
||||
|
||||
config SCSI_DEBUG
|
||||
tristate "SCSI debugging host simulator"
|
||||
depends on SCSI
|
||||
@ -1615,7 +1625,7 @@ config ATARI_SCSI_RESET_BOOT
|
||||
that leave the devices with SCSI operations partway completed.
|
||||
|
||||
config MAC_SCSI
|
||||
bool "Macintosh NCR5380 SCSI"
|
||||
tristate "Macintosh NCR5380 SCSI"
|
||||
depends on MAC && SCSI=y
|
||||
select SCSI_SPI_ATTRS
|
||||
help
|
||||
|
@ -100,7 +100,7 @@ obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
|
||||
obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
|
||||
obj-$(CONFIG_SCSI_EATA) += eata.o
|
||||
obj-$(CONFIG_SCSI_DC395x) += dc395x.o
|
||||
obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
|
||||
obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o
|
||||
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
|
||||
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
|
||||
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
|
||||
@ -143,6 +143,7 @@ obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
|
||||
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
|
||||
obj-$(CONFIG_XEN_SCSI_FRONTEND) += xen-scsifront.o
|
||||
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
|
||||
obj-$(CONFIG_SCSI_WD719X) += wd719x.o
|
||||
|
||||
obj-$(CONFIG_ARM) += arm/
|
||||
|
||||
|
@ -11,8 +11,6 @@
|
||||
* drew@colorado.edu
|
||||
* +1 (303) 666-5836
|
||||
*
|
||||
* DISTRIBUTION RELEASE 6.
|
||||
*
|
||||
* For more information, please consult
|
||||
*
|
||||
* NCR 5380 Family
|
||||
@ -279,7 +277,7 @@ static void do_reset(struct Scsi_Host *host);
|
||||
* Set up the internal fields in the SCSI command.
|
||||
*/
|
||||
|
||||
static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
|
||||
static inline void initialize_SCp(struct scsi_cmnd *cmd)
|
||||
{
|
||||
/*
|
||||
* Initialize the Scsi Pointer field so that all of the commands in the
|
||||
@ -574,12 +572,12 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
|
||||
int trying_irqs, i, mask;
|
||||
NCR5380_setup(instance);
|
||||
|
||||
for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
|
||||
for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
|
||||
if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
|
||||
trying_irqs |= mask;
|
||||
|
||||
timeout = jiffies + (250 * HZ / 1000);
|
||||
probe_irq = SCSI_IRQ_NONE;
|
||||
probe_irq = NO_IRQ;
|
||||
|
||||
/*
|
||||
* A interrupt is triggered whenever BSY = false, SEL = true
|
||||
@ -596,13 +594,13 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
|
||||
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
|
||||
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
|
||||
|
||||
while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout))
|
||||
while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
|
||||
schedule_timeout_uninterruptible(1);
|
||||
|
||||
NCR5380_write(SELECT_ENABLE_REG, 0);
|
||||
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
|
||||
|
||||
for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
|
||||
for (i = 1, mask = 2; i < 16; ++i, mask <<= 1)
|
||||
if (trying_irqs & mask)
|
||||
free_irq(i, NULL);
|
||||
|
||||
@ -610,50 +608,70 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
|
||||
}
|
||||
|
||||
/**
|
||||
* NCR58380_print_options - show options
|
||||
* @instance: unused for now
|
||||
* NCR58380_info - report driver and host information
|
||||
* @instance: relevant scsi host instance
|
||||
*
|
||||
* Called by probe code indicating the NCR5380 driver options that
|
||||
* were selected. At some point this will switch to runtime options
|
||||
* read from the adapter in question
|
||||
* For use as the host template info() handler.
|
||||
*
|
||||
* Locks: none
|
||||
*/
|
||||
|
||||
static void __init __maybe_unused
|
||||
NCR5380_print_options(struct Scsi_Host *instance)
|
||||
static const char *NCR5380_info(struct Scsi_Host *instance)
|
||||
{
|
||||
printk(" generic options"
|
||||
#ifdef AUTOPROBE_IRQ
|
||||
" AUTOPROBE_IRQ"
|
||||
struct NCR5380_hostdata *hostdata = shost_priv(instance);
|
||||
|
||||
return hostdata->info;
|
||||
}
|
||||
|
||||
static void prepare_info(struct Scsi_Host *instance)
|
||||
{
|
||||
struct NCR5380_hostdata *hostdata = shost_priv(instance);
|
||||
|
||||
snprintf(hostdata->info, sizeof(hostdata->info),
|
||||
"%s, io_port 0x%lx, n_io_port %d, "
|
||||
"base 0x%lx, irq %d, "
|
||||
"can_queue %d, cmd_per_lun %d, "
|
||||
"sg_tablesize %d, this_id %d, "
|
||||
"flags { %s%s%s}, "
|
||||
#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
|
||||
"USLEEP_POLL %d, USLEEP_WAITLONG %d, "
|
||||
#endif
|
||||
#ifdef AUTOSENSE
|
||||
" AUTOSENSE"
|
||||
"options { %s} ",
|
||||
instance->hostt->name, instance->io_port, instance->n_io_port,
|
||||
instance->base, instance->irq,
|
||||
instance->can_queue, instance->cmd_per_lun,
|
||||
instance->sg_tablesize, instance->this_id,
|
||||
hostdata->flags & FLAG_NCR53C400 ? "NCR53C400 " : "",
|
||||
hostdata->flags & FLAG_DTC3181E ? "DTC3181E " : "",
|
||||
hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
|
||||
#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
|
||||
USLEEP_POLL, USLEEP_WAITLONG,
|
||||
#endif
|
||||
#ifdef AUTOPROBE_IRQ
|
||||
"AUTOPROBE_IRQ "
|
||||
#endif
|
||||
#ifdef DIFFERENTIAL
|
||||
" DIFFERENTIAL"
|
||||
"DIFFERENTIAL "
|
||||
#endif
|
||||
#ifdef REAL_DMA
|
||||
" REAL DMA"
|
||||
"REAL_DMA "
|
||||
#endif
|
||||
#ifdef REAL_DMA_POLL
|
||||
" REAL DMA POLL"
|
||||
"REAL_DMA_POLL "
|
||||
#endif
|
||||
#ifdef PARITY
|
||||
" PARITY"
|
||||
"PARITY "
|
||||
#endif
|
||||
#ifdef PSEUDO_DMA
|
||||
" PSEUDO DMA"
|
||||
"PSEUDO_DMA "
|
||||
#endif
|
||||
#ifdef UNSAFE
|
||||
" UNSAFE "
|
||||
"UNSAFE "
|
||||
#endif
|
||||
);
|
||||
printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
|
||||
printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
|
||||
if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {
|
||||
printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);
|
||||
}
|
||||
#ifdef NCR53C400
|
||||
"NCR53C400 "
|
||||
#endif
|
||||
"");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -672,6 +690,7 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
|
||||
NCR5380_dprint_phase(NDEBUG_ANY, instance);
|
||||
}
|
||||
|
||||
#ifdef PSEUDO_DMA
|
||||
/******************************************/
|
||||
/*
|
||||
* /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
|
||||
@ -689,19 +708,18 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
|
||||
static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
|
||||
char *buffer, int length)
|
||||
{
|
||||
#ifdef DTC_PUBLIC_RELEASE
|
||||
dtc_wmaxi = dtc_maxi = 0;
|
||||
#endif
|
||||
#ifdef PAS16_PUBLIC_RELEASE
|
||||
pas_wmaxi = pas_maxi = 0;
|
||||
#endif
|
||||
return (-ENOSYS); /* Currently this is a no-op */
|
||||
struct NCR5380_hostdata *hostdata = shost_priv(instance);
|
||||
|
||||
hostdata->spin_max_r = 0;
|
||||
hostdata->spin_max_w = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef SPRINTF
|
||||
#define SPRINTF(args...) seq_printf(m, ## args)
|
||||
static
|
||||
void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m);
|
||||
void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
|
||||
static
|
||||
void lprint_command(unsigned char *cmd, struct seq_file *m);
|
||||
static
|
||||
@ -711,56 +729,31 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
|
||||
struct Scsi_Host *instance)
|
||||
{
|
||||
struct NCR5380_hostdata *hostdata;
|
||||
Scsi_Cmnd *ptr;
|
||||
struct scsi_cmnd *ptr;
|
||||
|
||||
hostdata = (struct NCR5380_hostdata *) instance->hostdata;
|
||||
|
||||
SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE);
|
||||
if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400)
|
||||
SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE);
|
||||
#ifdef DTC_PUBLIC_RELEASE
|
||||
SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);
|
||||
#endif
|
||||
#ifdef T128_PUBLIC_RELEASE
|
||||
SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);
|
||||
#endif
|
||||
#ifdef GENERIC_NCR5380_PUBLIC_RELEASE
|
||||
SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);
|
||||
#endif
|
||||
#ifdef PAS16_PUBLIC_RELEASE
|
||||
SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
|
||||
#endif
|
||||
|
||||
SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base);
|
||||
SPRINTF("io_port: %04x ", (int) instance->io_port);
|
||||
if (instance->irq == SCSI_IRQ_NONE)
|
||||
SPRINTF("IRQ: None.\n");
|
||||
else
|
||||
SPRINTF("IRQ: %d.\n", instance->irq);
|
||||
|
||||
#ifdef DTC_PUBLIC_RELEASE
|
||||
SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi);
|
||||
#endif
|
||||
#ifdef PAS16_PUBLIC_RELEASE
|
||||
SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi);
|
||||
#ifdef PSEUDO_DMA
|
||||
SPRINTF("Highwater I/O busy spin counts: write %d, read %d\n",
|
||||
hostdata->spin_max_w, hostdata->spin_max_r);
|
||||
#endif
|
||||
spin_lock_irq(instance->host_lock);
|
||||
if (!hostdata->connected)
|
||||
SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
|
||||
else
|
||||
lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
|
||||
lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
|
||||
SPRINTF("scsi%d: issue_queue\n", instance->host_no);
|
||||
for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
|
||||
for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
|
||||
lprint_Scsi_Cmnd(ptr, m);
|
||||
|
||||
SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
|
||||
for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
|
||||
for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
|
||||
lprint_Scsi_Cmnd(ptr, m);
|
||||
spin_unlock_irq(instance->host_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m)
|
||||
static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
|
||||
{
|
||||
SPRINTF("scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
|
||||
SPRINTF(" command = ");
|
||||
@ -836,18 +829,6 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
|
||||
|
||||
INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
|
||||
|
||||
#ifdef NCR5380_STATS
|
||||
for (i = 0; i < 8; ++i) {
|
||||
hostdata->time_read[i] = 0;
|
||||
hostdata->time_write[i] = 0;
|
||||
hostdata->bytes_read[i] = 0;
|
||||
hostdata->bytes_write[i] = 0;
|
||||
}
|
||||
hostdata->timebase = 0;
|
||||
hostdata->pendingw = 0;
|
||||
hostdata->pendingr = 0;
|
||||
#endif
|
||||
|
||||
/* The CHECK code seems to break the 53C400. Will check it later maybe */
|
||||
if (flags & FLAG_NCR53C400)
|
||||
hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
|
||||
@ -857,11 +838,7 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
|
||||
hostdata->host = instance;
|
||||
hostdata->time_expires = 0;
|
||||
|
||||
#ifndef AUTOSENSE
|
||||
if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)
|
||||
printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n"
|
||||
" be incorrectly cleared.\n", instance->host_no);
|
||||
#endif /* def AUTOSENSE */
|
||||
prepare_info(instance);
|
||||
|
||||
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
|
||||
NCR5380_write(MODE_REG, MR_BASE);
|
||||
@ -935,11 +912,11 @@ static void NCR5380_exit(struct Scsi_Host *instance)
|
||||
* Locks: host lock taken by caller
|
||||
*/
|
||||
|
||||
static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
|
||||
static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
|
||||
{
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
|
||||
Scsi_Cmnd *tmp;
|
||||
struct scsi_cmnd *tmp;
|
||||
|
||||
#if (NDEBUG & NDEBUG_NO_WRITE)
|
||||
switch (cmd->cmnd[0]) {
|
||||
@ -952,25 +929,6 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)
|
||||
}
|
||||
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
|
||||
|
||||
#ifdef NCR5380_STATS
|
||||
switch (cmd->cmnd[0]) {
|
||||
case WRITE:
|
||||
case WRITE_6:
|
||||
case WRITE_10:
|
||||
hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
|
||||
hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
|
||||
hostdata->pendingw++;
|
||||
break;
|
||||
case READ:
|
||||
case READ_6:
|
||||
case READ_10:
|
||||
hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
|
||||
hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
|
||||
hostdata->pendingr++;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We use the host_scribble field as a pointer to the next command
|
||||
* in a queue
|
||||
@ -992,7 +950,7 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)
|
||||
cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
|
||||
hostdata->issue_queue = cmd;
|
||||
} else {
|
||||
for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
|
||||
for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (struct scsi_cmnd *) tmp->host_scribble);
|
||||
LIST(cmd, tmp);
|
||||
tmp->host_scribble = (unsigned char *) cmd;
|
||||
}
|
||||
@ -1023,7 +981,7 @@ static void NCR5380_main(struct work_struct *work)
|
||||
struct NCR5380_hostdata *hostdata =
|
||||
container_of(work, struct NCR5380_hostdata, coroutine.work);
|
||||
struct Scsi_Host *instance = hostdata->host;
|
||||
Scsi_Cmnd *tmp, *prev;
|
||||
struct scsi_cmnd *tmp, *prev;
|
||||
int done;
|
||||
|
||||
spin_lock_irq(instance->host_lock);
|
||||
@ -1036,7 +994,7 @@ static void NCR5380_main(struct work_struct *work)
|
||||
* Search through the issue_queue for a command destined
|
||||
* for a target that's not busy.
|
||||
*/
|
||||
for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
|
||||
for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
|
||||
{
|
||||
if (prev != tmp)
|
||||
dprintk(NDEBUG_LISTS, "MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
|
||||
@ -1048,7 +1006,7 @@ static void NCR5380_main(struct work_struct *work)
|
||||
prev->host_scribble = tmp->host_scribble;
|
||||
} else {
|
||||
REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
|
||||
hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
|
||||
hostdata->issue_queue = (struct scsi_cmnd *) tmp->host_scribble;
|
||||
}
|
||||
tmp->host_scribble = NULL;
|
||||
|
||||
@ -1073,14 +1031,14 @@ static void NCR5380_main(struct work_struct *work)
|
||||
hostdata->selecting = NULL;
|
||||
/* RvC: have to preset this to indicate a new command is being performed */
|
||||
|
||||
if (!NCR5380_select(instance, tmp,
|
||||
/*
|
||||
* REQUEST SENSE commands are issued without tagged
|
||||
* queueing, even on SCSI-II devices because the
|
||||
* contingent allegiance condition exists for the
|
||||
* entire unit.
|
||||
*/
|
||||
(tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
|
||||
/*
|
||||
* REQUEST SENSE commands are issued without tagged
|
||||
* queueing, even on SCSI-II devices because the
|
||||
* contingent allegiance condition exists for the
|
||||
* entire unit.
|
||||
*/
|
||||
|
||||
if (!NCR5380_select(instance, tmp)) {
|
||||
break;
|
||||
} else {
|
||||
LIST(tmp, hostdata->issue_queue);
|
||||
@ -1095,9 +1053,9 @@ static void NCR5380_main(struct work_struct *work)
|
||||
/* exited locked */
|
||||
} /* if (!hostdata->connected) */
|
||||
if (hostdata->selecting) {
|
||||
tmp = (Scsi_Cmnd *) hostdata->selecting;
|
||||
tmp = (struct scsi_cmnd *) hostdata->selecting;
|
||||
/* Selection will drop and retake the lock */
|
||||
if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
|
||||
if (!NCR5380_select(instance, tmp)) {
|
||||
/* Ok ?? */
|
||||
} else {
|
||||
/* RvC: device failed, so we wait a long time
|
||||
@ -1216,47 +1174,16 @@ static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* collect_stats - collect stats on a scsi command
|
||||
* @hostdata: adapter
|
||||
* @cmd: command being issued
|
||||
*
|
||||
* Update the statistical data by parsing the command in question
|
||||
*/
|
||||
|
||||
static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd)
|
||||
{
|
||||
#ifdef NCR5380_STATS
|
||||
switch (cmd->cmnd[0]) {
|
||||
case WRITE:
|
||||
case WRITE_6:
|
||||
case WRITE_10:
|
||||
hostdata->time_write[scmd_id(cmd)] += (jiffies - hostdata->timebase);
|
||||
hostdata->pendingw--;
|
||||
break;
|
||||
case READ:
|
||||
case READ_6:
|
||||
case READ_10:
|
||||
hostdata->time_read[scmd_id(cmd)] += (jiffies - hostdata->timebase);
|
||||
hostdata->pendingr--;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
|
||||
* int tag);
|
||||
* Function : int NCR5380_select(struct Scsi_Host *instance,
|
||||
* struct scsi_cmnd *cmd)
|
||||
*
|
||||
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
|
||||
* including ARBITRATION, SELECTION, and initial message out for
|
||||
* IDENTIFY and queue messages.
|
||||
*
|
||||
* Inputs : instance - instantiation of the 5380 driver on which this
|
||||
* target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
|
||||
* new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
|
||||
* the command that is presently connected.
|
||||
* target lives, cmd - SCSI command to execute.
|
||||
*
|
||||
* Returns : -1 if selection could not execute for some reason,
|
||||
* 0 if selection succeeded or failed because the target
|
||||
@ -1278,7 +1205,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd)
|
||||
* Locks: caller holds hostdata lock in IRQ mode
|
||||
*/
|
||||
|
||||
static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag)
|
||||
static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
|
||||
{
|
||||
NCR5380_local_declare();
|
||||
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
|
||||
@ -1476,7 +1403,6 @@ part2:
|
||||
return -1;
|
||||
}
|
||||
cmd->result = DID_BAD_TARGET << 16;
|
||||
collect_stats(hostdata, cmd);
|
||||
cmd->scsi_done(cmd);
|
||||
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
|
||||
dprintk(NDEBUG_SELECTION, "scsi%d : target did not respond within 250ms\n", instance->host_no);
|
||||
@ -1513,7 +1439,7 @@ part2:
|
||||
}
|
||||
|
||||
dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
|
||||
tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun);
|
||||
tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
|
||||
|
||||
len = 1;
|
||||
cmd->tag = 0;
|
||||
@ -2086,7 +2012,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
#endif
|
||||
unsigned char *data;
|
||||
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
|
||||
Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
|
||||
struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
|
||||
/* RvC: we need to set the end of the polling time */
|
||||
unsigned long poll_time = jiffies + USLEEP_POLL;
|
||||
|
||||
@ -2228,7 +2154,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
cmd->next_link->tag = cmd->tag;
|
||||
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
|
||||
dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun);
|
||||
collect_stats(hostdata, cmd);
|
||||
cmd->scsi_done(cmd);
|
||||
cmd = hostdata->connected;
|
||||
break;
|
||||
@ -2263,7 +2188,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
else if (status_byte(cmd->SCp.Status) != GOOD)
|
||||
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
|
||||
|
||||
#ifdef AUTOSENSE
|
||||
if ((cmd->cmnd[0] == REQUEST_SENSE) &&
|
||||
hostdata->ses.cmd_len) {
|
||||
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
|
||||
@ -2278,12 +2202,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
LIST(cmd, hostdata->issue_queue);
|
||||
cmd->host_scribble = (unsigned char *)
|
||||
hostdata->issue_queue;
|
||||
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
|
||||
hostdata->issue_queue = (struct scsi_cmnd *) cmd;
|
||||
dprintk(NDEBUG_QUEUES, "scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
|
||||
} else
|
||||
#endif /* def AUTOSENSE */
|
||||
{
|
||||
collect_stats(hostdata, cmd);
|
||||
} else {
|
||||
cmd->scsi_done(cmd);
|
||||
}
|
||||
|
||||
@ -2430,7 +2351,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
|
||||
hostdata->connected = NULL;
|
||||
cmd->result = DID_ERROR << 16;
|
||||
collect_stats(hostdata, cmd);
|
||||
cmd->scsi_done(cmd);
|
||||
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
|
||||
return;
|
||||
@ -2479,7 +2399,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
|
||||
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
|
||||
*
|
||||
* Purpose : does reselection, initializing the instance->connected
|
||||
* field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
|
||||
* field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
|
||||
* nexus has been reestablished,
|
||||
*
|
||||
* Inputs : instance - this instance of the NCR5380.
|
||||
@ -2496,7 +2416,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
|
||||
int len;
|
||||
unsigned char msg[3];
|
||||
unsigned char *data;
|
||||
Scsi_Cmnd *tmp = NULL, *prev;
|
||||
struct scsi_cmnd *tmp = NULL, *prev;
|
||||
int abort = 0;
|
||||
NCR5380_setup(instance);
|
||||
|
||||
@ -2562,7 +2482,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
|
||||
*/
|
||||
|
||||
|
||||
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
|
||||
for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
|
||||
if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
|
||||
) {
|
||||
if (prev) {
|
||||
@ -2570,7 +2490,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
|
||||
prev->host_scribble = tmp->host_scribble;
|
||||
} else {
|
||||
REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
|
||||
hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
|
||||
hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
|
||||
}
|
||||
tmp->host_scribble = NULL;
|
||||
break;
|
||||
@ -2601,7 +2521,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
|
||||
*
|
||||
* Inputs : instance - this instance of the NCR5380.
|
||||
*
|
||||
* Returns : pointer to the Scsi_Cmnd structure for which the I_T_L
|
||||
* Returns : pointer to the scsi_cmnd structure for which the I_T_L
|
||||
* nexus has been reestablished, on failure NULL is returned.
|
||||
*/
|
||||
|
||||
@ -2643,32 +2563,32 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
|
||||
#endif /* def REAL_DMA */
|
||||
|
||||
/*
|
||||
* Function : int NCR5380_abort (Scsi_Cmnd *cmd)
|
||||
* Function : int NCR5380_abort (struct scsi_cmnd *cmd)
|
||||
*
|
||||
* Purpose : abort a command
|
||||
*
|
||||
* Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
|
||||
* host byte of the result field to, if zero DID_ABORTED is
|
||||
* Inputs : cmd - the scsi_cmnd to abort, code - code to set the
|
||||
* host byte of the result field to, if zero DID_ABORTED is
|
||||
* used.
|
||||
*
|
||||
* Returns : 0 - success, -1 on failure.
|
||||
* Returns : SUCCESS - success, FAILED on failure.
|
||||
*
|
||||
* XXX - there is no way to abort the command that is currently
|
||||
* connected, you have to wait for it to complete. If this is
|
||||
* XXX - there is no way to abort the command that is currently
|
||||
* connected, you have to wait for it to complete. If this is
|
||||
* a problem, we could implement longjmp() / setjmp(), setjmp()
|
||||
* called where the loop started in NCR5380_main().
|
||||
*
|
||||
* Locks: host lock taken by caller
|
||||
*/
|
||||
|
||||
static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
static int NCR5380_abort(struct scsi_cmnd *cmd)
|
||||
{
|
||||
NCR5380_local_declare();
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
|
||||
Scsi_Cmnd *tmp, **prev;
|
||||
|
||||
printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
|
||||
scsi_print_command(cmd);
|
||||
struct scsi_cmnd *tmp, **prev;
|
||||
|
||||
scmd_printk(KERN_WARNING, cmd, "aborting command\n");
|
||||
|
||||
NCR5380_print_status(instance);
|
||||
|
||||
@ -2704,7 +2624,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
* aborted flag and get back into our main loop.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2714,10 +2634,10 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
*/
|
||||
|
||||
dprintk(NDEBUG_ABORT, "scsi%d : abort going into loop.\n", instance->host_no);
|
||||
for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
|
||||
for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
|
||||
if (cmd == tmp) {
|
||||
REMOVE(5, *prev, tmp, tmp->host_scribble);
|
||||
(*prev) = (Scsi_Cmnd *) tmp->host_scribble;
|
||||
(*prev) = (struct scsi_cmnd *) tmp->host_scribble;
|
||||
tmp->host_scribble = NULL;
|
||||
tmp->result = DID_ABORT << 16;
|
||||
dprintk(NDEBUG_ABORT, "scsi%d : abort removed command from issue queue.\n", instance->host_no);
|
||||
@ -2770,20 +2690,20 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
* it from the disconnected queue.
|
||||
*/
|
||||
|
||||
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
|
||||
for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = (struct scsi_cmnd *) tmp->host_scribble)
|
||||
if (cmd == tmp) {
|
||||
dprintk(NDEBUG_ABORT, "scsi%d : aborting disconnected command.\n", instance->host_no);
|
||||
|
||||
if (NCR5380_select(instance, cmd, (int) cmd->tag))
|
||||
if (NCR5380_select(instance, cmd))
|
||||
return FAILED;
|
||||
dprintk(NDEBUG_ABORT, "scsi%d : nexus reestablished.\n", instance->host_no);
|
||||
|
||||
do_abort(instance);
|
||||
|
||||
for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
|
||||
for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
|
||||
if (cmd == tmp) {
|
||||
REMOVE(5, *prev, tmp, tmp->host_scribble);
|
||||
*prev = (Scsi_Cmnd *) tmp->host_scribble;
|
||||
*prev = (struct scsi_cmnd *) tmp->host_scribble;
|
||||
tmp->host_scribble = NULL;
|
||||
tmp->result = DID_ABORT << 16;
|
||||
tmp->scsi_done(tmp);
|
||||
@ -2806,7 +2726,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
|
||||
|
||||
/*
|
||||
* Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
|
||||
* Function : int NCR5380_bus_reset (struct scsi_cmnd *cmd)
|
||||
*
|
||||
* Purpose : reset the SCSI bus.
|
||||
*
|
||||
@ -2815,7 +2735,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
|
||||
* Locks: host lock taken by caller
|
||||
*/
|
||||
|
||||
static int NCR5380_bus_reset(Scsi_Cmnd * cmd)
|
||||
static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct Scsi_Host *instance = cmd->device->host;
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
* drew@colorado.edu
|
||||
* +1 (303) 666-5836
|
||||
*
|
||||
* DISTRIBUTION RELEASE 7
|
||||
*
|
||||
* For more information, please consult
|
||||
*
|
||||
* NCR 5380 Family
|
||||
@ -25,13 +23,7 @@
|
||||
#define NCR5380_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#ifdef AUTOSENSE
|
||||
#include <scsi/scsi_eh.h>
|
||||
#endif
|
||||
|
||||
#define NCR5380_PUBLIC_RELEASE 7
|
||||
#define NCR53C400_PUBLIC_RELEASE 2
|
||||
|
||||
#define NDEBUG_ARBITRATION 0x1
|
||||
#define NDEBUG_AUTOSENSE 0x2
|
||||
@ -224,33 +216,44 @@
|
||||
#define DISCONNECT_LONG 2
|
||||
|
||||
/*
|
||||
* These are "special" values for the tag parameter passed to NCR5380_select.
|
||||
* "Special" value for the (unsigned char) command tag, to indicate
|
||||
* I_T_L nexus instead of I_T_L_Q.
|
||||
*/
|
||||
|
||||
#define TAG_NEXT -1 /* Use next free tag */
|
||||
#define TAG_NONE -2 /*
|
||||
* Establish I_T_L nexus instead of I_T_L_Q
|
||||
* even on SCSI-II devices.
|
||||
*/
|
||||
#define TAG_NONE 0xff
|
||||
|
||||
/*
|
||||
* These are "special" values for the irq and dma_channel fields of the
|
||||
* Scsi_Host structure
|
||||
*/
|
||||
|
||||
#define SCSI_IRQ_NONE 255
|
||||
#define DMA_NONE 255
|
||||
#define IRQ_AUTO 254
|
||||
#define DMA_AUTO 254
|
||||
#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */
|
||||
|
||||
#ifndef NO_IRQ
|
||||
#define NO_IRQ 0
|
||||
#endif
|
||||
|
||||
#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */
|
||||
#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */
|
||||
#define FLAG_NCR53C400 4 /* NCR53c400 */
|
||||
#define FLAG_NO_PSEUDO_DMA 8 /* Inhibit DMA */
|
||||
#define FLAG_DTC3181E 16 /* DTC3181E */
|
||||
#define FLAG_LATE_DMA_SETUP 32 /* Setup NCR before DMA H/W */
|
||||
#define FLAG_TAGGED_QUEUING 64 /* as X3T9.2 spelled it */
|
||||
|
||||
#ifndef ASM
|
||||
|
||||
#ifdef SUPPORT_TAGS
|
||||
struct tag_alloc {
|
||||
DECLARE_BITMAP(allocated, MAX_TAGS);
|
||||
int nr_allocated;
|
||||
int queue_size;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct NCR5380_hostdata {
|
||||
NCR5380_implementation_fields; /* implementation specific */
|
||||
struct Scsi_Host *host; /* Host backpointer */
|
||||
@ -263,9 +266,9 @@ struct NCR5380_hostdata {
|
||||
volatile int dma_len; /* requested length of DMA */
|
||||
#endif
|
||||
volatile unsigned char last_message; /* last message OUT */
|
||||
volatile Scsi_Cmnd *connected; /* currently connected command */
|
||||
volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */
|
||||
volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */
|
||||
volatile struct scsi_cmnd *connected; /* currently connected command */
|
||||
volatile struct scsi_cmnd *issue_queue; /* waiting to be issued */
|
||||
volatile struct scsi_cmnd *disconnected_queue; /* waiting for reconnect */
|
||||
volatile int restart_select; /* we have disconnected,
|
||||
used to restart
|
||||
NCR5380_select() */
|
||||
@ -273,19 +276,21 @@ struct NCR5380_hostdata {
|
||||
int flags;
|
||||
unsigned long time_expires; /* in jiffies, set prior to sleeping */
|
||||
int select_time; /* timer in select for target response */
|
||||
volatile Scsi_Cmnd *selecting;
|
||||
volatile struct scsi_cmnd *selecting;
|
||||
struct delayed_work coroutine; /* our co-routine */
|
||||
#ifdef NCR5380_STATS
|
||||
unsigned timebase; /* Base for time calcs */
|
||||
long time_read[8]; /* time to do reads */
|
||||
long time_write[8]; /* time to do writes */
|
||||
unsigned long bytes_read[8]; /* bytes read */
|
||||
unsigned long bytes_write[8]; /* bytes written */
|
||||
unsigned pendingr;
|
||||
unsigned pendingw;
|
||||
#endif
|
||||
#ifdef AUTOSENSE
|
||||
struct scsi_eh_save ses;
|
||||
char info[256];
|
||||
int read_overruns; /* number of bytes to cut from a
|
||||
* transfer to handle chip overruns */
|
||||
int retain_dma_intr;
|
||||
struct work_struct main_task;
|
||||
volatile int main_running;
|
||||
#ifdef SUPPORT_TAGS
|
||||
struct tag_alloc TagAlloc[8][8]; /* 8 targets and 8 LUNs */
|
||||
#endif
|
||||
#ifdef PSEUDO_DMA
|
||||
unsigned spin_max_r;
|
||||
unsigned spin_max_w;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -296,7 +301,8 @@ struct NCR5380_hostdata {
|
||||
#endif
|
||||
|
||||
#define dprintk(flg, fmt, ...) \
|
||||
do { if ((NDEBUG) & (flg)) pr_debug(fmt, ## __VA_ARGS__); } while (0)
|
||||
do { if ((NDEBUG) & (flg)) \
|
||||
printk(KERN_DEBUG fmt, ## __VA_ARGS__); } while (0)
|
||||
|
||||
#if NDEBUG
|
||||
#define NCR5380_dprint(flg, arg) \
|
||||
@ -320,17 +326,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance);
|
||||
static irqreturn_t NCR5380_intr(int irq, void *dev_id);
|
||||
#endif
|
||||
static void NCR5380_main(struct work_struct *work);
|
||||
static void __maybe_unused NCR5380_print_options(struct Scsi_Host *instance);
|
||||
static int NCR5380_abort(Scsi_Cmnd * cmd);
|
||||
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
|
||||
static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
|
||||
static int __maybe_unused NCR5380_show_info(struct seq_file *,
|
||||
struct Scsi_Host *);
|
||||
static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
|
||||
char *buffer, int length);
|
||||
|
||||
static const char *NCR5380_info(struct Scsi_Host *instance);
|
||||
static void NCR5380_reselect(struct Scsi_Host *instance);
|
||||
static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
|
||||
static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd);
|
||||
#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
|
||||
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
|
||||
#endif
|
||||
|
@ -2181,7 +2181,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
|
||||
(fsa_dev_ptr[cid].sense_data.sense_key ==
|
||||
NOT_READY)) {
|
||||
switch (scsicmd->cmnd[0]) {
|
||||
case SERVICE_ACTION_IN:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
if (!(dev->raw_io_interface) ||
|
||||
!(dev->raw_io_64) ||
|
||||
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
|
||||
@ -2309,7 +2309,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
|
||||
scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
|
||||
return aac_get_container_name(scsicmd);
|
||||
}
|
||||
case SERVICE_ACTION_IN:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
if (!(dev->raw_io_interface) ||
|
||||
!(dev->raw_io_64) ||
|
||||
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
|
||||
|
@ -462,9 +462,9 @@ static int aac_slave_configure(struct scsi_device *sdev)
|
||||
depth = 256;
|
||||
else if (depth < 2)
|
||||
depth = 2;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
|
||||
scsi_change_queue_depth(sdev, depth);
|
||||
} else
|
||||
scsi_adjust_queue_depth(sdev, 0, 1);
|
||||
scsi_change_queue_depth(sdev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -478,12 +478,8 @@ static int aac_slave_configure(struct scsi_device *sdev)
|
||||
* total capacity and the queue depth supported by the target device.
|
||||
*/
|
||||
|
||||
static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
|
||||
int reason)
|
||||
static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
|
||||
(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
|
||||
struct scsi_device * dev;
|
||||
@ -504,10 +500,10 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
|
||||
depth = 256;
|
||||
else if (depth < 2)
|
||||
depth = 2;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
|
||||
} else
|
||||
scsi_adjust_queue_depth(sdev, 0, 1);
|
||||
return sdev->queue_depth;
|
||||
return scsi_change_queue_depth(sdev, depth);
|
||||
}
|
||||
|
||||
return scsi_change_queue_depth(sdev, 1);
|
||||
}
|
||||
|
||||
static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -555,7 +551,7 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
|
||||
AAC_DRIVERNAME,
|
||||
host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
|
||||
switch (cmd->cmnd[0]) {
|
||||
case SERVICE_ACTION_IN:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
if (!(aac->raw_io_interface) ||
|
||||
!(aac->raw_io_64) ||
|
||||
((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
|
||||
|
@ -7706,7 +7706,7 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
|
||||
asc_dvc->cfg->can_tagged_qng |= tid_bit;
|
||||
asc_dvc->use_tagged_qng |= tid_bit;
|
||||
}
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
|
||||
scsi_change_queue_depth(sdev,
|
||||
asc_dvc->max_dvc_qng[sdev->id]);
|
||||
}
|
||||
} else {
|
||||
@ -7714,7 +7714,6 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
|
||||
asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
|
||||
asc_dvc->use_tagged_qng &= ~tid_bit;
|
||||
}
|
||||
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
|
||||
}
|
||||
|
||||
if ((sdev->lun == 0) &&
|
||||
@ -7848,12 +7847,8 @@ advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
|
||||
}
|
||||
}
|
||||
|
||||
if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
|
||||
adv_dvc->max_dvc_qng);
|
||||
} else {
|
||||
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
|
||||
}
|
||||
if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported)
|
||||
scsi_change_queue_depth(sdev, adv_dvc->max_dvc_qng);
|
||||
}
|
||||
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -531,7 +531,7 @@ static int aha1740_eh_abort_handler (Scsi_Cmnd *dummy)
|
||||
* quiet as possible...
|
||||
*/
|
||||
|
||||
return 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static struct scsi_host_template aha1740_template = {
|
||||
|
@ -925,6 +925,7 @@ struct scsi_host_template aic79xx_driver_template = {
|
||||
.slave_configure = ahd_linux_slave_configure,
|
||||
.target_alloc = ahd_linux_target_alloc,
|
||||
.target_destroy = ahd_linux_target_destroy,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
/******************************** Bus DMA *************************************/
|
||||
@ -1468,12 +1469,9 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
|
||||
|
||||
switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
|
||||
case AHD_DEV_Q_BASIC:
|
||||
scsi_set_tag_type(sdev, MSG_SIMPLE_TASK);
|
||||
scsi_activate_tcq(sdev, dev->openings + dev->active);
|
||||
break;
|
||||
case AHD_DEV_Q_TAGGED:
|
||||
scsi_set_tag_type(sdev, MSG_ORDERED_TASK);
|
||||
scsi_activate_tcq(sdev, dev->openings + dev->active);
|
||||
scsi_change_queue_depth(sdev,
|
||||
dev->openings + dev->active);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
@ -1482,7 +1480,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
|
||||
* serially on the controller/device. This should
|
||||
* remove some latency.
|
||||
*/
|
||||
scsi_deactivate_tcq(sdev, 1);
|
||||
scsi_change_queue_depth(sdev, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1619,15 +1617,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
|
||||
}
|
||||
|
||||
if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
|
||||
int msg_bytes;
|
||||
uint8_t tag_msgs[2];
|
||||
|
||||
msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
|
||||
if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
|
||||
hscb->control |= tag_msgs[0];
|
||||
if (tag_msgs[0] == MSG_ORDERED_TASK)
|
||||
dev->commands_since_idle_or_otag = 0;
|
||||
} else
|
||||
if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
|
||||
&& (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
|
||||
hscb->control |= MSG_ORDERED_TASK;
|
||||
|
@ -812,6 +812,7 @@ struct scsi_host_template aic7xxx_driver_template = {
|
||||
.slave_configure = ahc_linux_slave_configure,
|
||||
.target_alloc = ahc_linux_target_alloc,
|
||||
.target_destroy = ahc_linux_target_destroy,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
/**************************** Tasklet Handler *********************************/
|
||||
@ -1334,13 +1335,9 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
|
||||
}
|
||||
switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
|
||||
case AHC_DEV_Q_BASIC:
|
||||
scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
|
||||
scsi_activate_tcq(sdev, dev->openings + dev->active);
|
||||
break;
|
||||
case AHC_DEV_Q_TAGGED:
|
||||
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
|
||||
scsi_activate_tcq(sdev, dev->openings + dev->active);
|
||||
break;
|
||||
scsi_change_queue_depth(sdev,
|
||||
dev->openings + dev->active);
|
||||
default:
|
||||
/*
|
||||
* We allow the OS to queue 2 untagged transactions to
|
||||
@ -1348,7 +1345,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
|
||||
* serially on the controller/device. This should
|
||||
* remove some latency.
|
||||
*/
|
||||
scsi_deactivate_tcq(sdev, 2);
|
||||
scsi_change_queue_depth(sdev, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1447,7 +1444,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
|
||||
* we are storing a full busy target *lun*
|
||||
* table in SCB space.
|
||||
*/
|
||||
if (!blk_rq_tagged(cmd->request)
|
||||
if (!(cmd->flags & SCMD_TAGGED)
|
||||
&& (ahc->features & AHC_SCB_BTT) == 0) {
|
||||
int target_offset;
|
||||
|
||||
@ -1501,15 +1498,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
|
||||
}
|
||||
|
||||
if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
|
||||
int msg_bytes;
|
||||
uint8_t tag_msgs[2];
|
||||
|
||||
msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
|
||||
if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
|
||||
hscb->control |= tag_msgs[0];
|
||||
if (tag_msgs[0] == MSG_ORDERED_TASK)
|
||||
dev->commands_since_idle_or_otag = 0;
|
||||
} else if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
|
||||
if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
|
||||
&& (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
|
||||
hscb->control |= MSG_ORDERED_TASK;
|
||||
dev->commands_since_idle_or_otag = 0;
|
||||
|
@ -78,7 +78,7 @@ void asd_dev_gone(struct domain_device *dev);
|
||||
|
||||
void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
|
||||
|
||||
int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
|
||||
int asd_execute_task(struct sas_task *task, gfp_t gfp_flags);
|
||||
|
||||
void asd_set_dmamode(struct domain_device *dev);
|
||||
|
||||
|
@ -1200,8 +1200,7 @@ static void asd_start_scb_timers(struct list_head *list)
|
||||
* Case A: we can send the whole batch at once. Increment "pending"
|
||||
* in the beginning of this function, when it is checked, in order to
|
||||
* eliminate races when this function is called by multiple processes.
|
||||
* Case B: should never happen if the managing layer considers
|
||||
* lldd_queue_size.
|
||||
* Case B: should never happen.
|
||||
*/
|
||||
int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
|
||||
int num)
|
||||
|
@ -49,14 +49,6 @@ MODULE_PARM_DESC(use_msi, "\n"
|
||||
"\tEnable(1) or disable(0) using PCI MSI.\n"
|
||||
"\tDefault: 0");
|
||||
|
||||
static int lldd_max_execute_num = 0;
|
||||
module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(collector, "\n"
|
||||
"\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
|
||||
"\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
|
||||
"\tThe aic94xx SAS LLDD supports both modes.\n"
|
||||
"\tDefault: 0 (Direct Mode).\n");
|
||||
|
||||
static struct scsi_transport_template *aic94xx_transport_template;
|
||||
static int asd_scan_finished(struct Scsi_Host *, unsigned long);
|
||||
static void asd_scan_start(struct Scsi_Host *);
|
||||
@ -83,6 +75,8 @@ static struct scsi_host_template aic94xx_sht = {
|
||||
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
|
||||
.target_destroy = sas_target_destroy,
|
||||
.ioctl = sas_ioctl,
|
||||
.use_blk_tags = 1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static int asd_map_memio(struct asd_ha_struct *asd_ha)
|
||||
@ -709,9 +703,6 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
|
||||
asd_ha->sas_ha.sas_port= sas_ports;
|
||||
asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
|
||||
|
||||
asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
|
||||
asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num;
|
||||
|
||||
return sas_register_ha(&asd_ha->sas_ha);
|
||||
}
|
||||
|
||||
|
@ -543,8 +543,7 @@ static int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
|
||||
return res;
|
||||
}
|
||||
|
||||
int asd_execute_task(struct sas_task *task, const int num,
|
||||
gfp_t gfp_flags)
|
||||
int asd_execute_task(struct sas_task *task, gfp_t gfp_flags)
|
||||
{
|
||||
int res = 0;
|
||||
LIST_HEAD(alist);
|
||||
@ -553,11 +552,11 @@ int asd_execute_task(struct sas_task *task, const int num,
|
||||
struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
|
||||
unsigned long flags;
|
||||
|
||||
res = asd_can_queue(asd_ha, num);
|
||||
res = asd_can_queue(asd_ha, 1);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = num;
|
||||
res = 1;
|
||||
ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
|
||||
if (res) {
|
||||
res = -ENOMEM;
|
||||
@ -568,7 +567,7 @@ int asd_execute_task(struct sas_task *task, const int num,
|
||||
list_for_each_entry(a, &alist, list) {
|
||||
a->uldd_task = t;
|
||||
t->lldd_task = a;
|
||||
t = list_entry(t->list.next, struct sas_task, list);
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(a, &alist, list) {
|
||||
t = a->uldd_task;
|
||||
@ -601,7 +600,7 @@ int asd_execute_task(struct sas_task *task, const int num,
|
||||
}
|
||||
list_del_init(&alist);
|
||||
|
||||
res = asd_post_ascb_list(asd_ha, ascb, num);
|
||||
res = asd_post_ascb_list(asd_ha, ascb, 1);
|
||||
if (unlikely(res)) {
|
||||
a = NULL;
|
||||
__list_add(&alist, ascb->list.prev, &ascb->list);
|
||||
@ -639,6 +638,6 @@ out_err_unmap:
|
||||
out_err:
|
||||
if (ascb)
|
||||
asd_ascb_free_list(ascb);
|
||||
asd_can_dequeue(asd_ha, num);
|
||||
asd_can_dequeue(asd_ha, 1);
|
||||
return res;
|
||||
}
|
||||
|
586
drivers/scsi/am53c974.c
Normal file
586
drivers/scsi/am53c974.c
Normal file
@ -0,0 +1,586 @@
|
||||
/*
|
||||
* AMD am53c974 driver.
|
||||
* Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "esp_scsi.h"
|
||||
|
||||
#define DRV_MODULE_NAME "am53c974"
|
||||
#define DRV_MODULE_VERSION "1.00"
|
||||
|
||||
static bool am53c974_debug;
|
||||
static bool am53c974_fenab = true;
|
||||
|
||||
#define esp_dma_log(f, a...) \
|
||||
do { \
|
||||
if (am53c974_debug) \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ##a); \
|
||||
} while (0)
|
||||
|
||||
#define ESP_DMA_CMD 0x10
|
||||
#define ESP_DMA_STC 0x11
|
||||
#define ESP_DMA_SPA 0x12
|
||||
#define ESP_DMA_WBC 0x13
|
||||
#define ESP_DMA_WAC 0x14
|
||||
#define ESP_DMA_STATUS 0x15
|
||||
#define ESP_DMA_SMDLA 0x16
|
||||
#define ESP_DMA_WMAC 0x17
|
||||
|
||||
#define ESP_DMA_CMD_IDLE 0x00
|
||||
#define ESP_DMA_CMD_BLAST 0x01
|
||||
#define ESP_DMA_CMD_ABORT 0x02
|
||||
#define ESP_DMA_CMD_START 0x03
|
||||
#define ESP_DMA_CMD_MASK 0x03
|
||||
#define ESP_DMA_CMD_DIAG 0x04
|
||||
#define ESP_DMA_CMD_MDL 0x10
|
||||
#define ESP_DMA_CMD_INTE_P 0x20
|
||||
#define ESP_DMA_CMD_INTE_D 0x40
|
||||
#define ESP_DMA_CMD_DIR 0x80
|
||||
|
||||
#define ESP_DMA_STAT_PWDN 0x01
|
||||
#define ESP_DMA_STAT_ERROR 0x02
|
||||
#define ESP_DMA_STAT_ABORT 0x04
|
||||
#define ESP_DMA_STAT_DONE 0x08
|
||||
#define ESP_DMA_STAT_SCSIINT 0x10
|
||||
#define ESP_DMA_STAT_BCMPLT 0x20
|
||||
|
||||
/* EEPROM is accessed with 16-bit values */
|
||||
#define DC390_EEPROM_READ 0x80
|
||||
#define DC390_EEPROM_LEN 0x40
|
||||
|
||||
/*
|
||||
* DC390 EEPROM
|
||||
*
|
||||
* 8 * 4 bytes of per-device options
|
||||
* followed by HBA specific options
|
||||
*/
|
||||
|
||||
/* Per-device options */
|
||||
#define DC390_EE_MODE1 0x00
|
||||
#define DC390_EE_SPEED 0x01
|
||||
|
||||
/* HBA-specific options */
|
||||
#define DC390_EE_ADAPT_SCSI_ID 0x40
|
||||
#define DC390_EE_MODE2 0x41
|
||||
#define DC390_EE_DELAY 0x42
|
||||
#define DC390_EE_TAG_CMD_NUM 0x43
|
||||
|
||||
#define DC390_EE_MODE1_PARITY_CHK 0x01
|
||||
#define DC390_EE_MODE1_SYNC_NEGO 0x02
|
||||
#define DC390_EE_MODE1_EN_DISC 0x04
|
||||
#define DC390_EE_MODE1_SEND_START 0x08
|
||||
#define DC390_EE_MODE1_TCQ 0x10
|
||||
|
||||
#define DC390_EE_MODE2_MORE_2DRV 0x01
|
||||
#define DC390_EE_MODE2_GREATER_1G 0x02
|
||||
#define DC390_EE_MODE2_RST_SCSI_BUS 0x04
|
||||
#define DC390_EE_MODE2_ACTIVE_NEGATION 0x08
|
||||
#define DC390_EE_MODE2_NO_SEEK 0x10
|
||||
#define DC390_EE_MODE2_LUN_CHECK 0x20
|
||||
|
||||
struct pci_esp_priv {
|
||||
struct esp *esp;
|
||||
u8 dma_status;
|
||||
};
|
||||
|
||||
static void pci_esp_dma_drain(struct esp *esp);
|
||||
|
||||
static inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp)
|
||||
{
|
||||
struct pci_dev *pdev = esp->dev;
|
||||
|
||||
return pci_get_drvdata(pdev);
|
||||
}
|
||||
|
||||
static void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg)
|
||||
{
|
||||
iowrite8(val, esp->regs + (reg * 4UL));
|
||||
}
|
||||
|
||||
static u8 pci_esp_read8(struct esp *esp, unsigned long reg)
|
||||
{
|
||||
return ioread8(esp->regs + (reg * 4UL));
|
||||
}
|
||||
|
||||
static void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg)
|
||||
{
|
||||
return iowrite32(val, esp->regs + (reg * 4UL));
|
||||
}
|
||||
|
||||
static dma_addr_t pci_esp_map_single(struct esp *esp, void *buf,
|
||||
size_t sz, int dir)
|
||||
{
|
||||
return pci_map_single(esp->dev, buf, sz, dir);
|
||||
}
|
||||
|
||||
static int pci_esp_map_sg(struct esp *esp, struct scatterlist *sg,
|
||||
int num_sg, int dir)
|
||||
{
|
||||
return pci_map_sg(esp->dev, sg, num_sg, dir);
|
||||
}
|
||||
|
||||
static void pci_esp_unmap_single(struct esp *esp, dma_addr_t addr,
|
||||
size_t sz, int dir)
|
||||
{
|
||||
pci_unmap_single(esp->dev, addr, sz, dir);
|
||||
}
|
||||
|
||||
static void pci_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
|
||||
int num_sg, int dir)
|
||||
{
|
||||
pci_unmap_sg(esp->dev, sg, num_sg, dir);
|
||||
}
|
||||
|
||||
static int pci_esp_irq_pending(struct esp *esp)
|
||||
{
|
||||
struct pci_esp_priv *pep = pci_esp_get_priv(esp);
|
||||
|
||||
pep->dma_status = pci_esp_read8(esp, ESP_DMA_STATUS);
|
||||
esp_dma_log("dma intr dreg[%02x]\n", pep->dma_status);
|
||||
|
||||
if (pep->dma_status & (ESP_DMA_STAT_ERROR |
|
||||
ESP_DMA_STAT_ABORT |
|
||||
ESP_DMA_STAT_DONE |
|
||||
ESP_DMA_STAT_SCSIINT))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_esp_reset_dma(struct esp *esp)
|
||||
{
|
||||
/* Nothing to do ? */
|
||||
}
|
||||
|
||||
static void pci_esp_dma_drain(struct esp *esp)
|
||||
{
|
||||
u8 resid;
|
||||
int lim = 1000;
|
||||
|
||||
|
||||
if ((esp->sreg & ESP_STAT_PMASK) == ESP_DOP ||
|
||||
(esp->sreg & ESP_STAT_PMASK) == ESP_DIP)
|
||||
/* Data-In or Data-Out, nothing to be done */
|
||||
return;
|
||||
|
||||
while (--lim > 0) {
|
||||
resid = pci_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES;
|
||||
if (resid <= 1)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
if (resid > 1) {
|
||||
/* FIFO not cleared */
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"FIFO not cleared, %d bytes left\n",
|
||||
resid);
|
||||
}
|
||||
|
||||
/*
|
||||
* When there is a residual BCMPLT will never be set
|
||||
* (obviously). But we still have to issue the BLAST
|
||||
* command, otherwise the data will not being transferred.
|
||||
* But we'll never know when the BLAST operation is
|
||||
* finished. So check for some time and give up eventually.
|
||||
*/
|
||||
lim = 1000;
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_BLAST, ESP_DMA_CMD);
|
||||
while (pci_esp_read8(esp, ESP_DMA_STATUS) & ESP_DMA_STAT_BCMPLT) {
|
||||
if (--lim == 0)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
|
||||
esp_dma_log("DMA blast done (%d tries, %d bytes left)\n", lim, resid);
|
||||
/* BLAST residual handling is currently untested */
|
||||
if (WARN_ON_ONCE(resid == 1)) {
|
||||
struct esp_cmd_entry *ent = esp->active_cmd;
|
||||
|
||||
ent->flags |= ESP_CMD_FLAG_RESIDUAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_esp_dma_invalidate(struct esp *esp)
|
||||
{
|
||||
struct pci_esp_priv *pep = pci_esp_get_priv(esp);
|
||||
|
||||
esp_dma_log("invalidate DMA\n");
|
||||
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
|
||||
pep->dma_status = 0;
|
||||
}
|
||||
|
||||
static int pci_esp_dma_error(struct esp *esp)
|
||||
{
|
||||
struct pci_esp_priv *pep = pci_esp_get_priv(esp);
|
||||
|
||||
if (pep->dma_status & ESP_DMA_STAT_ERROR) {
|
||||
u8 dma_cmd = pci_esp_read8(esp, ESP_DMA_CMD);
|
||||
|
||||
if ((dma_cmd & ESP_DMA_CMD_MASK) == ESP_DMA_CMD_START)
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_ABORT, ESP_DMA_CMD);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (pep->dma_status & ESP_DMA_STAT_ABORT) {
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
|
||||
pep->dma_status = pci_esp_read8(esp, ESP_DMA_CMD);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
|
||||
u32 dma_count, int write, u8 cmd)
|
||||
{
|
||||
struct pci_esp_priv *pep = pci_esp_get_priv(esp);
|
||||
u32 val = 0;
|
||||
|
||||
BUG_ON(!(cmd & ESP_CMD_DMA));
|
||||
|
||||
pep->dma_status = 0;
|
||||
|
||||
/* Set DMA engine to IDLE */
|
||||
if (write)
|
||||
/* DMA write direction logic is inverted */
|
||||
val |= ESP_DMA_CMD_DIR;
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_IDLE | val, ESP_DMA_CMD);
|
||||
|
||||
pci_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
|
||||
pci_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
|
||||
if (esp->config2 & ESP_CONFIG2_FENAB)
|
||||
pci_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
|
||||
|
||||
pci_esp_write32(esp, esp_count, ESP_DMA_STC);
|
||||
pci_esp_write32(esp, addr, ESP_DMA_SPA);
|
||||
|
||||
esp_dma_log("start dma addr[%x] count[%d:%d]\n",
|
||||
addr, esp_count, dma_count);
|
||||
|
||||
scsi_esp_cmd(esp, cmd);
|
||||
/* Send DMA Start command */
|
||||
pci_esp_write8(esp, ESP_DMA_CMD_START | val, ESP_DMA_CMD);
|
||||
}
|
||||
|
||||
static u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
|
||||
{
|
||||
int dma_limit = 16;
|
||||
u32 base, end;
|
||||
|
||||
/*
|
||||
* If CONFIG2_FENAB is set we can
|
||||
* handle up to 24 bit addresses
|
||||
*/
|
||||
if (esp->config2 & ESP_CONFIG2_FENAB)
|
||||
dma_limit = 24;
|
||||
|
||||
if (dma_len > (1U << dma_limit))
|
||||
dma_len = (1U << dma_limit);
|
||||
|
||||
/*
|
||||
* Prevent crossing a 24-bit address boundary.
|
||||
*/
|
||||
base = dma_addr & ((1U << 24) - 1U);
|
||||
end = base + dma_len;
|
||||
if (end > (1U << 24))
|
||||
end = (1U <<24);
|
||||
dma_len = end - base;
|
||||
|
||||
return dma_len;
|
||||
}
|
||||
|
||||
static const struct esp_driver_ops pci_esp_ops = {
|
||||
.esp_write8 = pci_esp_write8,
|
||||
.esp_read8 = pci_esp_read8,
|
||||
.map_single = pci_esp_map_single,
|
||||
.map_sg = pci_esp_map_sg,
|
||||
.unmap_single = pci_esp_unmap_single,
|
||||
.unmap_sg = pci_esp_unmap_sg,
|
||||
.irq_pending = pci_esp_irq_pending,
|
||||
.reset_dma = pci_esp_reset_dma,
|
||||
.dma_drain = pci_esp_dma_drain,
|
||||
.dma_invalidate = pci_esp_dma_invalidate,
|
||||
.send_dma_cmd = pci_esp_send_dma_cmd,
|
||||
.dma_error = pci_esp_dma_error,
|
||||
.dma_length_limit = pci_esp_dma_length_limit,
|
||||
};
|
||||
|
||||
/*
|
||||
* Read DC-390 eeprom
|
||||
*/
|
||||
static void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
|
||||
{
|
||||
u8 carry_flag = 1, j = 0x80, bval;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
if (carry_flag) {
|
||||
pci_write_config_byte(pdev, 0x80, 0x40);
|
||||
bval = 0xc0;
|
||||
} else
|
||||
bval = 0x80;
|
||||
|
||||
udelay(160);
|
||||
pci_write_config_byte(pdev, 0x80, bval);
|
||||
udelay(160);
|
||||
pci_write_config_byte(pdev, 0x80, 0);
|
||||
udelay(160);
|
||||
|
||||
carry_flag = (cmd & j) ? 1 : 0;
|
||||
j >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static u16 dc390_eeprom_get_data(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
u16 wval = 0;
|
||||
u8 bval;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
wval <<= 1;
|
||||
|
||||
pci_write_config_byte(pdev, 0x80, 0x80);
|
||||
udelay(160);
|
||||
pci_write_config_byte(pdev, 0x80, 0x40);
|
||||
udelay(160);
|
||||
pci_read_config_byte(pdev, 0x00, &bval);
|
||||
|
||||
if (bval == 0x22)
|
||||
wval |= 1;
|
||||
}
|
||||
|
||||
return wval;
|
||||
}
|
||||
|
||||
static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
|
||||
{
|
||||
u8 cmd = DC390_EEPROM_READ, i;
|
||||
|
||||
for (i = 0; i < DC390_EEPROM_LEN; i++) {
|
||||
pci_write_config_byte(pdev, 0xc0, 0);
|
||||
udelay(160);
|
||||
|
||||
dc390_eeprom_prepare_read(pdev, cmd++);
|
||||
*ptr++ = dc390_eeprom_get_data(pdev);
|
||||
|
||||
pci_write_config_byte(pdev, 0x80, 0);
|
||||
pci_write_config_byte(pdev, 0x80, 0);
|
||||
udelay(160);
|
||||
}
|
||||
}
|
||||
|
||||
static void dc390_check_eeprom(struct esp *esp)
|
||||
{
|
||||
u8 EEbuf[128];
|
||||
u16 *ptr = (u16 *)EEbuf, wval = 0;
|
||||
int i;
|
||||
|
||||
dc390_read_eeprom((struct pci_dev *)esp->dev, ptr);
|
||||
|
||||
for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++)
|
||||
wval += *ptr;
|
||||
|
||||
/* no Tekram EEprom found */
|
||||
if (wval != 0x1234) {
|
||||
struct pci_dev *pdev = esp->dev;
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"No valid Tekram EEprom found\n");
|
||||
return;
|
||||
}
|
||||
esp->scsi_id = EEbuf[DC390_EE_ADAPT_SCSI_ID];
|
||||
esp->num_tags = 2 << EEbuf[DC390_EE_TAG_CMD_NUM];
|
||||
if (EEbuf[DC390_EE_MODE2] & DC390_EE_MODE2_ACTIVE_NEGATION)
|
||||
esp->config4 |= ESP_CONFIG4_RADE | ESP_CONFIG4_RAE;
|
||||
}
|
||||
|
||||
static int pci_esp_probe_one(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct scsi_host_template *hostt = &scsi_esp_template;
|
||||
int err = -ENODEV;
|
||||
struct Scsi_Host *shost;
|
||||
struct esp *esp;
|
||||
struct pci_esp_priv *pep;
|
||||
|
||||
if (pci_enable_device(pdev)) {
|
||||
dev_printk(KERN_INFO, &pdev->dev, "cannot enable device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"failed to set 32bit DMA mask\n");
|
||||
goto fail_disable_device;
|
||||
}
|
||||
|
||||
shost = scsi_host_alloc(hostt, sizeof(struct esp));
|
||||
if (!shost) {
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"failed to allocate scsi host\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_disable_device;
|
||||
}
|
||||
|
||||
pep = kzalloc(sizeof(struct pci_esp_priv), GFP_KERNEL);
|
||||
if (!pep) {
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"failed to allocate esp_priv\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_host_alloc;
|
||||
}
|
||||
|
||||
esp = shost_priv(shost);
|
||||
esp->host = shost;
|
||||
esp->dev = pdev;
|
||||
esp->ops = &pci_esp_ops;
|
||||
/*
|
||||
* The am53c974 HBA has a design flaw of generating
|
||||
* spurious DMA completion interrupts when using
|
||||
* DMA for command submission.
|
||||
*/
|
||||
esp->flags |= ESP_FLAG_USE_FIFO;
|
||||
/*
|
||||
* Enable CONFIG2_FENAB to allow for large DMA transfers
|
||||
*/
|
||||
if (am53c974_fenab)
|
||||
esp->config2 |= ESP_CONFIG2_FENAB;
|
||||
|
||||
pep->esp = esp;
|
||||
|
||||
if (pci_request_regions(pdev, DRV_MODULE_NAME)) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"pci memory selection failed\n");
|
||||
goto fail_priv_alloc;
|
||||
}
|
||||
|
||||
esp->regs = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!esp->regs) {
|
||||
dev_printk(KERN_ERR, &pdev->dev, "pci I/O map failed\n");
|
||||
err = -EINVAL;
|
||||
goto fail_release_regions;
|
||||
}
|
||||
esp->dma_regs = esp->regs;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
esp->command_block = pci_alloc_consistent(pdev, 16,
|
||||
&esp->command_block_dma);
|
||||
if (!esp->command_block) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to allocate command block\n");
|
||||
err = -ENOMEM;
|
||||
goto fail_unmap_regs;
|
||||
}
|
||||
|
||||
err = request_irq(pdev->irq, scsi_esp_intr, IRQF_SHARED,
|
||||
DRV_MODULE_NAME, esp);
|
||||
if (err < 0) {
|
||||
dev_printk(KERN_ERR, &pdev->dev, "failed to register IRQ\n");
|
||||
goto fail_unmap_command_block;
|
||||
}
|
||||
|
||||
esp->scsi_id = 7;
|
||||
dc390_check_eeprom(esp);
|
||||
|
||||
shost->this_id = esp->scsi_id;
|
||||
shost->max_id = 8;
|
||||
shost->irq = pdev->irq;
|
||||
shost->io_port = pci_resource_start(pdev, 0);
|
||||
shost->n_io_port = pci_resource_len(pdev, 0);
|
||||
shost->unique_id = shost->io_port;
|
||||
esp->scsi_id_mask = (1 << esp->scsi_id);
|
||||
/* Assume 40MHz clock */
|
||||
esp->cfreq = 40000000;
|
||||
|
||||
pci_set_drvdata(pdev, pep);
|
||||
|
||||
err = scsi_esp_register(esp, &pdev->dev);
|
||||
if (err)
|
||||
goto fail_free_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_free_irq:
|
||||
free_irq(pdev->irq, esp);
|
||||
fail_unmap_command_block:
|
||||
pci_free_consistent(pdev, 16, esp->command_block,
|
||||
esp->command_block_dma);
|
||||
fail_unmap_regs:
|
||||
pci_iounmap(pdev, esp->regs);
|
||||
fail_release_regions:
|
||||
pci_release_regions(pdev);
|
||||
fail_priv_alloc:
|
||||
kfree(pep);
|
||||
fail_host_alloc:
|
||||
scsi_host_put(shost);
|
||||
fail_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pci_esp_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_esp_priv *pep = pci_get_drvdata(pdev);
|
||||
struct esp *esp = pep->esp;
|
||||
|
||||
scsi_esp_unregister(esp);
|
||||
free_irq(pdev->irq, esp);
|
||||
pci_free_consistent(pdev, 16, esp->command_block,
|
||||
esp->command_block_dma);
|
||||
pci_iounmap(pdev, esp->regs);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
kfree(pep);
|
||||
|
||||
scsi_host_put(esp->host);
|
||||
}
|
||||
|
||||
static struct pci_device_id am53c974_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, am53c974_pci_tbl);
|
||||
|
||||
static struct pci_driver am53c974_driver = {
|
||||
.name = DRV_MODULE_NAME,
|
||||
.id_table = am53c974_pci_tbl,
|
||||
.probe = pci_esp_probe_one,
|
||||
.remove = pci_esp_remove_one,
|
||||
};
|
||||
|
||||
static int __init am53c974_module_init(void)
|
||||
{
|
||||
return pci_register_driver(&am53c974_driver);
|
||||
}
|
||||
|
||||
static void __exit am53c974_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&am53c974_driver);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("AM53C974 SCSI driver");
|
||||
MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_MODULE_VERSION);
|
||||
MODULE_ALIAS("tmscsim");
|
||||
|
||||
module_param(am53c974_debug, bool, 0644);
|
||||
MODULE_PARM_DESC(am53c974_debug, "Enable debugging");
|
||||
|
||||
module_param(am53c974_fenab, bool, 0444);
|
||||
MODULE_PARM_DESC(am53c974_fenab, "Enable 24-bit DMA transfer sizes");
|
||||
|
||||
module_init(am53c974_module_init);
|
||||
module_exit(am53c974_module_exit);
|
@ -114,16 +114,11 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
|
||||
static const char *arcmsr_info(struct Scsi_Host *);
|
||||
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
|
||||
static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
|
||||
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
|
||||
int queue_depth, int reason)
|
||||
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
|
||||
{
|
||||
if (reason != SCSI_QDEPTH_DEFAULT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
|
||||
queue_depth = ARCMSR_MAX_CMD_PERLUN;
|
||||
scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
|
||||
return queue_depth;
|
||||
return scsi_change_queue_depth(sdev, queue_depth);
|
||||
}
|
||||
|
||||
static struct scsi_host_template arcmsr_scsi_host_template = {
|
||||
|
@ -850,13 +850,13 @@ static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
|
||||
host->host->host_no, SCpnt->result);
|
||||
__scsi_print_command(SCpnt->cmnd);
|
||||
scmd_printk(KERN_ERR, SCpnt,
|
||||
"incomplete data transfer detected: "
|
||||
"result=%08X", SCpnt->result);
|
||||
scsi_print_command(SCpnt);
|
||||
acornscsi_dumpdma(host, "done");
|
||||
acornscsi_dumplog(host, SCpnt->device->id);
|
||||
SCpnt->result &= 0xffff;
|
||||
SCpnt->result |= DID_ERROR << 16;
|
||||
acornscsi_dumplog(host, SCpnt->device->id);
|
||||
set_host_byte(SCpnt, DID_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,12 @@
|
||||
#include <asm/ecard.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "../scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include <scsi/scsicam.h>
|
||||
|
||||
#define AUTOSENSE
|
||||
#define PSEUDO_DMA
|
||||
|
||||
#define CUMANASCSI_PUBLIC_RELEASE 1
|
||||
|
||||
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
|
||||
#define NCR5380_local_declare() struct Scsi_Host *_instance
|
||||
#define NCR5380_setup(instance) _instance = instance
|
||||
@ -30,6 +26,7 @@
|
||||
#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
|
||||
#define NCR5380_intr cumanascsi_intr
|
||||
#define NCR5380_queue_command cumanascsi_queue_command
|
||||
#define NCR5380_info cumanascsi_info
|
||||
|
||||
#define NCR5380_implementation_fields \
|
||||
unsigned ctrl; \
|
||||
@ -42,11 +39,6 @@ void cumanascsi_setup(char *str, int *ints)
|
||||
{
|
||||
}
|
||||
|
||||
const char *cumanascsi_info(struct Scsi_Host *spnt)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
#define CTRL 0x16fc
|
||||
#define STAT 0x2004
|
||||
#define L(v) (((v)<<16)|((v) & 0x0000ffff))
|
||||
@ -267,14 +259,6 @@ static int cumanascsi1_probe(struct expansion_card *ec,
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
printk("scsi%d: at port 0x%08lx irq %d",
|
||||
host->host_no, host->io_port, host->irq);
|
||||
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
|
||||
host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
|
||||
printk("\nscsi%d:", host->host_no);
|
||||
NCR5380_print_options(host);
|
||||
printk("\n");
|
||||
|
||||
ret = scsi_add_host(host, &ec->dev);
|
||||
if (ret)
|
||||
goto out_free_irq;
|
||||
|
@ -308,8 +308,7 @@ static void fas216_log_command(FAS216_Info *info, int level,
|
||||
fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
printk(" CDB: ");
|
||||
__scsi_print_command(SCpnt->cmnd);
|
||||
scsi_print_command(SCpnt);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2079,14 +2078,12 @@ fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
|
||||
"detected: res=%08X ptr=%p len=%X CDB: ",
|
||||
info->host->host_no, '0' + SCpnt->device->id,
|
||||
SCpnt->result, info->scsi.SCp.ptr,
|
||||
info->scsi.SCp.this_residual);
|
||||
__scsi_print_command(SCpnt->cmnd);
|
||||
SCpnt->result &= ~(255 << 16);
|
||||
SCpnt->result |= DID_BAD_TARGET << 16;
|
||||
scmd_printk(KERN_ERR, SCpnt,
|
||||
"incomplete data transfer detected: res=%08X ptr=%p len=%X\n",
|
||||
SCpnt->result, info->scsi.SCp.ptr,
|
||||
info->scsi.SCp.this_residual);
|
||||
scsi_print_command(SCpnt);
|
||||
set_host_byte(SCpnt, DID_ERROR);
|
||||
goto request_sense;
|
||||
}
|
||||
}
|
||||
@ -2158,12 +2155,11 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
|
||||
* to transfer, we should not have a valid pointer.
|
||||
*/
|
||||
if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
|
||||
printk("scsi%d.%c: zero bytes left to transfer, but "
|
||||
"buffer pointer still valid: ptr=%p len=%08x CDB: ",
|
||||
info->host->host_no, '0' + SCpnt->device->id,
|
||||
info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
|
||||
scmd_printk(KERN_INFO, SCpnt,
|
||||
"zero bytes left to transfer, but buffer pointer still valid: ptr=%p len=%08x\n",
|
||||
info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
|
||||
info->scsi.SCp.ptr = NULL;
|
||||
__scsi_print_command(SCpnt->cmnd);
|
||||
scsi_print_command(SCpnt);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2427,14 +2423,11 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
|
||||
|
||||
info->stats.aborts += 1;
|
||||
|
||||
printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
|
||||
__scsi_print_command(SCpnt->cmnd);
|
||||
scmd_printk(KERN_WARNING, SCpnt, "abort command\n");
|
||||
|
||||
print_debug_list();
|
||||
fas216_dumpstate(info);
|
||||
|
||||
printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt);
|
||||
|
||||
switch (fas216_find_command(info, SCpnt)) {
|
||||
/*
|
||||
* We found the command, and cleared it out. Either
|
||||
@ -2442,7 +2435,7 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
|
||||
* target, or the busylun bit is not set.
|
||||
*/
|
||||
case res_success:
|
||||
printk("success\n");
|
||||
scmd_printk(KERN_WARNING, SCpnt, "abort %p success\n", SCpnt);
|
||||
result = SUCCESS;
|
||||
break;
|
||||
|
||||
@ -2452,14 +2445,13 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
|
||||
* if the bus is free.
|
||||
*/
|
||||
case res_hw_abort:
|
||||
|
||||
|
||||
/*
|
||||
* We are unable to abort the command for some reason.
|
||||
*/
|
||||
default:
|
||||
case res_failed:
|
||||
printk("failed\n");
|
||||
scmd_printk(KERN_WARNING, SCpnt, "abort %p failed\n", SCpnt);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2664,8 +2656,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
|
||||
|
||||
fas216_checkmagic(info);
|
||||
|
||||
printk("scsi%d.%c: %s: resetting host\n",
|
||||
info->host->host_no, '0' + SCpnt->device->id, __func__);
|
||||
fas216_log(info, LOG_ERROR, "resetting host");
|
||||
|
||||
/*
|
||||
* Reset the SCSI chip.
|
||||
|
@ -14,13 +14,9 @@
|
||||
#include <asm/ecard.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "../scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#define AUTOSENSE
|
||||
/*#define PSEUDO_DMA*/
|
||||
|
||||
#define OAKSCSI_PUBLIC_RELEASE 1
|
||||
#define DONT_USE_INTR
|
||||
|
||||
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
|
||||
@ -29,10 +25,9 @@
|
||||
|
||||
#define NCR5380_read(reg) readb(_base + ((reg) << 2))
|
||||
#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
|
||||
#define NCR5380_intr oakscsi_intr
|
||||
#define NCR5380_queue_command oakscsi_queue_command
|
||||
#define NCR5380_info oakscsi_info
|
||||
#define NCR5380_show_info oakscsi_show_info
|
||||
#define NCR5380_write_info oakscsi_write_info
|
||||
|
||||
#define NCR5380_implementation_fields \
|
||||
void __iomem *base
|
||||
@ -42,11 +37,6 @@
|
||||
#undef START_DMA_INITIATOR_RECEIVE_REG
|
||||
#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
|
||||
|
||||
const char * oakscsi_info (struct Scsi_Host *spnt)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
#define STAT ((128 + 16) << 2)
|
||||
#define DATA ((128 + 8) << 2)
|
||||
|
||||
@ -114,7 +104,6 @@ printk("reading %p len %d\n", addr, len);
|
||||
static struct scsi_host_template oakscsi_template = {
|
||||
.module = THIS_MODULE,
|
||||
.show_info = oakscsi_show_info,
|
||||
.write_info = oakscsi_write_info,
|
||||
.name = "Oak 16-bit SCSI",
|
||||
.info = oakscsi_info,
|
||||
.queuecommand = oakscsi_queue_command,
|
||||
@ -150,19 +139,11 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
|
||||
goto unreg;
|
||||
}
|
||||
|
||||
host->irq = IRQ_NONE;
|
||||
host->irq = NO_IRQ;
|
||||
host->n_io_port = 255;
|
||||
|
||||
NCR5380_init(host, 0);
|
||||
|
||||
printk("scsi%d: at port 0x%08lx irqs disabled",
|
||||
host->host_no, host->io_port);
|
||||
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
|
||||
host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
|
||||
printk("\nscsi%d:", host->host_no);
|
||||
NCR5380_print_options(host);
|
||||
printk("\n");
|
||||
|
||||
ret = scsi_add_host(host, &ec->dev);
|
||||
if (ret)
|
||||
goto out_unmap;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -64,45 +64,57 @@
|
||||
/**************************************************************************/
|
||||
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#define AUTOSENSE
|
||||
/* For the Atari version, use only polled IO or REAL_DMA */
|
||||
#define REAL_DMA
|
||||
/* Support tagged queuing? (on devices that are able to... :-) */
|
||||
#define SUPPORT_TAGS
|
||||
#define MAX_TAGS 32
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/nvram.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/atarihw.h>
|
||||
#include <asm/atariints.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "atari_scsi.h"
|
||||
#include "NCR5380.h"
|
||||
#include <asm/atari_stdma.h>
|
||||
#include <asm/atari_stram.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/stat.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
/* Definitions for the core NCR5380 driver. */
|
||||
|
||||
#define REAL_DMA
|
||||
#define SUPPORT_TAGS
|
||||
#define MAX_TAGS 32
|
||||
#define DMA_MIN_SIZE 32
|
||||
|
||||
#define NCR5380_implementation_fields /* none */
|
||||
|
||||
#define NCR5380_read(reg) atari_scsi_reg_read(reg)
|
||||
#define NCR5380_write(reg, value) atari_scsi_reg_write(reg, value)
|
||||
|
||||
#define NCR5380_queue_command atari_scsi_queue_command
|
||||
#define NCR5380_abort atari_scsi_abort
|
||||
#define NCR5380_show_info atari_scsi_show_info
|
||||
#define NCR5380_info atari_scsi_info
|
||||
|
||||
#define NCR5380_dma_read_setup(instance, data, count) \
|
||||
atari_scsi_dma_setup(instance, data, count, 0)
|
||||
#define NCR5380_dma_write_setup(instance, data, count) \
|
||||
atari_scsi_dma_setup(instance, data, count, 1)
|
||||
#define NCR5380_dma_residual(instance) \
|
||||
atari_scsi_dma_residual(instance)
|
||||
#define NCR5380_dma_xfer_len(instance, cmd, phase) \
|
||||
atari_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
|
||||
|
||||
#define NCR5380_acquire_dma_irq(instance) falcon_get_lock(instance)
|
||||
#define NCR5380_release_dma_irq(instance) falcon_release_lock()
|
||||
|
||||
#include "NCR5380.h"
|
||||
|
||||
|
||||
#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI)
|
||||
|
||||
@ -149,23 +161,6 @@ static inline unsigned long SCSI_DMA_GETADR(void)
|
||||
return adr;
|
||||
}
|
||||
|
||||
static inline void ENABLE_IRQ(void)
|
||||
{
|
||||
if (IS_A_TT())
|
||||
atari_enable_irq(IRQ_TT_MFP_SCSI);
|
||||
else
|
||||
atari_enable_irq(IRQ_MFP_FSCSI);
|
||||
}
|
||||
|
||||
static inline void DISABLE_IRQ(void)
|
||||
{
|
||||
if (IS_A_TT())
|
||||
atari_disable_irq(IRQ_TT_MFP_SCSI);
|
||||
else
|
||||
atari_disable_irq(IRQ_MFP_FSCSI);
|
||||
}
|
||||
|
||||
|
||||
#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \
|
||||
(atari_scsi_host->hostdata))->dma_len)
|
||||
|
||||
@ -178,30 +173,9 @@ static inline void DISABLE_IRQ(void)
|
||||
#define AFTER_RESET_DELAY (5*HZ/2)
|
||||
#endif
|
||||
|
||||
/***************************** Prototypes *****************************/
|
||||
|
||||
#ifdef REAL_DMA
|
||||
static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
|
||||
static void atari_scsi_fetch_restbytes(void);
|
||||
static long atari_scsi_dma_residual(struct Scsi_Host *instance);
|
||||
static int falcon_classify_cmd(Scsi_Cmnd *cmd);
|
||||
static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
|
||||
Scsi_Cmnd *cmd, int write_flag);
|
||||
#endif
|
||||
static irqreturn_t scsi_tt_intr(int irq, void *dummy);
|
||||
static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
|
||||
static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
|
||||
static void falcon_get_lock(void);
|
||||
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
|
||||
static void atari_scsi_reset_boot(void);
|
||||
#endif
|
||||
static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
|
||||
static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
|
||||
static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
|
||||
static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
|
||||
|
||||
/************************* End of Prototypes **************************/
|
||||
|
||||
|
||||
static struct Scsi_Host *atari_scsi_host;
|
||||
static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
|
||||
@ -226,8 +200,6 @@ static char *atari_dma_orig_addr;
|
||||
/* mask for address bits that can't be used with the ST-DMA */
|
||||
static unsigned long atari_dma_stram_mask;
|
||||
#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
|
||||
/* number of bytes to cut from a transfer to handle NCR overruns */
|
||||
static int atari_read_overruns;
|
||||
#endif
|
||||
|
||||
static int setup_can_queue = -1;
|
||||
@ -386,10 +358,6 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
|
||||
|
||||
NCR5380_intr(irq, dummy);
|
||||
|
||||
#if 0
|
||||
/* To be sure the int is not masked */
|
||||
atari_enable_irq(IRQ_TT_MFP_SCSI);
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -480,257 +448,35 @@ static void atari_scsi_fetch_restbytes(void)
|
||||
#endif /* REAL_DMA */
|
||||
|
||||
|
||||
static int falcon_got_lock = 0;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);
|
||||
static int falcon_trying_lock = 0;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);
|
||||
static int falcon_dont_release = 0;
|
||||
|
||||
/* This function releases the lock on the DMA chip if there is no
|
||||
* connected command and the disconnected queue is empty. On
|
||||
* releasing, instances of falcon_get_lock are awoken, that put
|
||||
* themselves to sleep for fairness. They can now try to get the lock
|
||||
* again (but others waiting longer more probably will win).
|
||||
* connected command and the disconnected queue is empty.
|
||||
*/
|
||||
|
||||
static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
|
||||
static void falcon_release_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_A_TT())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (falcon_got_lock && !hostdata->disconnected_queue &&
|
||||
!hostdata->issue_queue && !hostdata->connected) {
|
||||
|
||||
if (falcon_dont_release) {
|
||||
#if 0
|
||||
printk("WARNING: Lock release not allowed. Ignored\n");
|
||||
#endif
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
falcon_got_lock = 0;
|
||||
if (stdma_is_locked_by(scsi_falcon_intr))
|
||||
stdma_release();
|
||||
wake_up(&falcon_fairness_wait);
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* This function manages the locking of the ST-DMA.
|
||||
* If the DMA isn't locked already for SCSI, it tries to lock it by
|
||||
* calling stdma_lock(). But if the DMA is locked by the SCSI code and
|
||||
* there are other drivers waiting for the chip, we do not issue the
|
||||
* command immediately but wait on 'falcon_fairness_queue'. We will be
|
||||
* waked up when the DMA is unlocked by some SCSI interrupt. After that
|
||||
* we try to get the lock again.
|
||||
* But we must be prepared that more than one instance of
|
||||
* falcon_get_lock() is waiting on the fairness queue. They should not
|
||||
* try all at once to call stdma_lock(), one is enough! For that, the
|
||||
* first one sets 'falcon_trying_lock', others that see that variable
|
||||
* set wait on the queue 'falcon_try_wait'.
|
||||
* Complicated, complicated.... Sigh...
|
||||
* command immediately but tell the SCSI mid-layer to defer.
|
||||
*/
|
||||
|
||||
static void falcon_get_lock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_A_TT())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
wait_event_cmd(falcon_fairness_wait,
|
||||
in_interrupt() || !falcon_got_lock || !stdma_others_waiting(),
|
||||
local_irq_restore(flags),
|
||||
local_irq_save(flags));
|
||||
|
||||
while (!falcon_got_lock) {
|
||||
if (in_irq())
|
||||
panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
|
||||
if (!falcon_trying_lock) {
|
||||
falcon_trying_lock = 1;
|
||||
stdma_lock(scsi_falcon_intr, NULL);
|
||||
falcon_got_lock = 1;
|
||||
falcon_trying_lock = 0;
|
||||
wake_up(&falcon_try_wait);
|
||||
} else {
|
||||
wait_event_cmd(falcon_try_wait,
|
||||
falcon_got_lock && !falcon_trying_lock,
|
||||
local_irq_restore(flags),
|
||||
local_irq_save(flags));
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
if (!falcon_got_lock)
|
||||
panic("Falcon SCSI: someone stole the lock :-(\n");
|
||||
}
|
||||
|
||||
|
||||
static int __init atari_scsi_detect(struct scsi_host_template *host)
|
||||
{
|
||||
static int called = 0;
|
||||
struct Scsi_Host *instance;
|
||||
|
||||
if (!MACH_IS_ATARI ||
|
||||
(!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
|
||||
called)
|
||||
return 0;
|
||||
|
||||
host->proc_name = "Atari";
|
||||
|
||||
atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read :
|
||||
atari_scsi_falcon_reg_read;
|
||||
atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
|
||||
atari_scsi_falcon_reg_write;
|
||||
|
||||
/* setup variables */
|
||||
host->can_queue =
|
||||
(setup_can_queue > 0) ? setup_can_queue :
|
||||
IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE;
|
||||
host->cmd_per_lun =
|
||||
(setup_cmd_per_lun > 0) ? setup_cmd_per_lun :
|
||||
IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN;
|
||||
/* Force sg_tablesize to 0 on a Falcon! */
|
||||
host->sg_tablesize =
|
||||
!IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE :
|
||||
(setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE;
|
||||
|
||||
if (setup_hostid >= 0)
|
||||
host->this_id = setup_hostid;
|
||||
else {
|
||||
/* use 7 as default */
|
||||
host->this_id = 7;
|
||||
/* Test if a host id is set in the NVRam */
|
||||
if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
|
||||
unsigned char b = nvram_read_byte( 14 );
|
||||
/* Arbitration enabled? (for TOS) If yes, use configured host ID */
|
||||
if (b & 0x80)
|
||||
host->this_id = b & 7;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_TAGS
|
||||
if (setup_use_tagged_queuing < 0)
|
||||
setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
|
||||
#endif
|
||||
#ifdef REAL_DMA
|
||||
/* If running on a Falcon and if there's TT-Ram (i.e., more than one
|
||||
* memory block, since there's always ST-Ram in a Falcon), then allocate a
|
||||
* STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative
|
||||
* Ram.
|
||||
*/
|
||||
if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
|
||||
!ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
|
||||
atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
|
||||
if (!atari_dma_buffer) {
|
||||
printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
|
||||
"double buffer\n");
|
||||
return 0;
|
||||
}
|
||||
atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
|
||||
atari_dma_orig_addr = 0;
|
||||
}
|
||||
#endif
|
||||
instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
|
||||
if (instance == NULL) {
|
||||
atari_stram_free(atari_dma_buffer);
|
||||
atari_dma_buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
atari_scsi_host = instance;
|
||||
/*
|
||||
* Set irq to 0, to avoid that the mid-level code disables our interrupt
|
||||
* during queue_command calls. This is completely unnecessary, and even
|
||||
* worse causes bad problems on the Falcon, where the int is shared with
|
||||
* IDE and floppy!
|
||||
*/
|
||||
instance->irq = 0;
|
||||
|
||||
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
|
||||
atari_scsi_reset_boot();
|
||||
#endif
|
||||
NCR5380_init(instance, 0);
|
||||
|
||||
if (IS_A_TT()) {
|
||||
|
||||
/* This int is actually "pseudo-slow", i.e. it acts like a slow
|
||||
* interrupt after having cleared the pending flag for the DMA
|
||||
* interrupt. */
|
||||
if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
|
||||
"SCSI NCR5380", instance)) {
|
||||
printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI);
|
||||
scsi_unregister(atari_scsi_host);
|
||||
atari_stram_free(atari_dma_buffer);
|
||||
atari_dma_buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
|
||||
#ifdef REAL_DMA
|
||||
tt_scsi_dma.dma_ctrl = 0;
|
||||
atari_dma_residual = 0;
|
||||
|
||||
if (MACH_IS_MEDUSA) {
|
||||
/* While the read overruns (described by Drew Eckhardt in
|
||||
* NCR5380.c) never happened on TTs, they do in fact on the Medusa
|
||||
* (This was the cause why SCSI didn't work right for so long
|
||||
* there.) Since handling the overruns slows down a bit, I turned
|
||||
* the #ifdef's into a runtime condition.
|
||||
*
|
||||
* In principle it should be sufficient to do max. 1 byte with
|
||||
* PIO, but there is another problem on the Medusa with the DMA
|
||||
* rest data register. So 'atari_read_overruns' is currently set
|
||||
* to 4 to avoid having transfers that aren't a multiple of 4. If
|
||||
* the rest data bug is fixed, this can be lowered to 1.
|
||||
*/
|
||||
atari_read_overruns = 4;
|
||||
}
|
||||
#endif /*REAL_DMA*/
|
||||
} else { /* ! IS_A_TT */
|
||||
|
||||
/* Nothing to do for the interrupt: the ST-DMA is initialized
|
||||
* already by atari_init_INTS()
|
||||
*/
|
||||
|
||||
#ifdef REAL_DMA
|
||||
atari_dma_residual = 0;
|
||||
atari_dma_active = 0;
|
||||
atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
|
||||
: 0xff000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
|
||||
#ifdef SUPPORT_TAGS
|
||||
"TAGGED-QUEUING=%s "
|
||||
#endif
|
||||
"HOSTID=%d",
|
||||
instance->host_no, instance->hostt->can_queue,
|
||||
instance->hostt->cmd_per_lun,
|
||||
instance->hostt->sg_tablesize,
|
||||
#ifdef SUPPORT_TAGS
|
||||
setup_use_tagged_queuing ? "yes" : "no",
|
||||
#endif
|
||||
instance->hostt->this_id );
|
||||
NCR5380_print_options(instance);
|
||||
printk("\n");
|
||||
|
||||
called = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int atari_scsi_release(struct Scsi_Host *sh)
|
||||
static int falcon_get_lock(struct Scsi_Host *instance)
|
||||
{
|
||||
if (IS_A_TT())
|
||||
free_irq(IRQ_TT_MFP_SCSI, sh);
|
||||
if (atari_dma_buffer)
|
||||
atari_stram_free(atari_dma_buffer);
|
||||
NCR5380_exit(sh);
|
||||
return 1;
|
||||
|
||||
if (in_interrupt())
|
||||
return stdma_try_lock(scsi_falcon_intr, instance);
|
||||
|
||||
stdma_lock(scsi_falcon_intr, instance);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -739,7 +485,7 @@ static int __init atari_scsi_setup(char *str)
|
||||
{
|
||||
/* Format of atascsi parameter is:
|
||||
* atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
|
||||
* Defaults depend on TT or Falcon, hostid determined at run time.
|
||||
* Defaults depend on TT or Falcon, determined at run time.
|
||||
* Negative values mean don't change.
|
||||
*/
|
||||
int ints[6];
|
||||
@ -750,36 +496,17 @@ static int __init atari_scsi_setup(char *str)
|
||||
printk("atari_scsi_setup: no arguments!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ints[0] >= 1) {
|
||||
if (ints[1] > 0)
|
||||
/* no limits on this, just > 0 */
|
||||
setup_can_queue = ints[1];
|
||||
}
|
||||
if (ints[0] >= 2) {
|
||||
if (ints[2] > 0)
|
||||
setup_cmd_per_lun = ints[2];
|
||||
}
|
||||
if (ints[0] >= 3) {
|
||||
if (ints[3] >= 0) {
|
||||
setup_sg_tablesize = ints[3];
|
||||
/* Must be <= SG_ALL (255) */
|
||||
if (setup_sg_tablesize > SG_ALL)
|
||||
setup_sg_tablesize = SG_ALL;
|
||||
}
|
||||
}
|
||||
if (ints[0] >= 4) {
|
||||
/* Must be between 0 and 7 */
|
||||
if (ints[4] >= 0 && ints[4] <= 7)
|
||||
setup_hostid = ints[4];
|
||||
else if (ints[4] > 7)
|
||||
printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
|
||||
}
|
||||
if (ints[0] >= 1)
|
||||
setup_can_queue = ints[1];
|
||||
if (ints[0] >= 2)
|
||||
setup_cmd_per_lun = ints[2];
|
||||
if (ints[0] >= 3)
|
||||
setup_sg_tablesize = ints[3];
|
||||
if (ints[0] >= 4)
|
||||
setup_hostid = ints[4];
|
||||
#ifdef SUPPORT_TAGS
|
||||
if (ints[0] >= 5) {
|
||||
if (ints[5] >= 0)
|
||||
setup_use_tagged_queuing = !!ints[5];
|
||||
}
|
||||
if (ints[0] >= 5)
|
||||
setup_use_tagged_queuing = ints[5];
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@ -788,45 +515,6 @@ static int __init atari_scsi_setup(char *str)
|
||||
__setup("atascsi=", atari_scsi_setup);
|
||||
#endif /* !MODULE */
|
||||
|
||||
static int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
|
||||
{
|
||||
int rv;
|
||||
struct NCR5380_hostdata *hostdata =
|
||||
(struct NCR5380_hostdata *)cmd->device->host->hostdata;
|
||||
|
||||
/* For doing the reset, SCSI interrupts must be disabled first,
|
||||
* since the 5380 raises its IRQ line while _RST is active and we
|
||||
* can't disable interrupts completely, since we need the timer.
|
||||
*/
|
||||
/* And abort a maybe active DMA transfer */
|
||||
if (IS_A_TT()) {
|
||||
atari_turnoff_irq(IRQ_TT_MFP_SCSI);
|
||||
#ifdef REAL_DMA
|
||||
tt_scsi_dma.dma_ctrl = 0;
|
||||
#endif /* REAL_DMA */
|
||||
} else {
|
||||
atari_turnoff_irq(IRQ_MFP_FSCSI);
|
||||
#ifdef REAL_DMA
|
||||
st_dma.dma_mode_status = 0x90;
|
||||
atari_dma_active = 0;
|
||||
atari_dma_orig_addr = NULL;
|
||||
#endif /* REAL_DMA */
|
||||
}
|
||||
|
||||
rv = NCR5380_bus_reset(cmd);
|
||||
|
||||
/* Re-enable ints */
|
||||
if (IS_A_TT()) {
|
||||
atari_turnon_irq(IRQ_TT_MFP_SCSI);
|
||||
} else {
|
||||
atari_turnon_irq(IRQ_MFP_FSCSI);
|
||||
}
|
||||
if (rv == SUCCESS)
|
||||
falcon_release_lock_if_possible(hostdata);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
|
||||
static void __init atari_scsi_reset_boot(void)
|
||||
@ -860,15 +548,6 @@ static void __init atari_scsi_reset_boot(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static const char *atari_scsi_info(struct Scsi_Host *host)
|
||||
{
|
||||
/* atari_scsi_detect() is verbose enough... */
|
||||
static const char string[] = "Atari native SCSI";
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
#if defined(REAL_DMA)
|
||||
|
||||
static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
|
||||
@ -949,7 +628,7 @@ static long atari_scsi_dma_residual(struct Scsi_Host *instance)
|
||||
#define CMD_SURELY_BYTE_MODE 1
|
||||
#define CMD_MODE_UNKNOWN 2
|
||||
|
||||
static int falcon_classify_cmd(Scsi_Cmnd *cmd)
|
||||
static int falcon_classify_cmd(struct scsi_cmnd *cmd)
|
||||
{
|
||||
unsigned char opcode = cmd->cmnd[0];
|
||||
|
||||
@ -981,7 +660,7 @@ static int falcon_classify_cmd(Scsi_Cmnd *cmd)
|
||||
*/
|
||||
|
||||
static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
|
||||
Scsi_Cmnd *cmd, int write_flag)
|
||||
struct scsi_cmnd *cmd, int write_flag)
|
||||
{
|
||||
unsigned long possible_len, limit;
|
||||
|
||||
@ -1099,23 +778,247 @@ static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
|
||||
|
||||
#include "atari_NCR5380.c"
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
|
||||
{
|
||||
int rv;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
#ifdef REAL_DMA
|
||||
/* Abort a maybe active DMA transfer */
|
||||
if (IS_A_TT()) {
|
||||
tt_scsi_dma.dma_ctrl = 0;
|
||||
} else {
|
||||
st_dma.dma_mode_status = 0x90;
|
||||
atari_dma_active = 0;
|
||||
atari_dma_orig_addr = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
rv = NCR5380_bus_reset(cmd);
|
||||
|
||||
/* The 5380 raises its IRQ line while _RST is active but the ST DMA
|
||||
* "lock" has been released so this interrupt may end up handled by
|
||||
* floppy or IDE driver (if one of them holds the lock). The NCR5380
|
||||
* interrupt flag has been cleared already.
|
||||
*/
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#define DRV_MODULE_NAME "atari_scsi"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
|
||||
static struct scsi_host_template atari_scsi_template = {
|
||||
.module = THIS_MODULE,
|
||||
.proc_name = DRV_MODULE_NAME,
|
||||
.show_info = atari_scsi_show_info,
|
||||
.name = "Atari native SCSI",
|
||||
.detect = atari_scsi_detect,
|
||||
.release = atari_scsi_release,
|
||||
.info = atari_scsi_info,
|
||||
.queuecommand = atari_scsi_queue_command,
|
||||
.eh_abort_handler = atari_scsi_abort,
|
||||
.eh_bus_reset_handler = atari_scsi_bus_reset,
|
||||
.can_queue = 0, /* initialized at run-time */
|
||||
.this_id = 0, /* initialized at run-time */
|
||||
.sg_tablesize = 0, /* initialized at run-time */
|
||||
.cmd_per_lun = 0, /* initialized at run-time */
|
||||
.this_id = 7,
|
||||
.use_clustering = DISABLE_CLUSTERING
|
||||
};
|
||||
|
||||
static int __init atari_scsi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct Scsi_Host *instance;
|
||||
int error;
|
||||
struct resource *irq;
|
||||
int host_flags = 0;
|
||||
|
||||
#include "scsi_module.c"
|
||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!irq)
|
||||
return -ENODEV;
|
||||
|
||||
if (ATARIHW_PRESENT(TT_SCSI)) {
|
||||
atari_scsi_reg_read = atari_scsi_tt_reg_read;
|
||||
atari_scsi_reg_write = atari_scsi_tt_reg_write;
|
||||
} else {
|
||||
atari_scsi_reg_read = atari_scsi_falcon_reg_read;
|
||||
atari_scsi_reg_write = atari_scsi_falcon_reg_write;
|
||||
}
|
||||
|
||||
/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary.
|
||||
* Higher values should work, too; try it!
|
||||
* (But cmd_per_lun costs memory!)
|
||||
*
|
||||
* But there seems to be a bug somewhere that requires CAN_QUEUE to be
|
||||
* 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
|
||||
* changed CMD_PER_LUN...
|
||||
*
|
||||
* Note: The Falcon currently uses 8/1 setting due to unsolved problems
|
||||
* with cmd_per_lun != 1
|
||||
*/
|
||||
if (ATARIHW_PRESENT(TT_SCSI)) {
|
||||
atari_scsi_template.can_queue = 16;
|
||||
atari_scsi_template.cmd_per_lun = 8;
|
||||
atari_scsi_template.sg_tablesize = SG_ALL;
|
||||
} else {
|
||||
atari_scsi_template.can_queue = 8;
|
||||
atari_scsi_template.cmd_per_lun = 1;
|
||||
atari_scsi_template.sg_tablesize = SG_NONE;
|
||||
}
|
||||
|
||||
if (setup_can_queue > 0)
|
||||
atari_scsi_template.can_queue = setup_can_queue;
|
||||
|
||||
if (setup_cmd_per_lun > 0)
|
||||
atari_scsi_template.cmd_per_lun = setup_cmd_per_lun;
|
||||
|
||||
/* Leave sg_tablesize at 0 on a Falcon! */
|
||||
if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
|
||||
atari_scsi_template.sg_tablesize = setup_sg_tablesize;
|
||||
|
||||
if (setup_hostid >= 0) {
|
||||
atari_scsi_template.this_id = setup_hostid & 7;
|
||||
} else {
|
||||
/* Test if a host id is set in the NVRam */
|
||||
if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
|
||||
unsigned char b = nvram_read_byte(14);
|
||||
|
||||
/* Arbitration enabled? (for TOS)
|
||||
* If yes, use configured host ID
|
||||
*/
|
||||
if (b & 0x80)
|
||||
atari_scsi_template.this_id = b & 7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef REAL_DMA
|
||||
/* If running on a Falcon and if there's TT-Ram (i.e., more than one
|
||||
* memory block, since there's always ST-Ram in a Falcon), then
|
||||
* allocate a STRAM_BUFFER_SIZE byte dribble buffer for transfers
|
||||
* from/to alternative Ram.
|
||||
*/
|
||||
if (ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(EXTD_DMA) &&
|
||||
m68k_num_memory > 1) {
|
||||
atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
|
||||
if (!atari_dma_buffer) {
|
||||
pr_err(PFX "can't allocate ST-RAM double buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
|
||||
atari_dma_orig_addr = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
instance = scsi_host_alloc(&atari_scsi_template,
|
||||
sizeof(struct NCR5380_hostdata));
|
||||
if (!instance) {
|
||||
error = -ENOMEM;
|
||||
goto fail_alloc;
|
||||
}
|
||||
atari_scsi_host = instance;
|
||||
|
||||
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
|
||||
atari_scsi_reset_boot();
|
||||
#endif
|
||||
|
||||
instance->irq = irq->start;
|
||||
|
||||
host_flags |= IS_A_TT() ? 0 : FLAG_LATE_DMA_SETUP;
|
||||
|
||||
#ifdef SUPPORT_TAGS
|
||||
host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
|
||||
#endif
|
||||
|
||||
NCR5380_init(instance, host_flags);
|
||||
|
||||
if (IS_A_TT()) {
|
||||
error = request_irq(instance->irq, scsi_tt_intr, 0,
|
||||
"NCR5380", instance);
|
||||
if (error) {
|
||||
pr_err(PFX "request irq %d failed, aborting\n",
|
||||
instance->irq);
|
||||
goto fail_irq;
|
||||
}
|
||||
tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
|
||||
#ifdef REAL_DMA
|
||||
tt_scsi_dma.dma_ctrl = 0;
|
||||
atari_dma_residual = 0;
|
||||
|
||||
/* While the read overruns (described by Drew Eckhardt in
|
||||
* NCR5380.c) never happened on TTs, they do in fact on the
|
||||
* Medusa (This was the cause why SCSI didn't work right for
|
||||
* so long there.) Since handling the overruns slows down
|
||||
* a bit, I turned the #ifdef's into a runtime condition.
|
||||
*
|
||||
* In principle it should be sufficient to do max. 1 byte with
|
||||
* PIO, but there is another problem on the Medusa with the DMA
|
||||
* rest data register. So read_overruns is currently set
|
||||
* to 4 to avoid having transfers that aren't a multiple of 4.
|
||||
* If the rest data bug is fixed, this can be lowered to 1.
|
||||
*/
|
||||
if (MACH_IS_MEDUSA) {
|
||||
struct NCR5380_hostdata *hostdata =
|
||||
shost_priv(instance);
|
||||
|
||||
hostdata->read_overruns = 4;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* Nothing to do for the interrupt: the ST-DMA is initialized
|
||||
* already.
|
||||
*/
|
||||
#ifdef REAL_DMA
|
||||
atari_dma_residual = 0;
|
||||
atari_dma_active = 0;
|
||||
atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
|
||||
: 0xff000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
error = scsi_add_host(instance, NULL);
|
||||
if (error)
|
||||
goto fail_host;
|
||||
|
||||
platform_set_drvdata(pdev, instance);
|
||||
|
||||
scsi_scan_host(instance);
|
||||
return 0;
|
||||
|
||||
fail_host:
|
||||
if (IS_A_TT())
|
||||
free_irq(instance->irq, instance);
|
||||
fail_irq:
|
||||
NCR5380_exit(instance);
|
||||
scsi_host_put(instance);
|
||||
fail_alloc:
|
||||
if (atari_dma_buffer)
|
||||
atari_stram_free(atari_dma_buffer);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __exit atari_scsi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct Scsi_Host *instance = platform_get_drvdata(pdev);
|
||||
|
||||
scsi_remove_host(instance);
|
||||
if (IS_A_TT())
|
||||
free_irq(instance->irq, instance);
|
||||
NCR5380_exit(instance);
|
||||
scsi_host_put(instance);
|
||||
if (atari_dma_buffer)
|
||||
atari_stram_free(atari_dma_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver atari_scsi_driver = {
|
||||
.remove = __exit_p(atari_scsi_remove),
|
||||
.driver = {
|
||||
.name = DRV_MODULE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(atari_scsi_driver, atari_scsi_probe);
|
||||
|
||||
MODULE_ALIAS("platform:" DRV_MODULE_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* atari_scsi.h -- Header file for the Atari native SCSI driver
|
||||
*
|
||||
* Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||
*
|
||||
* (Loosely based on the work of Robert De Vries' team)
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ATARI_SCSI_H
|
||||
#define ATARI_SCSI_H
|
||||
|
||||
/* (I_HAVE_OVERRUNS stuff removed) */
|
||||
|
||||
#ifndef ASM
|
||||
/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
|
||||
* values should work, too; try it! (but cmd_per_lun costs memory!) */
|
||||
|
||||
/* But there seems to be a bug somewhere that requires CAN_QUEUE to be
|
||||
* 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
|
||||
* changed CMD_PER_LUN... */
|
||||
|
||||
/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
|
||||
* cmd_per_lun != 1 */
|
||||
|
||||
#define ATARI_TT_CAN_QUEUE 16
|
||||
#define ATARI_TT_CMD_PER_LUN 8
|
||||
#define ATARI_TT_SG_TABLESIZE SG_ALL
|
||||
|
||||
#define ATARI_FALCON_CAN_QUEUE 8
|
||||
#define ATARI_FALCON_CMD_PER_LUN 1
|
||||
#define ATARI_FALCON_SG_TABLESIZE SG_NONE
|
||||
|
||||
#define DEFAULT_USE_TAGGED_QUEUING 0
|
||||
|
||||
|
||||
#define NCR5380_implementation_fields /* none */
|
||||
|
||||
#define NCR5380_read(reg) atari_scsi_reg_read( reg )
|
||||
#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value )
|
||||
|
||||
#define NCR5380_intr atari_scsi_intr
|
||||
#define NCR5380_queue_command atari_scsi_queue_command
|
||||
#define NCR5380_abort atari_scsi_abort
|
||||
#define NCR5380_show_info atari_scsi_show_info
|
||||
#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0)
|
||||
#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1)
|
||||
#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst )
|
||||
#define NCR5380_dma_xfer_len(i,cmd,phase) \
|
||||
atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
|
||||
|
||||
#endif /* ndef ASM */
|
||||
#endif /* ATARI_SCSI_H */
|
||||
|
||||
|
@ -556,7 +556,7 @@ static struct scsi_host_template beiscsi_sht = {
|
||||
.name = "Emulex 10Gbe open-iscsi Initiator Driver",
|
||||
.proc_name = DRV_NAME,
|
||||
.queuecommand = iscsi_queuecommand,
|
||||
.change_queue_depth = iscsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.slave_configure = beiscsi_slave_configure,
|
||||
.target_alloc = iscsi_target_alloc,
|
||||
.eh_abort_handler = beiscsi_eh_abort,
|
||||
@ -570,7 +570,7 @@ static struct scsi_host_template beiscsi_sht = {
|
||||
.cmd_per_lun = BEISCSI_CMD_PER_LUN,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
|
||||
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static struct scsi_transport_template *beiscsi_scsi_transport;
|
||||
|
@ -260,18 +260,9 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
|
||||
unsigned long flags;
|
||||
void *kern_buf;
|
||||
|
||||
kern_buf = kzalloc(nbytes, GFP_KERNEL);
|
||||
|
||||
if (!kern_buf) {
|
||||
printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
|
||||
bfad->inst_no);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
|
||||
kfree(kern_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kern_buf = memdup_user(buf, nbytes);
|
||||
if (IS_ERR(kern_buf))
|
||||
return PTR_ERR(kern_buf);
|
||||
|
||||
rc = sscanf(kern_buf, "%x:%x", &addr, &len);
|
||||
if (rc < 2) {
|
||||
@ -336,18 +327,9 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
|
||||
unsigned long flags;
|
||||
void *kern_buf;
|
||||
|
||||
kern_buf = kzalloc(nbytes, GFP_KERNEL);
|
||||
|
||||
if (!kern_buf) {
|
||||
printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
|
||||
bfad->inst_no);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
|
||||
kfree(kern_buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
kern_buf = memdup_user(buf, nbytes);
|
||||
if (IS_ERR(kern_buf))
|
||||
return PTR_ERR(kern_buf);
|
||||
|
||||
rc = sscanf(kern_buf, "%x:%x", &addr, &val);
|
||||
if (rc < 2) {
|
||||
|
@ -776,11 +776,7 @@ bfad_thread_workq(struct bfad_s *bfad)
|
||||
static int
|
||||
bfad_im_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->tagged_supported)
|
||||
scsi_activate_tcq(sdev, bfa_lun_queue_depth);
|
||||
else
|
||||
scsi_deactivate_tcq(sdev, bfa_lun_queue_depth);
|
||||
|
||||
scsi_change_queue_depth(sdev, bfa_lun_queue_depth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -804,6 +800,7 @@ struct scsi_host_template bfad_im_scsi_host_template = {
|
||||
.shost_attrs = bfad_im_host_attrs,
|
||||
.max_sectors = BFAD_MAX_SECTORS,
|
||||
.vendor_id = BFA_PCI_VENDOR_ID_BROCADE,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
struct scsi_host_template bfad_im_vport_template = {
|
||||
@ -825,6 +822,7 @@ struct scsi_host_template bfad_im_vport_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = bfad_im_vport_attrs,
|
||||
.max_sectors = BFAD_MAX_SECTORS,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
bfa_status_t
|
||||
@ -868,14 +866,8 @@ bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
|
||||
if (bfa_lun_queue_depth > tmp_sdev->queue_depth) {
|
||||
if (tmp_sdev->id != sdev->id)
|
||||
continue;
|
||||
if (tmp_sdev->ordered_tags)
|
||||
scsi_adjust_queue_depth(tmp_sdev,
|
||||
MSG_ORDERED_TAG,
|
||||
tmp_sdev->queue_depth + 1);
|
||||
else
|
||||
scsi_adjust_queue_depth(tmp_sdev,
|
||||
MSG_SIMPLE_TAG,
|
||||
tmp_sdev->queue_depth + 1);
|
||||
scsi_change_queue_depth(tmp_sdev,
|
||||
tmp_sdev->queue_depth + 1);
|
||||
|
||||
itnim->last_ramp_up_time = jiffies;
|
||||
}
|
||||
|
@ -1088,7 +1088,7 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
|
||||
mutex_unlock(&bnx2fc_dev_lock);
|
||||
rtnl_unlock();
|
||||
|
||||
if (IS_ERR(vn_port)) {
|
||||
if (!vn_port) {
|
||||
printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n",
|
||||
netdev->name);
|
||||
return -EIO;
|
||||
@ -2202,6 +2202,7 @@ static int _bnx2fc_create(struct net_device *netdev,
|
||||
interface = bnx2fc_interface_create(hba, netdev, fip_mode);
|
||||
if (!interface) {
|
||||
printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto ifput_err;
|
||||
}
|
||||
|
||||
@ -2790,13 +2791,15 @@ static struct scsi_host_template bnx2fc_shost_template = {
|
||||
.eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */
|
||||
.eh_host_reset_handler = fc_eh_host_reset,
|
||||
.slave_alloc = fc_slave_alloc,
|
||||
.change_queue_depth = fc_change_queue_depth,
|
||||
.change_queue_type = fc_change_queue_type,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.change_queue_type = scsi_change_queue_type,
|
||||
.this_id = -1,
|
||||
.cmd_per_lun = 3,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
|
||||
.max_sectors = 1024,
|
||||
.use_blk_tags = 1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static struct libfc_function_template bnx2fc_libfc_fcn_templ = {
|
||||
|
@ -1725,7 +1725,6 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
|
||||
struct fcp_cmnd *fcp_cmnd)
|
||||
{
|
||||
struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
|
||||
char tag[2];
|
||||
|
||||
memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd));
|
||||
|
||||
@ -1739,21 +1738,10 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
|
||||
fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags;
|
||||
fcp_cmnd->fc_flags = io_req->io_req_flags;
|
||||
|
||||
if (scsi_populate_tag_msg(sc_cmd, tag)) {
|
||||
switch (tag[0]) {
|
||||
case HEAD_OF_QUEUE_TAG:
|
||||
fcp_cmnd->fc_pri_ta = FCP_PTA_HEADQ;
|
||||
break;
|
||||
case ORDERED_QUEUE_TAG:
|
||||
fcp_cmnd->fc_pri_ta = FCP_PTA_ORDERED;
|
||||
break;
|
||||
default:
|
||||
fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (sc_cmd->flags & SCMD_TAGGED)
|
||||
fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
else
|
||||
fcp_cmnd->fc_pri_ta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
|
||||
|
@ -2259,7 +2259,7 @@ static struct scsi_host_template bnx2i_host_template = {
|
||||
.eh_abort_handler = iscsi_eh_abort,
|
||||
.eh_device_reset_handler = iscsi_eh_device_reset,
|
||||
.eh_target_reset_handler = iscsi_eh_recover_target,
|
||||
.change_queue_depth = iscsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.target_alloc = iscsi_target_alloc,
|
||||
.can_queue = 2048,
|
||||
.max_sectors = 127,
|
||||
@ -2268,6 +2268,7 @@ static struct scsi_host_template bnx2i_host_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.sg_tablesize = ISCSI_MAX_BDS_PER_CMD,
|
||||
.shost_attrs = bnx2i_dev_attributes,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
struct iscsi_transport bnx2i_iscsi_transport = {
|
||||
|
@ -85,8 +85,7 @@ static const char * vendor_labels[CH_TYPES-4] = {
|
||||
// module_param_string_array(vendor_labels, NULL, 0444);
|
||||
|
||||
#define ch_printk(prefix, ch, fmt, a...) \
|
||||
sdev_printk(prefix, (ch)->device, "[%s] " fmt, \
|
||||
(ch)->name, ##a)
|
||||
sdev_prefix_printk(prefix, (ch)->device, (ch)->name, fmt, ##a)
|
||||
|
||||
#define DPRINTK(fmt, arg...) \
|
||||
do { \
|
||||
@ -183,7 +182,7 @@ static int ch_find_errno(struct scsi_sense_hdr *sshdr)
|
||||
}
|
||||
|
||||
static int
|
||||
ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
|
||||
ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
|
||||
void *buffer, unsigned buflength,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
@ -197,7 +196,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
|
||||
errno = 0;
|
||||
if (debug) {
|
||||
DPRINTK("command: ");
|
||||
__scsi_print_command(cmd);
|
||||
__scsi_print_command(cmd, cmd_len);
|
||||
}
|
||||
|
||||
result = scsi_execute_req(ch->device, cmd, direction, buffer,
|
||||
@ -207,7 +206,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
|
||||
DPRINTK("result: 0x%x\n",result);
|
||||
if (driver_byte(result) & DRIVER_SENSE) {
|
||||
if (debug)
|
||||
scsi_print_sense_hdr(ch->name, &sshdr);
|
||||
scsi_print_sense_hdr(ch->device, ch->name, &sshdr);
|
||||
errno = ch_find_errno(&sshdr);
|
||||
|
||||
switch(sshdr.sense_key) {
|
||||
@ -258,7 +257,8 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
|
||||
cmd[3] = elem & 0xff;
|
||||
cmd[5] = 1;
|
||||
cmd[9] = 255;
|
||||
if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
|
||||
if (0 == (result = ch_do_scsi(ch, cmd, 12,
|
||||
buffer, 256, DMA_FROM_DEVICE))) {
|
||||
if (((buffer[16] << 8) | buffer[17]) != elem) {
|
||||
DPRINTK("asked for element 0x%02x, got 0x%02x\n",
|
||||
elem,(buffer[16] << 8) | buffer[17]);
|
||||
@ -288,7 +288,7 @@ ch_init_elem(scsi_changer *ch)
|
||||
memset(cmd,0,sizeof(cmd));
|
||||
cmd[0] = INITIALIZE_ELEMENT_STATUS;
|
||||
cmd[1] = (ch->device->lun & 0x7) << 5;
|
||||
err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
|
||||
err = ch_do_scsi(ch, cmd, 6, NULL, 0, DMA_NONE);
|
||||
VPRINTK(KERN_INFO, "... finished\n");
|
||||
return err;
|
||||
}
|
||||
@ -310,10 +310,10 @@ ch_readconfig(scsi_changer *ch)
|
||||
cmd[1] = (ch->device->lun & 0x7) << 5;
|
||||
cmd[2] = 0x1d;
|
||||
cmd[4] = 255;
|
||||
result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
|
||||
result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
|
||||
if (0 != result) {
|
||||
cmd[1] |= (1<<3);
|
||||
result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
|
||||
result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
|
||||
}
|
||||
if (0 == result) {
|
||||
ch->firsts[CHET_MT] =
|
||||
@ -438,7 +438,7 @@ ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
|
||||
cmd[4] = (elem >> 8) & 0xff;
|
||||
cmd[5] = elem & 0xff;
|
||||
cmd[8] = rotate ? 1 : 0;
|
||||
return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
|
||||
return ch_do_scsi(ch, cmd, 10, NULL, 0, DMA_NONE);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -459,7 +459,7 @@ ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
|
||||
cmd[6] = (dest >> 8) & 0xff;
|
||||
cmd[7] = dest & 0xff;
|
||||
cmd[10] = rotate ? 1 : 0;
|
||||
return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
|
||||
return ch_do_scsi(ch, cmd, 12, NULL,0, DMA_NONE);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -485,7 +485,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
|
||||
cmd[9] = dest2 & 0xff;
|
||||
cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
|
||||
|
||||
return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
|
||||
return ch_do_scsi(ch, cmd, 12, NULL, 0, DMA_NONE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -535,7 +535,7 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
|
||||
memcpy(buffer,tag,32);
|
||||
ch_check_voltag(buffer);
|
||||
|
||||
result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE);
|
||||
result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_TO_DEVICE);
|
||||
kfree(buffer);
|
||||
return result;
|
||||
}
|
||||
@ -616,6 +616,11 @@ static long ch_ioctl(struct file *file,
|
||||
int retval;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
|
||||
file->f_flags & O_NDELAY);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
switch (cmd) {
|
||||
case CHIOGPARAMS:
|
||||
{
|
||||
@ -766,7 +771,8 @@ static long ch_ioctl(struct file *file,
|
||||
ch_cmd[5] = 1;
|
||||
ch_cmd[9] = 255;
|
||||
|
||||
result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE);
|
||||
result = ch_do_scsi(ch, ch_cmd, 12,
|
||||
buffer, 256, DMA_FROM_DEVICE);
|
||||
if (!result) {
|
||||
cge.cge_status = buffer[18];
|
||||
cge.cge_flags = 0;
|
||||
@ -966,9 +972,9 @@ static int ch_remove(struct device *dev)
|
||||
}
|
||||
|
||||
static struct scsi_driver ch_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.gendrv = {
|
||||
.name = "ch",
|
||||
.owner = THIS_MODULE,
|
||||
.probe = ch_probe,
|
||||
.remove = ch_remove,
|
||||
},
|
||||
|
@ -21,15 +21,21 @@
|
||||
|
||||
|
||||
/* Commands with service actions that change the command name */
|
||||
#define SERVICE_ACTION_IN_12 0xab
|
||||
#define SERVICE_ACTION_OUT_12 0xa9
|
||||
#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
|
||||
#define SERVICE_ACTION_IN_16 0x9e
|
||||
#define SERVICE_ACTION_OUT_16 0x9f
|
||||
#define THIRD_PARTY_COPY_OUT 0x83
|
||||
#define THIRD_PARTY_COPY_IN 0x84
|
||||
|
||||
#define VENDOR_SPECIFIC_CDB 0xc0
|
||||
|
||||
struct sa_name_list {
|
||||
int opcode;
|
||||
const struct value_name_pair *arr;
|
||||
int arr_sz;
|
||||
};
|
||||
|
||||
struct value_name_pair {
|
||||
int value;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
static const char * cdb_byte0_names[] = {
|
||||
@ -102,11 +108,6 @@ static const char * cdb_byte0_names[] = {
|
||||
"Volume set (out), Send DVD structure",
|
||||
};
|
||||
|
||||
struct value_name_pair {
|
||||
int value;
|
||||
const char * name;
|
||||
};
|
||||
|
||||
static const struct value_name_pair maint_in_arr[] = {
|
||||
{0x5, "Report identifying information"},
|
||||
{0xa, "Report target port groups"},
|
||||
@ -244,170 +245,119 @@ static const struct value_name_pair variable_length_arr[] = {
|
||||
};
|
||||
#define VARIABLE_LENGTH_SZ ARRAY_SIZE(variable_length_arr)
|
||||
|
||||
static const char * get_sa_name(const struct value_name_pair * arr,
|
||||
int arr_sz, int service_action)
|
||||
static struct sa_name_list sa_names_arr[] = {
|
||||
{VARIABLE_LENGTH_CMD, variable_length_arr, VARIABLE_LENGTH_SZ},
|
||||
{MAINTENANCE_IN, maint_in_arr, MAINT_IN_SZ},
|
||||
{MAINTENANCE_OUT, maint_out_arr, MAINT_OUT_SZ},
|
||||
{PERSISTENT_RESERVE_IN, pr_in_arr, PR_IN_SZ},
|
||||
{PERSISTENT_RESERVE_OUT, pr_out_arr, PR_OUT_SZ},
|
||||
{SERVICE_ACTION_IN_12, serv_in12_arr, SERV_IN12_SZ},
|
||||
{SERVICE_ACTION_OUT_12, serv_out12_arr, SERV_OUT12_SZ},
|
||||
{SERVICE_ACTION_BIDIRECTIONAL, serv_bidi_arr, SERV_BIDI_SZ},
|
||||
{SERVICE_ACTION_IN_16, serv_in16_arr, SERV_IN16_SZ},
|
||||
{SERVICE_ACTION_OUT_16, serv_out16_arr, SERV_OUT16_SZ},
|
||||
{THIRD_PARTY_COPY_IN, tpc_in_arr, TPC_IN_SZ},
|
||||
{THIRD_PARTY_COPY_OUT, tpc_out_arr, TPC_OUT_SZ},
|
||||
{0, NULL, 0},
|
||||
};
|
||||
|
||||
#else /* ifndef CONFIG_SCSI_CONSTANTS */
|
||||
static const char *cdb_byte0_names[0];
|
||||
|
||||
static struct sa_name_list sa_names_arr[] = {
|
||||
{VARIABLE_LENGTH_CMD, NULL, 0},
|
||||
{MAINTENANCE_IN, NULL, 0},
|
||||
{MAINTENANCE_OUT, NULL, 0},
|
||||
{PERSISTENT_RESERVE_IN, NULL, 0},
|
||||
{PERSISTENT_RESERVE_OUT, NULL, 0},
|
||||
{SERVICE_ACTION_IN_12, NULL, 0},
|
||||
{SERVICE_ACTION_OUT_12, NULL, 0},
|
||||
{SERVICE_ACTION_BIDIRECTIONAL, NULL, 0},
|
||||
{SERVICE_ACTION_IN_16, NULL, 0},
|
||||
{SERVICE_ACTION_OUT_16, NULL, 0},
|
||||
{THIRD_PARTY_COPY_IN, NULL, 0},
|
||||
{THIRD_PARTY_COPY_OUT, NULL, 0},
|
||||
{0, NULL, 0},
|
||||
};
|
||||
#endif /* CONFIG_SCSI_CONSTANTS */
|
||||
|
||||
static bool scsi_opcode_sa_name(int opcode, int service_action,
|
||||
const char **cdb_name, const char **sa_name)
|
||||
{
|
||||
int k;
|
||||
struct sa_name_list *sa_name_ptr;
|
||||
const struct value_name_pair *arr = NULL;
|
||||
int arr_sz, k;
|
||||
|
||||
*cdb_name = NULL;
|
||||
if (opcode >= VENDOR_SPECIFIC_CDB)
|
||||
return false;
|
||||
|
||||
if (opcode < ARRAY_SIZE(cdb_byte0_names))
|
||||
*cdb_name = cdb_byte0_names[opcode];
|
||||
|
||||
for (sa_name_ptr = sa_names_arr; sa_name_ptr->arr; ++sa_name_ptr) {
|
||||
if (sa_name_ptr->opcode == opcode) {
|
||||
arr = sa_name_ptr->arr;
|
||||
arr_sz = sa_name_ptr->arr_sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!arr)
|
||||
return false;
|
||||
|
||||
for (k = 0; k < arr_sz; ++k, ++arr) {
|
||||
if (service_action == arr->value)
|
||||
break;
|
||||
}
|
||||
return (k < arr_sz) ? arr->name : NULL;
|
||||
if (k < arr_sz)
|
||||
*sa_name = arr->name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
|
||||
static void print_opcode_name(unsigned char * cdbp, int cdb_len)
|
||||
static void print_opcode_name(const unsigned char *cdbp, size_t cdb_len)
|
||||
{
|
||||
int sa, len, cdb0;
|
||||
int fin_name = 0;
|
||||
const char * name;
|
||||
int sa, cdb0;
|
||||
const char *cdb_name = NULL, *sa_name = NULL;
|
||||
|
||||
cdb0 = cdbp[0];
|
||||
switch(cdb0) {
|
||||
case VARIABLE_LENGTH_CMD:
|
||||
len = scsi_varlen_cdb_length(cdbp);
|
||||
if (len < 10) {
|
||||
printk("short variable length command, "
|
||||
"len=%d ext_len=%d", len, cdb_len);
|
||||
break;
|
||||
if (cdb0 == VARIABLE_LENGTH_CMD) {
|
||||
if (cdb_len < 10) {
|
||||
printk("short variable length command, len=%zu",
|
||||
cdb_len);
|
||||
return;
|
||||
}
|
||||
sa = (cdbp[8] << 8) + cdbp[9];
|
||||
name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ,
|
||||
sa);
|
||||
if (name)
|
||||
printk("%s", name);
|
||||
else
|
||||
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
|
||||
} else
|
||||
sa = cdbp[1] & 0x1f;
|
||||
|
||||
if ((cdb_len > 0) && (len != cdb_len))
|
||||
printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
|
||||
|
||||
break;
|
||||
case MAINTENANCE_IN:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case MAINTENANCE_OUT:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case PERSISTENT_RESERVE_IN:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(pr_in_arr, PR_IN_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case PERSISTENT_RESERVE_OUT:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(pr_out_arr, PR_OUT_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case SERVICE_ACTION_IN_12:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case SERVICE_ACTION_OUT_12:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case SERVICE_ACTION_BIDIRECTIONAL:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(serv_bidi_arr, SERV_BIDI_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case SERVICE_ACTION_IN_16:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case SERVICE_ACTION_OUT_16:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case THIRD_PARTY_COPY_IN:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(tpc_in_arr, TPC_IN_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
case THIRD_PARTY_COPY_OUT:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
name = get_sa_name(tpc_out_arr, TPC_OUT_SZ, sa);
|
||||
fin_name = 1;
|
||||
break;
|
||||
default:
|
||||
if (cdb0 < 0xc0) {
|
||||
name = cdb_byte0_names[cdb0];
|
||||
if (name)
|
||||
printk("%s", name);
|
||||
else
|
||||
printk("cdb[0]=0x%x (reserved)", cdb0);
|
||||
} else
|
||||
if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
|
||||
if (cdb_name)
|
||||
printk("%s", cdb_name);
|
||||
else if (cdb0 >= VENDOR_SPECIFIC_CDB)
|
||||
printk("cdb[0]=0x%x (vendor)", cdb0);
|
||||
break;
|
||||
}
|
||||
if (fin_name) {
|
||||
if (name)
|
||||
printk("%s", name);
|
||||
else if (cdb0 >= 0x60 && cdb0 < 0x7e)
|
||||
printk("cdb[0]=0x%x (reserved)", cdb0);
|
||||
else
|
||||
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* ifndef CONFIG_SCSI_CONSTANTS */
|
||||
|
||||
static void print_opcode_name(unsigned char * cdbp, int cdb_len)
|
||||
{
|
||||
int sa, len, cdb0;
|
||||
|
||||
cdb0 = cdbp[0];
|
||||
switch(cdb0) {
|
||||
case VARIABLE_LENGTH_CMD:
|
||||
len = scsi_varlen_cdb_length(cdbp);
|
||||
if (len < 10) {
|
||||
printk("short opcode=0x%x command, len=%d "
|
||||
"ext_len=%d", cdb0, len, cdb_len);
|
||||
break;
|
||||
}
|
||||
sa = (cdbp[8] << 8) + cdbp[9];
|
||||
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
|
||||
if (len != cdb_len)
|
||||
printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
|
||||
break;
|
||||
case MAINTENANCE_IN:
|
||||
case MAINTENANCE_OUT:
|
||||
case PERSISTENT_RESERVE_IN:
|
||||
case PERSISTENT_RESERVE_OUT:
|
||||
case SERVICE_ACTION_IN_12:
|
||||
case SERVICE_ACTION_OUT_12:
|
||||
case SERVICE_ACTION_BIDIRECTIONAL:
|
||||
case SERVICE_ACTION_IN_16:
|
||||
case SERVICE_ACTION_OUT_16:
|
||||
case THIRD_PARTY_COPY_IN:
|
||||
case THIRD_PARTY_COPY_OUT:
|
||||
sa = cdbp[1] & 0x1f;
|
||||
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
|
||||
break;
|
||||
default:
|
||||
if (cdb0 < 0xc0)
|
||||
printk("cdb[0]=0x%x", cdb0);
|
||||
} else {
|
||||
if (sa_name)
|
||||
printk("%s", sa_name);
|
||||
else if (cdb_name)
|
||||
printk("%s, sa=0x%x", cdb_name, sa);
|
||||
else
|
||||
printk("cdb[0]=0x%x (vendor)", cdb0);
|
||||
break;
|
||||
printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void __scsi_print_command(unsigned char *cdb)
|
||||
void __scsi_print_command(const unsigned char *cdb, size_t cdb_len)
|
||||
{
|
||||
int k, len;
|
||||
|
||||
print_opcode_name(cdb, 0);
|
||||
print_opcode_name(cdb, cdb_len);
|
||||
len = scsi_command_size(cdb);
|
||||
if (cdb_len < len)
|
||||
len = cdb_len;
|
||||
/* print out all bytes in cdb */
|
||||
for (k = 0; k < len; ++k)
|
||||
printk(" %02x", cdb[k]);
|
||||
@ -433,41 +383,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_print_command);
|
||||
|
||||
/**
|
||||
* scsi_print_status - print scsi status description
|
||||
* @scsi_status: scsi status value
|
||||
*
|
||||
* If the status is recognized, the description is printed.
|
||||
* Otherwise "Unknown status" is output. No trailing space.
|
||||
* If CONFIG_SCSI_CONSTANTS is not set, then print status in hex
|
||||
* (e.g. "0x2" for Check Condition).
|
||||
**/
|
||||
void
|
||||
scsi_print_status(unsigned char scsi_status) {
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
const char * ccp;
|
||||
|
||||
switch (scsi_status) {
|
||||
case 0: ccp = "Good"; break;
|
||||
case 0x2: ccp = "Check Condition"; break;
|
||||
case 0x4: ccp = "Condition Met"; break;
|
||||
case 0x8: ccp = "Busy"; break;
|
||||
case 0x10: ccp = "Intermediate"; break;
|
||||
case 0x14: ccp = "Intermediate-Condition Met"; break;
|
||||
case 0x18: ccp = "Reservation Conflict"; break;
|
||||
case 0x22: ccp = "Command Terminated"; break; /* obsolete */
|
||||
case 0x28: ccp = "Task set Full"; break; /* was: Queue Full */
|
||||
case 0x30: ccp = "ACA Active"; break;
|
||||
case 0x40: ccp = "Task Aborted"; break;
|
||||
default: ccp = "Unknown status";
|
||||
}
|
||||
printk(KERN_INFO "%s", ccp);
|
||||
#else
|
||||
printk(KERN_INFO "0x%0x", scsi_status);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_print_status);
|
||||
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
|
||||
struct error_info {
|
||||
@ -1292,18 +1207,19 @@ static const struct error_info additional[] =
|
||||
|
||||
struct error_info2 {
|
||||
unsigned char code1, code2_min, code2_max;
|
||||
const char * str;
|
||||
const char * fmt;
|
||||
};
|
||||
|
||||
static const struct error_info2 additional2[] =
|
||||
{
|
||||
{0x40, 0x00, 0x7f, "Ram failure (%x)"},
|
||||
{0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"},
|
||||
{0x41, 0x00, 0xff, "Data path failure (%x)"},
|
||||
{0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"},
|
||||
{0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"},
|
||||
{0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"},
|
||||
{0, 0, 0, NULL}
|
||||
{0x40, 0x00, 0x7f, "Ram failure", ""},
|
||||
{0x40, 0x80, 0xff, "Diagnostic failure on component", ""},
|
||||
{0x41, 0x00, 0xff, "Data path failure", ""},
|
||||
{0x42, 0x00, 0xff, "Power-on or self-test failure", ""},
|
||||
{0x4D, 0x00, 0xff, "Tagged overlapped commands", "task tag "},
|
||||
{0x70, 0x00, 0xff, "Decompression exception", "short algorithm id of "},
|
||||
{0, 0, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
/* description of the sense key values */
|
||||
@ -1349,69 +1265,79 @@ EXPORT_SYMBOL(scsi_sense_key_string);
|
||||
* This string may contain a "%x" and should be printed with ascq as arg.
|
||||
*/
|
||||
const char *
|
||||
scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
|
||||
scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt)
|
||||
{
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
int i;
|
||||
unsigned short code = ((asc << 8) | ascq);
|
||||
|
||||
*fmt = NULL;
|
||||
for (i = 0; additional[i].text; i++)
|
||||
if (additional[i].code12 == code)
|
||||
return additional[i].text;
|
||||
for (i = 0; additional2[i].fmt; i++) {
|
||||
if (additional2[i].code1 == asc &&
|
||||
ascq >= additional2[i].code2_min &&
|
||||
ascq <= additional2[i].code2_max)
|
||||
return additional2[i].fmt;
|
||||
ascq <= additional2[i].code2_max) {
|
||||
*fmt = additional2[i].fmt;
|
||||
return additional2[i].str;
|
||||
}
|
||||
}
|
||||
#else
|
||||
*fmt = NULL;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_extd_sense_format);
|
||||
|
||||
void
|
||||
scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
|
||||
scsi_show_extd_sense(const struct scsi_device *sdev, const char *name,
|
||||
unsigned char asc, unsigned char ascq)
|
||||
{
|
||||
const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
|
||||
const char *extd_sense_fmt = NULL;
|
||||
const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
|
||||
&extd_sense_fmt);
|
||||
|
||||
if (extd_sense_fmt) {
|
||||
if (strstr(extd_sense_fmt, "%x")) {
|
||||
printk("Add. Sense: ");
|
||||
printk(extd_sense_fmt, ascq);
|
||||
} else
|
||||
printk("Add. Sense: %s", extd_sense_fmt);
|
||||
} else {
|
||||
if (asc >= 0x80)
|
||||
printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
|
||||
ascq);
|
||||
if (ascq >= 0x80)
|
||||
printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
|
||||
ascq);
|
||||
if (extd_sense_str) {
|
||||
if (extd_sense_fmt)
|
||||
sdev_prefix_printk(KERN_INFO, sdev, name,
|
||||
"Add. Sense: %s (%s%x)",
|
||||
extd_sense_str, extd_sense_fmt,
|
||||
ascq);
|
||||
else
|
||||
printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
|
||||
}
|
||||
sdev_prefix_printk(KERN_INFO, sdev, name,
|
||||
"Add. Sense: %s", extd_sense_str);
|
||||
|
||||
printk("\n");
|
||||
} else {
|
||||
sdev_prefix_printk(KERN_INFO, sdev, name,
|
||||
"%sASC=0x%x %sASCQ=0x%x\n",
|
||||
asc >= 0x80 ? "<<vendor>> " : "", asc,
|
||||
ascq >= 0x80 ? "<<vendor>> " : "", ascq);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_show_extd_sense);
|
||||
|
||||
void
|
||||
scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr)
|
||||
scsi_show_sense_hdr(const struct scsi_device *sdev, const char *name,
|
||||
const struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
const char *sense_txt;
|
||||
|
||||
sense_txt = scsi_sense_key_string(sshdr->sense_key);
|
||||
if (sense_txt)
|
||||
printk("Sense Key : %s ", sense_txt);
|
||||
sdev_prefix_printk(KERN_INFO, sdev, name,
|
||||
"Sense Key : %s [%s]%s\n", sense_txt,
|
||||
scsi_sense_is_deferred(sshdr) ?
|
||||
"deferred" : "current",
|
||||
sshdr->response_code >= 0x72 ?
|
||||
" [descriptor]" : "");
|
||||
else
|
||||
printk("Sense Key : 0x%x ", sshdr->sense_key);
|
||||
|
||||
printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " :
|
||||
"[current] ");
|
||||
|
||||
if (sshdr->response_code >= 0x72)
|
||||
printk("[descriptor]");
|
||||
|
||||
printk("\n");
|
||||
sdev_prefix_printk(KERN_INFO, sdev, name,
|
||||
"Sense Key : 0x%x [%s]%s", sshdr->sense_key,
|
||||
scsi_sense_is_deferred(sshdr) ?
|
||||
"deferred" : "current",
|
||||
sshdr->response_code >= 0x72 ?
|
||||
" [descriptor]" : "");
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_show_sense_hdr);
|
||||
|
||||
@ -1419,141 +1345,55 @@ EXPORT_SYMBOL(scsi_show_sense_hdr);
|
||||
* Print normalized SCSI sense header with a prefix.
|
||||
*/
|
||||
void
|
||||
scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
|
||||
scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
|
||||
const struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
printk(KERN_INFO "%s: ", name);
|
||||
scsi_show_sense_hdr(sshdr);
|
||||
printk(KERN_INFO "%s: ", name);
|
||||
scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
|
||||
scsi_show_sense_hdr(sdev, name, sshdr);
|
||||
scsi_show_extd_sense(sdev, name, sshdr->asc, sshdr->ascq);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_print_sense_hdr);
|
||||
|
||||
/*
|
||||
* Print normalized SCSI sense header with device information and a prefix.
|
||||
*/
|
||||
void
|
||||
scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc,
|
||||
struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
scmd_printk(KERN_INFO, scmd, "%s: ", desc);
|
||||
scsi_show_sense_hdr(sshdr);
|
||||
scmd_printk(KERN_INFO, scmd, "%s: ", desc);
|
||||
scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_cmd_print_sense_hdr);
|
||||
|
||||
static void
|
||||
scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
|
||||
struct scsi_sense_hdr *sshdr)
|
||||
scsi_dump_sense_buffer(const unsigned char *sense_buffer, int sense_len)
|
||||
{
|
||||
int k, num, res;
|
||||
int k, num;
|
||||
|
||||
res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
|
||||
if (0 == res) {
|
||||
/* this may be SCSI-1 sense data */
|
||||
num = (sense_len < 32) ? sense_len : 32;
|
||||
printk("Unrecognized sense data (in hex):");
|
||||
for (k = 0; k < num; ++k) {
|
||||
if (0 == (k % 16)) {
|
||||
printk("\n");
|
||||
printk(KERN_INFO " ");
|
||||
}
|
||||
printk("%02x ", sense_buffer[k]);
|
||||
num = (sense_len < 32) ? sense_len : 32;
|
||||
printk("Unrecognized sense data (in hex):");
|
||||
for (k = 0; k < num; ++k) {
|
||||
if (0 == (k % 16)) {
|
||||
printk("\n");
|
||||
printk(KERN_INFO " ");
|
||||
}
|
||||
printk("\n");
|
||||
return;
|
||||
printk("%02x ", sense_buffer[k]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
|
||||
struct scsi_sense_hdr *sshdr)
|
||||
{
|
||||
int k, num, res;
|
||||
|
||||
if (sshdr->response_code < 0x72)
|
||||
{
|
||||
/* only decode extras for "fixed" format now */
|
||||
char buff[80];
|
||||
int blen, fixed_valid;
|
||||
unsigned int info;
|
||||
|
||||
fixed_valid = sense_buffer[0] & 0x80;
|
||||
info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
|
||||
(sense_buffer[5] << 8) | sense_buffer[6]);
|
||||
res = 0;
|
||||
memset(buff, 0, sizeof(buff));
|
||||
blen = sizeof(buff) - 1;
|
||||
if (fixed_valid)
|
||||
res += snprintf(buff + res, blen - res,
|
||||
"Info fld=0x%x", info);
|
||||
if (sense_buffer[2] & 0x80) {
|
||||
/* current command has read a filemark */
|
||||
if (res > 0)
|
||||
res += snprintf(buff + res, blen - res, ", ");
|
||||
res += snprintf(buff + res, blen - res, "FMK");
|
||||
}
|
||||
if (sense_buffer[2] & 0x40) {
|
||||
/* end-of-medium condition exists */
|
||||
if (res > 0)
|
||||
res += snprintf(buff + res, blen - res, ", ");
|
||||
res += snprintf(buff + res, blen - res, "EOM");
|
||||
}
|
||||
if (sense_buffer[2] & 0x20) {
|
||||
/* incorrect block length requested */
|
||||
if (res > 0)
|
||||
res += snprintf(buff + res, blen - res, ", ");
|
||||
res += snprintf(buff + res, blen - res, "ILI");
|
||||
}
|
||||
if (res > 0)
|
||||
printk("%s\n", buff);
|
||||
} else if (sshdr->additional_length > 0) {
|
||||
/* descriptor format with sense descriptors */
|
||||
num = 8 + sshdr->additional_length;
|
||||
num = (sense_len < num) ? sense_len : num;
|
||||
printk("Descriptor sense data with sense descriptors "
|
||||
"(in hex):");
|
||||
for (k = 0; k < num; ++k) {
|
||||
if (0 == (k % 16)) {
|
||||
printk("\n");
|
||||
printk(KERN_INFO " ");
|
||||
}
|
||||
printk("%02x ", sense_buffer[k]);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normalize and print sense buffer with name prefix */
|
||||
void __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
|
||||
int sense_len)
|
||||
void __scsi_print_sense(const struct scsi_device *sdev, const char *name,
|
||||
const unsigned char *sense_buffer, int sense_len)
|
||||
{
|
||||
struct scsi_sense_hdr sshdr;
|
||||
|
||||
printk(KERN_INFO "%s: ", name);
|
||||
scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr);
|
||||
scsi_show_sense_hdr(&sshdr);
|
||||
scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr);
|
||||
printk(KERN_INFO "%s: ", name);
|
||||
scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
|
||||
if (!scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) {
|
||||
scsi_dump_sense_buffer(sense_buffer, sense_len);
|
||||
return;
|
||||
}
|
||||
scsi_show_sense_hdr(sdev, name, &sshdr);
|
||||
scsi_show_extd_sense(sdev, name, sshdr.asc, sshdr.ascq);
|
||||
}
|
||||
EXPORT_SYMBOL(__scsi_print_sense);
|
||||
|
||||
/* Normalize and print sense buffer in SCSI command */
|
||||
void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
|
||||
void scsi_print_sense(const struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct scsi_sense_hdr sshdr;
|
||||
struct gendisk *disk = cmd->request->rq_disk;
|
||||
const char *disk_name = disk ? disk->disk_name : NULL;
|
||||
|
||||
scmd_printk(KERN_INFO, cmd, " ");
|
||||
scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
|
||||
&sshdr);
|
||||
scsi_show_sense_hdr(&sshdr);
|
||||
scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
|
||||
&sshdr);
|
||||
scmd_printk(KERN_INFO, cmd, " ");
|
||||
scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
|
||||
__scsi_print_sense(cmd->device, disk_name, cmd->sense_buffer,
|
||||
SCSI_SENSE_BUFFERSIZE);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_print_sense);
|
||||
|
||||
@ -1565,38 +1405,87 @@ static const char * const hostbyte_table[]={
|
||||
"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE",
|
||||
"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
|
||||
"DID_NEXUS_FAILURE" };
|
||||
#define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
|
||||
|
||||
static const char * const driverbyte_table[]={
|
||||
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
|
||||
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
|
||||
#define NUM_DRIVERBYTE_STRS ARRAY_SIZE(driverbyte_table)
|
||||
|
||||
void scsi_show_result(int result)
|
||||
{
|
||||
int hb = host_byte(result);
|
||||
int db = driver_byte(result);
|
||||
|
||||
printk("Result: hostbyte=%s driverbyte=%s\n",
|
||||
(hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"),
|
||||
(db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void scsi_show_result(int result)
|
||||
{
|
||||
printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
|
||||
host_byte(result), driver_byte(result));
|
||||
}
|
||||
|
||||
#endif
|
||||
EXPORT_SYMBOL(scsi_show_result);
|
||||
|
||||
|
||||
void scsi_print_result(struct scsi_cmnd *cmd)
|
||||
const char *scsi_hostbyte_string(int result)
|
||||
{
|
||||
scmd_printk(KERN_INFO, cmd, " ");
|
||||
scsi_show_result(cmd->result);
|
||||
const char *hb_string = NULL;
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
int hb = host_byte(result);
|
||||
|
||||
if (hb < ARRAY_SIZE(hostbyte_table))
|
||||
hb_string = hostbyte_table[hb];
|
||||
#endif
|
||||
return hb_string;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_hostbyte_string);
|
||||
|
||||
const char *scsi_driverbyte_string(int result)
|
||||
{
|
||||
const char *db_string = NULL;
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
int db = driver_byte(result);
|
||||
|
||||
if (db < ARRAY_SIZE(driverbyte_table))
|
||||
db_string = driverbyte_table[db];
|
||||
#endif
|
||||
return db_string;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_driverbyte_string);
|
||||
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
#define scsi_mlreturn_name(result) { result, #result }
|
||||
static const struct value_name_pair scsi_mlreturn_arr[] = {
|
||||
scsi_mlreturn_name(NEEDS_RETRY),
|
||||
scsi_mlreturn_name(SUCCESS),
|
||||
scsi_mlreturn_name(FAILED),
|
||||
scsi_mlreturn_name(QUEUED),
|
||||
scsi_mlreturn_name(SOFT_ERROR),
|
||||
scsi_mlreturn_name(ADD_TO_MLQUEUE),
|
||||
scsi_mlreturn_name(TIMEOUT_ERROR),
|
||||
scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED),
|
||||
scsi_mlreturn_name(FAST_IO_FAIL)
|
||||
};
|
||||
#endif
|
||||
|
||||
const char *scsi_mlreturn_string(int result)
|
||||
{
|
||||
#ifdef CONFIG_SCSI_CONSTANTS
|
||||
const struct value_name_pair *arr = scsi_mlreturn_arr;
|
||||
int k;
|
||||
|
||||
for (k = 0; k < ARRAY_SIZE(scsi_mlreturn_arr); ++k, ++arr) {
|
||||
if (result == arr->value)
|
||||
return arr->name;
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_mlreturn_string);
|
||||
|
||||
void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition)
|
||||
{
|
||||
const char *mlret_string = scsi_mlreturn_string(disposition);
|
||||
const char *hb_string = scsi_hostbyte_string(cmd->result);
|
||||
const char *db_string = scsi_driverbyte_string(cmd->result);
|
||||
|
||||
if (hb_string || db_string)
|
||||
scmd_printk(KERN_INFO, cmd,
|
||||
"%s%s Result: hostbyte=%s driverbyte=%s",
|
||||
msg ? msg : "",
|
||||
mlret_string ? mlret_string : "UNKNOWN",
|
||||
hb_string ? hb_string : "invalid",
|
||||
db_string ? db_string : "invalid");
|
||||
else
|
||||
scmd_printk(KERN_INFO, cmd,
|
||||
"%s%s Result: hostbyte=0x%02x driverbyte=0x%02x",
|
||||
msg ? msg : "",
|
||||
mlret_string ? mlret_string : "UNKNOWN",
|
||||
host_byte(cmd->result), driver_byte(cmd->result));
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_print_result);
|
||||
|
@ -152,28 +152,6 @@ csio_scsi_itnexus_loss_error(uint16_t error)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
csio_scsi_tag(struct scsi_cmnd *scmnd, uint8_t *tag, uint8_t hq,
|
||||
uint8_t oq, uint8_t sq)
|
||||
{
|
||||
char stag[2];
|
||||
|
||||
if (scsi_populate_tag_msg(scmnd, stag)) {
|
||||
switch (stag[0]) {
|
||||
case HEAD_OF_QUEUE_TAG:
|
||||
*tag = hq;
|
||||
break;
|
||||
case ORDERED_QUEUE_TAG:
|
||||
*tag = oq;
|
||||
break;
|
||||
default:
|
||||
*tag = sq;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
*tag = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* csio_scsi_fcp_cmnd - Frame the SCSI FCP command paylod.
|
||||
* @req: IO req structure.
|
||||
@ -192,11 +170,12 @@ csio_scsi_fcp_cmnd(struct csio_ioreq *req, void *addr)
|
||||
int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun);
|
||||
fcp_cmnd->fc_tm_flags = 0;
|
||||
fcp_cmnd->fc_cmdref = 0;
|
||||
fcp_cmnd->fc_pri_ta = 0;
|
||||
|
||||
memcpy(fcp_cmnd->fc_cdb, scmnd->cmnd, 16);
|
||||
csio_scsi_tag(scmnd, &fcp_cmnd->fc_pri_ta,
|
||||
FCP_PTA_HEADQ, FCP_PTA_ORDERED, FCP_PTA_SIMPLE);
|
||||
if (scmnd->flags & SCMD_TAGGED)
|
||||
fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
|
||||
else
|
||||
fcp_cmnd->fc_pri_ta = 0;
|
||||
fcp_cmnd->fc_dl = cpu_to_be32(scsi_bufflen(scmnd));
|
||||
|
||||
if (req->nsge)
|
||||
@ -2262,11 +2241,7 @@ csio_slave_alloc(struct scsi_device *sdev)
|
||||
static int
|
||||
csio_slave_configure(struct scsi_device *sdev)
|
||||
{
|
||||
if (sdev->tagged_supported)
|
||||
scsi_activate_tcq(sdev, csio_lun_qdepth);
|
||||
else
|
||||
scsi_deactivate_tcq(sdev, csio_lun_qdepth);
|
||||
|
||||
scsi_change_queue_depth(sdev, csio_lun_qdepth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2311,6 +2286,7 @@ struct scsi_host_template csio_fcoe_shost_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = csio_fcoe_lport_attrs,
|
||||
.max_sectors = CSIO_MAX_SECTOR_SIZE,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
struct scsi_host_template csio_fcoe_shost_vport_template = {
|
||||
@ -2330,6 +2306,7 @@ struct scsi_host_template csio_fcoe_shost_vport_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.shost_attrs = csio_fcoe_vport_attrs,
|
||||
.max_sectors = CSIO_MAX_SECTOR_SIZE,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -86,7 +86,7 @@ static struct scsi_host_template cxgb3i_host_template = {
|
||||
.proc_name = DRV_MODULE_NAME,
|
||||
.can_queue = CXGB3I_SCSI_HOST_QDEPTH,
|
||||
.queuecommand = iscsi_queuecommand,
|
||||
.change_queue_depth = iscsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.max_sectors = 0xFFFF,
|
||||
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
|
||||
@ -96,6 +96,7 @@ static struct scsi_host_template cxgb3i_host_template = {
|
||||
.target_alloc = iscsi_target_alloc,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.this_id = -1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static struct iscsi_transport cxgb3i_iscsi_transport = {
|
||||
|
@ -89,7 +89,7 @@ static struct scsi_host_template cxgb4i_host_template = {
|
||||
.proc_name = DRV_MODULE_NAME,
|
||||
.can_queue = CXGB4I_SCSI_HOST_QDEPTH,
|
||||
.queuecommand = iscsi_queuecommand,
|
||||
.change_queue_depth = iscsi_change_queue_depth,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.max_sectors = 0xFFFF,
|
||||
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
|
||||
@ -99,6 +99,7 @@ static struct scsi_host_template cxgb4i_host_template = {
|
||||
.target_alloc = iscsi_target_alloc,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.this_id = -1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static struct iscsi_transport cxgb4i_iscsi_transport = {
|
||||
|
@ -98,27 +98,51 @@ device_handler_match(struct scsi_device_handler *scsi_dh,
|
||||
static int scsi_dh_handler_attach(struct scsi_device *sdev,
|
||||
struct scsi_device_handler *scsi_dh)
|
||||
{
|
||||
int err = 0;
|
||||
struct scsi_dh_data *d;
|
||||
|
||||
if (sdev->scsi_dh_data) {
|
||||
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
|
||||
err = -EBUSY;
|
||||
else
|
||||
kref_get(&sdev->scsi_dh_data->kref);
|
||||
} else if (scsi_dh->attach) {
|
||||
err = scsi_dh->attach(sdev);
|
||||
if (!err) {
|
||||
kref_init(&sdev->scsi_dh_data->kref);
|
||||
sdev->scsi_dh_data->sdev = sdev;
|
||||
}
|
||||
return -EBUSY;
|
||||
|
||||
kref_get(&sdev->scsi_dh_data->kref);
|
||||
return 0;
|
||||
}
|
||||
return err;
|
||||
|
||||
if (!try_module_get(scsi_dh->module))
|
||||
return -EINVAL;
|
||||
|
||||
d = scsi_dh->attach(sdev);
|
||||
if (IS_ERR(d)) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
|
||||
scsi_dh->name, PTR_ERR(d));
|
||||
module_put(scsi_dh->module);
|
||||
return PTR_ERR(d);
|
||||
}
|
||||
|
||||
d->scsi_dh = scsi_dh;
|
||||
kref_init(&d->kref);
|
||||
d->sdev = sdev;
|
||||
|
||||
spin_lock_irq(sdev->request_queue->queue_lock);
|
||||
sdev->scsi_dh_data = d;
|
||||
spin_unlock_irq(sdev->request_queue->queue_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __detach_handler (struct kref *kref)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
|
||||
scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
|
||||
struct scsi_dh_data *scsi_dh_data =
|
||||
container_of(kref, struct scsi_dh_data, kref);
|
||||
struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
|
||||
struct scsi_device *sdev = scsi_dh_data->sdev;
|
||||
|
||||
spin_lock_irq(sdev->request_queue->queue_lock);
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irq(sdev->request_queue->queue_lock);
|
||||
|
||||
scsi_dh->detach(sdev);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
|
||||
module_put(scsi_dh->module);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -141,7 +165,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
|
||||
if (!scsi_dh)
|
||||
scsi_dh = sdev->scsi_dh_data->scsi_dh;
|
||||
|
||||
if (scsi_dh && scsi_dh->detach)
|
||||
if (scsi_dh)
|
||||
kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
|
||||
}
|
||||
|
||||
@ -330,6 +354,9 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
||||
if (get_device_handler(scsi_dh->name))
|
||||
return -EBUSY;
|
||||
|
||||
if (!scsi_dh->attach || !scsi_dh->detach)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&list_lock);
|
||||
list_add(&scsi_dh->list, &scsi_dh_list);
|
||||
spin_unlock(&list_lock);
|
||||
|
@ -62,6 +62,7 @@
|
||||
#define ALUA_OPTIMIZE_STPG 1
|
||||
|
||||
struct alua_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
int group_id;
|
||||
int rel_port;
|
||||
int tpgs;
|
||||
@ -87,9 +88,7 @@ static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
|
||||
|
||||
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
||||
BUG_ON(scsi_dh_data == NULL);
|
||||
return ((struct alua_dh_data *) scsi_dh_data->buf);
|
||||
return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data);
|
||||
}
|
||||
|
||||
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
|
||||
@ -825,8 +824,49 @@ static bool alua_match(struct scsi_device *sdev)
|
||||
return (scsi_device_tpgs(sdev) != 0);
|
||||
}
|
||||
|
||||
static int alua_bus_attach(struct scsi_device *sdev);
|
||||
static void alua_bus_detach(struct scsi_device *sdev);
|
||||
/*
|
||||
* alua_bus_attach - Attach device handler
|
||||
* @sdev: device to be attached to
|
||||
*/
|
||||
static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct alua_dh_data *h;
|
||||
int err;
|
||||
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
h->tpgs = TPGS_MODE_UNINITIALIZED;
|
||||
h->state = TPGS_STATE_OPTIMIZED;
|
||||
h->group_id = -1;
|
||||
h->rel_port = -1;
|
||||
h->buff = h->inq;
|
||||
h->bufflen = ALUA_INQUIRY_SIZE;
|
||||
h->sdev = sdev;
|
||||
|
||||
err = alua_initialize(sdev, h);
|
||||
if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
|
||||
goto failed;
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME);
|
||||
return &h->dh_data;
|
||||
failed:
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_bus_detach - Detach device handler
|
||||
* @sdev: device to be detached from
|
||||
*/
|
||||
static void alua_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct alua_dh_data *h = get_alua_data(sdev);
|
||||
|
||||
if (h->buff && h->inq != h->buff)
|
||||
kfree(h->buff);
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
static struct scsi_device_handler alua_dh = {
|
||||
.name = ALUA_DH_NAME,
|
||||
@ -840,78 +880,6 @@ static struct scsi_device_handler alua_dh = {
|
||||
.match = alua_match,
|
||||
};
|
||||
|
||||
/*
|
||||
* alua_bus_attach - Attach device handler
|
||||
* @sdev: device to be attached to
|
||||
*/
|
||||
static int alua_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct alua_dh_data *h;
|
||||
unsigned long flags;
|
||||
int err = SCSI_DH_OK;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
ALUA_DH_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &alua_dh;
|
||||
h = (struct alua_dh_data *) scsi_dh_data->buf;
|
||||
h->tpgs = TPGS_MODE_UNINITIALIZED;
|
||||
h->state = TPGS_STATE_OPTIMIZED;
|
||||
h->group_id = -1;
|
||||
h->rel_port = -1;
|
||||
h->buff = h->inq;
|
||||
h->bufflen = ALUA_INQUIRY_SIZE;
|
||||
h->sdev = sdev;
|
||||
|
||||
err = alua_initialize(sdev, h);
|
||||
if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED))
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME);
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* alua_bus_detach - Detach device handler
|
||||
* @sdev: device to be detached from
|
||||
*/
|
||||
static void alua_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct alua_dh_data *h;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
h = (struct alua_dh_data *) scsi_dh_data->buf;
|
||||
if (h->buff && h->inq != h->buff)
|
||||
kfree(h->buff);
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME);
|
||||
}
|
||||
|
||||
static int __init alua_init(void)
|
||||
{
|
||||
int r;
|
||||
|
@ -72,6 +72,7 @@ static const char * lun_state[] =
|
||||
};
|
||||
|
||||
struct clariion_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
/*
|
||||
* Flags:
|
||||
* CLARIION_SHORT_TRESPASS
|
||||
@ -116,9 +117,8 @@ struct clariion_dh_data {
|
||||
static inline struct clariion_dh_data
|
||||
*get_clariion_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
||||
BUG_ON(scsi_dh_data == NULL);
|
||||
return ((struct clariion_dh_data *) scsi_dh_data->buf);
|
||||
return container_of(sdev->scsi_dh_data, struct clariion_dh_data,
|
||||
dh_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -622,7 +622,10 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct scsi_dh_devlist clariion_dev_list[] = {
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} clariion_dev_list[] = {
|
||||
{"DGC", "RAID"},
|
||||
{"DGC", "DISK"},
|
||||
{"DGC", "VRAID"},
|
||||
@ -647,39 +650,14 @@ static bool clariion_match(struct scsi_device *sdev)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int clariion_bus_attach(struct scsi_device *sdev);
|
||||
static void clariion_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler clariion_dh = {
|
||||
.name = CLARIION_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.devlist = clariion_dev_list,
|
||||
.attach = clariion_bus_attach,
|
||||
.detach = clariion_bus_detach,
|
||||
.check_sense = clariion_check_sense,
|
||||
.activate = clariion_activate,
|
||||
.prep_fn = clariion_prep_fn,
|
||||
.set_params = clariion_set_params,
|
||||
.match = clariion_match,
|
||||
};
|
||||
|
||||
static int clariion_bus_attach(struct scsi_device *sdev)
|
||||
static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct clariion_dh_data *h;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
CLARIION_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &clariion_dh;
|
||||
h = (struct clariion_dh_data *) scsi_dh_data->buf;
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
h->lun_state = CLARIION_LUN_UNINITIALIZED;
|
||||
h->default_sp = CLARIION_UNBOUND_LU;
|
||||
h->current_sp = CLARIION_UNBOUND_LU;
|
||||
@ -692,45 +670,37 @@ static int clariion_bus_attach(struct scsi_device *sdev)
|
||||
if (err != SCSI_DH_OK)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_INFO, sdev,
|
||||
"%s: connected to SP %c Port %d (%s, default SP %c)\n",
|
||||
CLARIION_NAME, h->current_sp + 'A',
|
||||
h->port, lun_state[h->lun_state],
|
||||
h->default_sp + 'A');
|
||||
|
||||
return 0;
|
||||
return &h->dh_data;
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
CLARIION_NAME);
|
||||
return -EINVAL;
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static void clariion_bus_detach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
unsigned long flags;
|
||||
struct clariion_dh_data *h = get_clariion_data(sdev);
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
|
||||
CLARIION_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
static struct scsi_device_handler clariion_dh = {
|
||||
.name = CLARIION_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.attach = clariion_bus_attach,
|
||||
.detach = clariion_bus_detach,
|
||||
.check_sense = clariion_check_sense,
|
||||
.activate = clariion_activate,
|
||||
.prep_fn = clariion_prep_fn,
|
||||
.set_params = clariion_set_params,
|
||||
.match = clariion_match,
|
||||
};
|
||||
|
||||
static int __init clariion_init(void)
|
||||
{
|
||||
int r;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define HP_SW_PATH_PASSIVE 1
|
||||
|
||||
struct hp_sw_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
|
||||
int path_state;
|
||||
int retries;
|
||||
@ -51,9 +52,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *);
|
||||
|
||||
static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
||||
BUG_ON(scsi_dh_data == NULL);
|
||||
return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
|
||||
return container_of(sdev->scsi_dh_data, struct hp_sw_dh_data, dh_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -312,7 +311,10 @@ static int hp_sw_activate(struct scsi_device *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} hp_sw_dh_data_list[] = {
|
||||
{"COMPAQ", "MSA1000 VOLUME"},
|
||||
{"COMPAQ", "HSV110"},
|
||||
{"HP", "HSV100"},
|
||||
@ -338,37 +340,14 @@ static bool hp_sw_match(struct scsi_device *sdev)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hp_sw_bus_attach(struct scsi_device *sdev);
|
||||
static void hp_sw_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler hp_sw_dh = {
|
||||
.name = HP_SW_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.devlist = hp_sw_dh_data_list,
|
||||
.attach = hp_sw_bus_attach,
|
||||
.detach = hp_sw_bus_detach,
|
||||
.activate = hp_sw_activate,
|
||||
.prep_fn = hp_sw_prep_fn,
|
||||
.match = hp_sw_match,
|
||||
};
|
||||
|
||||
static int hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct hp_sw_dh_data *h;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
|
||||
HP_SW_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &hp_sw_dh;
|
||||
h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
|
||||
h = kzalloc(sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
h->path_state = HP_SW_PATH_UNINITIALIZED;
|
||||
h->retries = HP_SW_RETRIES;
|
||||
h->sdev = sdev;
|
||||
@ -377,42 +356,32 @@ static int hp_sw_bus_attach(struct scsi_device *sdev)
|
||||
if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
|
||||
goto failed;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto failed;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
|
||||
HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
|
||||
"active":"passive");
|
||||
|
||||
return 0;
|
||||
|
||||
return &h->dh_data;
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
HP_SW_NAME);
|
||||
return -EINVAL;
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static void hp_sw_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
unsigned long flags;
|
||||
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
module_put(THIS_MODULE);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
|
||||
|
||||
kfree(scsi_dh_data);
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
static struct scsi_device_handler hp_sw_dh = {
|
||||
.name = HP_SW_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.attach = hp_sw_bus_attach,
|
||||
.detach = hp_sw_bus_detach,
|
||||
.activate = hp_sw_activate,
|
||||
.prep_fn = hp_sw_prep_fn,
|
||||
.match = hp_sw_match,
|
||||
};
|
||||
|
||||
static int __init hp_sw_init(void)
|
||||
{
|
||||
return scsi_register_device_handler(&hp_sw_dh);
|
||||
|
@ -181,6 +181,7 @@ struct c2_inquiry {
|
||||
};
|
||||
|
||||
struct rdac_dh_data {
|
||||
struct scsi_dh_data dh_data;
|
||||
struct rdac_controller *ctlr;
|
||||
#define UNINITIALIZED_LUN (1 << 8)
|
||||
unsigned lun;
|
||||
@ -261,9 +262,7 @@ do { \
|
||||
|
||||
static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
|
||||
BUG_ON(scsi_dh_data == NULL);
|
||||
return ((struct rdac_dh_data *) scsi_dh_data->buf);
|
||||
return container_of(sdev->scsi_dh_data, struct rdac_dh_data, dh_data);
|
||||
}
|
||||
|
||||
static struct request *get_rdac_req(struct scsi_device *sdev,
|
||||
@ -779,7 +778,10 @@ static int rdac_check_sense(struct scsi_device *sdev,
|
||||
return SCSI_RETURN_NOT_HANDLED;
|
||||
}
|
||||
|
||||
static const struct scsi_dh_devlist rdac_dev_list[] = {
|
||||
static const struct {
|
||||
char *vendor;
|
||||
char *model;
|
||||
} rdac_dev_list[] = {
|
||||
{"IBM", "1722"},
|
||||
{"IBM", "1724"},
|
||||
{"IBM", "1726"},
|
||||
@ -825,40 +827,16 @@ static bool rdac_match(struct scsi_device *sdev)
|
||||
return false;
|
||||
}
|
||||
|
||||
static int rdac_bus_attach(struct scsi_device *sdev);
|
||||
static void rdac_bus_detach(struct scsi_device *sdev);
|
||||
|
||||
static struct scsi_device_handler rdac_dh = {
|
||||
.name = RDAC_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.devlist = rdac_dev_list,
|
||||
.prep_fn = rdac_prep_fn,
|
||||
.check_sense = rdac_check_sense,
|
||||
.attach = rdac_bus_attach,
|
||||
.detach = rdac_bus_detach,
|
||||
.activate = rdac_activate,
|
||||
.match = rdac_match,
|
||||
};
|
||||
|
||||
static int rdac_bus_attach(struct scsi_device *sdev)
|
||||
static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct rdac_dh_data *h;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
char array_name[ARRAY_LABEL_LEN];
|
||||
char array_id[UNIQUE_ID_LEN];
|
||||
|
||||
scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
|
||||
+ sizeof(*h) , GFP_KERNEL);
|
||||
if (!scsi_dh_data) {
|
||||
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
|
||||
RDAC_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_dh_data->scsi_dh = &rdac_dh;
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
h = kzalloc(sizeof(*h) , GFP_KERNEL);
|
||||
if (!h)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
h->lun = UNINITIALIZED_LUN;
|
||||
h->state = RDAC_STATE_ACTIVE;
|
||||
|
||||
@ -878,19 +856,12 @@ static int rdac_bus_attach(struct scsi_device *sdev)
|
||||
if (err != SCSI_DH_OK)
|
||||
goto clean_ctlr;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
goto clean_ctlr;
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = scsi_dh_data;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
sdev_printk(KERN_NOTICE, sdev,
|
||||
"%s: LUN %d (%s) (%s)\n",
|
||||
RDAC_NAME, h->lun, mode[(int)h->mode],
|
||||
lun_state[(int)h->lun_state]);
|
||||
|
||||
return 0;
|
||||
return &h->dh_data;
|
||||
|
||||
clean_ctlr:
|
||||
spin_lock(&list_lock);
|
||||
@ -898,37 +869,34 @@ clean_ctlr:
|
||||
spin_unlock(&list_lock);
|
||||
|
||||
failed:
|
||||
kfree(scsi_dh_data);
|
||||
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
|
||||
RDAC_NAME);
|
||||
return -EINVAL;
|
||||
kfree(h);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static void rdac_bus_detach( struct scsi_device *sdev )
|
||||
{
|
||||
struct scsi_dh_data *scsi_dh_data;
|
||||
struct rdac_dh_data *h;
|
||||
unsigned long flags;
|
||||
struct rdac_dh_data *h = get_rdac_data(sdev);
|
||||
|
||||
scsi_dh_data = sdev->scsi_dh_data;
|
||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||
if (h->ctlr && h->ctlr->ms_queued)
|
||||
flush_workqueue(kmpath_rdacd);
|
||||
|
||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||
sdev->scsi_dh_data = NULL;
|
||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||
|
||||
spin_lock(&list_lock);
|
||||
if (h->ctlr)
|
||||
kref_put(&h->ctlr->kref, release_controller);
|
||||
spin_unlock(&list_lock);
|
||||
kfree(scsi_dh_data);
|
||||
module_put(THIS_MODULE);
|
||||
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
|
||||
static struct scsi_device_handler rdac_dh = {
|
||||
.name = RDAC_NAME,
|
||||
.module = THIS_MODULE,
|
||||
.prep_fn = rdac_prep_fn,
|
||||
.check_sense = rdac_check_sense,
|
||||
.attach = rdac_bus_attach,
|
||||
.detach = rdac_bus_detach,
|
||||
.activate = rdac_activate,
|
||||
.match = rdac_match,
|
||||
};
|
||||
|
||||
static int __init rdac_init(void)
|
||||
{
|
||||
|
@ -33,20 +33,20 @@
|
||||
/*
|
||||
* Definitions for the generic 5380 driver.
|
||||
*/
|
||||
#define AUTOSENSE
|
||||
|
||||
#define DONT_USE_INTR
|
||||
|
||||
#define NCR5380_read(reg) inb(port + reg)
|
||||
#define NCR5380_write(reg, value) outb(value, port + reg)
|
||||
|
||||
#define NCR5380_implementation_fields unsigned int port
|
||||
#define NCR5380_local_declare() NCR5380_implementation_fields
|
||||
#define NCR5380_implementation_fields /* none */
|
||||
#define NCR5380_local_declare() unsigned int port
|
||||
#define NCR5380_setup(instance) port = instance->io_port
|
||||
|
||||
/*
|
||||
* Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include "scsi.h"
|
||||
|
||||
#include "NCR5380.h"
|
||||
#include "NCR5380.c"
|
||||
@ -58,6 +58,7 @@
|
||||
static struct scsi_host_template dmx3191d_driver_template = {
|
||||
.proc_name = DMX3191D_DRIVER_NAME,
|
||||
.name = "Domex DMX3191D",
|
||||
.info = NCR5380_info,
|
||||
.queuecommand = NCR5380_queue_command,
|
||||
.eh_abort_handler = NCR5380_abort,
|
||||
.eh_bus_reset_handler = NCR5380_bus_reset,
|
||||
@ -90,31 +91,23 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
|
||||
if (!shost)
|
||||
goto out_release_region;
|
||||
shost->io_port = io;
|
||||
shost->irq = pdev->irq;
|
||||
|
||||
/* This card does not seem to raise an interrupt on pdev->irq.
|
||||
* Steam-powered SCSI controllers run without an IRQ anyway.
|
||||
*/
|
||||
shost->irq = NO_IRQ;
|
||||
|
||||
NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
|
||||
|
||||
if (request_irq(pdev->irq, NCR5380_intr, IRQF_SHARED,
|
||||
DMX3191D_DRIVER_NAME, shost)) {
|
||||
/*
|
||||
* Steam powered scsi controllers run without an IRQ anyway
|
||||
*/
|
||||
printk(KERN_WARNING "dmx3191: IRQ %d not available - "
|
||||
"switching to polled mode.\n", pdev->irq);
|
||||
shost->irq = SCSI_IRQ_NONE;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, shost);
|
||||
|
||||
error = scsi_add_host(shost, &pdev->dev);
|
||||
if (error)
|
||||
goto out_free_irq;
|
||||
goto out_release_region;
|
||||
|
||||
scsi_scan_host(shost);
|
||||
return 0;
|
||||
|
||||
out_free_irq:
|
||||
free_irq(shost->irq, shost);
|
||||
out_release_region:
|
||||
release_region(io, DMX3191D_REGION_LEN);
|
||||
out_disable_device:
|
||||
@ -131,8 +124,6 @@ static void dmx3191d_remove_one(struct pci_dev *pdev)
|
||||
|
||||
NCR5380_exit(shost);
|
||||
|
||||
if (shost->irq != SCSI_IRQ_NONE)
|
||||
free_irq(shost->irq, shost);
|
||||
release_region(shost->io_port, DMX3191D_REGION_LEN);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
|
@ -415,10 +415,8 @@ static int adpt_slave_configure(struct scsi_device * device)
|
||||
pHba = (adpt_hba *) host->hostdata[0];
|
||||
|
||||
if (host->can_queue && device->tagged_supported) {
|
||||
scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
|
||||
scsi_change_queue_depth(device,
|
||||
host->can_queue - 1);
|
||||
} else {
|
||||
scsi_adjust_queue_depth(device, 0, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
|
||||
#define AUTOSENSE
|
||||
#define PSEUDO_DMA
|
||||
#define DONT_USE_INTR
|
||||
#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */
|
||||
@ -18,29 +17,9 @@
|
||||
* (Unix and Linux consulting and custom programming)
|
||||
* drew@colorado.edu
|
||||
* +1 (303) 440-4894
|
||||
*
|
||||
* DISTRIBUTION RELEASE 1.
|
||||
*
|
||||
* For more information, please consult
|
||||
*
|
||||
* NCR 5380 Family
|
||||
* SCSI Protocol Controller
|
||||
* Databook
|
||||
*/
|
||||
*/
|
||||
|
||||
/*
|
||||
* Options :
|
||||
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
|
||||
* for commands that return with a CHECK CONDITION status.
|
||||
*
|
||||
* PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
|
||||
* increase compared to polled I/O.
|
||||
*
|
||||
* PARITY - enable parity checking. Not supported.
|
||||
*
|
||||
* UNSAFE - leave interrupts enabled during pseudo-DMA transfers.
|
||||
* You probably want this.
|
||||
*
|
||||
* The card is detected and initialized in one of several ways :
|
||||
* 1. Autoprobe (default) - since the board is memory mapped,
|
||||
* a BIOS signature is scanned for to locate the registers.
|
||||
@ -79,15 +58,11 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "dtc.h"
|
||||
#define AUTOPROBE_IRQ
|
||||
#include "NCR5380.h"
|
||||
|
||||
|
||||
#define DTC_PUBLIC_RELEASE 2
|
||||
|
||||
/*
|
||||
* The DTC3180 & 3280 boards are memory mapped.
|
||||
*
|
||||
@ -173,10 +148,13 @@ static const struct signature {
|
||||
*
|
||||
*/
|
||||
|
||||
static void __init dtc_setup(char *str, int *ints)
|
||||
static int __init dtc_setup(char *str)
|
||||
{
|
||||
static int commandline_current = 0;
|
||||
int i;
|
||||
int ints[10];
|
||||
|
||||
get_options(str, ARRAY_SIZE(ints), ints);
|
||||
if (ints[0] != 2)
|
||||
printk("dtc_setup: usage dtc=address,irq\n");
|
||||
else if (commandline_current < NO_OVERRIDES) {
|
||||
@ -189,7 +167,10 @@ static void __init dtc_setup(char *str, int *ints)
|
||||
}
|
||||
++commandline_current;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("dtc=", dtc_setup);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -213,10 +194,6 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
|
||||
void __iomem *base;
|
||||
int sig, count;
|
||||
|
||||
tpnt->proc_name = "dtc3x80";
|
||||
tpnt->show_info = dtc_show_info;
|
||||
tpnt->write_info = dtc_write_info;
|
||||
|
||||
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
|
||||
addr = 0;
|
||||
base = NULL;
|
||||
@ -271,38 +248,33 @@ found:
|
||||
else
|
||||
instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
|
||||
|
||||
/* Compatibility with documented NCR5380 kernel parameters */
|
||||
if (instance->irq == 255)
|
||||
instance->irq = NO_IRQ;
|
||||
|
||||
#ifndef DONT_USE_INTR
|
||||
/* With interrupts enabled, it will sometimes hang when doing heavy
|
||||
* reads. So better not enable them until I finger it out. */
|
||||
if (instance->irq != SCSI_IRQ_NONE)
|
||||
if (instance->irq != NO_IRQ)
|
||||
if (request_irq(instance->irq, dtc_intr, 0,
|
||||
"dtc", instance)) {
|
||||
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
|
||||
instance->irq = SCSI_IRQ_NONE;
|
||||
instance->irq = NO_IRQ;
|
||||
}
|
||||
|
||||
if (instance->irq == SCSI_IRQ_NONE) {
|
||||
if (instance->irq == NO_IRQ) {
|
||||
printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
|
||||
printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
|
||||
}
|
||||
#else
|
||||
if (instance->irq != SCSI_IRQ_NONE)
|
||||
if (instance->irq != NO_IRQ)
|
||||
printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
|
||||
instance->irq = SCSI_IRQ_NONE;
|
||||
instance->irq = NO_IRQ;
|
||||
#endif
|
||||
#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
|
||||
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
|
||||
if (instance->irq == SCSI_IRQ_NONE)
|
||||
printk(" interrupts disabled");
|
||||
else
|
||||
printk(" irq %d", instance->irq);
|
||||
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
|
||||
NCR5380_print_options(instance);
|
||||
printk("\n");
|
||||
|
||||
++current_override;
|
||||
++count;
|
||||
}
|
||||
@ -354,20 +326,18 @@ static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
|
||||
* timeout.
|
||||
*/
|
||||
|
||||
static int dtc_maxi = 0;
|
||||
static int dtc_wmaxi = 0;
|
||||
|
||||
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
|
||||
{
|
||||
unsigned char *d = dst;
|
||||
int i; /* For counting time spent in the poll-loop */
|
||||
struct NCR5380_hostdata *hostdata = shost_priv(instance);
|
||||
NCR5380_local_declare();
|
||||
NCR5380_setup(instance);
|
||||
|
||||
i = 0;
|
||||
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
|
||||
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
|
||||
if (instance->irq == SCSI_IRQ_NONE)
|
||||
if (instance->irq == NO_IRQ)
|
||||
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
|
||||
else
|
||||
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
|
||||
@ -391,8 +361,8 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
|
||||
NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
|
||||
rtrc(0);
|
||||
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
|
||||
if (i > dtc_maxi)
|
||||
dtc_maxi = i;
|
||||
if (i > hostdata->spin_max_r)
|
||||
hostdata->spin_max_r = i;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -412,13 +382,14 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
|
||||
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
|
||||
{
|
||||
int i;
|
||||
struct NCR5380_hostdata *hostdata = shost_priv(instance);
|
||||
NCR5380_local_declare();
|
||||
NCR5380_setup(instance);
|
||||
|
||||
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
|
||||
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
|
||||
/* set direction (write) */
|
||||
if (instance->irq == SCSI_IRQ_NONE)
|
||||
if (instance->irq == NO_IRQ)
|
||||
NCR5380_write(DTC_CONTROL_REG, 0);
|
||||
else
|
||||
NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
|
||||
@ -444,8 +415,8 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
|
||||
/* Check for parity error here. fixme. */
|
||||
NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
|
||||
rtrc(0);
|
||||
if (i > dtc_wmaxi)
|
||||
dtc_wmaxi = i;
|
||||
if (i > hostdata->spin_max_w)
|
||||
hostdata->spin_max_w = i;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -457,7 +428,7 @@ static int dtc_release(struct Scsi_Host *shost)
|
||||
{
|
||||
NCR5380_local_declare();
|
||||
NCR5380_setup(shost);
|
||||
if (shost->irq)
|
||||
if (shost->irq != NO_IRQ)
|
||||
free_irq(shost->irq, shost);
|
||||
NCR5380_exit(shost);
|
||||
if (shost->io_port && shost->n_io_port)
|
||||
@ -471,6 +442,10 @@ static struct scsi_host_template driver_template = {
|
||||
.name = "DTC 3180/3280 ",
|
||||
.detect = dtc_detect,
|
||||
.release = dtc_release,
|
||||
.proc_name = "dtc3x80",
|
||||
.show_info = dtc_show_info,
|
||||
.write_info = dtc_write_info,
|
||||
.info = dtc_info,
|
||||
.queuecommand = dtc_queue_command,
|
||||
.eh_abort_handler = dtc_abort,
|
||||
.eh_bus_reset_handler = dtc_bus_reset,
|
||||
|
@ -5,24 +5,6 @@
|
||||
* (Unix and Linux consulting and custom programming)
|
||||
* drew@colorado.edu
|
||||
* +1 (303) 440-4894
|
||||
*
|
||||
* DISTRIBUTION RELEASE 2.
|
||||
*
|
||||
* For more information, please consult
|
||||
*
|
||||
*
|
||||
*
|
||||
* and
|
||||
*
|
||||
* NCR 5380 Family
|
||||
* SCSI Protocol Controller
|
||||
* Databook
|
||||
*
|
||||
* NCR Microelectronics
|
||||
* 1635 Aeroplaza Drive
|
||||
* Colorado Springs, CO 80916
|
||||
* 1+ (719) 578-3400
|
||||
* 1+ (800) 334-5454
|
||||
*/
|
||||
|
||||
#ifndef DTC3280_H
|
||||
@ -32,13 +14,6 @@
|
||||
#define DTCDEBUG_INIT 0x1
|
||||
#define DTCDEBUG_TRANSFER 0x2
|
||||
|
||||
static int dtc_abort(Scsi_Cmnd *);
|
||||
static int dtc_biosparam(struct scsi_device *, struct block_device *,
|
||||
sector_t, int*);
|
||||
static int dtc_detect(struct scsi_host_template *);
|
||||
static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
|
||||
static int dtc_bus_reset(Scsi_Cmnd *);
|
||||
|
||||
#ifndef CMD_PER_LUN
|
||||
#define CMD_PER_LUN 2
|
||||
#endif
|
||||
@ -88,6 +63,7 @@ static int dtc_bus_reset(Scsi_Cmnd *);
|
||||
#define NCR5380_queue_command dtc_queue_command
|
||||
#define NCR5380_abort dtc_abort
|
||||
#define NCR5380_bus_reset dtc_bus_reset
|
||||
#define NCR5380_info dtc_info
|
||||
#define NCR5380_show_info dtc_show_info
|
||||
#define NCR5380_write_info dtc_write_info
|
||||
|
||||
|
@ -946,20 +946,18 @@ static int eata2x_slave_configure(struct scsi_device *dev)
|
||||
|
||||
if (TLDEV(dev->type) && dev->tagged_supported) {
|
||||
if (tag_mode == TAG_SIMPLE) {
|
||||
scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
|
||||
tag_suffix = ", simple tags";
|
||||
} else if (tag_mode == TAG_ORDERED) {
|
||||
scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);
|
||||
tag_suffix = ", ordered tags";
|
||||
} else {
|
||||
scsi_adjust_queue_depth(dev, 0, tqd);
|
||||
tag_suffix = ", no tags";
|
||||
}
|
||||
scsi_change_queue_depth(dev, tqd);
|
||||
} else if (TLDEV(dev->type) && linked_comm) {
|
||||
scsi_adjust_queue_depth(dev, 0, tqd);
|
||||
scsi_change_queue_depth(dev, tqd);
|
||||
tag_suffix = ", untagged";
|
||||
} else {
|
||||
scsi_adjust_queue_depth(dev, 0, utqd);
|
||||
scsi_change_queue_depth(dev, utqd);
|
||||
tag_suffix = "";
|
||||
}
|
||||
|
||||
|
@ -972,11 +972,6 @@ u8 handle_hba_ioctl(struct esas2r_adapter *a,
|
||||
struct atto_ioctl *ioctl_hba);
|
||||
int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd);
|
||||
int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh);
|
||||
int esas2r_slave_alloc(struct scsi_device *dev);
|
||||
int esas2r_slave_configure(struct scsi_device *dev);
|
||||
void esas2r_slave_destroy(struct scsi_device *dev);
|
||||
int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason);
|
||||
int esas2r_change_queue_type(struct scsi_device *dev, int type);
|
||||
long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* SCSI error handler (eh) functions */
|
||||
|
@ -117,9 +117,8 @@ static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
|
||||
|
||||
rq = esas2r_alloc_request(a);
|
||||
if (rq == NULL) {
|
||||
up(&a->fm_api_semaphore);
|
||||
fi->status = FI_STAT_BUSY;
|
||||
return;
|
||||
goto free_sem;
|
||||
}
|
||||
|
||||
if (fi == &a->firmware.header) {
|
||||
@ -135,7 +134,7 @@ static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
|
||||
if (a->firmware.header_buff == NULL) {
|
||||
esas2r_debug("failed to allocate header buffer!");
|
||||
fi->status = FI_STAT_BUSY;
|
||||
return;
|
||||
goto free_req;
|
||||
}
|
||||
|
||||
memcpy(a->firmware.header_buff, fi,
|
||||
@ -171,9 +170,10 @@ all_done:
|
||||
a->firmware.header_buff,
|
||||
(dma_addr_t)a->firmware.header_buff_phys);
|
||||
}
|
||||
|
||||
up(&a->fm_api_semaphore);
|
||||
free_req:
|
||||
esas2r_free_request(a, (struct esas2r_request *)rq);
|
||||
free_sem:
|
||||
up(&a->fm_api_semaphore);
|
||||
return;
|
||||
|
||||
}
|
||||
@ -1420,9 +1420,10 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
|
||||
|
||||
rq = esas2r_alloc_request(a);
|
||||
if (rq == NULL) {
|
||||
up(&a->nvram_semaphore);
|
||||
ioctl->data.prw.code = 0;
|
||||
break;
|
||||
kfree(ioctl);
|
||||
esas2r_log(ESAS2R_LOG_WARN,
|
||||
"could not allocate an internal request");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
code = esas2r_write_params(a, rq,
|
||||
@ -1523,9 +1524,12 @@ ioctl_done:
|
||||
case -EINVAL:
|
||||
ioctl->header.return_code = IOCTL_INVALID_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
ioctl->header.return_code = IOCTL_GENERAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
ioctl->header.return_code = IOCTL_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
/* Always copy the buffer back, if only to pick up the status */
|
||||
|
@ -254,12 +254,10 @@ static struct scsi_host_template driver_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.emulated = 0,
|
||||
.proc_name = ESAS2R_DRVR_NAME,
|
||||
.slave_configure = esas2r_slave_configure,
|
||||
.slave_alloc = esas2r_slave_alloc,
|
||||
.slave_destroy = esas2r_slave_destroy,
|
||||
.change_queue_depth = esas2r_change_queue_depth,
|
||||
.change_queue_type = esas2r_change_queue_type,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.change_queue_type = scsi_change_queue_type,
|
||||
.max_sectors = 0xFFFF,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
|
||||
int sgl_page_size = 512;
|
||||
@ -1057,7 +1055,7 @@ int esas2r_eh_abort(struct scsi_cmnd *cmd)
|
||||
|
||||
cmd->scsi_done(cmd);
|
||||
|
||||
return 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&a->queue_lock, flags);
|
||||
@ -1259,60 +1257,6 @@ int esas2r_target_reset(struct scsi_cmnd *cmd)
|
||||
return esas2r_dev_targ_reset(cmd, true);
|
||||
}
|
||||
|
||||
int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason)
|
||||
{
|
||||
esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth);
|
||||
|
||||
scsi_adjust_queue_depth(dev, scsi_get_tag_type(dev), depth);
|
||||
|
||||
return dev->queue_depth;
|
||||
}
|
||||
|
||||
int esas2r_change_queue_type(struct scsi_device *dev, int type)
|
||||
{
|
||||
esas2r_log(ESAS2R_LOG_INFO, "change_queue_type %p, %d", dev, type);
|
||||
|
||||
if (dev->tagged_supported) {
|
||||
scsi_set_tag_type(dev, type);
|
||||
|
||||
if (type)
|
||||
scsi_activate_tcq(dev, dev->queue_depth);
|
||||
else
|
||||
scsi_deactivate_tcq(dev, dev->queue_depth);
|
||||
} else {
|
||||
type = 0;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
int esas2r_slave_alloc(struct scsi_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int esas2r_slave_configure(struct scsi_device *dev)
|
||||
{
|
||||
esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
|
||||
"esas2r_slave_configure()");
|
||||
|
||||
if (dev->tagged_supported) {
|
||||
scsi_set_tag_type(dev, MSG_SIMPLE_TAG);
|
||||
scsi_activate_tcq(dev, cmd_per_lun);
|
||||
} else {
|
||||
scsi_set_tag_type(dev, 0);
|
||||
scsi_deactivate_tcq(dev, cmd_per_lun);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esas2r_slave_destroy(struct scsi_device *dev)
|
||||
{
|
||||
esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
|
||||
"esas2r_slave_destroy()");
|
||||
}
|
||||
|
||||
void esas2r_log_request_failure(struct esas2r_adapter *a,
|
||||
struct esas2r_request *rq)
|
||||
{
|
||||
|
@ -49,55 +49,67 @@ static u32 esp_debug;
|
||||
#define ESP_DEBUG_DATADONE 0x00000100
|
||||
#define ESP_DEBUG_RECONNECT 0x00000200
|
||||
#define ESP_DEBUG_AUTOSENSE 0x00000400
|
||||
#define ESP_DEBUG_EVENT 0x00000800
|
||||
#define ESP_DEBUG_COMMAND 0x00001000
|
||||
|
||||
#define esp_log_intr(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_INTR) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_reset(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_RESET) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_msgin(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_MSGIN) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_msgout(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_MSGOUT) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_cmddone(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_CMDDONE) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_disconnect(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_DISCONNECT) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_datastart(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_DATASTART) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_datadone(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_DATADONE) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_reconnect(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_RECONNECT) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_autosense(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \
|
||||
printk(f, ## a); \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_event(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_EVENT) \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_log_command(f, a...) \
|
||||
do { if (esp_debug & ESP_DEBUG_COMMAND) \
|
||||
shost_printk(KERN_DEBUG, esp->host, f, ## a); \
|
||||
} while (0)
|
||||
|
||||
#define esp_read8(REG) esp->ops->esp_read8(esp, REG)
|
||||
@ -126,10 +138,29 @@ void scsi_esp_cmd(struct esp *esp, u8 val)
|
||||
|
||||
esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
|
||||
|
||||
esp_log_command("cmd[%02x]\n", val);
|
||||
esp_write8(val, ESP_CMD);
|
||||
}
|
||||
EXPORT_SYMBOL(scsi_esp_cmd);
|
||||
|
||||
static void esp_send_dma_cmd(struct esp *esp, int len, int max_len, int cmd)
|
||||
{
|
||||
if (esp->flags & ESP_FLAG_USE_FIFO) {
|
||||
int i;
|
||||
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
for (i = 0; i < len; i++)
|
||||
esp_write8(esp->command_block[i], ESP_FDATA);
|
||||
scsi_esp_cmd(esp, cmd);
|
||||
} else {
|
||||
if (esp->rev == FASHME)
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
cmd |= ESP_CMD_DMA;
|
||||
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
|
||||
len, max_len, 0, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_event(struct esp *esp, u8 val)
|
||||
{
|
||||
struct esp_event_ent *p;
|
||||
@ -150,19 +181,17 @@ static void esp_dump_cmd_log(struct esp *esp)
|
||||
int idx = esp->esp_event_cur;
|
||||
int stop = idx;
|
||||
|
||||
printk(KERN_INFO PFX "esp%d: Dumping command log\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_INFO, esp->host, "Dumping command log\n");
|
||||
do {
|
||||
struct esp_event_ent *p = &esp->esp_event_log[idx];
|
||||
|
||||
printk(KERN_INFO PFX "esp%d: ent[%d] %s ",
|
||||
esp->host->unique_id, idx,
|
||||
p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");
|
||||
|
||||
printk("val[%02x] sreg[%02x] seqreg[%02x] "
|
||||
"sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
|
||||
p->val, p->sreg, p->seqreg,
|
||||
p->sreg2, p->ireg, p->select_state, p->event);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"ent[%d] %s val[%02x] sreg[%02x] seqreg[%02x] "
|
||||
"sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
|
||||
idx,
|
||||
p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT",
|
||||
p->val, p->sreg, p->seqreg,
|
||||
p->sreg2, p->ireg, p->select_state, p->event);
|
||||
|
||||
idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
|
||||
} while (idx != stop);
|
||||
@ -176,9 +205,8 @@ static void esp_flush_fifo(struct esp *esp)
|
||||
|
||||
while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {
|
||||
if (--lim == 0) {
|
||||
printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "
|
||||
"will not clear!\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ALERT, esp->host,
|
||||
"ESP_FF_BYTES will not clear!\n");
|
||||
break;
|
||||
}
|
||||
udelay(1);
|
||||
@ -240,6 +268,19 @@ static void esp_reset_esp(struct esp *esp)
|
||||
} else {
|
||||
esp->min_period = ((5 * esp->ccycle) / 1000);
|
||||
}
|
||||
if (esp->rev == FAS236) {
|
||||
/*
|
||||
* The AM53c974 chip returns the same ID as FAS236;
|
||||
* try to configure glitch eater.
|
||||
*/
|
||||
u8 config4 = ESP_CONFIG4_GE1;
|
||||
esp_write8(config4, ESP_CFG4);
|
||||
config4 = esp_read8(ESP_CFG4);
|
||||
if (config4 & ESP_CONFIG4_GE1) {
|
||||
esp->rev = PCSCSI;
|
||||
esp_write8(esp->config4, ESP_CFG4);
|
||||
}
|
||||
}
|
||||
esp->max_period = (esp->max_period + 3)>>2;
|
||||
esp->min_period = (esp->min_period + 3)>>2;
|
||||
|
||||
@ -265,7 +306,8 @@ static void esp_reset_esp(struct esp *esp)
|
||||
/* fallthrough... */
|
||||
|
||||
case FAS236:
|
||||
/* Fast 236 or HME */
|
||||
case PCSCSI:
|
||||
/* Fast 236, AM53c974 or HME */
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
if (esp->rev == FASHME) {
|
||||
u8 cfg3 = esp->target[0].esp_config3;
|
||||
@ -383,12 +425,11 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
|
||||
p->cur_residue -= len;
|
||||
p->tot_residue -= len;
|
||||
if (p->cur_residue < 0 || p->tot_residue < 0) {
|
||||
printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",
|
||||
esp->host->unique_id);
|
||||
printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "
|
||||
"len[%u]\n",
|
||||
esp->host->unique_id,
|
||||
p->cur_residue, p->tot_residue, len);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Data transfer overflow.\n");
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"cur_residue[%d] tot_residue[%d] len[%u]\n",
|
||||
p->cur_residue, p->tot_residue, len);
|
||||
p->cur_residue = 0;
|
||||
p->tot_residue = 0;
|
||||
}
|
||||
@ -604,9 +645,8 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
|
||||
|
||||
|
||||
if (!ent->sense_ptr) {
|
||||
esp_log_autosense("esp%d: Doing auto-sense for "
|
||||
"tgt[%d] lun[%d]\n",
|
||||
esp->host->unique_id, tgt, lun);
|
||||
esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n",
|
||||
tgt, lun);
|
||||
|
||||
ent->sense_ptr = cmd->sense_buffer;
|
||||
ent->sense_dma = esp->ops->map_single(esp,
|
||||
@ -642,10 +682,7 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
|
||||
|
||||
val = (p - esp->command_block);
|
||||
|
||||
if (esp->rev == FASHME)
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
|
||||
val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
|
||||
esp_send_dma_cmd(esp, val, 16, ESP_CMD_SELA);
|
||||
}
|
||||
|
||||
static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
|
||||
@ -663,7 +700,7 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
|
||||
return ent;
|
||||
}
|
||||
|
||||
if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
|
||||
if (!spi_populate_tag_msg(&ent->tag[0], cmd)) {
|
||||
ent->tag[0] = 0;
|
||||
ent->tag[1] = 0;
|
||||
}
|
||||
@ -781,12 +818,12 @@ build_identify:
|
||||
}
|
||||
|
||||
if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
|
||||
start_cmd = ESP_CMD_DMA | ESP_CMD_SELA;
|
||||
start_cmd = ESP_CMD_SELA;
|
||||
if (ent->tag[0]) {
|
||||
*p++ = ent->tag[0];
|
||||
*p++ = ent->tag[1];
|
||||
|
||||
start_cmd = ESP_CMD_DMA | ESP_CMD_SA3;
|
||||
start_cmd = ESP_CMD_SA3;
|
||||
}
|
||||
|
||||
for (i = 0; i < cmd->cmd_len; i++)
|
||||
@ -806,7 +843,7 @@ build_identify:
|
||||
esp->msg_out_len += 2;
|
||||
}
|
||||
|
||||
start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS;
|
||||
start_cmd = ESP_CMD_SELAS;
|
||||
esp->select_state = ESP_SELECT_MSGOUT;
|
||||
}
|
||||
val = tgt;
|
||||
@ -826,10 +863,7 @@ build_identify:
|
||||
printk("]\n");
|
||||
}
|
||||
|
||||
if (esp->rev == FASHME)
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
|
||||
val, 16, 0, start_cmd);
|
||||
esp_send_dma_cmd(esp, val, 16, start_cmd);
|
||||
}
|
||||
|
||||
static struct esp_cmd_entry *esp_get_ent(struct esp *esp)
|
||||
@ -953,8 +987,8 @@ static int esp_check_gross_error(struct esp *esp)
|
||||
* - DMA programmed with wrong direction
|
||||
* - improper phase change
|
||||
*/
|
||||
printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n",
|
||||
esp->host->unique_id, esp->sreg);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Gross error sreg[%02x]\n", esp->sreg);
|
||||
/* XXX Reset the chip. XXX */
|
||||
return 1;
|
||||
}
|
||||
@ -974,7 +1008,6 @@ static int esp_check_spur_intr(struct esp *esp)
|
||||
|
||||
default:
|
||||
if (!(esp->sreg & ESP_STAT_INTR)) {
|
||||
esp->ireg = esp_read8(ESP_INTRPT);
|
||||
if (esp->ireg & ESP_INTR_SR)
|
||||
return 1;
|
||||
|
||||
@ -982,14 +1015,13 @@ static int esp_check_spur_intr(struct esp *esp)
|
||||
* ESP is not, the only possibility is a DMA error.
|
||||
*/
|
||||
if (!esp->ops->dma_error(esp)) {
|
||||
printk(KERN_ERR PFX "esp%d: Spurious irq, "
|
||||
"sreg=%02x.\n",
|
||||
esp->host->unique_id, esp->sreg);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Spurious irq, sreg=%02x.\n",
|
||||
esp->sreg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk(KERN_ERR PFX "esp%d: DMA error\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ERR, esp->host, "DMA error\n");
|
||||
|
||||
/* XXX Reset the chip. XXX */
|
||||
return -1;
|
||||
@ -1002,7 +1034,7 @@ static int esp_check_spur_intr(struct esp *esp)
|
||||
|
||||
static void esp_schedule_reset(struct esp *esp)
|
||||
{
|
||||
esp_log_reset("ESP: esp_schedule_reset() from %pf\n",
|
||||
esp_log_reset("esp_schedule_reset() from %pf\n",
|
||||
__builtin_return_address(0));
|
||||
esp->flags |= ESP_FLAG_RESETTING;
|
||||
esp_event(esp, ESP_EVENT_RESET);
|
||||
@ -1019,20 +1051,20 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
|
||||
int i;
|
||||
|
||||
if (!lp->num_tagged) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect w/num_tagged==0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_log_reconnect("ESP: reconnect tag, ");
|
||||
esp_log_reconnect("reconnect tag, ");
|
||||
|
||||
for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
|
||||
if (esp->ops->irq_pending(esp))
|
||||
break;
|
||||
}
|
||||
if (i == ESP_QUICKIRQ_LIMIT) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect IRQ1 timeout\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1043,14 +1075,14 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
|
||||
i, esp->ireg, esp->sreg);
|
||||
|
||||
if (esp->ireg & ESP_INTR_DC) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect, got disconnect.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n",
|
||||
esp->host->unique_id, esp->sreg);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect, not MIP sreg[%02x].\n", esp->sreg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1073,8 +1105,7 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
|
||||
udelay(1);
|
||||
}
|
||||
if (i == ESP_RESELECT_TAG_LIMIT) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n",
|
||||
esp->host->unique_id);
|
||||
shost_printk(KERN_ERR, esp->host, "Reconnect IRQ2 timeout\n");
|
||||
return NULL;
|
||||
}
|
||||
esp->ops->dma_drain(esp);
|
||||
@ -1087,17 +1118,17 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
|
||||
|
||||
if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
|
||||
esp->command_block[0] > ORDERED_QUEUE_TAG) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect, bad tag "
|
||||
"type %02x.\n",
|
||||
esp->host->unique_id, esp->command_block[0]);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect, bad tag type %02x.\n",
|
||||
esp->command_block[0]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ent = lp->tagged_cmds[esp->command_block[1]];
|
||||
if (!ent) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect, no entry for "
|
||||
"tag %02x.\n",
|
||||
esp->host->unique_id, esp->command_block[1]);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect, no entry for tag %02x.\n",
|
||||
esp->command_block[1]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1163,9 +1194,9 @@ static int esp_reconnect(struct esp *esp)
|
||||
tp = &esp->target[target];
|
||||
dev = __scsi_device_lookup_by_target(tp->starget, lun);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
|
||||
"tgt[%u] lun[%u]\n",
|
||||
esp->host->unique_id, target, lun);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Reconnect, no lp tgt[%u] lun[%u]\n",
|
||||
target, lun);
|
||||
goto do_reset;
|
||||
}
|
||||
lp = dev->hostdata;
|
||||
@ -1291,8 +1322,8 @@ static int esp_finish_select(struct esp *esp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk("ESP: Unexpected selection completion ireg[%x].\n",
|
||||
esp->ireg);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected selection completion ireg[%x]\n", esp->ireg);
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1312,11 +1343,42 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
|
||||
(((unsigned int)esp_read8(ESP_TCMED)) << 8));
|
||||
if (esp->rev == FASHME)
|
||||
ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16;
|
||||
if (esp->rev == PCSCSI && (esp->config2 & ESP_CONFIG2_FENAB))
|
||||
ecount |= ((unsigned int)esp_read8(ESP_TCHI)) << 16;
|
||||
}
|
||||
|
||||
bytes_sent = esp->data_dma_len;
|
||||
bytes_sent -= ecount;
|
||||
|
||||
/*
|
||||
* The am53c974 has a DMA 'pecularity'. The doc states:
|
||||
* In some odd byte conditions, one residual byte will
|
||||
* be left in the SCSI FIFO, and the FIFO Flags will
|
||||
* never count to '0 '. When this happens, the residual
|
||||
* byte should be retrieved via PIO following completion
|
||||
* of the BLAST operation.
|
||||
*/
|
||||
if (fifo_cnt == 1 && ent->flags & ESP_CMD_FLAG_RESIDUAL) {
|
||||
size_t count = 1;
|
||||
size_t offset = bytes_sent;
|
||||
u8 bval = esp_read8(ESP_FDATA);
|
||||
|
||||
if (ent->flags & ESP_CMD_FLAG_AUTOSENSE)
|
||||
ent->sense_ptr[bytes_sent] = bval;
|
||||
else {
|
||||
struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
|
||||
u8 *ptr;
|
||||
|
||||
ptr = scsi_kmap_atomic_sg(p->cur_sg, p->u.num_sg,
|
||||
&offset, &count);
|
||||
if (likely(ptr)) {
|
||||
*(ptr + offset) = bval;
|
||||
scsi_kunmap_atomic_sg(ptr);
|
||||
}
|
||||
}
|
||||
bytes_sent += fifo_cnt;
|
||||
ent->flags &= ~ESP_CMD_FLAG_RESIDUAL;
|
||||
}
|
||||
if (!(ent->flags & ESP_CMD_FLAG_WRITE))
|
||||
bytes_sent -= fifo_cnt;
|
||||
|
||||
@ -1556,8 +1618,8 @@ static void esp_msgin_extended(struct esp *esp)
|
||||
return;
|
||||
}
|
||||
|
||||
printk("ESP: Unexpected extended msg type %x\n",
|
||||
esp->msg_in[2]);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected extended msg type %x\n", esp->msg_in[2]);
|
||||
|
||||
esp->msg_out[0] = ABORT_TASK_SET;
|
||||
esp->msg_out_len = 1;
|
||||
@ -1574,7 +1636,8 @@ static int esp_msgin_process(struct esp *esp)
|
||||
|
||||
if (msg0 & 0x80) {
|
||||
/* Identify */
|
||||
printk("ESP: Unexpected msgin identify\n");
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected msgin identify\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1640,10 +1703,12 @@ static int esp_msgin_process(struct esp *esp)
|
||||
|
||||
static int esp_process_event(struct esp *esp)
|
||||
{
|
||||
int write;
|
||||
int write, i;
|
||||
|
||||
again:
|
||||
write = 0;
|
||||
esp_log_event("process event %d phase %x\n",
|
||||
esp->event, esp->sreg & ESP_STAT_PMASK);
|
||||
switch (esp->event) {
|
||||
case ESP_EVENT_CHECK_PHASE:
|
||||
switch (esp->sreg & ESP_STAT_PMASK) {
|
||||
@ -1673,8 +1738,9 @@ again:
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("ESP: Unexpected phase, sreg=%02x\n",
|
||||
esp->sreg);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected phase, sreg=%02x\n",
|
||||
esp->sreg);
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1708,18 +1774,17 @@ again:
|
||||
esp->data_dma_len = dma_len;
|
||||
|
||||
if (!dma_len) {
|
||||
printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
|
||||
esp->host->unique_id);
|
||||
printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n",
|
||||
esp->host->unique_id,
|
||||
(unsigned long long)esp_cur_dma_addr(ent, cmd),
|
||||
esp_cur_dma_len(ent, cmd));
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"DMA length is zero!\n");
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"cur adr[%08llx] len[%08x]\n",
|
||||
(unsigned long long)esp_cur_dma_addr(ent, cmd),
|
||||
esp_cur_dma_len(ent, cmd));
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_log_datastart("ESP: start data addr[%08llx] len[%u] "
|
||||
"write(%d)\n",
|
||||
esp_log_datastart("start data addr[%08llx] len[%u] write(%d)\n",
|
||||
(unsigned long long)dma_addr, dma_len, write);
|
||||
|
||||
esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
|
||||
@ -1733,7 +1798,8 @@ again:
|
||||
int bytes_sent;
|
||||
|
||||
if (esp->ops->dma_error(esp)) {
|
||||
printk("ESP: data done, DMA error, resetting\n");
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"data done, DMA error, resetting\n");
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1749,14 +1815,15 @@ again:
|
||||
/* We should always see exactly a bus-service
|
||||
* interrupt at the end of a successful transfer.
|
||||
*/
|
||||
printk("ESP: data done, not BSERV, resetting\n");
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"data done, not BSERV, resetting\n");
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
|
||||
|
||||
esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n",
|
||||
esp_log_datadone("data done flgs[%x] sent[%d]\n",
|
||||
ent->flags, bytes_sent);
|
||||
|
||||
if (bytes_sent < 0) {
|
||||
@ -1785,8 +1852,9 @@ again:
|
||||
}
|
||||
|
||||
if (ent->message != COMMAND_COMPLETE) {
|
||||
printk("ESP: Unexpected message %x in status\n",
|
||||
ent->message);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected message %x in status\n",
|
||||
ent->message);
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1804,8 +1872,7 @@ again:
|
||||
scsi_esp_cmd(esp, ESP_CMD_ESEL);
|
||||
|
||||
if (ent->message == COMMAND_COMPLETE) {
|
||||
esp_log_cmddone("ESP: Command done status[%x] "
|
||||
"message[%x]\n",
|
||||
esp_log_cmddone("Command done status[%x] message[%x]\n",
|
||||
ent->status, ent->message);
|
||||
if (ent->status == SAM_STAT_TASK_SET_FULL)
|
||||
esp_event_queue_full(esp, ent);
|
||||
@ -1821,16 +1888,16 @@ again:
|
||||
DID_OK));
|
||||
}
|
||||
} else if (ent->message == DISCONNECT) {
|
||||
esp_log_disconnect("ESP: Disconnecting tgt[%d] "
|
||||
"tag[%x:%x]\n",
|
||||
esp_log_disconnect("Disconnecting tgt[%d] tag[%x:%x]\n",
|
||||
cmd->device->id,
|
||||
ent->tag[0], ent->tag[1]);
|
||||
|
||||
esp->active_cmd = NULL;
|
||||
esp_maybe_execute_command(esp);
|
||||
} else {
|
||||
printk("ESP: Unexpected message %x in freebus\n",
|
||||
ent->message);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected message %x in freebus\n",
|
||||
ent->message);
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1862,6 +1929,10 @@ again:
|
||||
if (esp->msg_out_len == 1) {
|
||||
esp_write8(esp->msg_out[0], ESP_FDATA);
|
||||
scsi_esp_cmd(esp, ESP_CMD_TI);
|
||||
} else if (esp->flags & ESP_FLAG_USE_FIFO) {
|
||||
for (i = 0; i < esp->msg_out_len; i++)
|
||||
esp_write8(esp->msg_out[i], ESP_FDATA);
|
||||
scsi_esp_cmd(esp, ESP_CMD_TI);
|
||||
} else {
|
||||
/* Use DMA. */
|
||||
memcpy(esp->command_block,
|
||||
@ -1917,7 +1988,7 @@ again:
|
||||
val = esp_read8(ESP_FDATA);
|
||||
esp->msg_in[esp->msg_in_len++] = val;
|
||||
|
||||
esp_log_msgin("ESP: Got msgin byte %x\n", val);
|
||||
esp_log_msgin("Got msgin byte %x\n", val);
|
||||
|
||||
if (!esp_msgin_process(esp))
|
||||
esp->msg_in_len = 0;
|
||||
@ -1930,7 +2001,8 @@ again:
|
||||
if (esp->event != ESP_EVENT_FREE_BUS)
|
||||
esp_event(esp, ESP_EVENT_CHECK_PHASE);
|
||||
} else {
|
||||
printk("ESP: MSGIN neither BSERV not FDON, resetting");
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"MSGIN neither BSERV not FDON, resetting");
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
}
|
||||
@ -1938,11 +2010,7 @@ again:
|
||||
case ESP_EVENT_CMD_START:
|
||||
memcpy(esp->command_block, esp->cmd_bytes_ptr,
|
||||
esp->cmd_bytes_left);
|
||||
if (esp->rev == FASHME)
|
||||
scsi_esp_cmd(esp, ESP_CMD_FLUSH);
|
||||
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
|
||||
esp->cmd_bytes_left, 16, 0,
|
||||
ESP_CMD_DMA | ESP_CMD_TI);
|
||||
esp_send_dma_cmd(esp, esp->cmd_bytes_left, 16, ESP_CMD_TI);
|
||||
esp_event(esp, ESP_EVENT_CMD_DONE);
|
||||
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
|
||||
break;
|
||||
@ -1961,8 +2029,8 @@ again:
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("ESP: Unexpected event %x, resetting\n",
|
||||
esp->event);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"Unexpected event %x, resetting\n", esp->event);
|
||||
esp_schedule_reset(esp);
|
||||
return 0;
|
||||
break;
|
||||
@ -2044,7 +2112,12 @@ static void __esp_interrupt(struct esp *esp)
|
||||
int finish_reset, intr_done;
|
||||
u8 phase;
|
||||
|
||||
/*
|
||||
* Once INTRPT is read STATUS and SSTEP are cleared.
|
||||
*/
|
||||
esp->sreg = esp_read8(ESP_STATUS);
|
||||
esp->seqreg = esp_read8(ESP_SSTEP);
|
||||
esp->ireg = esp_read8(ESP_INTRPT);
|
||||
|
||||
if (esp->flags & ESP_FLAG_RESETTING) {
|
||||
finish_reset = 1;
|
||||
@ -2057,8 +2130,6 @@ static void __esp_interrupt(struct esp *esp)
|
||||
return;
|
||||
}
|
||||
|
||||
esp->ireg = esp_read8(ESP_INTRPT);
|
||||
|
||||
if (esp->ireg & ESP_INTR_SR)
|
||||
finish_reset = 1;
|
||||
|
||||
@ -2085,14 +2156,15 @@ static void __esp_interrupt(struct esp *esp)
|
||||
}
|
||||
}
|
||||
|
||||
esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] "
|
||||
esp_log_intr("intr sreg[%02x] seqreg[%02x] "
|
||||
"sreg2[%02x] ireg[%02x]\n",
|
||||
esp->sreg, esp->seqreg, esp->sreg2, esp->ireg);
|
||||
|
||||
intr_done = 0;
|
||||
|
||||
if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) {
|
||||
printk("ESP: unexpected IREG %02x\n", esp->ireg);
|
||||
shost_printk(KERN_INFO, esp->host,
|
||||
"unexpected IREG %02x\n", esp->ireg);
|
||||
if (esp->ireg & ESP_INTR_IC)
|
||||
esp_dump_cmd_log(esp);
|
||||
|
||||
@ -2149,46 +2221,50 @@ static void esp_get_revision(struct esp *esp)
|
||||
u8 val;
|
||||
|
||||
esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
|
||||
esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
|
||||
val = esp_read8(ESP_CFG2);
|
||||
val &= ~ESP_CONFIG2_MAGIC;
|
||||
if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
|
||||
/* If what we write to cfg2 does not come back, cfg2 is not
|
||||
* implemented, therefore this must be a plain esp100.
|
||||
*/
|
||||
esp->rev = ESP100;
|
||||
} else {
|
||||
esp->config2 = 0;
|
||||
esp_set_all_config3(esp, 5);
|
||||
esp->prev_cfg3 = 5;
|
||||
if (esp->config2 == 0) {
|
||||
esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
esp_write8(0, ESP_CFG3);
|
||||
|
||||
val = esp_read8(ESP_CFG2);
|
||||
val &= ~ESP_CONFIG2_MAGIC;
|
||||
|
||||
esp->config2 = 0;
|
||||
if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
|
||||
/*
|
||||
* If what we write to cfg2 does not come back,
|
||||
* cfg2 is not implemented.
|
||||
* Therefore this must be a plain esp100.
|
||||
*/
|
||||
esp->rev = ESP100;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
esp_set_all_config3(esp, 5);
|
||||
esp->prev_cfg3 = 5;
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
esp_write8(0, ESP_CFG3);
|
||||
esp_write8(esp->prev_cfg3, ESP_CFG3);
|
||||
|
||||
val = esp_read8(ESP_CFG3);
|
||||
if (val != 5) {
|
||||
/* The cfg2 register is implemented, however
|
||||
* cfg3 is not, must be esp100a.
|
||||
*/
|
||||
esp->rev = ESP100A;
|
||||
} else {
|
||||
esp_set_all_config3(esp, 0);
|
||||
esp->prev_cfg3 = 0;
|
||||
esp_write8(esp->prev_cfg3, ESP_CFG3);
|
||||
|
||||
val = esp_read8(ESP_CFG3);
|
||||
if (val != 5) {
|
||||
/* The cfg2 register is implemented, however
|
||||
* cfg3 is not, must be esp100a.
|
||||
*/
|
||||
esp->rev = ESP100A;
|
||||
/* All of cfg{1,2,3} implemented, must be one of
|
||||
* the fas variants, figure out which one.
|
||||
*/
|
||||
if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
|
||||
esp->rev = FAST;
|
||||
esp->sync_defp = SYNC_DEFP_FAST;
|
||||
} else {
|
||||
esp_set_all_config3(esp, 0);
|
||||
esp->prev_cfg3 = 0;
|
||||
esp_write8(esp->prev_cfg3, ESP_CFG3);
|
||||
|
||||
/* All of cfg{1,2,3} implemented, must be one of
|
||||
* the fas variants, figure out which one.
|
||||
*/
|
||||
if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
|
||||
esp->rev = FAST;
|
||||
esp->sync_defp = SYNC_DEFP_FAST;
|
||||
} else {
|
||||
esp->rev = ESP236;
|
||||
}
|
||||
esp->config2 = 0;
|
||||
esp_write8(esp->config2, ESP_CFG2);
|
||||
esp->rev = ESP236;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2308,6 +2384,7 @@ static const char *esp_chip_names[] = {
|
||||
"FAS100A",
|
||||
"FAST",
|
||||
"FASHME",
|
||||
"AM53C974",
|
||||
};
|
||||
|
||||
static struct scsi_transport_template *esp_transport_template;
|
||||
@ -2317,6 +2394,10 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
|
||||
static int instance;
|
||||
int err;
|
||||
|
||||
if (!esp->num_tags)
|
||||
esp->num_tags = ESP_DEFAULT_TAGS;
|
||||
else if (esp->num_tags >= ESP_MAX_TAG)
|
||||
esp->num_tags = ESP_MAX_TAG - 1;
|
||||
esp->host->transportt = esp_transport_template;
|
||||
esp->host->max_lun = ESP_MAX_LUN;
|
||||
esp->host->cmd_per_lun = 2;
|
||||
@ -2330,12 +2411,13 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
|
||||
|
||||
esp_bootup_reset(esp);
|
||||
|
||||
printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n",
|
||||
esp->host->unique_id, esp->regs, esp->dma_regs,
|
||||
esp->host->irq);
|
||||
printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
|
||||
esp->host->unique_id, esp_chip_names[esp->rev],
|
||||
esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
|
||||
dev_printk(KERN_INFO, dev, "esp%u: regs[%1p:%1p] irq[%u]\n",
|
||||
esp->host->unique_id, esp->regs, esp->dma_regs,
|
||||
esp->host->irq);
|
||||
dev_printk(KERN_INFO, dev,
|
||||
"esp%u: is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
|
||||
esp->host->unique_id, esp_chip_names[esp->rev],
|
||||
esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
|
||||
|
||||
/* Let the SCSI bus reset settle. */
|
||||
ssleep(esp_bus_reset_settle);
|
||||
@ -2402,28 +2484,10 @@ static int esp_slave_configure(struct scsi_device *dev)
|
||||
{
|
||||
struct esp *esp = shost_priv(dev->host);
|
||||
struct esp_target_data *tp = &esp->target[dev->id];
|
||||
int goal_tags, queue_depth;
|
||||
|
||||
goal_tags = 0;
|
||||
if (dev->tagged_supported)
|
||||
scsi_change_queue_depth(dev, esp->num_tags);
|
||||
|
||||
if (dev->tagged_supported) {
|
||||
/* XXX make this configurable somehow XXX */
|
||||
goal_tags = ESP_DEFAULT_TAGS;
|
||||
|
||||
if (goal_tags > ESP_MAX_TAG)
|
||||
goal_tags = ESP_MAX_TAG;
|
||||
}
|
||||
|
||||
queue_depth = goal_tags;
|
||||
if (queue_depth < dev->host->cmd_per_lun)
|
||||
queue_depth = dev->host->cmd_per_lun;
|
||||
|
||||
if (goal_tags) {
|
||||
scsi_set_tag_type(dev, MSG_ORDERED_TAG);
|
||||
scsi_activate_tcq(dev, queue_depth);
|
||||
} else {
|
||||
scsi_deactivate_tcq(dev, queue_depth);
|
||||
}
|
||||
tp->flags |= ESP_TGT_DISCONNECT;
|
||||
|
||||
if (!spi_initial_dv(dev->sdev_target))
|
||||
@ -2451,19 +2515,20 @@ static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
|
||||
* XXX much for the final driver.
|
||||
*/
|
||||
spin_lock_irqsave(esp->host->host_lock, flags);
|
||||
printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n",
|
||||
esp->host->unique_id, cmd, cmd->cmnd[0]);
|
||||
shost_printk(KERN_ERR, esp->host, "Aborting command [%p:%02x]\n",
|
||||
cmd, cmd->cmnd[0]);
|
||||
ent = esp->active_cmd;
|
||||
if (ent)
|
||||
printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n",
|
||||
esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
|
||||
shost_printk(KERN_ERR, esp->host,
|
||||
"Current command [%p:%02x]\n",
|
||||
ent->cmd, ent->cmd->cmnd[0]);
|
||||
list_for_each_entry(ent, &esp->queued_cmds, list) {
|
||||
printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n",
|
||||
esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
|
||||
shost_printk(KERN_ERR, esp->host, "Queued command [%p:%02x]\n",
|
||||
ent->cmd, ent->cmd->cmnd[0]);
|
||||
}
|
||||
list_for_each_entry(ent, &esp->active_cmds, list) {
|
||||
printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n",
|
||||
esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
|
||||
shost_printk(KERN_ERR, esp->host, " Active command [%p:%02x]\n",
|
||||
ent->cmd, ent->cmd->cmnd[0]);
|
||||
}
|
||||
esp_dump_cmd_log(esp);
|
||||
spin_unlock_irqrestore(esp->host->host_lock, flags);
|
||||
@ -2631,6 +2696,7 @@ struct scsi_host_template scsi_esp_template = {
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.max_sectors = 0xffff,
|
||||
.skip_settle_delay = 1,
|
||||
.use_blk_tags = 1,
|
||||
};
|
||||
EXPORT_SYMBOL(scsi_esp_template);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* esp_scsi.h: Defines and structures for the ESP drier.
|
||||
/* esp_scsi.h: Defines and structures for the ESP driver.
|
||||
*
|
||||
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
|
||||
*/
|
||||
@ -25,6 +25,7 @@
|
||||
#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */
|
||||
#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */
|
||||
#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */
|
||||
#define ESP_CFG4 0x0dUL /* rw Fourth cfg register 0x34 */
|
||||
#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */
|
||||
#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
|
||||
#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
|
||||
@ -76,6 +77,18 @@
|
||||
#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
|
||||
#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
|
||||
|
||||
/* ESP config register 4 read-write, found only on am53c974 chips */
|
||||
#define ESP_CONFIG4_RADE 0x04 /* Active negation */
|
||||
#define ESP_CONFIG4_RAE 0x08 /* Active negation on REQ and ACK */
|
||||
#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature */
|
||||
#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 */
|
||||
#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 */
|
||||
|
||||
#define ESP_CONFIG_GE_12NS (0)
|
||||
#define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1)
|
||||
#define ESP_CONFIG_GE_35NS (ESP_CONFIG_GE0)
|
||||
#define ESP_CONFIG_GE_0NS (ESP_CONFIG_GE0 | ESP_CONFIG_GE1)
|
||||
|
||||
/* ESP command register read-write */
|
||||
/* Group 1 commands: These may be sent at any point in time to the ESP
|
||||
* chip. None of them can generate interrupts 'cept
|
||||
@ -254,6 +267,7 @@ enum esp_rev {
|
||||
FAS100A = 0x04,
|
||||
FAST = 0x05,
|
||||
FASHME = 0x06,
|
||||
PCSCSI = 0x07, /* AM53c974 */
|
||||
};
|
||||
|
||||
struct esp_cmd_entry {
|
||||
@ -269,6 +283,7 @@ struct esp_cmd_entry {
|
||||
#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */
|
||||
#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */
|
||||
#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
|
||||
#define ESP_CMD_FLAG_RESIDUAL 0x08 /* AM53c974 BLAST residual */
|
||||
|
||||
u8 tag[2];
|
||||
u8 orig_tag[2];
|
||||
@ -283,7 +298,6 @@ struct esp_cmd_entry {
|
||||
struct completion *eh_done;
|
||||
};
|
||||
|
||||
/* XXX make this configurable somehow XXX */
|
||||
#define ESP_DEFAULT_TAGS 16
|
||||
|
||||
#define ESP_MAX_TARGET 16
|
||||
@ -445,7 +459,7 @@ struct esp {
|
||||
u8 prev_soff;
|
||||
u8 prev_stp;
|
||||
u8 prev_cfg3;
|
||||
u8 __pad;
|
||||
u8 num_tags;
|
||||
|
||||
struct list_head esp_cmd_pool;
|
||||
|
||||
@ -466,6 +480,7 @@ struct esp {
|
||||
u8 bursts;
|
||||
u8 config1;
|
||||
u8 config2;
|
||||
u8 config4;
|
||||
|
||||
u8 scsi_id;
|
||||
u32 scsi_id_mask;
|
||||
@ -479,6 +494,7 @@ struct esp {
|
||||
#define ESP_FLAG_WIDE_CAPABLE 0x00000008
|
||||
#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
|
||||
#define ESP_FLAG_DISABLE_SYNC 0x00000020
|
||||
#define ESP_FLAG_USE_FIFO 0x00000040
|
||||
|
||||
u8 select_state;
|
||||
#define ESP_SELECT_NONE 0x00 /* Not selecting */
|
||||
|
@ -280,14 +280,16 @@ static struct scsi_host_template fcoe_shost_template = {
|
||||
.eh_device_reset_handler = fc_eh_device_reset,
|
||||
.eh_host_reset_handler = fc_eh_host_reset,
|
||||
.slave_alloc = fc_slave_alloc,
|
||||
.change_queue_depth = fc_change_queue_depth,
|
||||
.change_queue_type = fc_change_queue_type,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.change_queue_type = scsi_change_queue_type,
|
||||
.this_id = -1,
|
||||
.cmd_per_lun = 3,
|
||||
.can_queue = FCOE_MAX_OUTSTANDING_COMMANDS,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
.sg_tablesize = SG_ALL,
|
||||
.max_sectors = 0xffff,
|
||||
.use_blk_tags = 1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
#define DRV_NAME "fnic"
|
||||
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
|
||||
#define DRV_VERSION "1.6.0.11"
|
||||
#define DRV_VERSION "1.6.0.16"
|
||||
#define PFX DRV_NAME ": "
|
||||
#define DFX DRV_NAME "%d: "
|
||||
|
||||
|
@ -135,6 +135,11 @@ void fnic_handle_link(struct work_struct *work)
|
||||
fnic->lport->host->host_no, FNIC_FC_LE,
|
||||
"Link Status: UP_DOWN",
|
||||
strlen("Link Status: UP_DOWN"));
|
||||
if (fnic->config.flags & VFCF_FIP_CAPABLE) {
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
|
||||
"deleting fip-timer during link-down\n");
|
||||
del_timer_sync(&fnic->fip_timer);
|
||||
}
|
||||
fcoe_ctlr_link_down(&fnic->ctlr);
|
||||
}
|
||||
|
||||
|
@ -95,12 +95,10 @@ static int fnic_slave_alloc(struct scsi_device *sdev)
|
||||
{
|
||||
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
|
||||
|
||||
sdev->tagged_supported = 1;
|
||||
|
||||
if (!rport || fc_remote_port_chkready(rport))
|
||||
return -ENXIO;
|
||||
|
||||
scsi_activate_tcq(sdev, fnic_max_qdepth);
|
||||
scsi_change_queue_depth(sdev, fnic_max_qdepth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -112,8 +110,8 @@ static struct scsi_host_template fnic_host_template = {
|
||||
.eh_device_reset_handler = fnic_device_reset,
|
||||
.eh_host_reset_handler = fnic_host_reset,
|
||||
.slave_alloc = fnic_slave_alloc,
|
||||
.change_queue_depth = fc_change_queue_depth,
|
||||
.change_queue_type = fc_change_queue_type,
|
||||
.change_queue_depth = scsi_change_queue_depth,
|
||||
.change_queue_type = scsi_change_queue_type,
|
||||
.this_id = -1,
|
||||
.cmd_per_lun = 3,
|
||||
.can_queue = FNIC_DFLT_IO_REQ,
|
||||
@ -121,6 +119,8 @@ static struct scsi_host_template fnic_host_template = {
|
||||
.sg_tablesize = FNIC_MAX_SG_DESC_CNT,
|
||||
.max_sectors = 0xffff,
|
||||
.shost_attrs = fnic_attrs,
|
||||
.use_blk_tags = 1,
|
||||
.track_queue_depth = 1,
|
||||
};
|
||||
|
||||
static void
|
||||
@ -438,21 +438,30 @@ static int fnic_dev_wait(struct vnic_dev *vdev,
|
||||
unsigned long time;
|
||||
int done;
|
||||
int err;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
err = start(vdev, arg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Wait for func to complete...2 seconds max */
|
||||
/* Wait for func to complete.
|
||||
* Sometime schedule_timeout_uninterruptible take long time
|
||||
* to wake up so we do not retry as we are only waiting for
|
||||
* 2 seconds in while loop. By adding count, we make sure
|
||||
* we try atleast three times before returning -ETIMEDOUT
|
||||
*/
|
||||
time = jiffies + (HZ * 2);
|
||||
do {
|
||||
err = finished(vdev, &done);
|
||||
count++;
|
||||
if (err)
|
||||
return err;
|
||||
if (done)
|
||||
return 0;
|
||||
schedule_timeout_uninterruptible(HZ / 10);
|
||||
} while (time_after(time, jiffies));
|
||||
} while (time_after(time, jiffies) || (count < 3));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -325,13 +325,11 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
|
||||
struct fc_rport_libfc_priv *rp = rport->dd_data;
|
||||
struct host_sg_desc *desc;
|
||||
struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats;
|
||||
u8 pri_tag = 0;
|
||||
unsigned int i;
|
||||
unsigned long intr_flags;
|
||||
int flags;
|
||||
u8 exch_flags;
|
||||
struct scsi_lun fc_lun;
|
||||
char msg[2];
|
||||
|
||||
if (sg_count) {
|
||||
/* For each SGE, create a device desc entry */
|
||||
@ -357,12 +355,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
|
||||
|
||||
int_to_scsilun(sc->device->lun, &fc_lun);
|
||||
|
||||
pri_tag = FCPIO_ICMND_PTA_SIMPLE;
|
||||
msg[0] = MSG_SIMPLE_TAG;
|
||||
scsi_populate_tag_msg(sc, msg);
|
||||
if (msg[0] == MSG_ORDERED_TAG)
|
||||
pri_tag = FCPIO_ICMND_PTA_ORDERED;
|
||||
|
||||
/* Enqueue the descriptor in the Copy WQ */
|
||||
spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags);
|
||||
|
||||
@ -394,7 +386,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
|
||||
io_req->sgl_list_pa,
|
||||
io_req->sense_buf_pa,
|
||||
0, /* scsi cmd ref, always 0 */
|
||||
pri_tag, /* scsi pri and tag */
|
||||
FCPIO_ICMND_PTA_SIMPLE,
|
||||
/* scsi pri and tag */
|
||||
flags, /* command flags */
|
||||
sc->cmnd, sc->cmd_len,
|
||||
scsi_bufflen(sc),
|
||||
@ -428,8 +421,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
|
||||
int ret;
|
||||
u64 cmd_trace;
|
||||
int sg_count = 0;
|
||||
unsigned long flags;
|
||||
unsigned long flags = 0;
|
||||
unsigned long ptr;
|
||||
struct fc_rport_priv *rdata;
|
||||
spinlock_t *io_lock = NULL;
|
||||
|
||||
if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
@ -443,6 +438,16 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
|
||||
return 0;
|
||||
}
|
||||
|
||||
rdata = lp->tt.rport_lookup(lp, rport->port_id);
|
||||
if (!rdata || (rdata->rp_state == RPORT_ST_DELETE)) {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
|
||||
"returning IO as rport is removed\n");
|
||||
atomic64_inc(&fnic_stats->misc_stats.rport_not_ready);
|
||||
sc->result = DID_NO_CONNECT;
|
||||
done(sc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->state != LPORT_ST_READY || !(lp->link_up))
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
||||
@ -505,6 +510,13 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Will acquire lock defore setting to IO initialized.
|
||||
*/
|
||||
|
||||
io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
spin_lock_irqsave(io_lock, flags);
|
||||
|
||||
/* initialize rest of io_req */
|
||||
io_req->port_id = rport->port_id;
|
||||
io_req->start_time = jiffies;
|
||||
@ -521,11 +533,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
|
||||
* In case another thread cancelled the request,
|
||||
* refetch the pointer under the lock.
|
||||
*/
|
||||
spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc);
|
||||
FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no,
|
||||
sc->request->tag, sc, 0, 0, 0,
|
||||
(((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc)));
|
||||
spin_lock_irqsave(io_lock, flags);
|
||||
io_req = (struct fnic_io_req *)CMD_SP(sc);
|
||||
CMD_SP(sc) = NULL;
|
||||
CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE;
|
||||
@ -534,6 +544,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
|
||||
fnic_release_ioreq_buf(fnic, io_req, sc);
|
||||
mempool_free(io_req, fnic->io_req_pool);
|
||||
}
|
||||
atomic_dec(&fnic->in_flight);
|
||||
/* acquire host lock before returning to SCSI */
|
||||
spin_lock(lp->host->host_lock);
|
||||
return ret;
|
||||
} else {
|
||||
atomic64_inc(&fnic_stats->io_stats.active_ios);
|
||||
atomic64_inc(&fnic_stats->io_stats.num_ios);
|
||||
@ -555,6 +569,11 @@ out:
|
||||
sc->request->tag, sc, io_req,
|
||||
sg_count, cmd_trace,
|
||||
(((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc)));
|
||||
|
||||
/* if only we issued IO, will we have the io lock */
|
||||
if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED)
|
||||
spin_unlock_irqrestore(io_lock, flags);
|
||||
|
||||
atomic_dec(&fnic->in_flight);
|
||||
/* acquire host lock before returning to SCSI */
|
||||
spin_lock(lp->host->host_lock);
|
||||
|
@ -624,12 +624,12 @@ int fnic_fc_trace_set_data(u32 host_no, u8 frame_type,
|
||||
if (frame_type == FNIC_FC_RECV) {
|
||||
eth_fcoe_hdr_len = sizeof(struct ethhdr) +
|
||||
sizeof(struct fcoe_hdr);
|
||||
fc_trc_frame_len = fc_trc_frame_len + eth_fcoe_hdr_len;
|
||||
memset((char *)fc_trace, 0xff, eth_fcoe_hdr_len);
|
||||
/* Copy the rest of data frame */
|
||||
memcpy((char *)(fc_trace + eth_fcoe_hdr_len), (void *)frame,
|
||||
min_t(u8, fc_trc_frame_len,
|
||||
(u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE)));
|
||||
(u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE
|
||||
- eth_fcoe_hdr_len)));
|
||||
} else {
|
||||
memcpy((char *)fc_trace, (void *)frame,
|
||||
min_t(u8, fc_trc_frame_len,
|
||||
|
@ -18,20 +18,6 @@
|
||||
*
|
||||
* Added ISAPNP support for DTC436 adapters,
|
||||
* Thomas Sailer, sailer@ife.ee.ethz.ch
|
||||
*
|
||||
* ALPHA RELEASE 1.
|
||||
*
|
||||
* For more information, please consult
|
||||
*
|
||||
* NCR 5380 Family
|
||||
* SCSI Protocol Controller
|
||||
* Databook
|
||||
*
|
||||
* NCR Microelectronics
|
||||
* 1635 Aeroplaza Drive
|
||||
* Colorado Springs, CO 80916
|
||||
* 1+ (719) 578-3400
|
||||
* 1+ (800) 334-5454
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -40,14 +26,6 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Options :
|
||||
*
|
||||
* PARITY - enable parity checking. Not supported.
|
||||
*
|
||||
* SCSI2 - enable support for SCSI-II tagged queueing. Untested.
|
||||
*
|
||||
* USLEEP - enable support for devices that don't disconnect. Untested.
|
||||
*
|
||||
* The card is detected and initialized in one of several ways :
|
||||
* 1. With command line overrides - NCR5380=port,irq may be
|
||||
* used on the LILO command line to override the defaults.
|
||||
@ -79,27 +57,21 @@
|
||||
*/
|
||||
|
||||
/* settings for DTC3181E card with only Mustek scanner attached */
|
||||
#define USLEEP
|
||||
#define USLEEP_POLL 1
|
||||
#define USLEEP_SLEEP 20
|
||||
#define USLEEP_WAITLONG 500
|
||||
|
||||
#define AUTOPROBE_IRQ
|
||||
#define AUTOSENSE
|
||||
|
||||
|
||||
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
|
||||
#define NCR53C400_PSEUDO_DMA 1
|
||||
#define PSEUDO_DMA
|
||||
#define NCR53C400
|
||||
#define NCR5380_STATS
|
||||
#undef NCR5380_STAT_LIMIT
|
||||
#endif
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include "scsi.h"
|
||||
#include <scsi/scsi_host.h>
|
||||
#include "g_NCR5380.h"
|
||||
#include "NCR5380.h"
|
||||
@ -277,7 +249,7 @@ static int __init do_DTC3181E_setup(char *str)
|
||||
* Locks: none
|
||||
*/
|
||||
|
||||
int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
|
||||
static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
|
||||
{
|
||||
static int current_override = 0;
|
||||
int count;
|
||||
@ -335,7 +307,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
|
||||
if (pnp_irq_valid(dev, 0))
|
||||
overrides[count].irq = pnp_irq(dev, 0);
|
||||
else
|
||||
overrides[count].irq = SCSI_IRQ_NONE;
|
||||
overrides[count].irq = NO_IRQ;
|
||||
if (pnp_dma_valid(dev, 0))
|
||||
overrides[count].dma = pnp_dma(dev, 0);
|
||||
else
|
||||
@ -455,46 +427,28 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
|
||||
else
|
||||
instance->irq = NCR5380_probe_irq(instance, 0xffff);
|
||||
|
||||
if (instance->irq != SCSI_IRQ_NONE)
|
||||
/* Compatibility with documented NCR5380 kernel parameters */
|
||||
if (instance->irq == 255)
|
||||
instance->irq = NO_IRQ;
|
||||
|
||||
if (instance->irq != NO_IRQ)
|
||||
if (request_irq(instance->irq, generic_NCR5380_intr,
|
||||
0, "NCR5380", instance)) {
|
||||
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
|
||||
instance->irq = SCSI_IRQ_NONE;
|
||||
instance->irq = NO_IRQ;
|
||||
}
|
||||
|
||||
if (instance->irq == SCSI_IRQ_NONE) {
|
||||
if (instance->irq == NO_IRQ) {
|
||||
printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
|
||||
printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
|
||||
if (instance->irq == SCSI_IRQ_NONE)
|
||||
printk(" interrupts disabled");
|
||||
else
|
||||
printk(" irq %d", instance->irq);
|
||||
printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
|
||||
NCR5380_print_options(instance);
|
||||
printk("\n");
|
||||
|
||||
++current_override;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_NCR5380_info - reporting string
|
||||
* @host: NCR5380 to report on
|
||||
*
|
||||
* Report driver information for the NCR5380
|
||||
*/
|
||||
|
||||
const char *generic_NCR5380_info(struct Scsi_Host *host)
|
||||
{
|
||||
static const char string[] = "Generic NCR5380/53C400 Driver";
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_NCR5380_release_resources - free resources
|
||||
* @instance: host adapter to clean up
|
||||
@ -504,12 +458,12 @@ const char *generic_NCR5380_info(struct Scsi_Host *host)
|
||||
* Locks: none
|
||||
*/
|
||||
|
||||
int generic_NCR5380_release_resources(struct Scsi_Host *instance)
|
||||
static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
|
||||
{
|
||||
NCR5380_local_declare();
|
||||
NCR5380_setup(instance);
|
||||
|
||||
if (instance->irq != SCSI_IRQ_NONE)
|
||||
if (instance->irq != NO_IRQ)
|
||||
free_irq(instance->irq, instance);
|
||||
NCR5380_exit(instance);
|
||||
|
||||
@ -741,163 +695,9 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
|
||||
|
||||
#include "NCR5380.c"
|
||||
|
||||
#define PRINTP(x) seq_printf(m, x)
|
||||
#define ANDP ,
|
||||
|
||||
static void sprint_opcode(struct seq_file *m, int opcode)
|
||||
{
|
||||
PRINTP("0x%02x " ANDP opcode);
|
||||
}
|
||||
|
||||
static void sprint_command(struct seq_file *m, unsigned char *command)
|
||||
{
|
||||
int i, s;
|
||||
sprint_opcode(m, command[0]);
|
||||
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
|
||||
PRINTP("%02x " ANDP command[i]);
|
||||
PRINTP("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* sprintf_Scsi_Cmnd - print a scsi command
|
||||
* @m: seq_fil to print into
|
||||
* @cmd: SCSI command block
|
||||
*
|
||||
* Print out the target and command data in hex
|
||||
*/
|
||||
|
||||
static void sprint_Scsi_Cmnd(struct seq_file *m, Scsi_Cmnd * cmd)
|
||||
{
|
||||
PRINTP("host number %d destination target %d, lun %llu\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun);
|
||||
PRINTP(" command = ");
|
||||
sprint_command(m, cmd->cmnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_NCR5380_proc_info - /proc for NCR5380 driver
|
||||
* @buffer: buffer to print into
|
||||
* @start: start position
|
||||
* @offset: offset into buffer
|
||||
* @len: length
|
||||
* @hostno: instance to affect
|
||||
* @inout: read/write
|
||||
*
|
||||
* Provide the procfs information for the 5380 controller. We fill
|
||||
* this with useful debugging information including the commands
|
||||
* being executed, disconnected command queue and the statistical
|
||||
* data
|
||||
*
|
||||
* Locks: global cli/lock for queue walk
|
||||
*/
|
||||
|
||||
static int generic_NCR5380_show_info(struct seq_file *m, struct Scsi_Host *scsi_ptr)
|
||||
{
|
||||
NCR5380_local_declare();
|
||||
unsigned long flags;
|
||||
unsigned char status;
|
||||
int i;
|
||||
Scsi_Cmnd *ptr;
|
||||
struct NCR5380_hostdata *hostdata;
|
||||
#ifdef NCR5380_STATS
|
||||
struct scsi_device *dev;
|
||||
#endif
|
||||
|
||||
NCR5380_setup(scsi_ptr);
|
||||
hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
|
||||
|
||||
spin_lock_irqsave(scsi_ptr->host_lock, flags);
|
||||
PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
|
||||
PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
|
||||
PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
|
||||
#ifdef NCR53C400
|
||||
PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
|
||||
PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not");
|
||||
# if NCR53C400_PSEUDO_DMA
|
||||
PRINTP("NCR53C400 pseudo DMA used\n");
|
||||
# endif
|
||||
#else
|
||||
PRINTP("NO NCR53C400 driver extensions\n");
|
||||
#endif
|
||||
PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
|
||||
if (scsi_ptr->irq == SCSI_IRQ_NONE)
|
||||
PRINTP("no interrupt\n");
|
||||
else
|
||||
PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
|
||||
|
||||
#ifdef NCR5380_STATS
|
||||
if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
|
||||
PRINTP("There are commands pending, transfer rates may be crud\n");
|
||||
if (hostdata->pendingr)
|
||||
PRINTP(" %d pending reads" ANDP hostdata->pendingr);
|
||||
if (hostdata->pendingw)
|
||||
PRINTP(" %d pending writes" ANDP hostdata->pendingw);
|
||||
if (hostdata->pendingr || hostdata->pendingw)
|
||||
PRINTP("\n");
|
||||
shost_for_each_device(dev, scsi_ptr) {
|
||||
unsigned long br = hostdata->bytes_read[dev->id];
|
||||
unsigned long bw = hostdata->bytes_write[dev->id];
|
||||
long tr = hostdata->time_read[dev->id] / HZ;
|
||||
long tw = hostdata->time_write[dev->id] / HZ;
|
||||
|
||||
PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
|
||||
for (i = 0; i < 8; i++)
|
||||
if (dev->vendor[i] >= 0x20)
|
||||
seq_putc(m, dev->vendor[i]);
|
||||
seq_putc(m, ' ');
|
||||
for (i = 0; i < 16; i++)
|
||||
if (dev->model[i] >= 0x20)
|
||||
seq_putc(m, dev->model[i]);
|
||||
seq_putc(m, ' ');
|
||||
for (i = 0; i < 4; i++)
|
||||
if (dev->rev[i] >= 0x20)
|
||||
seq_putc(m, dev->rev[i]);
|
||||
seq_putc(m, ' ');
|
||||
|
||||
PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr);
|
||||
if (tr)
|
||||
PRINTP(" @ %5ld bps" ANDP br / tr);
|
||||
|
||||
PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw);
|
||||
if (tw)
|
||||
PRINTP(" @ %5ld bps" ANDP bw / tw);
|
||||
PRINTP("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
status = NCR5380_read(STATUS_REG);
|
||||
if (!(status & SR_REQ))
|
||||
PRINTP("REQ not asserted, phase unknown.\n");
|
||||
else {
|
||||
for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
|
||||
PRINTP("Phase %s\n" ANDP phases[i].name);
|
||||
}
|
||||
|
||||
if (!hostdata->connected) {
|
||||
PRINTP("No currently connected command\n");
|
||||
} else {
|
||||
sprint_Scsi_Cmnd(m, (Scsi_Cmnd *) hostdata->connected);
|
||||
}
|
||||
|
||||
PRINTP("issue_queue\n");
|
||||
|
||||
for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
|
||||
sprint_Scsi_Cmnd(m, ptr);
|
||||
|
||||
PRINTP("disconnected_queue\n");
|
||||
|
||||
for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
|
||||
sprint_Scsi_Cmnd(m, ptr);
|
||||
|
||||
spin_unlock_irqrestore(scsi_ptr->host_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef PRINTP
|
||||
#undef ANDP
|
||||
|
||||
static struct scsi_host_template driver_template = {
|
||||
.show_info = generic_NCR5380_show_info,
|
||||
.name = "Generic NCR5380/NCR53C400 Scsi Driver",
|
||||
.name = "Generic NCR5380/NCR53C400 SCSI",
|
||||
.detect = generic_NCR5380_detect,
|
||||
.release = generic_NCR5380_release_resources,
|
||||
.info = generic_NCR5380_info,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user