|
@@ -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
|