📄 mptsas.c
字号:
*/ parent = &ioc->sh->shost_gendev; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(p, &ioc->sas_topology, list) { for (j = 0; j < p->num_phys; j++) { if (port_info->phy_info[i].identify.handle == p->phy_info[j].attached.handle) parent = &p->phy_info[j].rphy->dev; } } mutex_unlock(&ioc->sas_topology_mutex); mptsas_probe_one_phy(parent, &port_info->phy_info[i], ioc->sas_index, 0); ioc->sas_index++; } return 0; out_free_port_info: if (ex) { if (ex->phy_info) kfree(ex->phy_info); kfree(ex); } out: return error;}/* * mptsas_delete_expander_phys * * * This will traverse topology, and remove expanders * that are no longer present */static voidmptsas_delete_expander_phys(MPT_ADAPTER *ioc){ struct mptsas_portinfo buffer; struct mptsas_portinfo *port_info, *n, *parent; int i; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { if (port_info->phy_info && (!(port_info->phy_info[0].identify.device_info & MPI_SAS_DEVICE_INFO_SMP_TARGET))) continue; if (mptsas_sas_expander_pg0(ioc, &buffer, (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { /* * Obtain the port_info instance to the parent port */ parent = mptsas_find_portinfo_by_handle(ioc, port_info->phy_info[0].identify.handle_parent); if (!parent) goto next_port; /* * Delete rphys in the parent that point * to this expander. The transport layer will * cleanup all the children. */ for (i = 0; i < parent->num_phys; i++) { if ((!parent->phy_info[i].rphy) || (parent->phy_info[i].attached.sas_address != port_info->phy_info[i].identify.sas_address)) continue; sas_rphy_delete(parent->phy_info[i].rphy); memset(&parent->phy_info[i].attached, 0, sizeof(struct mptsas_devinfo)); parent->phy_info[i].rphy = NULL; parent->phy_info[i].starget = NULL; } next_port: list_del(&port_info->list); if (port_info->phy_info) kfree(port_info->phy_info); kfree(port_info); } /* * Free this memory allocated from inside * mptsas_sas_expander_pg0 */ if (buffer.phy_info) kfree(buffer.phy_info); } mutex_unlock(&ioc->sas_topology_mutex);}/* * Start of day discovery */static voidmptsas_scan_sas_topology(MPT_ADAPTER *ioc){ u32 handle = 0xFFFF; int i; mutex_lock(&ioc->sas_discovery_mutex); mptsas_probe_hba_phys(ioc); while (!mptsas_probe_expander_phys(ioc, &handle)) ; /* Reporting RAID volumes. */ if (!ioc->raid_data.pIocPg2) goto out; if (!ioc->raid_data.pIocPg2->NumActiveVolumes) goto out; for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { scsi_add_device(ioc->sh, ioc->num_ports, ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); } out: mutex_unlock(&ioc->sas_discovery_mutex);}/* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders */static voidmptscsih_discovery_work(void * arg){ struct mptsas_discovery_event *ev = arg; MPT_ADAPTER *ioc = ev->ioc; u32 handle = 0xFFFF; mutex_lock(&ioc->sas_discovery_mutex); ioc->sas_discovery_runtime=1; mptsas_delete_expander_phys(ioc); mptsas_probe_hba_phys(ioc); while (!mptsas_probe_expander_phys(ioc, &handle)) ; kfree(ev); ioc->sas_discovery_runtime=0; mutex_unlock(&ioc->sas_discovery_mutex);}static struct mptsas_phyinfo *mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id){ struct mptsas_portinfo *port_info; struct mptsas_devinfo device_info; struct mptsas_phyinfo *phy_info = NULL; int i, error; /* * Retrieve the parent sas_address */ error = mptsas_sas_device_pg0(ioc, &device_info, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), parent_handle); if (error) return NULL; /* * The phy_info structures are never deallocated during lifetime of * a host, so the code below is safe without additional refcounting. */ 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].identify.sas_address == device_info.sas_address && port_info->phy_info[i].phy_id == phy_id) { phy_info = &port_info->phy_info[i]; break; } } } mutex_unlock(&ioc->sas_topology_mutex); return phy_info;}static struct mptsas_phyinfo *mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id){ struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; int i; /* * The phy_info structures are never deallocated during lifetime of * a host, so the code below is safe without additional refcounting. */ 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 (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); return phy_info;}/* * Work queue thread to clear the persitency table */static voidmptscsih_sas_persist_clear_table(void * arg){ MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);}static voidmptsas_reprobe_lun(struct scsi_device *sdev, void *data){ sdev->no_uld_attach = data ? 1 : 0; scsi_device_reprobe(sdev);}static voidmptsas_reprobe_target(struct scsi_target *starget, int uld_attach){ starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, mptsas_reprobe_lun);}/* * Work queue thread to handle SAS hotplug events */static voidmptsas_hotplug_work(void *arg){ struct mptsas_hotplug_event *ev = arg; MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; struct scsi_device *sdev; struct sas_identify identify; char *ds = NULL; struct mptsas_devinfo sas_device; VirtTarget *vtarget; mutex_lock(&ioc->sas_discovery_mutex); switch (ev->event_type) { case MPTSAS_DEL_DEVICE: phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); /* * Sanity checks, for non-existing phys and remote rphys. */ if (!phy_info) break; if (!phy_info->rphy) break; if (phy_info->starget) { vtarget = phy_info->starget->hostdata; if (!vtarget) break; /* * Handling RAID components */ if (ev->phys_disk_num_valid) { vtarget->target_id = ev->phys_disk_num; vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; mptsas_reprobe_target(vtarget->starget, 1); 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); sas_rphy_delete(phy_info->rphy); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); phy_info->rphy = NULL; phy_info->starget = NULL; break; case MPTSAS_ADD_DEVICE: if (ev->phys_disk_num_valid) mpt_findImVolumes(ioc); /* * Refresh sas device pg0 data */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) break; phy_info = mptsas_find_phyinfo_by_parent(ioc, sas_device.handle_parent, sas_device.phy_id); if (!phy_info) { u32 handle = 0xFFFF; /* * Its possible when an expander has been hot added * containing attached devices, the sas firmware * may send a RC_ADDED event prior to the * DISCOVERY STOP event. If that occurs, our * view of the topology in the driver in respect to this * expander might of not been setup, and we hit this * condition. * Therefore, this code kicks off discovery to * refresh the data. * Then again, we check whether the parent phy has * been created. */ ioc->sas_discovery_runtime=1; mptsas_delete_expander_phys(ioc); mptsas_probe_hba_phys(ioc); while (!mptsas_probe_expander_phys(ioc, &handle)) ; ioc->sas_discovery_runtime=0; phy_info = mptsas_find_phyinfo_by_parent(ioc, sas_device.handle_parent, sas_device.phy_id); if (!phy_info) break; } if (phy_info->starget) { vtarget = phy_info->starget->hostdata; if (!vtarget) break; /* * Handling RAID components */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; vtarget->target_id = ev->id; mptsas_reprobe_target(phy_info->starget, 0); } break; } if (phy_info->rphy) break; memcpy(&phy_info->attached, &sas_device, sizeof(struct mptsas_devinfo)); 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); mptsas_parse_device_info(&identify, &phy_info->attached); switch (identify.device_type) { case SAS_END_DEVICE: rphy = sas_end_device_alloc(phy_info->phy); break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: rphy = sas_expander_alloc(phy_info->phy, identify.device_type); break; default: rphy = NULL; break; } if (!rphy) break; /* non-fatal: an rphy can be added later */ rphy->identify = identify; if (sas_rphy_add(rphy)) { sas_rphy_free(rphy); break; } 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 raid volume, 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 raid volume, channel %d, id %d\n", ioc->name, ioc->num_ports, ev->id); scsi_remove_device(sdev); scsi_device_put(sdev); mpt_findImVolumes(ioc); break; case MPTSAS_IGNORE_EVENT: default: break; } kfree(ev); mutex_unlock(&ioc->sas_discovery_mutex);}static voidmptscsih_send_sas_event(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data){ struct mptsas_hotplug_event *ev; u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); __le64 sas_address; if ((device_info & (MPI_SAS_DEVICE_INFO_SSP_TARGET | MPI_SAS_DEVICE_INFO_STP_TARGET | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) return; switch (sas_event_data->ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: ev = kmalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); break; } INIT_WORK(&ev->work, mptsas_hotplug_work, ev); ev->ioc = ioc; ev->handle = le16_to_cpu(sas_event_data->DevHandle); ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle); ev->channel = sas_event_data->Bus; ev->id = sas_event_data->TargetID; ev->phy_id = sas_event_data->PhyNum; memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64)); ev->sas_address = le64_to_cpu(sas_address); ev->device_info = device_info; if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) ev->event_type = MPTSAS_ADD_DEVICE; else ev->event_type = MPTSAS_DEL_DEVICE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -