summaryrefslogtreecommitdiffstats
path: root/drivers/message/fusion/mptsas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-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 5a06d8d8694..8e77837c07e 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