diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 5a06d8d8694eb3cff0322e479a089ffb5d7021c1..8e77837c07ec4e983618149596740883766091b4 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