Commit c73787ee authored by Moore, Eric's avatar Moore, Eric Committed by James Bottomley

[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: default avatarEric Moore <Eric.Moore@lsil.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent d99ca418
...@@ -89,6 +89,8 @@ static int mptsasMgmtCtx = -1; ...@@ -89,6 +89,8 @@ static int mptsasMgmtCtx = -1;
enum mptsas_hotplug_action { enum mptsas_hotplug_action {
MPTSAS_ADD_DEVICE, MPTSAS_ADD_DEVICE,
MPTSAS_DEL_DEVICE, MPTSAS_DEL_DEVICE,
MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID,
}; };
struct mptsas_hotplug_event { struct mptsas_hotplug_event {
...@@ -114,6 +116,7 @@ struct mptsas_hotplug_event { ...@@ -114,6 +116,7 @@ struct mptsas_hotplug_event {
struct mptsas_devinfo { struct mptsas_devinfo {
u16 handle; /* unique id to address this device */ 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 phy_id; /* phy number of parent device */
u8 port_id; /* sas physical port this device u8 port_id; /* sas physical port this device
is assoc'd with */ is assoc'd with */
...@@ -714,6 +717,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, ...@@ -714,6 +717,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
mptsas_print_device_pg0(buffer); mptsas_print_device_pg0(buffer);
device_info->handle = le16_to_cpu(buffer->DevHandle); 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->phy_id = buffer->PhyNum;
device_info->port_id = buffer->PhysicalPort; device_info->port_id = buffer->PhysicalPort;
device_info->id = buffer->TargetID; device_info->id = buffer->TargetID;
...@@ -863,6 +867,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, ...@@ -863,6 +867,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
return error; 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 static void
mptsas_parse_device_info(struct sas_identify *identify, mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info) struct mptsas_devinfo *device_info)
...@@ -1227,7 +1251,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) ...@@ -1227,7 +1251,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
} }
static struct mptsas_phyinfo * 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_portinfo *port_info;
struct mptsas_phyinfo *phy_info = NULL; struct mptsas_phyinfo *phy_info = NULL;
...@@ -1239,13 +1263,13 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) ...@@ -1239,13 +1263,13 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
*/ */
mutex_lock(&ioc->sas_topology_mutex); mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) { list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) { for (i = 0; i < port_info->num_phys; i++)
if (port_info->phy_info[i].attached.handle == handle) { 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]; phy_info = &port_info->phy_info[i];
break; break;
} }
} }
}
mutex_unlock(&ioc->sas_topology_mutex); mutex_unlock(&ioc->sas_topology_mutex);
return phy_info; return phy_info;
...@@ -1258,36 +1282,58 @@ mptsas_hotplug_work(void *arg) ...@@ -1258,36 +1282,58 @@ mptsas_hotplug_work(void *arg)
MPT_ADAPTER *ioc = ev->ioc; MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info; struct mptsas_phyinfo *phy_info;
struct sas_rphy *rphy; struct sas_rphy *rphy;
struct scsi_device *sdev;
char *ds = NULL; char *ds = NULL;
struct mptsas_devinfo sas_device;
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";
switch (ev->event_type) { switch (ev->event_type) {
case MPTSAS_DEL_DEVICE: 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) { if (!phy_info) {
printk("mptsas: remove event for non-existant PHY.\n"); printk("mptsas: remove event for non-existant PHY.\n");
break; 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) { if (phy_info->rphy) {
sas_rphy_delete(phy_info->rphy); sas_rphy_delete(phy_info->rphy);
phy_info->rphy = NULL; phy_info->rphy = NULL;
} }
break; break;
case MPTSAS_ADD_DEVICE: 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, phy_info = mptsas_find_phyinfo_by_parent(ioc,
ev->parent_handle, ev->phy_id); ev->parent_handle, ev->phy_id);
...@@ -1310,10 +1356,23 @@ mptsas_hotplug_work(void *arg) ...@@ -1310,10 +1356,23 @@ mptsas_hotplug_work(void *arg)
phy_info->attached.sas_address = ev->sas_address; phy_info->attached.sas_address = ev->sas_address;
phy_info->attached.device_info = ev->device_info; 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); rphy = sas_rphy_alloc(phy_info->phy);
if (!rphy) if (!rphy)
break; /* non-fatal: an rphy can be added later */ 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); mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
if (sas_rphy_add(rphy)) { if (sas_rphy_add(rphy)) {
sas_rphy_free(rphy); sas_rphy_free(rphy);
...@@ -1322,6 +1381,40 @@ mptsas_hotplug_work(void *arg) ...@@ -1322,6 +1381,40 @@ mptsas_hotplug_work(void *arg)
phy_info->rphy = rphy; phy_info->rphy = rphy;
break; 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); kfree(ev);
...@@ -1372,23 +1465,78 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, ...@@ -1372,23 +1465,78 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
schedule_work(&ev->work); 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 static int
mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{ {
int rc=1;
u8 event = le32_to_cpu(reply->Event) & 0xFF; u8 event = le32_to_cpu(reply->Event) & 0xFF;
if (!ioc->sh) if (!ioc->sh)
return 1; goto out;
switch (event) { switch (event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
mptscsih_send_sas_event(ioc, mptscsih_send_sas_event(ioc,
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); (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: default:
return mptscsih_event_process(ioc, reply); rc = mptscsih_event_process(ioc, reply);
break;
} }
out:
return rc;
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment