Skip to content

Commit

Permalink
[SCSI] aacraid: handle AIF hotplug events (update)
Browse files Browse the repository at this point in the history
Received from Mark Salyzyn from Adaptec.

Hotplug sniffs the AIFs (events) from the adapter and if a container
change resulting in the device going offline (container zero), online
(container zero completed) or changing capacity (morph) it will take
actions by calling the appropriate API.

Signed-off-by: Mark Haverkamp <markh@osdl.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
  • Loading branch information
Mark Haverkamp authored and James Bottomley committed Sep 26, 2005
1 parent 2f13098 commit 131256c
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 2 deletions.
4 changes: 3 additions & 1 deletion drivers/scsi/aacraid/aachba.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
* is updated in the struct fsa_dev_info structure rather than returned.
*/

static int probe_container(struct aac_dev *dev, int cid)
int probe_container(struct aac_dev *dev, int cid)
{
struct fsa_dev_info *fsa_dev_ptr;
int status;
Expand Down Expand Up @@ -1471,6 +1471,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case TEST_UNIT_READY:
spin_unlock_irq(host->host_lock);
probe_container(dev, cid);
if ((fsa_dev_ptr[cid].valid & 1) == 0)
fsa_dev_ptr[cid].valid = 0;
spin_lock_irq(host->host_lock);
if (fsa_dev_ptr[cid].valid == 0) {
scsicmd->result = DID_NO_CONNECT << 16;
Expand Down
4 changes: 4 additions & 0 deletions drivers/scsi/aacraid/aacraid.h
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,9 @@ struct fsa_dev_info {
u64 last;
u64 size;
u32 type;
u32 config_waiting_on;
u16 queue_depth;
u8 config_needed;
u8 valid;
u8 ro;
u8 locked;
Expand Down Expand Up @@ -1715,6 +1717,7 @@ extern struct aac_common aac_config;
#define AifCmdJobProgress 2 /* Progress report */
#define AifJobCtrZero 101 /* Array Zero progress */
#define AifJobStsSuccess 1 /* Job completes */
#define AifJobStsRunning 102 /* Job running */
#define AifCmdAPIReport 3 /* Report from other user of API */
#define AifCmdDriverNotify 4 /* Notify host driver of event */
#define AifDenMorphComplete 200 /* A morph operation completed */
Expand Down Expand Up @@ -1785,6 +1788,7 @@ int fib_adapter_complete(struct fib * fibptr, unsigned short size);
struct aac_driver_ident* aac_get_driver_ident(int devtype);
int aac_get_adapter_info(struct aac_dev* dev);
int aac_send_shutdown(struct aac_dev *dev);
int probe_container(struct aac_dev *dev, int cid);
extern int numacb;
extern int acbsize;
extern char aac_driver_version[];
274 changes: 273 additions & 1 deletion drivers/scsi/aacraid/commsup.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <linux/completion.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <asm/semaphore.h>

#include "aacraid.h"
Expand Down Expand Up @@ -791,6 +792,268 @@ void aac_printf(struct aac_dev *dev, u32 val)
memset(cp, 0, 256);
}


/**
* aac_handle_aif - Handle a message from the firmware
* @dev: Which adapter this fib is from
* @fibptr: Pointer to fibptr from adapter
*
* This routine handles a driver notify fib from the adapter and
* dispatches it to the appropriate routine for handling.
*/

static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{
struct hw_fib * hw_fib = fibptr->hw_fib;
struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
int busy;
u32 container;
struct scsi_device *device;
enum {
NOTHING,
DELETE,
ADD,
CHANGE
} device_config_needed;

/* Sniff for container changes */

if (!dev)
return;
container = (u32)-1;

/*
* We have set this up to try and minimize the number of
* re-configures that take place. As a result of this when
* certain AIF's come in we will set a flag waiting for another
* type of AIF before setting the re-config flag.
*/
switch (le32_to_cpu(aifcmd->command)) {
case AifCmdDriverNotify:
switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
/*
* Morph or Expand complete
*/
case AifDenMorphComplete:
case AifDenVolumeExtendComplete:
container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
if (container >= dev->maximum_num_containers)
break;

/*
* Find the Scsi_Device associated with the SCSI
* address. Make sure we have the right array, and if
* so set the flag to initiate a new re-config once we
* see an AifEnConfigChange AIF come through.
*/

if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
device = scsi_device_lookup(dev->scsi_host_ptr,
CONTAINER_TO_CHANNEL(container),
CONTAINER_TO_ID(container),
CONTAINER_TO_LUN(container));
if (device) {
dev->fsa_dev[container].config_needed = CHANGE;
dev->fsa_dev[container].config_waiting_on = AifEnConfigChange;
scsi_device_put(device);
}
}
}

/*
* If we are waiting on something and this happens to be
* that thing then set the re-configure flag.
*/
if (container != (u32)-1) {
if (container >= dev->maximum_num_containers)
break;
if (dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data))
dev->fsa_dev[container].config_waiting_on = 0;
} else for (container = 0;
container < dev->maximum_num_containers; ++container) {
if (dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data))
dev->fsa_dev[container].config_waiting_on = 0;
}
break;

