提交 c9802cd9 编写于 作者: J James Bottomley

Merge mulgrave-w:git/scsi-misc-2.6

Conflicts:

	drivers/scsi/iscsi_tcp.c
	drivers/scsi/iscsi_tcp.h

Pretty horrible merge between crypto hash consolidation
and crypto_digest_...->crypto_hash_... conversion
Signed-off-by: NJames Bottomley <James.Bottomley@SteelEye.com>
**************************************************************************
** History
**
** REV# DATE NAME DESCRIPTION
** 1.00.00.00 3/31/2004 Erich Chen First release
** 1.10.00.04 7/28/2004 Erich Chen modify for ioctl
** 1.10.00.06 8/28/2004 Erich Chen modify for 2.6.x
** 1.10.00.08 9/28/2004 Erich Chen modify for x86_64
** 1.10.00.10 10/10/2004 Erich Chen bug fix for SMP & ioctl
** 1.20.00.00 11/29/2004 Erich Chen bug fix with arcmsr_bus_reset when PHY error
** 1.20.00.02 12/09/2004 Erich Chen bug fix with over 2T bytes RAID Volume
** 1.20.00.04 1/09/2005 Erich Chen fits for Debian linux kernel version 2.2.xx
** 1.20.00.05 2/20/2005 Erich Chen cleanly as look like a Linux driver at 2.6.x
** thanks for peoples kindness comment
** Kornel Wieliczek
** Christoph Hellwig
** Adrian Bunk
** Andrew Morton
** Christoph Hellwig
** James Bottomley
** Arjan van de Ven
** 1.20.00.06 3/12/2005 Erich Chen fix with arcmsr_pci_unmap_dma "unsigned long" cast,
** modify PCCB POOL allocated by "dma_alloc_coherent"
** (Kornel Wieliczek's comment)
** 1.20.00.07 3/23/2005 Erich Chen bug fix with arcmsr_scsi_host_template_init
** occur segmentation fault,
** if RAID adapter does not on PCI slot
** and modprobe/rmmod this driver twice.
** bug fix enormous stack usage (Adrian Bunk's comment)
** 1.20.00.08 6/23/2005 Erich Chen bug fix with abort command,
** in case of heavy loading when sata cable
** working on low quality connection
** 1.20.00.09 9/12/2005 Erich Chen bug fix with abort command handling, firmware version check
** and firmware update notify for hardware bug fix
** 1.20.00.10 9/23/2005 Erich Chen enhance sysfs function for change driver's max tag Q number.
** add DMA_64BIT_MASK for backward compatible with all 2.6.x
** add some useful message for abort command
** add ioctl code 'ARCMSR_IOCTL_FLUSH_ADAPTER_CACHE'
** customer can send this command for sync raid volume data
** 1.20.00.11 9/29/2005 Erich Chen by comment of Arjan van de Ven fix incorrect msleep redefine
** cast off sizeof(dma_addr_t) condition for 64bit pci_set_dma_mask
** 1.20.00.12 9/30/2005 Erich Chen bug fix with 64bit platform's ccbs using if over 4G system memory
** change 64bit pci_set_consistent_dma_mask into 32bit
** increcct adapter count if adapter initialize fail.
** miss edit at arcmsr_build_ccb....
** psge += sizeof(struct _SG64ENTRY *) =>
** psge += sizeof(struct _SG64ENTRY)
** 64 bits sg entry would be incorrectly calculated
** thanks Kornel Wieliczek give me kindly notify
** and detail description
** 1.20.00.13 11/15/2005 Erich Chen scheduling pending ccb with FIFO
** change the architecture of arcmsr command queue list
** for linux standard list
** enable usage of pci message signal interrupt
** follow Randy.Danlup kindness suggestion cleanup this code
**************************************************************************
\ No newline at end of file
此差异已折叠。
SAS Layer
---------
The SAS Layer is a management infrastructure which manages
SAS LLDDs. It sits between SCSI Core and SAS LLDDs. The
layout is as follows: while SCSI Core is concerned with
SAM/SPC issues, and a SAS LLDD+sequencer is concerned with
phy/OOB/link management, the SAS layer is concerned with:
* SAS Phy/Port/HA event management (LLDD generates,
SAS Layer processes),
* SAS Port management (creation/destruction),
* SAS Domain discovery and revalidation,
* SAS Domain device management,
* SCSI Host registration/unregistration,
* Device registration with SCSI Core (SAS) or libata
(SATA), and
* Expander management and exporting expander control
to user space.
A SAS LLDD is a PCI device driver. It is concerned with
phy/OOB management, and vendor specific tasks and generates
events to the SAS layer.
The SAS Layer does most SAS tasks as outlined in the SAS 1.1
spec.
The sas_ha_struct describes the SAS LLDD to the SAS layer.
Most of it is used by the SAS Layer but a few fields need to
be initialized by the LLDDs.
After initializing your hardware, from the probe() function
you call sas_register_ha(). It will register your LLDD with
the SCSI subsystem, creating a SCSI host and it will
register your SAS driver with the sysfs SAS tree it creates.
It will then return. Then you enable your phys to actually
start OOB (at which point your driver will start calling the
notify_* event callbacks).
Structure descriptions:
struct sas_phy --------------------
Normally this is statically embedded to your driver's
phy structure:
struct my_phy {
blah;
struct sas_phy sas_phy;
bleh;
};
And then all the phys are an array of my_phy in your HA
struct (shown below).
Then as you go along and initialize your phys you also
initialize the sas_phy struct, along with your own
phy structure.
In general, the phys are managed by the LLDD and the ports
are managed by the SAS layer. So the phys are initialized
and updated by the LLDD and the ports are initialized and
updated by the SAS layer.
There is a scheme where the LLDD can RW certain fields,
and the SAS layer can only read such ones, and vice versa.
The idea is to avoid unnecessary locking.
enabled -- must be set (0/1)
id -- must be set [0,MAX_PHYS)
class, proto, type, role, oob_mode, linkrate -- must be set
oob_mode -- you set this when OOB has finished and then notify
the SAS Layer.
sas_addr -- this normally points to an array holding the sas
address of the phy, possibly somewhere in your my_phy
struct.
attached_sas_addr -- set this when you (LLDD) receive an
IDENTIFY frame or a FIS frame, _before_ notifying the SAS
layer. The idea is that sometimes the LLDD may want to fake
or provide a different SAS address on that phy/port and this
allows it to do this. At best you should copy the sas
address from the IDENTIFY frame or maybe generate a SAS
address for SATA directly attached devices. The Discover
process may later change this.
frame_rcvd -- this is where you copy the IDENTIFY/FIS frame
when you get it; you lock, copy, set frame_rcvd_size and
unlock the lock, and then call the event. It is a pointer
since there's no way to know your hw frame size _exactly_,
so you define the actual array in your phy struct and let
this pointer point to it. You copy the frame from your
DMAable memory to that area holding the lock.
sas_prim -- this is where primitives go when they're
received. See sas.h. Grab the lock, set the primitive,
release the lock, notify.
port -- this points to the sas_port if the phy belongs
to a port -- the LLDD only reads this. It points to the
sas_port this phy is part of. Set by the SAS Layer.
ha -- may be set; the SAS layer sets it anyway.
lldd_phy -- you should set this to point to your phy so you
can find your way around faster when the SAS layer calls one
of your callbacks and passes you a phy. If the sas_phy is
embedded you can also use container_of -- whatever you
prefer.
struct sas_port --------------------
The LLDD doesn't set any fields of this struct -- it only
reads them. They should be self explanatory.
phy_mask is 32 bit, this should be enough for now, as I
haven't heard of a HA having more than 8 phys.
lldd_port -- I haven't found use for that -- maybe other
LLDD who wish to have internal port representation can make
use of this.
struct sas_ha_struct --------------------
It normally is statically declared in your own LLDD
structure describing your adapter:
struct my_sas_ha {
blah;
struct sas_ha_struct sas_ha;
struct my_phy phys[MAX_PHYS];
struct sas_port sas_ports[MAX_PHYS]; /* (1) */
bleh;
};
(1) If your LLDD doesn't have its own port representation.
What needs to be initialized (sample function given below).
pcidev
sas_addr -- since the SAS layer doesn't want to mess with
memory allocation, etc, this points to statically
allocated array somewhere (say in your host adapter
structure) and holds the SAS address of the host
adapter as given by you or the manufacturer, etc.
sas_port
sas_phy -- an array of pointers to structures. (see
note above on sas_addr).
These must be set. See more notes below.
num_phys -- the number of phys present in the sas_phy array,
and the number of ports present in the sas_port
array. There can be a maximum num_phys ports (one per
port) so we drop the num_ports, and only use
num_phys.
The event interface:
/* LLDD calls these to notify the class of an event. */
void (*notify_ha_event)(struct sas_ha_struct *, enum ha_event);
void (*notify_port_event)(struct sas_phy *, enum port_event);
void (*notify_phy_event)(struct sas_phy *, enum phy_event);
When sas_register_ha() returns, those are set and can be
called by the LLDD to notify the SAS layer of such events
the SAS layer.
The port notification:
/* The class calls these to notify the LLDD of an event. */
void (*lldd_port_formed)(struct sas_phy *);
void (*lldd_port_deformed)(struct sas_phy *);
If the LLDD wants notification when a port has been formed
or deformed it sets those to a function satisfying the type.
A SAS LLDD should also implement at least one of the Task
Management Functions (TMFs) described in SAM:
/* Task Management Functions. Must be called from process context. */
int (*lldd_abort_task)(struct sas_task *);
int (*lldd_abort_task_set)(struct domain_device *, u8 *lun);
int (*lldd_clear_aca)(struct domain_device *, u8 *lun);
int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
int (*lldd_I_T_nexus_reset)(struct domain_device *);
int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
int (*lldd_query_task)(struct sas_task *);
For more information please read SAM from T10.org.
Port and Adapter management:
/* Port and Adapter management */
int (*lldd_clear_nexus_port)(struct sas_port *);
int (*lldd_clear_nexus_ha)(struct sas_ha_struct *);
A SAS LLDD should implement at least one of those.
Phy management:
/* Phy management */
int (*lldd_control_phy)(struct sas_phy *, enum phy_func);
lldd_ha -- set this to point to your HA struct. You can also
use container_of if you embedded it as shown above.
A sample initialization and registration function
can look like this (called last thing from probe())
*but* before you enable the phys to do OOB:
static int register_sas_ha(struct my_sas_ha *my_ha)
{
int i;
static struct sas_phy *sas_phys[MAX_PHYS];
static struct sas_port *sas_ports[MAX_PHYS];
my_ha->sas_ha.sas_addr = &my_ha->sas_addr[0];
for (i = 0; i < MAX_PHYS; i++) {
sas_phys[i] = &my_ha->phys[i].sas_phy;
sas_ports[i] = &my_ha->sas_ports[i];
}
my_ha->sas_ha.sas_phy = sas_phys;
my_ha->sas_ha.sas_port = sas_ports;
my_ha->sas_ha.num_phys = MAX_PHYS;
my_ha->sas_ha.lldd_port_formed = my_port_formed;
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;
my_ha->sas_ha.lldd_abort_task_set = my_abort_task_set;
my_ha->sas_ha.lldd_clear_aca = my_clear_aca;
my_ha->sas_ha.lldd_clear_task_set = my_clear_task_set;
my_ha->sas_ha.lldd_I_T_nexus_reset= NULL; (2)
my_ha->sas_ha.lldd_lu_reset = my_lu_reset;
my_ha->sas_ha.lldd_query_task = my_query_task;
my_ha->sas_ha.lldd_clear_nexus_port = my_clear_nexus_port;
my_ha->sas_ha.lldd_clear_nexus_ha = my_clear_nexus_ha;
my_ha->sas_ha.lldd_control_phy = my_control_phy;
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
------
Events are _the only way_ a SAS LLDD notifies the SAS layer
of anything. There is no other method or way a LLDD to tell
the SAS layer of anything happening internally or in the SAS
domain.
Phy events:
PHYE_LOSS_OF_SIGNAL, (C)
PHYE_OOB_DONE,
PHYE_OOB_ERROR, (C)
PHYE_SPINUP_HOLD.
Port events, passed on a _phy_:
PORTE_BYTES_DMAED, (M)
PORTE_BROADCAST_RCVD, (E)
PORTE_LINK_RESET_ERR, (C)
PORTE_TIMER_EVENT, (C)
PORTE_HARD_RESET.
Host Adapter event:
HAE_RESET
A SAS LLDD should be able to generate
- at least one event from group C (choice),
- events marked M (mandatory) are mandatory (only one),
- events marked E (expander) if it wants the SAS layer
to handle domain revalidation (only one such).
- Unmarked events are optional.
Meaning:
HAE_RESET -- when your HA got internal error and was reset.
PORTE_BYTES_DMAED -- on receiving an IDENTIFY/FIS frame
PORTE_BROADCAST_RCVD -- on receiving a primitive
PORTE_LINK_RESET_ERR -- timer expired, loss of signal, loss
of DWS, etc. (*)
PORTE_TIMER_EVENT -- DWS reset timeout timer expired (*)
PORTE_HARD_RESET -- Hard Reset primitive received.
PHYE_LOSS_OF_SIGNAL -- the device is gone (*)
PHYE_OOB_DONE -- OOB went fine and oob_mode is valid
PHYE_OOB_ERROR -- Error while doing OOB, the device probably
got disconnected. (*)
PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
(*) should set/clear the appropriate fields in the phy,
or alternatively call the inlined sas_phy_disconnected()
which is just a helper, from their tasklet.
The Execute Command SCSI RPC:
int (*lldd_execute_task)(struct sas_task *, int num,
unsigned long 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.
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)
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
total_xfer_len -- total number of bytes expected to be transfered
data_dir -- PCI_DMA_...
task_done -- callback when the task has finished execution
};
When an external entity, entity other than the LLDD or the
SAS Layer, wants to work with a struct domain_device, it
_must_ call kobject_get() when getting a handle on the
device and kobject_put() when it is done with the device.
This does two things:
A) implements proper kfree() for the device;
B) increments/decrements the kref for all players:
domain_device
all domain_device's ... (if past an expander)
port
host adapter
pci device
and up the ladder, etc.
DISCOVERY
---------
The sysfs tree has the following purposes:
a) It shows you the physical layout of the SAS domain at
the current time, i.e. how the domain looks in the
physical world right now.
b) Shows some device parameters _at_discovery_time_.
This is a link to the tree(1) program, very useful in
viewing the SAS domain:
ftp://mama.indstate.edu/linux/tree/
I expect user space applications to actually create a
graphical interface of this.
That is, the sysfs domain tree doesn't show or keep state if
you e.g., change the meaning of the READY LED MEANING
setting, but it does show you the current connection status
of the domain device.
Keeping internal device state changes is responsibility of
upper layers (Command set drivers) and user space.
When a device or devices are unplugged from the domain, this
is reflected in the sysfs tree immediately, and the device(s)
removed from the system.
The structure domain_device describes any device in the SAS
domain. It is completely managed by the SAS layer. A task
points to a domain device, this is how the SAS LLDD knows
where to send the task(s) to. A SAS LLDD only reads the
contents of the domain_device structure, but it never creates
or destroys one.
Expander management from User Space
-----------------------------------
In each expander directory in sysfs, there is a file called
"smp_portal". It is a binary sysfs attribute file, which
implements an SMP portal (Note: this is *NOT* an SMP port),
to which user space applications can send SMP requests and
receive SMP responses.
Functionality is deceptively simple:
1. Build the SMP frame you want to send. The format and layout
is described in the SAS spec. Leave the CRC field equal 0.
open(2)
2. Open the expander's SMP portal sysfs file in RW mode.
write(2)
3. Write the frame you built in 1.
read(2)
4. Read the amount of data you expect to receive for the frame you built.
If you receive different amount of data you expected to receive,
then there was some kind of error.
close(2)
All this process is shown in detail in the function do_smp_func()
and its callers, in the file "expander_conf.c".
The kernel functionality is implemented in the file
"sas_expander.c".
The program "expander_conf.c" implements this. It takes one
argument, the sysfs file name of the SMP portal to the
expander, and gives expander information, including routing
tables.
The SMP portal gives you complete control of the expander,
so please be careful.
......@@ -848,21 +848,18 @@ struct request *blk_queue_find_tag(request_queue_t *q, int tag)
EXPORT_SYMBOL(blk_queue_find_tag);
/**
* __blk_queue_free_tags - release tag maintenance info
* @q: the request queue for the device
* __blk_free_tags - release a given set of tag maintenance info
* @bqt: the tag map to free
*
* Notes:
* blk_cleanup_queue() will take care of calling this function, if tagging
* has been used. So there's no need to call this directly.
**/
static void __blk_queue_free_tags(request_queue_t *q)
* Tries to free the specified @bqt@. Returns true if it was
* actually freed and false if there are still references using it
*/
static int __blk_free_tags(struct blk_queue_tag *bqt)
{
struct blk_queue_tag *bqt = q->queue_tags;
if (!bqt)
return;
int retval;
if (atomic_dec_and_test(&bqt->refcnt)) {
retval = atomic_dec_and_test(&bqt->refcnt);
if (retval) {
BUG_ON(bqt->busy);
BUG_ON(!list_empty(&bqt->busy_list));
......@@ -873,12 +870,49 @@ static void __blk_queue_free_tags(request_queue_t *q)
bqt->tag_map = NULL;
kfree(bqt);
}
return retval;
}
/**
* __blk_queue_free_tags - release tag maintenance info
* @q: the request queue for the device
*
* Notes:
* blk_cleanup_queue() will take care of calling this function, if tagging
* has been used. So there's no need to call this directly.
**/
static void __blk_queue_free_tags(request_queue_t *q)
{
struct blk_queue_tag *bqt = q->queue_tags;
if (!bqt)
return;
__blk_free_tags(bqt);
q->queue_tags = NULL;
q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
}
/**
* blk_free_tags - release a given set of tag maintenance info
* @bqt: the tag map to free
*
* For externally managed @bqt@ frees the map. Callers of this
* function must guarantee to have released all the queues that
* might have been using this tag map.
*/
void blk_free_tags(struct blk_queue_tag *bqt)
{
if (unlikely(!__blk_free_tags(bqt)))
BUG();
}
EXPORT_SYMBOL(blk_free_tags);
/**
* blk_queue_free_tags - release tag maintenance info
* @q: the request queue for the device
......@@ -901,7 +935,7 @@ init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth)
unsigned long *tag_map;
int nr_ulongs;
if (depth > q->nr_requests * 2) {
if (q && depth > q->nr_requests * 2) {
depth = q->nr_requests * 2;
printk(KERN_ERR "%s: adjusted depth to %d\n",
__FUNCTION__, depth);
......@@ -927,6 +961,38 @@ init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth)
return -ENOMEM;
}
static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q,
int depth)
{
struct blk_queue_tag *tags;
tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
if (!tags)
goto fail;
if (init_tag_map(q, tags, depth))
goto fail;
INIT_LIST_HEAD(&tags->busy_list);
tags->busy = 0;
atomic_set(&tags->refcnt, 1);
return tags;
fail:
kfree(tags);
return NULL;
}
/**
* blk_init_tags - initialize the tag info for an external tag map
* @depth: the maximum queue depth supported
* @tags: the tag to use
**/
struct blk_queue_tag *blk_init_tags(int depth)
{
return __blk_queue_init_tags(NULL, depth);
}
EXPORT_SYMBOL(blk_init_tags);
/**
* blk_queue_init_tags - initialize the queue tag info
* @q: the request queue for the device
......@@ -941,16 +1007,10 @@ int blk_queue_init_tags(request_queue_t *q, int depth,
BUG_ON(tags && q->queue_tags && tags != q->queue_tags);
if (!tags && !q->queue_tags) {
tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC);
if (!tags)
goto fail;
tags = __blk_queue_init_tags(q, depth);
if (init_tag_map(q, tags, depth))
if (!tags)
goto fail;
INIT_LIST_HEAD(&tags->busy_list);
tags->busy = 0;
atomic_set(&tags->refcnt, 1);
} else if (q->queue_tags) {
if ((rc = blk_queue_resize_tags(q, depth)))
return rc;
......@@ -1001,6 +1061,13 @@ int blk_queue_resize_tags(request_queue_t *q, int new_depth)
return 0;
}
/*
* Currently cannot replace a shared tag map with a new
* one, so error out if this is the case
*/
if (atomic_read(&bqt->refcnt) != 1)
return -EBUSY;
/*
* save the old state info, so we can copy it back
*/
......
......@@ -7115,7 +7115,7 @@ static struct pci_device_id DAC960_id_table[] = {
{
.vendor = PCI_VENDOR_ID_MYLEX,
.device = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
.subvendor = PCI_ANY_ID,
.subvendor = PCI_VENDOR_ID_MYLEX,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long) &DAC960_GEM_privdata,
},
......
......@@ -251,10 +251,6 @@ scsi_cmd_stack_free(int ctlr)
stk->pool = NULL;
}
/* scsi_device_types comes from scsi.h */
#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
"Unknown" : scsi_device_types[n]
#if 0
static int xmargin=8;
static int amargin=60;
......@@ -389,7 +385,7 @@ cciss_scsi_add_entry(int ctlr, int hostno,
time anyway (the scsi layer's inquiries will show that info) */
if (hostno != -1)
printk("cciss%d: %s device c%db%dt%dl%d added.\n",
ctlr, DEVICETYPE(sd->devtype), hostno,
ctlr, scsi_device_type(sd->devtype), hostno,
sd->bus, sd->target, sd->lun);
return 0;
}
......@@ -407,7 +403,7 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
ccissscsi[ctlr].ndevices--;
printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
ctlr, DEVICETYPE(sd.devtype), hostno,
ctlr, scsi_device_type(sd.devtype), hostno,
sd.bus, sd.target, sd.lun);
}
......@@ -458,7 +454,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
if (found == 0) { /* device no longer present. */
changes++;
/* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
ctlr, DEVICETYPE(csd->devtype), hostno,
ctlr, scsi_device_type(csd->devtype), hostno,
csd->bus, csd->target, csd->lun); */
cciss_scsi_remove_entry(ctlr, hostno, i);
/* note, i not incremented */
......@@ -468,7 +464,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
printk("cciss%d: device c%db%dt%dl%d type changed "
"(device type now %s).\n",
ctlr, hostno, csd->bus, csd->target, csd->lun,
DEVICETYPE(csd->devtype));
scsi_device_type(csd->devtype));
csd->devtype = sd[j].devtype;
i++; /* so just move along. */
} else /* device is same as it ever was, */
......@@ -1098,7 +1094,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
printk(KERN_INFO "cciss%d: %s ignored, "
"too many devices.\n", cntl_num,
DEVICETYPE(devtype));
scsi_device_type(devtype));
break;
}
memcpy(&currentsd[ncurrent].scsi3addr[0],
......
......@@ -141,18 +141,11 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
if (sc->sc_data_direction == DMA_TO_DEVICE) {
BUG_ON(ctask->total_length == 0);
/* bytes to be sent via RDMA operations */
iser_ctask->rdma_data_count = ctask->total_length -
ctask->imm_count -
ctask->unsol_count;
debug_scsi("cmd [itt %x total %d imm %d unsol_data %d "
"rdma_data %d]\n",
debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
ctask->itt, ctask->total_length, ctask->imm_count,
ctask->unsol_count, iser_ctask->rdma_data_count);
} else
/* bytes to be sent via RDMA operations */
iser_ctask->rdma_data_count = ctask->total_length;
ctask->unsol_count);
}
iser_ctask_rdma_init(iser_ctask);
}
......@@ -196,13 +189,10 @@ iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
{
struct iscsi_data hdr;
int error = 0;
struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
/* Send data-out PDUs while there's still unsolicited data to send */
while (ctask->unsol_count > 0) {
iscsi_prep_unsolicit_data_pdu(ctask, &hdr,
iser_ctask->rdma_data_count);
iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
hdr.itt, ctask->data_count);
......
......@@ -262,7 +262,6 @@ struct iscsi_iser_conn {
struct iscsi_iser_cmd_task {
struct iser_desc desc;
struct iscsi_iser_conn *iser_conn;
int rdma_data_count;/* RDMA bytes */
enum iser_task_status status;
int command_sent; /* set if command sent */
int dir[ISER_DIRS_NUM]; /* set if dir use*/
......
......@@ -162,7 +162,13 @@ static struct fc_function_template mptfc_transport_functions = {
.show_starget_port_id = 1,
.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
.show_rport_dev_loss_tmo = 1,
.show_host_supported_speeds = 1,
.show_host_maxframe_size = 1,
.show_host_speed = 1,
.show_host_fabric_name = 1,
.show_host_port_type = 1,
.show_host_port_state = 1,
.show_host_symbolic_name = 1,
};
static void
......@@ -839,33 +845,95 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
static void
mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
{
unsigned class = 0, cos = 0;
unsigned class = 0;
unsigned cos = 0;
unsigned speed;
unsigned port_type;
unsigned port_state;
FCPortPage0_t *pp0;
struct Scsi_Host *sh;
char *sn;
/* don't know what to do as only one scsi (fc) host was allocated */
if (portnum != 0)
return;
class = ioc->fc_port_page0[portnum].SupportedServiceClass;
pp0 = &ioc->fc_port_page0[portnum];
sh = ioc->sh;
sn = fc_host_symbolic_name(sh);
snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
ioc->prod_name,
MPT_FW_REV_MAGIC_ID_STRING,
ioc->facts.FWVersion.Word);
fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
fc_host_node_name(sh) =
(u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
fc_host_port_name(sh) =
(u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
fc_host_port_id(sh) = pp0->PortIdentifier;
class = pp0->SupportedServiceClass;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
cos |= FC_COS_CLASS1;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
cos |= FC_COS_CLASS2;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
cos |= FC_COS_CLASS3;
fc_host_supported_classes(sh) = cos;
if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
speed = FC_PORTSPEED_1GBIT;
else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
speed = FC_PORTSPEED_2GBIT;
else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
speed = FC_PORTSPEED_4GBIT;
else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
speed = FC_PORTSPEED_10GBIT;
else
speed = FC_PORTSPEED_UNKNOWN;
fc_host_speed(sh) = speed;
speed = 0;
if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
speed |= FC_PORTSPEED_1GBIT;
if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
speed |= FC_PORTSPEED_2GBIT;
if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
speed |= FC_PORTSPEED_4GBIT;
if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
speed |= FC_PORTSPEED_10GBIT;
fc_host_supported_speeds(sh) = speed;
port_state = FC_PORTSTATE_UNKNOWN;
if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
port_state = FC_PORTSTATE_ONLINE;
else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
port_state = FC_PORTSTATE_LINKDOWN;
fc_host_port_state(sh) = port_state;
port_type = FC_PORTTYPE_UNKNOWN;
if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
port_type = FC_PORTTYPE_PTP;
else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
port_type = FC_PORTTYPE_LPORT;
else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
port_type = FC_PORTTYPE_NLPORT;
else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
port_type = FC_PORTTYPE_NPORT;
fc_host_port_type(sh) = port_type;
fc_host_fabric_name(sh) =
(pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
(u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
(u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
fc_host_node_name(ioc->sh) =
(u64)ioc->fc_port_page0[portnum].WWNN.High << 32
| (u64)ioc->fc_port_page0[portnum].WWNN.Low;
fc_host_port_name(ioc->sh) =
(u64)ioc->fc_port_page0[portnum].WWPN.High << 32
| (u64)ioc->fc_port_page0[portnum].WWPN.Low;
fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
fc_host_supported_classes(ioc->sh) = cos;
fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
}
static void
......
......@@ -852,6 +852,10 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
dma_addr_t dma_handle;
int error;
/* FIXME: only have link errors on local phys */
if (!scsi_is_sas_phy_local(phy))
return -EINVAL;
hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
hdr.ExtPageLength = 0;
hdr.PageNumber = 1 /* page number 1*/;
......@@ -924,6 +928,10 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
unsigned long timeleft;
int error = -ERESTARTSYS;
/* FIXME: fusion doesn't allow non-local phy reset */
if (!scsi_is_sas_phy_local(phy))
return -EINVAL;
/* not implemented for expanders */
if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
return -ENXIO;
......@@ -1570,9 +1578,6 @@ static int mptsas_probe_one_phy(struct device *dev,
if (!phy_info->phy) {
if (local)
phy->local_attached = 1;
error = sas_phy_add(phy);
if (error) {
sas_phy_free(phy);
......@@ -1642,14 +1647,18 @@ static int mptsas_probe_one_phy(struct device *dev,
for (i = 0; i < port_info->num_phys; i++)
if (port_info->phy_info[i].identify.sas_address ==
identify.sas_address)
identify.sas_address) {
sas_port_mark_backlink(port);
goto out;
}
} else if (scsi_is_sas_rphy(parent)) {
struct sas_rphy *parent_rphy = dev_to_rphy(parent);
if (identify.sas_address ==
parent_rphy->identify.sas_address)
parent_rphy->identify.sas_address) {
sas_port_mark_backlink(port);
goto out;
}
}
switch (identify.device_type) {
......
......@@ -2176,6 +2176,7 @@ static int __init BusLogic_init(void)
{
int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
struct BusLogic_HostAdapter *PrototypeHostAdapter;
int ret = 0;
#ifdef MODULE
if (BusLogic)
......@@ -2282,25 +2283,49 @@ static int __init BusLogic_init(void)
perform Target Device Inquiry.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) {
BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
BusLogic_AcquireResources(HostAdapter) &&
BusLogic_CreateInitialCCBs(HostAdapter) &&
BusLogic_InitializeHostAdapter(HostAdapter) &&
BusLogic_TargetDeviceInquiry(HostAdapter)) {
/*
Initialization has been completed successfully. Release and
re-register usage of the I/O Address range so that the Model
Name of the Host Adapter will appear, and initialize the SCSI
Host structure.
*/
release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) {
printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address);
release_region(HostAdapter->IO_Address,
HostAdapter->AddressCount);
if (!request_region(HostAdapter->IO_Address,
HostAdapter->AddressCount,
HostAdapter->FullModelName)) {
printk(KERN_WARNING
"BusLogic: Release and re-register of "
"port 0x%04lx failed \n",
(unsigned long)HostAdapter->IO_Address);
BusLogic_DestroyCCBs(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
ret = -ENOMEM;
} else {
BusLogic_InitializeHostStructure(HostAdapter, Host);
scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
scsi_scan_host(Host);
BusLogicHostAdapterCount++;
BusLogic_InitializeHostStructure(HostAdapter,
Host);
if (scsi_add_host(Host, HostAdapter->PCI_Device
? &HostAdapter->PCI_Device->dev
: NULL)) {
printk(KERN_WARNING
"BusLogic: scsi_add_host()"
"failed!\n");
BusLogic_DestroyCCBs(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
ret = -ENODEV;
} else {
scsi_scan_host(Host);
BusLogicHostAdapterCount++;
}
}
} else {
/*
......@@ -2315,12 +2340,13 @@ static int __init BusLogic_init(void)
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
ret = -ENODEV;
}
}
kfree(PrototypeHostAdapter);
kfree(BusLogic_ProbeInfoList);
BusLogic_ProbeInfoList = NULL;
return 0;
return ret;
}
......@@ -2954,6 +2980,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
}
#if 0
/*
BusLogic_AbortCommand aborts Command if possible.
*/
......@@ -3024,6 +3051,7 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command)
return SUCCESS;
}
#endif
/*
BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
currently executing SCSI Commands as having been Reset.
......
......@@ -27,6 +27,11 @@ config SCSI
However, do not compile this as a module if your root file system
(the one containing the directory /) is located on a SCSI device.
config SCSI_NETLINK
bool
default n
select NET
config SCSI_PROC_FS
bool "legacy /proc/scsi/ support"
depends on SCSI && PROC_FS
......@@ -209,7 +214,7 @@ config SCSI_LOGGING
there should be no noticeable performance impact as long as you have
logging turned off.
menu "SCSI Transport Attributes"
menu "SCSI Transports"
depends on SCSI
config SCSI_SPI_ATTRS
......@@ -222,6 +227,7 @@ config SCSI_SPI_ATTRS
config SCSI_FC_ATTRS
tristate "FiberChannel Transport Attributes"
depends on SCSI
select SCSI_NETLINK
help
If you wish to export transport-specific information about
each attached FiberChannel device to sysfs, say Y.
......@@ -242,6 +248,8 @@ config SCSI_SAS_ATTRS
If you wish to export transport-specific information about
each attached SAS device to sysfs, say Y.
source "drivers/scsi/libsas/Kconfig"
endmenu
menu "SCSI low-level drivers"
......@@ -431,6 +439,7 @@ config SCSI_AIC7XXX_OLD
module will be called aic7xxx_old.
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
......@@ -469,6 +478,20 @@ config SCSI_IN2000
To compile this driver as a module, choose M here: the
module will be called in2000.
config SCSI_ARCMSR
tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
depends on PCI && SCSI
help
This driver supports all of ARECA's SATA RAID controller cards.
This is an ARECA-maintained driver by Erich Chen.
If you have any problems, please mail to: < erich@areca.com.tw >
Areca supports Linux RAID config tools.
< http://www.areca.com.tw >
To compile this driver as a module, choose M here: the
module will be called arcmsr (modprobe arcmsr).
source "drivers/scsi/megaraid/Kconfig.megaraid"
config SCSI_SATA
......@@ -1053,6 +1076,13 @@ config 53C700_LE_ON_BE
depends on SCSI_LASI700
default y
config SCSI_STEX
tristate "Promise SuperTrak EX Series support"
depends on PCI && SCSI
---help---
This driver supports Promise SuperTrak EX8350/8300/16350/16300
Storage controllers.
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
depends on PCI && SCSI
......
......@@ -32,6 +32,7 @@ obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
......@@ -59,6 +60,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/
obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
......@@ -67,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/
obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/
obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
......@@ -138,6 +141,7 @@ obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
obj-$(CONFIG_ARM) += arm/
......@@ -155,6 +159,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
scsi_scan.o scsi_sysfs.o \
scsi_devinfo.o
scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
......
......@@ -40,7 +40,7 @@ static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
return IRQ_HANDLED;
}
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
......@@ -115,7 +115,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
/* disable SCSI interrupts */
......@@ -217,7 +217,7 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
return num_a2091;
}
static int a2091_bus_reset(Scsi_Cmnd *cmd)
static int a2091_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
......
......@@ -13,10 +13,6 @@
int a2091_detect(struct scsi_host_template *);
int a2091_release(struct Scsi_Host *);
const char *wd33c93_info(void);
int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd33c93_abort(Scsi_Cmnd *);
int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
......
......@@ -44,7 +44,7 @@ static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
return IRQ_NONE;
}
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
......@@ -110,8 +110,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
int status)
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD;
......@@ -205,7 +205,7 @@ int __init a3000_detect(struct scsi_host_template *tpnt)
return 0;
}
static int a3000_bus_reset(Scsi_Cmnd *cmd)
static int a3000_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
......
......@@ -13,10 +13,6 @@
int a3000_detect(struct scsi_host_template *);
int a3000_release(struct Scsi_Host *);
const char *wd33c93_info(void);
int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd33c93_abort(Scsi_Cmnd *);
int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
......
......@@ -175,7 +175,7 @@ MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size.
*
* Query config status, and commit the configuration if needed.
*/
int aac_get_config_status(struct aac_dev *dev)
int aac_get_config_status(struct aac_dev *dev, int commit_flag)
{
int status = 0;
struct fib * fibptr;
......@@ -219,7 +219,7 @@ int aac_get_config_status(struct aac_dev *dev)
aac_fib_complete(fibptr);
/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
if (status >= 0) {
if (commit == 1) {
if ((commit == 1) || commit_flag) {
struct aac_commit_config * dinfo;
aac_fib_init(fibptr);
dinfo = (struct aac_commit_config *) fib_data(fibptr);
......@@ -489,6 +489,8 @@ int aac_probe_container(struct aac_dev *dev, int cid)
unsigned instance;
fsa_dev_ptr = dev->fsa_dev;
if (!fsa_dev_ptr)
return -ENOMEM;
instance = dev->scsi_host_ptr->unique_id;
if (!(fibptr = aac_fib_alloc(dev)))
......@@ -782,8 +784,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
}
tmp = le32_to_cpu(dev->adapter_info.kernelrev);
printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
if (!dev->in_reset) {
tmp = le32_to_cpu(dev->adapter_info.kernelrev);
printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
dev->name,
dev->id,
tmp>>24,
......@@ -792,20 +795,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
le32_to_cpu(dev->adapter_info.kernelbuild),
(int)sizeof(dev->supplement_adapter_info.BuildDate),
dev->supplement_adapter_info.BuildDate);
tmp = le32_to_cpu(dev->adapter_info.monitorrev);
printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
tmp = le32_to_cpu(dev->adapter_info.monitorrev);
printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.monitorbuild));
tmp = le32_to_cpu(dev->adapter_info.biosrev);
printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
tmp = le32_to_cpu(dev->adapter_info.biosrev);
printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.biosbuild));
if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
printk(KERN_INFO "%s%d: serial %x\n",
dev->name, dev->id,
le32_to_cpu(dev->adapter_info.serial[0]));
if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
printk(KERN_INFO "%s%d: serial %x\n",
dev->name, dev->id,
le32_to_cpu(dev->adapter_info.serial[0]));
}
dev->nondasd_support = 0;
dev->raid_scsi_mode = 0;
......@@ -1392,6 +1396,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
struct scsi_cmnd *cmd;
struct scsi_device *sdev = scsicmd->device;
int active = 0;
struct aac_dev *aac;
unsigned long flags;
/*
......@@ -1413,11 +1418,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
if (active)
return SCSI_MLQUEUE_DEVICE_BUSY;
aac = (struct aac_dev *)scsicmd->device->host->hostdata;
if (aac->in_reset)
return SCSI_MLQUEUE_HOST_BUSY;
/*
* Allocate and initialize a Fib
*/
if (!(cmd_fibcontext =
aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata)))
if (!(cmd_fibcontext = aac_fib_alloc(aac)))
return SCSI_MLQUEUE_HOST_BUSY;
aac_fib_init(cmd_fibcontext);
......@@ -1470,6 +1478,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
if (fsa_dev_ptr == NULL)
return -1;
/*
* If the bus, id or lun is out of range, return fail
* Test does not apply to ID 16, the pseudo id for the controller
......@@ -1499,6 +1509,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case INQUIRY:
case READ_CAPACITY:
case TEST_UNIT_READY:
if (dev->in_reset)
return -1;
spin_unlock_irq(host->host_lock);
aac_probe_container(dev, cid);
if ((fsa_dev_ptr[cid].valid & 1) == 0)
......@@ -1524,6 +1536,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
}
} else { /* check for physical non-dasd devices */
if(dev->nondasd_support == 1){
if (dev->in_reset)
return -1;
return aac_send_srb_fib(scsicmd);
} else {
scsicmd->result = DID_NO_CONNECT << 16;
......@@ -1579,6 +1593,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsicmd->scsi_done(scsicmd);
return 0;
}
if (dev->in_reset)
return -1;
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
......@@ -1734,6 +1750,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case READ_10:
case READ_12:
case READ_16:
if (dev->in_reset)
return -1;
/*
* Hack to keep track of ordinal number of the device that
* corresponds to a container. Needed to convert
......@@ -1752,6 +1770,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case WRITE_10:
case WRITE_12:
case WRITE_16:
if (dev->in_reset)
return -1;
return aac_write(scsicmd, cid);
case SYNCHRONIZE_CACHE:
......@@ -1782,6 +1802,8 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
if (!fsa_dev_ptr)
return -ENODEV;
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
return -EFAULT;
if (qd.cnum == -1)
......@@ -1843,6 +1865,10 @@ static int delete_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
if (!fsa_dev_ptr)
return -ENODEV;
if (!fsa_dev_ptr)
return -ENODEV;
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
return -EFAULT;
......
......@@ -1029,6 +1029,7 @@ struct aac_dev
init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
u8 raw_io_64;
u8 printf_enabled;
u8 in_reset;
};
#define aac_adapter_interrupt(dev) \
......@@ -1670,6 +1671,7 @@ extern struct aac_common aac_config;
#define RCV_TEMP_READINGS 0x00000025
#define GET_COMM_PREFERRED_SETTINGS 0x00000026
#define IOP_RESET 0x00001000
#define IOP_RESET_ALWAYS 0x00001001
#define RE_INIT_ADAPTER 0x000000ee
/*
......@@ -1788,7 +1790,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
int aac_get_config_status(struct aac_dev *dev);
int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
......@@ -1799,6 +1801,7 @@ int aac_sa_init(struct aac_dev *dev);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
......
......@@ -38,7 +38,7 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/delay.h> /* ssleep prototype */
#include <linux/kthread.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
......@@ -140,7 +140,8 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
fibptr->hw_fib_pa = hw_fib_pa;
fibptr->hw_fib = hw_fib;
}
aac_fib_free(fibptr);
if (retval != -EINTR)
aac_fib_free(fibptr);
return retval;
}
......@@ -297,7 +298,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
spin_unlock_irqrestore(&dev->fib_lock, flags);
/* If someone killed the AIF aacraid thread, restart it */
status = !dev->aif_thread;
if (status && dev->queues && dev->fsa_dev) {
if (status && !dev->in_reset && dev->queues && dev->fsa_dev) {
/* Be paranoid, be very paranoid! */
kthread_stop(dev->thread);
ssleep(1);
......@@ -621,7 +622,13 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
if(actual_fibsize != fibsize){ // User made a mistake - should not continue
dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
"Raw SRB command calculated fibsize=%d "
"user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
"issued fibsize=%d\n",
actual_fibsize, user_srbcmd->sg.count,
sizeof(struct aac_srb), sizeof(struct sgentry),
fibsize));
rcode = -EINVAL;
goto cleanup;
}
......@@ -663,6 +670,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
}
if (status == -EINTR) {
rcode = -EINTR;
goto cleanup;
}
if (status != 0){
dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
......@@ -696,8 +707,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
for(i=0; i <= sg_indx; i++){
kfree(sg_list[i]);
}
aac_fib_complete(srbfib);
aac_fib_free(srbfib);
if (rcode != -EINTR) {
aac_fib_complete(srbfib);
aac_fib_free(srbfib);
}
return rcode;
}
......
......@@ -180,7 +180,7 @@ int aac_send_shutdown(struct aac_dev * dev)
-2 /* Timeout silently */, 1,
NULL, NULL);
if (status == 0)
if (status >= 0)
aac_fib_complete(fibctx);
aac_fib_free(fibctx);
return status;
......
......@@ -40,8 +40,10 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
#include <asm/semaphore.h>
#include "aacraid.h"
......@@ -464,6 +466,8 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
if (!dev->queues)
return -ENODEV;
q = &dev->queues->queue[AdapNormCmdQueue];
if(wait)
......@@ -527,8 +531,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
} else
down(&fibptr->event_wait);
} else if (down_interruptible(&fibptr->event_wait)) {
spin_lock_irqsave(&fibptr->event_lock, flags);
if (fibptr->done == 0) {
fibptr->done = 2; /* Tell interrupt we aborted */
spin_unlock_irqrestore(&fibptr->event_lock, flags);
return -EINTR;
}
spin_unlock_irqrestore(&fibptr->event_lock, flags);
}
BUG_ON(fibptr->done == 0);
if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
......@@ -795,7 +806,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
/* Sniff for container changes */
if (!dev)
if (!dev || !dev->fsa_dev)
return;
container = (u32)-1;
......@@ -1045,6 +1056,262 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
static int _aac_reset_adapter(struct aac_dev *aac)
{
int index, quirks;
u32 ret;
int retval;
struct Scsi_Host *host;
struct scsi_device *dev;
struct scsi_cmnd *command;
struct scsi_cmnd *command_list;
/*
* Assumptions:
* - host is locked.
* - in_reset is asserted, so no new i/o is getting to the
* card.
* - The card is dead.
*/
host = aac->scsi_host_ptr;
scsi_block_requests(host);
aac_adapter_disable_int(aac);
spin_unlock_irq(host->host_lock);
kthread_stop(aac->thread);
/*
* If a positive health, means in a known DEAD PANIC
* state and the adapter could be reset to `try again'.
*/
retval = aac_adapter_check_health(aac);
if (retval == 0)
retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
if (retval)
retval = aac_adapter_sync_cmd(aac, IOP_RESET,
0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
if (retval)
goto out;
if (ret != 0x00000001) {
retval = -ENODEV;
goto out;
}
index = aac->cardtype;
/*
* Re-initialize the adapter, first free resources, then carefully
* apply the initialization sequence to come back again. Only risk
* is a change in Firmware dropping cache, it is assumed the caller
* will ensure that i/o is queisced and the card is flushed in that
* case.
*/
aac_fib_map_free(aac);
aac->hw_fib_va = NULL;
aac->hw_fib_pa = 0;
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
aac->comm_addr = NULL;
aac->comm_phys = 0;
kfree(aac->queues);
aac->queues = NULL;
free_irq(aac->pdev->irq, aac);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
goto out;
} else {
if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
goto out;
}
if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
goto out;
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
goto out;
aac->thread = kthread_run(aac_command_thread, aac, aac->name);
if (IS_ERR(aac->thread)) {
retval = PTR_ERR(aac->thread);
goto out;
}
(void)aac_get_adapter_info(aac);
quirks = aac_get_driver_ident(index)->quirks;
if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
host->sg_tablesize = 34;
host->max_sectors = (host->sg_tablesize * 8) + 112;
}
if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
host->sg_tablesize = 17;
host->max_sectors = (host->sg_tablesize * 8) + 112;
}
aac_get_config_status(aac, 1);
aac_get_containers(aac);
/*
* This is where the assumption that the Adapter is quiesced
* is important.
*/
command_list = NULL;
__shost_for_each_device(dev, host) {
unsigned long flags;
spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(command, &dev->cmd_list, list)
if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
command->SCp.buffer = (struct scatterlist *)command_list;
command_list = command;
}
spin_unlock_irqrestore(&dev->list_lock, flags);
}
while ((command = command_list)) {
command_list = (struct scsi_cmnd *)command->SCp.buffer;
command->SCp.buffer = NULL;
command->result = DID_OK << 16
| COMMAND_COMPLETE << 8
| SAM_STAT_TASK_SET_FULL;
command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
command->scsi_done(command);
}
retval = 0;
out:
aac->in_reset = 0;
scsi_unblock_requests(host);
spin_lock_irq(host->host_lock);
return retval;
}
int aac_check_health(struct aac_dev * aac)
{
int BlinkLED;
unsigned long time_now, flagv = 0;
struct list_head * entry;
struct Scsi_Host * host;
/* Extending the scope of fib_lock slightly to protect aac->in_reset */
if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
return 0;
if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) {
spin_unlock_irqrestore(&aac->fib_lock, flagv);
return 0; /* OK */
}
aac->in_reset = 1;
/* Fake up an AIF:
* aac_aifcmd.command = AifCmdEventNotify = 1
* aac_aifcmd.seqnum = 0xFFFFFFFF
* aac_aifcmd.data[0] = AifEnExpEvent = 23
* aac_aifcmd.data[1] = AifExeFirmwarePanic = 3
* aac.aifcmd.data[2] = AifHighPriority = 3
* aac.aifcmd.data[3] = BlinkLED
*/
time_now = jiffies/HZ;
entry = aac->fib_list.next;
/*
* For each Context that is on the
* fibctxList, make a copy of the
* fib, and then set the event to wake up the
* thread that is waiting for it.
*/
while (entry != &aac->fib_list) {
/*
* Extract the fibctx
*/
struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next);
struct hw_fib * hw_fib;
struct fib * fib;
/*
* Check if the queue is getting
* backlogged
*/
if (fibctx->count > 20) {
/*
* It's *not* jiffies folks,
* but jiffies / HZ, so do not
* panic ...
*/
u32 time_last = fibctx->jiffies;
/*
* Has it been > 2 minutes
* since the last read off
* the queue?
*/
if ((time_now - time_last) > aif_timeout) {
entry = entry->next;
aac_close_fib_context(aac, fibctx);
continue;
}
}
/*
* Warning: no sleep allowed while
* holding spinlock
*/
hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
if (fib && hw_fib) {
struct aac_aifcmd * aif;
memset(hw_fib, 0, sizeof(struct hw_fib));
memset(fib, 0, sizeof(struct fib));
fib->hw_fib = hw_fib;
fib->dev = aac;
aac_fib_init(fib);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof (struct fib);
fib->data = hw_fib->data;
aif = (struct aac_aifcmd *)hw_fib->data;
aif->command = cpu_to_le32(AifCmdEventNotify);
aif->seqnum = cpu_to_le32(0xFFFFFFFF);
aif->data[0] = cpu_to_le32(AifEnExpEvent);
aif->data[1] = cpu_to_le32(AifExeFirmwarePanic);
aif->data[2] = cpu_to_le32(AifHighPriority);
aif->data[3] = cpu_to_le32(BlinkLED);
/*
* Put the FIB onto the
* fibctx's fibs
*/
list_add_tail(&fib->fiblink, &fibctx->fib_list);
fibctx->count++;
/*
* Set the event to wake up the
* thread that will waiting.
*/
up(&fibctx->wait_sem);
} else {
printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
kfree(fib);
kfree(hw_fib);
}
entry = entry->next;
}
spin_unlock_irqrestore(&aac->fib_lock, flagv);
if (BlinkLED < 0) {
printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED);
goto out;
}
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
host = aac->scsi_host_ptr;
spin_lock_irqsave(host->host_lock, flagv);
BlinkLED = _aac_reset_adapter(aac);
spin_unlock_irqrestore(host->host_lock, flagv);
return BlinkLED;
out:
aac->in_reset = 0;
return BlinkLED;
}
/**
* aac_command_thread - command processing thread
* @dev: Adapter to monitor
......
......@@ -124,10 +124,15 @@ unsigned int aac_response_normal(struct aac_queue * q)
} else {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
fib->done = 1;
if (!fib->done)
fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
if (fib->done == 2) {
aac_fib_complete(fib);
aac_fib_free(fib);
}
}
consumed++;
spin_lock_irqsave(q->lock, flags);
......@@ -316,7 +321,8 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n"));
spin_lock_irqsave(&fib->event_lock, flagv);
fib->done = 1;
if (!fib->done)
fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
......
......@@ -454,17 +454,17 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
AAC_DRIVERNAME);
aac = (struct aac_dev *)host->hostdata;
if (aac_adapter_check_health(aac)) {
printk(KERN_ERR "%s: Host adapter appears dead\n",
AAC_DRIVERNAME);
return -ENODEV;
}
if ((count = aac_check_health(aac)))
return count;
/*
* Wait for all commands to complete to this specific
* target (block maximum 60 seconds).
*/
for (count = 60; count; --count) {
int active = 0;
int active = aac->in_reset;
if (active == 0)
__shost_for_each_device(dev, host) {
spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(command, &dev->cmd_list, list) {
......@@ -933,7 +933,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
else
shost->max_channel = 0;
aac_get_config_status(aac);
aac_get_config_status(aac, 0);
aac_get_containers(aac);
list_add(&aac->entry, insert);
......@@ -1013,6 +1013,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
list_del(&aac->entry);
scsi_host_put(shost);
pci_disable_device(pdev);
if (list_empty(&aac_devices)) {
unregister_chrdev(aac_cfg_major, "aac");
aac_cfg_major = -1;
}
}
static struct pci_driver aac_pci_driver = {
......
......@@ -395,6 +395,25 @@ static int aac_rkt_send(struct fib * fib)
return 0;
}
static int aac_rkt_restart_adapter(struct aac_dev *dev)
{
u32 var;
printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
dev->name, dev->id);
if (aac_rkt_check_health(dev) <= 0)
return 1;
if (rkt_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
&var, NULL, NULL, NULL, NULL))
return 1;
if (var != 0x00000001)
return 1;
if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
return 1;
return 0;
}
/**
* aac_rkt_init - initialize an i960 based AAC card
* @dev: device to configure
......@@ -417,6 +436,9 @@ int aac_rkt_init(struct aac_dev *dev)
/*
* Check to see if the board panic'd while booting.
*/
if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
if (aac_rkt_restart_adapter(dev))
goto error_iounmap;
/*
* Check to see if the board failed any self tests.
*/
......@@ -431,13 +453,6 @@ int aac_rkt_init(struct aac_dev *dev)
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
goto error_iounmap;
}
/*
* Check to see if the board panic'd while booting.
*/
if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
goto error_iounmap;
}
start = jiffies;
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
......
......@@ -394,6 +394,25 @@ static int aac_rx_send(struct fib * fib)
return 0;
}
static int aac_rx_restart_adapter(struct aac_dev *dev)
{
u32 var;
printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
dev->name, dev->id);
if (aac_rx_check_health(dev) <= 0)
return 1;
if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
&var, NULL, NULL, NULL, NULL))
return 1;
if (var != 0x00000001)
return 1;
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
return 1;
return 0;
}
/**
* aac_rx_init - initialize an i960 based AAC card
* @dev: device to configure
......@@ -416,6 +435,9 @@ int aac_rx_init(struct aac_dev *dev)
/*
* Check to see if the board panic'd while booting.
*/
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
if (aac_rx_restart_adapter(dev))
goto error_iounmap;
/*
* Check to see if the board failed any self tests.
*/
......@@ -423,13 +445,6 @@ int aac_rx_init(struct aac_dev *dev)
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
goto error_iounmap;
}
/*
* Check to see if the board panic'd while booting.
*/
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
goto error_iounmap;
}
/*
* Check to see if the monitor panic'd while booting.
*/
......
......@@ -888,10 +888,6 @@ typedef unsigned char uchar;
#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
#define ASC_PCI_VENDORID 0x10CD
#define ASC_PCI_DEVICEID_1200A 0x1100
#define ASC_PCI_DEVICEID_1200B 0x1200
#define ASC_PCI_DEVICEID_ULTRA 0x1300
#define ASC_PCI_REVISION_3150 0x02
#define ASC_PCI_REVISION_3050 0x03
......@@ -899,6 +895,14 @@ typedef unsigned char uchar;
#define ASC_DVCLIB_CALL_FAILED (0)
#define ASC_DVCLIB_CALL_ERROR (-1)
#define PCI_VENDOR_ID_ASP 0x10cd
#define PCI_DEVICE_ID_ASP_1200A 0x1100
#define PCI_DEVICE_ID_ASP_ABP940 0x1200
#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
#define PCI_DEVICE_ID_38C0800_REV1 0x2500
#define PCI_DEVICE_ID_38C1600_REV1 0x2700
/*
* Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
* The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
......@@ -1492,8 +1496,6 @@ typedef struct asc_dvc_cfg {
#define ASC_INIT_STATE_END_INQUIRY 0x0080
#define ASC_INIT_RESET_SCSI_DONE 0x0100
#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
#define ASC_PCI_DEVICE_ID_REV_A 0x1100
#define ASC_PCI_DEVICE_ID_REV_B 0x1200
#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
......@@ -2100,12 +2102,6 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
#define ADV_NUM_PAGE_CROSSING \
((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
/* a_condor.h */
#define ADV_PCI_VENDOR_ID 0x10CD
#define ADV_PCI_DEVICE_ID_REV_A 0x2300
#define ADV_PCI_DEVID_38C0800_REV1 0x2500
#define ADV_PCI_DEVID_38C1600_REV1 0x2700
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
......@@ -3569,14 +3565,7 @@ typedef struct scsi_cmnd REQ, *REQP;
#define PCI_MAX_SLOT 0x1F
#define PCI_MAX_BUS 0xFF
#define PCI_IOADDRESS_MASK 0xFFFE
#define ASC_PCI_VENDORID 0x10CD
#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
#define ASC_PCI_DEVICE_ID_1100 0x1100
#define ASC_PCI_DEVICE_ID_1200 0x1200
#define ASC_PCI_DEVICE_ID_1300 0x1300
#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */
#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */
#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */
#ifndef ADVANSYS_STATS
#define ASC_STATS(shp, counter)
......@@ -4330,12 +4319,12 @@ advansys_detect(struct scsi_host_template *tpnt)
struct pci_dev *pci_devp = NULL;
int pci_device_id_cnt = 0;
unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
ASC_PCI_DEVICE_ID_1100,
ASC_PCI_DEVICE_ID_1200,
ASC_PCI_DEVICE_ID_1300,
ASC_PCI_DEVICE_ID_2300,
ASC_PCI_DEVICE_ID_2500,
ASC_PCI_DEVICE_ID_2700
PCI_DEVICE_ID_ASP_1200A,
PCI_DEVICE_ID_ASP_ABP940,
PCI_DEVICE_ID_ASP_ABP940U,
PCI_DEVICE_ID_ASP_ABP940UW,
PCI_DEVICE_ID_38C0800_REV1,
PCI_DEVICE_ID_38C1600_REV1
};
ADV_PADDR pci_memory_address;
#endif /* CONFIG_PCI */
......@@ -4471,7 +4460,7 @@ advansys_detect(struct scsi_host_template *tpnt)
/* Find all PCI cards. */
while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
pci_device_id[pci_device_id_cnt], pci_devp)) ==
NULL) {
pci_device_id_cnt++;
......@@ -4575,9 +4564,9 @@ advansys_detect(struct scsi_host_template *tpnt)
*/
#ifdef CONFIG_PCI
if (asc_bus[bus] == ASC_IS_PCI &&
(pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
pci_devp->device == ASC_PCI_DEVICE_ID_2700))
(pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
{
boardp->flags |= ASC_IS_WIDE_BOARD;
}
......@@ -4600,11 +4589,11 @@ advansys_detect(struct scsi_host_template *tpnt)
adv_dvc_varp->isr_callback = adv_isr_callback;
adv_dvc_varp->async_callback = adv_async_callback;
#ifdef CONFIG_PCI
if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
{
ASC_DBG(1, "advansys_detect: ASC-3550\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
} else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
} else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
{
ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
......@@ -11922,7 +11911,7 @@ AscInitGetConfig(
PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigRevisionIDRegister);
if (PCIVendorID != ASC_PCI_VENDORID) {
if (PCIVendorID != PCI_VENDOR_ID_ASP) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
......@@ -11942,15 +11931,15 @@ AscInitGetConfig(
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
}
if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
(PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
(PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
DvcWritePCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer, 0x00);
if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
!= 0x00) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
} else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
} else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
if (DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer) < 0x20) {
DvcWritePCIConfigByte(asc_dvc,
......@@ -12037,8 +12026,8 @@ AscInitFromAscDvcVar(
AscSetChipCfgMsw(iop_base, cfg_msw);
if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
} else {
if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
(pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
(pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
}
......@@ -14275,8 +14264,8 @@ Default_38C0800_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
ADV_PCI_VENDOR_ID, /* 58 subsysvid */
ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
PCI_VENDOR_ID_ASP, /* 58 subsysvid */
PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
......@@ -14405,8 +14394,8 @@ Default_38C1600_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
ADV_PCI_VENDOR_ID, /* 58 subsysvid */
ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
PCI_VENDOR_ID_ASP, /* 58 subsysvid */
PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
......@@ -18225,3 +18214,22 @@ AdvInquiryHandling(
}
}
MODULE_LICENSE("Dual BSD/GPL");
/* PCI Devices supported by this driver */
static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
......@@ -253,6 +253,7 @@
#include <linux/isapnp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <asm/semaphore.h>
#include <scsi/scsicam.h>
......@@ -262,6 +263,8 @@
#include <scsi/scsi_transport_spi.h>
#include "aha152x.h"
static LIST_HEAD(aha152x_host_list);
/* DEFINES */
......@@ -423,8 +426,6 @@ MODULE_DEVICE_TABLE(isapnp, id_table);
#endif /* !PCMCIA */
static int registered_count=0;
static struct Scsi_Host *aha152x_host[2];
static struct scsi_host_template aha152x_driver_template;
/*
......@@ -541,6 +542,7 @@ struct aha152x_hostdata {
#ifdef __ISAPNP__
struct pnp_dev *pnpdev;
#endif
struct list_head host_list;
};
......@@ -755,20 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
return ptr;
}
static inline struct Scsi_Host *lookup_irq(int irqno)
{
int i;
for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
return aha152x_host[i];
return NULL;
}
static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *shpnt = lookup_irq(irqno);
struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
if (!shpnt) {
printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
......@@ -791,10 +782,11 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
return NULL;
}
/* need to have host registered before triggering any interrupt */
aha152x_host[registered_count] = shpnt;
memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
/* need to have host registered before triggering any interrupt */
list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
shpnt->io_port = setup->io_port;
shpnt->n_io_port = IO_RANGE;
......@@ -907,12 +899,10 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
scsi_scan_host(shpnt);
registered_count++;
return shpnt;
out_host_put:
aha152x_host[registered_count]=NULL;
list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
return NULL;
......@@ -937,6 +927,7 @@ void aha152x_release(struct Scsi_Host *shpnt)
#endif
scsi_remove_host(shpnt);
list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
}
......@@ -1459,9 +1450,12 @@ static struct work_struct aha152x_tq;
*/
static void run(void)
{
int i;
for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
is_complete(aha152x_host[i]);
struct aha152x_hostdata *hd;
list_for_each_entry(hd, &aha152x_host_list, host_list) {
struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
is_complete(shost);
}
}
......@@ -1471,7 +1465,7 @@ static void run(void)
*/
static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
{
struct Scsi_Host *shpnt = lookup_irq(irqno);
struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
unsigned long flags;
unsigned char rev, dmacntrl0;
......@@ -3953,16 +3947,17 @@ static int __init aha152x_init(void)
#endif
}
return registered_count>0;
return 1;
}
static void __exit aha152x_exit(void)
{
int i;
struct aha152x_hostdata *hd;
list_for_each_entry(hd, &aha152x_host_list, host_list) {
struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
for(i=0; i<ARRAY_SIZE(setup); i++) {
aha152x_release(aha152x_host[i]);
aha152x_host[i]=NULL;
aha152x_release(shost);
}
}
......
......@@ -321,7 +321,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
module_param(aic79xx, charp, 0444);
MODULE_PARM_DESC(aic79xx,
"period delimited, options string.\n"
"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
......@@ -346,7 +346,7 @@ MODULE_PARM_DESC(aic79xx,
" Shorten the selection timeout to 128ms\n"
"\n"
" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
"\n");
);
static void ahd_linux_handle_scsi_status(struct ahd_softc *,
struct scsi_device *,
......
......@@ -341,7 +341,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
module_param(aic7xxx, charp, 0444);
MODULE_PARM_DESC(aic7xxx,
"period delimited, options string.\n"
"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
......
......@@ -249,8 +249,6 @@
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
#include <linux/config.h> /* for CONFIG_PCI */
#define AIC7XXX_C_VERSION "5.2.6"
#define ALL_TARGETS -1
......
#
# Kernel configuration file for aic94xx SAS/SATA driver.
#
# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
# This file is licensed under GPLv2.
#
# This file is part of the aic94xx driver.
#
# The aic94xx driver is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 of the
# License.
#
# The aic94xx driver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Aic94xx Driver; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
config SCSI_AIC94XX
tristate "Adaptec AIC94xx SAS/SATA support"
depends on PCI
select SCSI_SAS_LIBSAS
help
This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
AIC94xx chip based host adapters.
config AIC94XX_DEBUG
bool "Compile in debug mode"
default y
depends on SCSI_AIC94XX
help
Compiles the aic94xx driver in debug mode. In debug mode,
the driver prints some messages to the console.
#
# Makefile for Adaptec aic94xx SAS/SATA driver.
#
# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
#
# This file is licensed under GPLv2.
#
# This file is part of the the aic94xx driver.
#
# The aic94xx driver is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 of the
# License.
#
# The aic94xx driver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the aic94xx driver; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ifeq ($(CONFIG_AIC94XX_DEBUG),y)
EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
endif
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
aic94xx-y += aic94xx_init.o \
aic94xx_hwi.o \
aic94xx_reg.o \
aic94xx_sds.o \
aic94xx_seq.o \
aic94xx_dump.o \
aic94xx_scb.o \
aic94xx_dev.o \
aic94xx_tmf.o \
aic94xx_task.o
/*
* Aic94xx SAS/SATA driver header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This file is part of the aic94xx driver.
*
* The aic94xx driver is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* The aic94xx driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id: //depot/aic94xx/aic94xx.h#31 $
*/
#ifndef _AIC94XX_H_
#define _AIC94XX_H_
#include <linux/slab.h>
#include <linux/ctype.h>
#include <scsi/libsas.h>
#define ASD_DRIVER_NAME "aic94xx"
#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver"
#define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
#ifdef ASD_ENTER_EXIT
#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
__FUNCTION__)
#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
__FUNCTION__)
#else
#define ENTER
#define EXIT
#endif
#ifdef ASD_DEBUG
#define ASD_DPRINTK asd_printk
#else
#define ASD_DPRINTK(fmt, ...)
#endif
/* 2*ITNL timeout + 1 second */
#define AIC94XX_SCB_TIMEOUT (5*HZ)
extern kmem_cache_t *asd_dma_token_cache;
extern kmem_cache_t *asd_ascb_cache;
extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
{
int i;
for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
snprintf(p, 3, "%02X", sas_addr[i]);
*p = '\0';
}
static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
{
int i;
for (i = 0; i < SAS_ADDR_SIZE; i++) {
u8 h, l;
if (!*p)
break;
h = isdigit(*p) ? *p-'0' : *p-'A'+10;
p++;
l = isdigit(*p) ? *p-'0' : *p-'A'+10;
p++;
sas_addr[i] = (h<<4) | l;
}
}
struct asd_ha_struct;
struct asd_ascb;
int asd_read_ocm(struct asd_ha_struct *asd_ha);
int asd_read_flash(struct asd_ha_struct *asd_ha);
int asd_dev_found(struct domain_device *dev);
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, unsigned long gfp_flags);
/* ---------- TMFs ---------- */
int asd_abort_task(struct sas_task *);
int asd_abort_task_set(struct domain_device *, u8 *lun);
int asd_clear_aca(struct domain_device *, u8 *lun);
int asd_clear_task_set(struct domain_device *, u8 *lun);
int asd_lu_reset(struct domain_device *, u8 *lun);
int asd_query_task(struct sas_task *);
/* ---------- Adapter and Port management ---------- */
int asd_clear_nexus_port(struct asd_sas_port *port);
int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
/* ---------- Phy Management ---------- */
int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg);
#endif
/*
* Aic94xx SAS/SATA DDB management
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This file is part of the aic94xx driver.
*
* The aic94xx driver is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* The aic94xx driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id: //depot/aic94xx/aic94xx_dev.c#21 $
*/
#include "aic94xx.h"
#include "aic94xx_hwi.h"
#include "aic94xx_reg.h"
#include "aic94xx_sas.h"
#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
(_ha)->hw_prof.max_ddbs)
#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
{
unsigned long flags;
int ddb, i;
spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
ddb = FIND_FREE_DDB(asd_ha);
if (ddb >= asd_ha->hw_prof.max_ddbs) {
ddb = -ENOMEM;
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
goto out;
}
SET_DDB(ddb, asd_ha);
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
out:
return ddb;
}
#define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
#define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
#define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
#define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
#define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags)
#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
#define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
#define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
#define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
#define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
#define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
#define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
#define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
{
unsigned long flags;
if (!ddb || ddb >= 0xFFFF)
return;
asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
CLEAR_DDB(ddb, asd_ha);
spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
}
static inline void asd_set_ddb_type(struct domain_device *dev)
{
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
int ddb = (int) (unsigned long) dev->lldd_dev;
if (dev->dev_type == SATA_PM_PORT)
asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
else if (dev->tproto)
asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
else
asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
}
static int asd_init_sata_tag_ddb(struct domain_device *dev)
{
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
int ddb, i;
ddb = asd_get_ddb(asd_ha);
if (ddb < 0)
return ddb;
for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
SISTER_DDB, ddb);
return 0;
}
static inline int asd_init_sata(struct domain_device *dev)
{
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
int ddb = (int) (unsigned long) dev->lldd_dev;
u32 qdepth = 0;
int res = 0;
asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
dev->sata_dev.identify_device &&
dev->sata_dev.identify_device[10] != 0) {
u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
if (w76 & 0x100) /* NCQ? */
qdepth = (w75 & 0x1F) + 1;
asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
(1<<qdepth)-1);
asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
}
if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
dev->dev_type == SATA_PM_PORT) {
struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
dev->frame_rcvd;
asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
}
asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
if (qdepth > 0)
res = asd_init_sata_tag_ddb(dev);
return res;
}
static int asd_init_target_ddb(struct domain_device *dev)
{
int ddb, i;
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
u8 flags = 0;
ddb = asd_get_ddb(asd_ha);
if (ddb < 0)
return ddb;
dev->lldd_dev = (void *) (unsigned long) ddb;
asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
for (i = 0; i < SAS_ADDR_SIZE; i++)
asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
dev->sas_addr[i]);
asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
asd_set_ddb_type(dev);
asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
if (dev->port->oob_mode != SATA_OOB_MODE) {
flags |= OPEN_REQUIRED;
if ((dev->dev_type == SATA_DEV) ||
(dev->tproto & SAS_PROTO_STP)) {
struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
if (rps_resp->frame_type == SMP_RESPONSE &&
rps_resp->function == SMP_REPORT_PHY_SATA &&
rps_resp->result == SMP_RESP_FUNC_ACC) {
if (rps_resp->rps.affil_valid)
flags |= STP_AFFIL_POL;
if (rps_resp->rps.affil_supp)
flags |= SUPPORTS_AFFIL;
}
} else {
flags |= CONCURRENT_CONN_SUPP;
if (!dev->parent &&
(dev->dev_type == EDGE_DEV ||
dev->dev_type == FANOUT_DEV))
asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
4);
else
asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
dev->pathways);
asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
}
}
if (dev->dev_type == SATA_PM)
flags |= SATA_MULTIPORT;
asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
flags = 0;
if (dev->tproto & SAS_PROTO_STP)
flags |= STP_CL_POL_NO_TX;
asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
i = asd_init_sata(dev);
if (i < 0) {
asd_free_ddb(asd_ha, ddb);
return i;
}
}
if (dev->dev_type == SAS_END_DEV) {
struct sas_end_device *rdev = rphy_to_end_device(dev->rphy);
if (rdev->I_T_nexus_loss_timeout > 0)
asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
min(rdev->I_T_nexus_loss_timeout,
(u16)ITNL_TIMEOUT_CONST));
else
asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
(u16)ITNL_TIMEOUT_CONST);
}
return 0;
}
static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
{
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
int ddb, i;
ddb = asd_get_ddb(asd_ha);
if (ddb < 0)
return ddb;
for (i = 0; i < 32; i += 2)
asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
SISTER_DDB, ddb);
return 0;
}
#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
#define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
/**
* asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
* dev: pointer to domain device
*
* For SATA Port Multiplier Ports we need to allocate one SATA Port
* Multiplier Port DDB and depending on whether the target on it
* supports SATA II NCQ, one SATA Tag DDB.
*/
static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
{
int ddb, i, parent_ddb, pmtable_ddb;
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
u8 flags;
ddb = asd_get_ddb(asd_ha);
if (ddb < 0)
return ddb;
asd_set_ddb_type(dev);
flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
asd_init_sata(dev);
parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
i = asd_init_sata_tag_ddb(dev);
if (i < 0) {
asd_free_ddb(asd_ha, ddb);
return i;
}
}
return 0;
}
static int asd_init_initiator_ddb(struct domain_device *dev)
{
return -ENODEV;
}
/**
* asd_init_sata_pm_ddb -- SATA Port Multiplier
* dev: pointer to domain device
*
* For STP and direct-attached SATA Port Multipliers we need
* one target port DDB entry and one SATA PM table DDB entry.
*/
static int asd_init_sata_pm_ddb(struct domain_device *dev)
{
int res = 0;
res = asd_init_target_ddb(dev);
if (res)
goto out;
res = asd_init_sata_pm_table_ddb(dev);
if (res)
asd_free_ddb(dev->port->ha->lldd_ha,
(int) (unsigned long) dev->lldd_dev);
out:
return res;
}
int asd_dev_found(struct domain_device *dev)
{
int res = 0;
switch (dev->dev_type) {
case SATA_PM:
res = asd_init_sata_pm_ddb(dev);
break;
case SATA_PM_PORT:
res = asd_init_sata_pm_port_ddb(dev);
break;
default:
if (dev->tproto)
res = asd_init_target_ddb(dev);
else
res = asd_init_initiator_ddb(dev);
}
return res;
}
void asd_dev_gone(struct domain_device *dev)
{
int ddb, sister_ddb;
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
ddb = (int) (unsigned long) dev->lldd_dev;
sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
if (sister_ddb != 0xFFFF)
asd_free_ddb(asd_ha, sister_ddb);
asd_free_ddb(asd_ha, ddb);
dev->lldd_dev = NULL;
}
此差异已折叠。
/*
* Aic94xx SAS/SATA driver dump header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This file is part of the aic94xx driver.
*
* The aic94xx driver is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* The aic94xx driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _AIC94XX_DUMP_H_
#define _AIC94XX_DUMP_H_
#ifdef ASD_DEBUG
void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
void asd_dump_frame_rcvd(struct asd_phy *phy,
struct done_list_struct *dl);
void asd_dump_scb_list(struct asd_ascb *ascb, int num);
#else /* ASD_DEBUG */
static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
u16 site_no) { }
static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
u8 lseq_mask) { }
static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
struct done_list_struct *dl) { }
static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
#endif /* ASD_DEBUG */
#endif /* _AIC94XX_DUMP_H_ */
此差异已折叠。
/*
* Aic94xx SAS/SATA driver hardware interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This file is part of the aic94xx driver.
*
* The aic94xx driver is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* The aic94xx driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _AIC94XX_HWI_H_
#define _AIC94XX_HWI_H_
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <scsi/libsas.h>
#include "aic94xx.h"
#include "aic94xx_sas.h"
/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
#define ASD_MAX_PHYS 8
#define ASD_PCBA_SN_SIZE 12
/* Those are to be further named properly, the "RAZORx" part, and
* subsequently included in include/linux/pci_ids.h.
*/
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
struct asd_ha_addrspace {
void __iomem *addr;
unsigned long start; /* pci resource start */
unsigned long len; /* pci resource len */
unsigned long flags; /* pci resource flags */
/* addresses internal to the host adapter */
u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
u32 swb_base;
u32 swc_base;
};
struct bios_struct {
int present;
u8 maj;
u8 min;
u32 bld;
};
struct unit_element_struct {
u16 num;
u16 size;
void *area;
};
struct flash_struct {
u32 bar;
int present;
int wide;
u8 manuf;
u8 dev_id;
u8 sec_prot;
u32 dir_offs;
};
struct asd_phy_desc {
/* From CTRL-A settings, then set to what is appropriate */
u8 sas_addr[SAS_ADDR_SIZE];
u8 max_sas_lrate;
u8 min_sas_lrate;
u8 max_sata_lrate;
u8 min_sata_lrate;
u8 flags;
#define ASD_CRC_DIS 1
#define ASD_SATA_SPINUP_HOLD 2
u8 phy_control_0; /* mode 5 reg 0x160 */
u8 phy_control_1; /* mode 5 reg 0x161 */
u8 phy_control_2; /* mode 5 reg 0x162 */
u8 phy_control_3; /* mode 5 reg 0x163 */
};
struct asd_dma_tok {
void *vaddr;
dma_addr_t dma_handle;
size_t size;
};
struct hw_profile {
struct bios_struct bios;
struct unit_element_struct ue;
struct flash_struct flash;
u8 sas_addr[SAS_ADDR_SIZE];
char pcba_sn[ASD_PCBA_SN_SIZE+1];
u8 enabled_phys; /* mask of enabled phys */
struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
u32 max_scbs; /* absolute sequencer scb queue size */
struct asd_dma_tok *scb_ext;
u32 max_ddbs;
struct asd_dma_tok *ddb_ext;
spinlock_t ddb_lock;
void *ddb_bitmap;
int num_phys; /* ENABLEABLE */
int max_phys; /* REPORTED + ENABLEABLE */
unsigned addr_range; /* max # of addrs; max # of possible ports */
unsigned port_name_base;
unsigned dev_name_base;
unsigned sata_name_base;
};
struct asd_ascb {
struct list_head list;
struct asd_ha_struct *ha;
struct scb *scb; /* equals dma_scb->vaddr */
struct asd_dma_tok dma_scb;
struct asd_dma_tok *sg_arr;
void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
u8 uldd_timer:1;
/* internally generated command */
struct timer_list timer;
struct completion completion;
u8 tag_valid:1;
__be16 tag; /* error recovery only */
/* If this is an Empty SCB, index of first edb in seq->edb_arr. */
int edb_index;
/* Used by the timer timeout function. */
int tc_index;
void *uldd_task;
};
#define ASD_DL_SIZE_BITS 0x8
#define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS))
#define ASD_DEF_DL_TOGGLE 0x01
struct asd_seq_data {
spinlock_t pend_q_lock;
u16 scbpro;
int pending;
struct list_head pend_q;
int can_queue; /* per adapter */
struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
spinlock_t tc_index_lock;
void **tc_index_array;
void *tc_index_bitmap;
int tc_index_bitmap_bits;
struct tasklet_struct dl_tasklet;
struct done_list_struct *dl; /* array of done list entries, equals */
struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
int dl_toggle;
int dl_next;
int num_edbs;
struct asd_dma_tok **edb_arr;
int num_escbs;
struct asd_ascb **escb_arr; /* array of pointers to escbs */
};
/* This is the Host Adapter structure. It describes the hardware
* SAS adapter.
*/
struct asd_ha_struct {
struct pci_dev *pcidev;
const char *name;
struct sas_ha_struct sas_ha;
u8 revision_id;
int iospace;
spinlock_t iolock;
struct asd_ha_addrspace io_handle[2];
struct hw_profile hw_prof;
struct asd_phy phys[ASD_MAX_PHYS];
struct asd_sas_port ports[ASD_MAX_PHYS];
struct dma_pool *scb_pool;
struct asd_seq_data seq; /* sequencer related */
};
/* ---------- Common macros ---------- */
#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \
? ((u32)((__dma_handle) >> 32)) \
: ((u32)0))
#define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev))
#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \
&& ((__site_no) & 0xF0FF) > 0x001F)
/* For each bit set in __lseq_mask, set __lseq to equal the bit
* position of the set bit and execute the statement following.
* __mc is the temporary mask, used as a mask "counter".
*/
#define for_each_sequencer(__lseq_mask, __mc, __lseq) \
for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
if (((__mc) & 1))
#define for_each_phy(__lseq_mask, __mc, __lseq) \
for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
if (((__mc) & 1))
#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
/* ---------- DMA allocs ---------- */
static inline struct asd_dma_tok *asd_dmatok_alloc(unsigned int flags)
{
return kmem_cache_alloc(asd_dma_token_cache, flags);
}
static inline void asd_dmatok_free(struct asd_dma_tok *token)
{
kmem_cache_free(asd_dma_token_cache, token);
}
static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
asd_ha, size_t size,
unsigned int flags)
{
struct asd_dma_tok *token = asd_dmatok_alloc(flags);
if (token) {
token->size = size;
token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
token->size,
&token->dma_handle,
flags);
if (!token->vaddr) {
asd_dmatok_free(token);
token = NULL;
}
}
return token;
}
static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
struct asd_dma_tok *token)
{
if (token) {
dma_free_coherent(&asd_ha->pcidev->dev, token->size,
token->vaddr, token->dma_handle);
asd_dmatok_free(token);
}
}
static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
struct asd_ascb *ascb)
{
INIT_LIST_HEAD(&ascb->list);
ascb->scb = ascb->dma_scb.vaddr;
ascb->ha = asd_ha;
ascb->timer.function = NULL;
init_timer(&ascb->timer);
ascb->tc_index = -1;
init_completion(&ascb->completion);
}
/* Must be called with the tc_index_lock held!
*/
static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
{
seq->tc_index_array[index] = NULL;
clear_bit(index, seq->tc_index_bitmap);
}
/* Must be called with the tc_index_lock held!
*/
static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
{
int index;
index = find_first_zero_bit(seq->tc_index_bitmap,
seq->tc_index_bitmap_bits);
if (index == seq->tc_index_bitmap_bits)
return -1;
seq->tc_index_array[index] = ptr;
set_bit(index, seq->tc_index_bitmap);
return index;
}
/* Must be called with the tc_index_lock held!
*/
static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
{
return seq->tc_index_array[index];
}
/**
* asd_ascb_free -- free a single aSCB after is has completed
* @ascb: pointer to the aSCB of interest
*
* This frees an aSCB after it has been executed/completed by
* the sequencer.
*/
static inline void asd_ascb_free(struct asd_ascb *ascb)
{
if (ascb) {
struct asd_ha_struct *asd_ha = ascb->ha;
unsigned long flags;
BUG_ON(!list_empty(&ascb->list));
spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
ascb->dma_scb.dma_handle);
kmem_cache_free(asd_ascb_cache, ascb);
}
}
/**
* asd_ascb_list_free -- free a list of ascbs
* @ascb_list: a list of ascbs
*
* This function will free a list of ascbs allocated by asd_ascb_alloc_list.
* It is used when say the scb queueing function returned QUEUE_FULL,
* and we do not need the ascbs any more.
*/
static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
{
LIST_HEAD(list);
struct list_head *n, *pos;
__list_add(&list, ascb_list->list.prev, &ascb_list->list);
list_for_each_safe(pos, n, &list) {
list_del_init(pos);
asd_ascb_free(list_entry(pos, struct asd_ascb, list));
}
}
/* ---------- Function declarations ---------- */
int asd_init_hw(struct asd_ha_struct *asd_ha);
irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
*asd_ha, int *num,
unsigned int gfp_mask);
int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
int num);
int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
int num);
int asd_init_post_escbs(struct asd_ha_struct *asd_ha);
void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
u8 subfunc);
void asd_ascb_timedout(unsigned long data);
int asd_chip_hardrst(struct asd_ha_struct *asd_ha);
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Aic94xx SAS/SATA driver sequencer interface header file.
*
* Copyright (C) 2005 Adaptec, Inc. All rights reserved.
* Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
*
* This file is licensed under GPLv2.
*
* This file is part of the aic94xx driver.
*
* The aic94xx driver is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the
* License.
*
* The aic94xx driver is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the aic94xx driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _AIC94XX_SEQ_H_
#define _AIC94XX_SEQ_H_
#define CSEQ_NUM_VECS 3
#define LSEQ_NUM_VECS 11
#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw"
/* Note: All quantites in the sequencer file are little endian */
struct sequencer_file_header {
/* Checksum of the entire contents of the sequencer excluding
* these four bytes */
u32 csum;
/* numeric major version */
u32 major;
/* numeric minor version */
u32 minor;
/* version string printed by driver */
char version[16];
u32 cseq_table_offset;
u32 cseq_table_size;
u32 lseq_table_offset;
u32 lseq_table_size;
u32 cseq_code_offset;
u32 cseq_code_size;
u32 lseq_code_offset;
u32 lseq_code_size;
u16 mode2_task;
u16 cseq_idle_loop;
u16 lseq_idle_loop;
} __attribute__((packed));
#ifdef __KERNEL__
int asd_pause_cseq(struct asd_ha_struct *asd_ha);
int asd_unpause_cseq(struct asd_ha_struct *asd_ha);
int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
int asd_init_seqs(struct asd_ha_struct *asd_ha);
int asd_start_seqs(struct asd_ha_struct *asd_ha);
void asd_update_port_links(struct asd_sas_phy *phy);
#endif
#endif
此差异已折叠。
此差异已折叠。
# File: drivers/arcmsr/Makefile
# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
arcmsr-objs := arcmsr_attr.o arcmsr_hba.o
obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -46,7 +46,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/pci.h> /* for PCI support */
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
......
......@@ -248,8 +248,7 @@ int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t of
if (scd->id == target) {
SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ",
alpa, target, u1[0], u1[1], u2[0], u2[1]);
SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
scsi_device_types[(short) scd->type] : "Unknown device");
SPRINTF ("%s ", scsi_device_type(scd->type));
for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
SPRINTF ("%c", scd->vendor[j]);
......
......@@ -811,7 +811,6 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
struct NCR5380_hostdata *hostdata;
#ifdef NCR5380_STATS
struct scsi_device *dev;
extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#endif
NCR5380_setup(scsi_ptr);
......@@ -851,7 +850,7 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
long tr = hostdata->time_read[dev->id] / HZ;
long tw = hostdata->time_write[dev->id] / HZ;
PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
for (i = 0; i < 8; i++)
if (dev->vendor[i] >= 0x20)
*(buffer + (len++)) = dev->vendor[i];
......
......@@ -47,7 +47,7 @@ void gvp11_setup (char *str, int *ints)
gvp11_xfer_mask = ints[1];
}
static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = GVP11_DMAC_INT_ENABLE;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
......@@ -142,8 +142,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
int status)
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
/* stop DMA */
DMA(instance)->SP_DMA = 1;
......@@ -341,7 +341,7 @@ int __init gvp11_detect(struct scsi_host_template *tpnt)
return num_gvp11;
}
static int gvp11_bus_reset(Scsi_Cmnd *cmd)
static int gvp11_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
......
......@@ -13,10 +13,6 @@
int gvp11_detect(struct scsi_host_template *);
int gvp11_release(struct Scsi_Host *);
const char *wd33c93_info(void);
int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd33c93_abort(Scsi_Cmnd *);
int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
......
......@@ -265,6 +265,9 @@ static void scsi_host_dev_release(struct device *dev)
destroy_workqueue(shost->work_q);
scsi_destroy_command_freelist(shost);
if (shost->bqt)
blk_free_tags(shost->bqt);
kfree(shost->shost_data);
if (parent)
......@@ -487,7 +490,9 @@ EXPORT_SYMBOL(scsi_is_host_device);
* @work: Work to queue for execution.
*
* Return value:
* 0 on success / != 0 for error
* 1 - work queued for execution
* 0 - work is already queued
* -EINVAL - work queue doesn't exist
**/
int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
{
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部