summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoore, Eric <Eric.Moore@lsil.com>2006-01-26 16:20:06 -0700
committerJames Bottomley <jejb@mulgrave.(none)>2006-01-31 14:39:37 -0600
commitc73787eecdbe4691d4e3f989052db8b552e1ac34 (patch)
treef5c53229a700edbc0f27a4fc203811032dcb1c02
parentd99ca4180fe44ae7f409fc73f1a09f270b8d458a (diff)
[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>
-rw-r--r--drivers/message/fusion/mptsas.c198
1 files changed, 173 insertions, 25 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 5a06d8d8694e..8e77837c07ec 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -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