case AifCmdEventNotify:
switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
/*
* Add an Array.
*/
case AifEnAddContainer:
container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
if (container >= dev->maximum_num_containers)
break;
dev->fsa_dev[container].config_needed = ADD;
dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange;
break;

/*
* Delete an Array.
*/
case AifEnDeleteContainer:
container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
if (container >= dev->maximum_num_containers)
break;
dev->fsa_dev[container].config_needed = DELETE;
dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange;
break;

/*
* Container change detected. If we currently are not
* waiting on something else, setup to wait on a Config Change.
*/
case AifEnContainerChange:
container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
if (container >= dev->maximum_num_containers)
break;
if (dev->fsa_dev[container].config_waiting_on)
break;
dev->fsa_dev[container].config_needed = CHANGE;
dev->fsa_dev[container].config_waiting_on =
AifEnConfigChange;
break;

case AifEnConfigChange:
break;

}

/*
* If we are waiting on something and this happens to be
* that thing then set the re-configure flag.
*/
if (container != (u32)-1) {
if (container >= dev->maximum_num_containers)
break;
if (dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data))
dev->fsa_dev[container].config_waiting_on = 0;
} else for (container = 0;
container < dev->maximum_num_containers; ++container) {
if (dev->fsa_dev[container].config_waiting_on ==
le32_to_cpu(*(u32 *)aifcmd->data))
dev->fsa_dev[container].config_waiting_on = 0;
}
break;

case AifCmdJobProgress:
/*
* These are job progress AIF's. When a Clear is being
* done on a container it is initially created then hidden from
* the OS. When the clear completes we don't get a config
* change so we monitor the job status complete on a clear then
* wait for a container change.
*/

if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
&& ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
|| (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
for (container = 0;
container < dev->maximum_num_containers;
++container) {
/*
* Stomp on all config sequencing for all
* containers?
*/
dev->fsa_dev[container].config_waiting_on =
AifEnContainerChange;
dev->fsa_dev[container].config_needed = ADD;
}
}
if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
&& (((u32 *)aifcmd->data)[6] == 0)
&& (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
for (container = 0;
container < dev->maximum_num_containers;
++container) {
/*
* Stomp on all config sequencing for all
* containers?
*/
dev->fsa_dev[container].config_waiting_on =
AifEnContainerChange;
dev->fsa_dev[container].config_needed = DELETE;
}
}
break;
}

device_config_needed = NOTHING;
for (container = 0; container < dev->maximum_num_containers;
++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0)
&& (dev->fsa_dev[container].config_needed != NOTHING)) {
device_config_needed =
dev->fsa_dev[container].config_needed;
dev->fsa_dev[container].config_needed = NOTHING;
break;
}
}
if (device_config_needed == NOTHING)
return;

/*
* If we decided that a re-configuration needs to be done,
* schedule it here on the way out the door, please close the door
* behind you.
*/

busy = 0;


/*
* Find the Scsi_Device associated with the SCSI address,
* and mark it as changed, invalidating the cache. This deals
* with changes to existing device IDs.
*/

if (!dev || !dev->scsi_host_ptr)
return;
/*
* force reload of disk info via 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))
probe_container(dev, container);
device = scsi_device_lookup(dev->scsi_host_ptr,
CONTAINER_TO_CHANNEL(container),
CONTAINER_TO_ID(container),
CONTAINER_TO_LUN(container));
if (device) {
switch (device_config_needed) {
case DELETE:
scsi_remove_device(device);
break;
case CHANGE:
if (!dev->fsa_dev[container].valid) {
scsi_remove_device(device);
break;
}
scsi_rescan_device(&device->sdev_gendev);

default:
break;
}
scsi_device_put(device);
}
if (device_config_needed == ADD) {
scsi_add_device(dev->scsi_host_ptr,
CONTAINER_TO_CHANNEL(container),
CONTAINER_TO_ID(container),
CONTAINER_TO_LUN(container));
}

}

/**
* aac_command_thread - command processing thread
* @dev: Adapter to monitor
Expand Down Expand Up @@ -860,6 +1123,7 @@ int aac_command_thread(struct aac_dev * dev)
aifcmd = (struct aac_aifcmd *) hw_fib->data;
if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
/* Handle Driver Notify Events */
aac_handle_aif(dev, fib);
*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
fib_adapter_complete(fib, (u16)sizeof(u32));
} else {
Expand All @@ -872,7 +1136,15 @@ int aac_command_thread(struct aac_dev * dev)
unsigned num;
struct hw_fib ** hw_fib_pool, ** hw_fib_p;
struct fib ** fib_pool, ** fib_p;


/* Sniff events */
if ((aifcmd->command ==
cpu_to_le32(AifCmdEventNotify)) ||
(aifcmd->command ==
cpu_to_le32(AifCmdJobProgress))) {
aac_handle_aif(dev, fib);
}

time_now = jiffies/HZ;

/*
Expand Down

0 comments on commit 131256c

Please sign in to comment.