summaryrefslogtreecommitdiff
path: root/drivers/scsi/aacraid/commsup.c
diff options
context:
space:
mode:
authorSalyzyn, Mark <Mark_Salyzyn@adaptec.com>2008-01-11 19:56:07 (GMT)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-23 17:29:26 (GMT)
commit0995ad382df77b438d0c1e4f93ff349aa2eb9caf (patch)
tree84125251a9f45d5c3d7d262900a572f62ad4d11b /drivers/scsi/aacraid/commsup.c
parentd9aa3af09cdc5d3ae0e67bed4107bcf7e25b9f31 (diff)
downloadlinux-0995ad382df77b438d0c1e4f93ff349aa2eb9caf.tar.xz
[SCSI] aacraid: respond to enclosure service events
Added support to respond to enclosure service events (controller AIFs) to add, online or offline physical targets reported to sg. Also added online and offlining of arrays. Removed an automatic variable definition in a sub block that hid an earlier definition, determined to be inert as the sub-block use did not interfere. Bumped the driver versioning to stamp the addition of this feature. Signed-off-by: Mark Salyzyn <aacraid@adaptec.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/aacraid/commsup.c')
-rw-r--r--drivers/scsi/aacraid/commsup.c96
1 files changed, 75 insertions, 21 deletions
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 3a3017d..6d88f30 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -775,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{
struct hw_fib * hw_fib = fibptr->hw_fib_va;
struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
- u32 container;
+ u32 channel, id, lun, container;
struct scsi_device *device;
enum {
NOTHING,
DELETE,
ADD,
CHANGE
- } device_config_needed;
+ } device_config_needed = NOTHING;
/* Sniff for container changes */
if (!dev || !dev->fsa_dev)
return;
- container = (u32)-1;
+ container = channel = id = lun = (u32)-1;
/*
* We have set this up to try and minimize the number of
@@ -901,6 +901,36 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
case AifEnConfigChange:
break;
+ case AifEnEnclosureManagement:
+ switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) {
+ case EM_DRIVE_INSERTION:
+ case EM_DRIVE_REMOVAL:
+ container = le32_to_cpu(
+ ((__le32 *)aifcmd->data)[2]);
+ if ((container >> 28))
+ break;
+ channel = (container >> 24) & 0xF;
+ if (channel >= dev->maximum_num_channels)
+ break;
+ id = container & 0xFFFF;
+ lun = (container >> 16) & 0xFF;
+ if (id >= dev->maximum_num_physicals) {
+ /* legacy dev_t ? */
+ if ((0x2000 <= id) || lun || channel ||
+ ((channel = (id >> 7) & 0x3F) >=
+ dev->maximum_num_channels))
+ break;
+ lun = (id >> 4) & 7;
+ id &= 0xF;
+ }
+ channel = aac_phys_to_logical(channel);
+ device_config_needed =
+ (((__le32 *)aifcmd->data)[3]
+ == cpu_to_le32(EM_DRIVE_INSERTION)) ?
+ ADD : DELETE;
+ break;
+ }
+ break;
}
/*
@@ -969,7 +999,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
break;
}
- device_config_needed = NOTHING;
+ if (device_config_needed == NOTHING)
for (container = 0; container < dev->maximum_num_containers;
++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) &&
@@ -978,6 +1008,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
device_config_needed =
dev->fsa_dev[container].config_needed;
dev->fsa_dev[container].config_needed = NOTHING;
+ channel = CONTAINER_TO_CHANNEL(container);
+ id = CONTAINER_TO_ID(container);
+ lun = CONTAINER_TO_LUN(container);
break;
}
}
@@ -1001,34 +1034,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
/*
* force reload of disk info via aac_probe_container
*/
- if ((device_config_needed == CHANGE)
- && (dev->fsa_dev[container].valid == 1))
- dev->fsa_dev[container].valid = 2;
- if ((device_config_needed == CHANGE) ||
- (device_config_needed == ADD))
+ if ((channel == CONTAINER_CHANNEL) &&
+ (device_config_needed != NOTHING)) {
+ if (dev->fsa_dev[container].valid == 1)
+ dev->fsa_dev[container].valid = 2;
aac_probe_container(dev, container);
- device = scsi_device_lookup(dev->scsi_host_ptr,
- CONTAINER_TO_CHANNEL(container),
- CONTAINER_TO_ID(container),
- CONTAINER_TO_LUN(container));
+ }
+ device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun);
if (device) {
switch (device_config_needed) {
case DELETE:
+ if (scsi_device_online(device)) {
+ scsi_device_set_state(device, SDEV_OFFLINE);
+ sdev_printk(KERN_INFO, device,
+ "Device offlined - %s\n",
+ (channel == CONTAINER_CHANNEL) ?
+ "array deleted" :
+ "enclosure services event");
+ }
+ break;
+ case ADD:
+ if (!scsi_device_online(device)) {
+ sdev_printk(KERN_INFO, device,
+ "Device online - %s\n",
+ (channel == CONTAINER_CHANNEL) ?
+ "array created" :
+ "enclosure services event");
+ scsi_device_set_state(device, SDEV_RUNNING);
+ }
+ /* FALLTHRU */
case CHANGE:
+ if ((channel == CONTAINER_CHANNEL)
+ && (!dev->fsa_dev[container].valid)) {
+ if (!scsi_device_online(device))
+ break;
+ scsi_device_set_state(device, SDEV_OFFLINE);
+ sdev_printk(KERN_INFO, device,
+ "Device offlined - %s\n",
+ "array failed");
+ break;
+ }
scsi_rescan_device(&device->sdev_gendev);
default:
break;
}
scsi_device_put(device);
+ device_config_needed = NOTHING;
}
- if (device_config_needed == ADD) {
- scsi_add_device(dev->scsi_host_ptr,
- CONTAINER_TO_CHANNEL(container),
- CONTAINER_TO_ID(container),
- CONTAINER_TO_LUN(container));
- }
-
+ if (device_config_needed == ADD)
+ scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
}
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
@@ -1469,7 +1524,6 @@ int aac_command_thread(void *data)
*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
aac_fib_adapter_complete(fib, (u16)sizeof(u32));
} else {
- struct list_head *entry;
/* The u32 here is important and intended. We are using
32bit wrapping time to fit the adapter field */