[SCSI] fusion: add support for raid hot add/del support

RAID event support.

This will hot add and remove raid volumes
when managment application creates and
deletes the volumes.  The driver is basically
responding to firmware asyn events, and reporting
the changes to the above layers.

Signed-off-by: Eric Moore <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
Moore, Eric 2006-01-26 16:20:06 -07:00 committed by James Bottomley
parent d99ca4180f
commit c73787eecd
1 changed files with 173 additions and 25 deletions

View File

@ -89,6 +89,8 @@ static int mptsasMgmtCtx = -1;
enum mptsas_hotplug_action {
MPTSAS_ADD_DEVICE,
MPTSAS_DEL_DEVICE,
MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID,
};
struct mptsas_hotplug_event {
@ -114,6 +116,7 @@ struct mptsas_hotplug_event {
struct mptsas_devinfo {
u16 handle; /* unique id to address this device */
u16 handle_parent; /* unique id to address parent device */
u8 phy_id; /* phy number of parent device */
u8 port_id; /* sas physical port this device
is assoc'd with */
@ -714,6 +717,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
mptsas_print_device_pg0(buffer);
device_info->handle = le16_to_cpu(buffer->DevHandle);
device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
device_info->phy_id = buffer->PhyNum;
device_info->port_id = buffer->PhysicalPort;
device_info->id = buffer->TargetID;
@ -863,6 +867,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
return error;
}
/*
* Returns true if there is a scsi end device
*/
static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)
{
if ((attached->handle) &&
(attached->device_info &
MPI_SAS_DEVICE_INFO_END_DEVICE) &&
((attached->device_info &
MPI_SAS_DEVICE_INFO_SSP_TARGET) |
(attached->device_info &
MPI_SAS_DEVICE_INFO_STP_TARGET) |
(attached->device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
return 1;
else
return 0;
}
static void
mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info)
@ -1227,7 +1251,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
}
static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
{
struct mptsas_portinfo *port_info;
struct mptsas_phyinfo *phy_info = NULL;
@ -1239,12 +1263,12 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
*/
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) {
if (port_info->phy_info[i].attached.handle == handle) {
phy_info = &port_info->phy_info[i];
break;
}
}
for (i = 0; i < port_info->num_phys; i++)
if (mptsas_is_end_device(&port_info->phy_info[i].attached))
if (port_info->phy_info[i].attached.id == id) {
phy_info = &port_info->phy_info[i];
break;
}
}
mutex_unlock(&ioc->sas_topology_mutex);
@ -1258,36 +1282,58 @@ mptsas_hotplug_work(void *arg)
MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info;
struct sas_rphy *rphy;
struct scsi_device *sdev;
char *ds = NULL;
if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
struct mptsas_devinfo sas_device;
switch (ev->event_type) {
case MPTSAS_DEL_DEVICE:
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, ev->phy_id);
phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle);
phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
if (!phy_info) {
printk("mptsas: remove event for non-existant PHY.\n");
break;
}
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
if (phy_info->rphy) {
sas_rphy_delete(phy_info->rphy);
phy_info->rphy = NULL;
}
break;
case MPTSAS_ADD_DEVICE:
printk(MYIOC_s_INFO_FMT
"attaching %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, ev->phy_id);
/*
* When there is no sas address,
* RAID volumes are being deleted,
* and hidden phy disk are being added.
* We don't know the SAS data yet,
* so lookup sas device page to get
* pertaining info
*/
if (!ev->sas_address) {
if (mptsas_sas_device_pg0(ioc,
&sas_device, ev->id,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT)))
break;
ev->handle = sas_device.handle;
ev->parent_handle = sas_device.handle_parent;
ev->channel = sas_device.channel;
ev->phy_id = sas_device.phy_id;
ev->sas_address = sas_device.sas_address;
ev->device_info = sas_device.device_info;
}
phy_info = mptsas_find_phyinfo_by_parent(ioc,
ev->parent_handle, ev->phy_id);
@ -1310,10 +1356,23 @@ mptsas_hotplug_work(void *arg)
phy_info->attached.sas_address = ev->sas_address;
phy_info->attached.device_info = ev->device_info;
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
"attaching %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, ev->phy_id);
rphy = sas_rphy_alloc(phy_info->phy);
if (!rphy)
break; /* non-fatal: an rphy can be added later */
rphy->scsi_target_id = phy_info->attached.id;
mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
if (sas_rphy_add(rphy)) {
sas_rphy_free(rphy);
@ -1322,6 +1381,40 @@ mptsas_hotplug_work(void *arg)
phy_info->rphy = rphy;
break;
case MPTSAS_ADD_RAID:
sdev = scsi_device_lookup(
ioc->sh,
ioc->num_ports,
ev->id,
0);
if (sdev) {
scsi_device_put(sdev);
break;
}
printk(MYIOC_s_INFO_FMT
"attaching device, channel %d, id %d\n",
ioc->name, ioc->num_ports, ev->id);
scsi_add_device(ioc->sh,
ioc->num_ports,
ev->id,
0);
mpt_findImVolumes(ioc);
break;
case MPTSAS_DEL_RAID:
sdev = scsi_device_lookup(
ioc->sh,
ioc->num_ports,
ev->id,
0);
if (!sdev)
break;
printk(MYIOC_s_INFO_FMT
"removing device, channel %d, id %d\n",
ioc->name, ioc->num_ports, ev->id);
scsi_remove_device(sdev);
scsi_device_put(sdev);
mpt_findImVolumes(ioc);
break;
}
kfree(ev);
@ -1372,23 +1465,78 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
schedule_work(&ev->work);
}
static void
mptscsih_send_raid_event(MPT_ADAPTER *ioc,
EVENT_DATA_RAID *raid_event_data)
{
struct mptsas_hotplug_event *ev;
RAID_VOL0_STATUS * volumeStatus;
if (ioc->bus_type != SAS)
return;
ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
printk(KERN_WARNING "mptsas: lost hotplug event\n");
return;
}
memset(ev,0,sizeof(struct mptsas_hotplug_event));
INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
ev->ioc = ioc;
ev->id = raid_event_data->VolumeID;
switch (raid_event_data->ReasonCode) {
case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
ev->event_type = MPTSAS_ADD_DEVICE;
break;
case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
ev->event_type = MPTSAS_DEL_DEVICE;
break;
case MPI_EVENT_RAID_RC_VOLUME_DELETED:
ev->event_type = MPTSAS_DEL_RAID;
break;
case MPI_EVENT_RAID_RC_VOLUME_CREATED:
ev->event_type = MPTSAS_ADD_RAID;
break;
case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
volumeStatus = (RAID_VOL0_STATUS *) &
raid_event_data->SettingsStatus;
ev->event_type = (volumeStatus->State ==
MPI_RAIDVOL0_STATUS_STATE_FAILED) ?
MPTSAS_DEL_RAID : MPTSAS_ADD_RAID;
break;
default:
break;
}
schedule_work(&ev->work);
}
static int
mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{
int rc=1;
u8 event = le32_to_cpu(reply->Event) & 0xFF;
if (!ioc->sh)
return 1;
goto out;
switch (event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
mptscsih_send_sas_event(ioc,
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
return 1; /* currently means nothing really */
break;
case MPI_EVENT_INTEGRATED_RAID:
mptscsih_send_raid_event(ioc,
(EVENT_DATA_RAID *)reply->Data);
break;
default:
return mptscsih_event_process(ioc, reply);
rc = mptscsih_event_process(ioc, reply);
break;
}
out:
return rc;
}
static int