📄 mptsas.c
字号:
* Fill in Attached device type. */ switch (device_info->device_info & MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { case MPI_SAS_DEVICE_INFO_NO_DEVICE: identify->device_type = SAS_PHY_UNUSED; break; case MPI_SAS_DEVICE_INFO_END_DEVICE: identify->device_type = SAS_END_DEVICE; break; case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: identify->device_type = SAS_EDGE_EXPANDER_DEVICE; break; case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; break; }}static int mptsas_probe_one_phy(struct device *dev, struct mptsas_phyinfo *phy_info, int index, int local){ struct sas_phy *phy; int error; phy = sas_phy_alloc(dev, index); if (!phy) return -ENOMEM; phy->port_identifier = phy_info->port_id; mptsas_parse_device_info(&phy->identify, &phy_info->identify); /* * Set Negotiated link rate. */ switch (phy_info->negotiated_link_rate) { case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: phy->negotiated_linkrate = SAS_PHY_DISABLED; break; case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; break; case MPI_SAS_IOUNIT0_RATE_1_5: phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; break; case MPI_SAS_IOUNIT0_RATE_3_0: phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; break; case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: case MPI_SAS_IOUNIT0_RATE_UNKNOWN: default: phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; break; } /* * Set Max hardware link rate. */ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; break; case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; break; default: break; } /* * Set Max programmed link rate. */ switch (phy_info->programmed_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; break; case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; break; default: break; } /* * Set Min hardware link rate. */ switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; break; case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; break; default: break; } /* * Set Min programmed link rate. */ switch (phy_info->programmed_link_rate & MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; break; case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; break; default: break; } if (local) phy->local_attached = 1; error = sas_phy_add(phy); if (error) { sas_phy_free(phy); return error; } phy_info->phy = phy; if (phy_info->attached.handle) { struct sas_rphy *rphy; rphy = sas_rphy_alloc(phy); if (!rphy) return 0; /* non-fatal: an rphy can be added later */ mptsas_parse_device_info(&rphy->identify, &phy_info->attached); error = sas_rphy_add(rphy); if (error) { sas_rphy_free(rphy); return error; } phy_info->rphy = rphy; } return 0;}static intmptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index){ struct mptsas_portinfo *port_info; u32 handle = 0xFFFF; int error = -ENOMEM, i; port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); if (!port_info) goto out; error = mptsas_sas_io_unit_pg0(ioc, port_info); if (error) goto out_free_port_info; ioc->num_ports = port_info->num_phys; mutex_lock(&ioc->sas_topology_mutex); list_add_tail(&port_info->list, &ioc->sas_topology); mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) { mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << MPI_SAS_PHY_PGAD_FORM_SHIFT), i); mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle); port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id; handle = port_info->phy_info[i].identify.handle; if (port_info->phy_info[i].attached.handle) { mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].attached, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].attached.handle); } mptsas_probe_one_phy(&ioc->sh->shost_gendev, &port_info->phy_info[i], *index, 1); (*index)++; } return 0; out_free_port_info: kfree(port_info); out: return error;}static intmptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index){ struct mptsas_portinfo *port_info, *p; int error = -ENOMEM, i, j; port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); if (!port_info) goto out; error = mptsas_sas_expander_pg0(ioc, port_info, (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); if (error) goto out_free_port_info; *handle = port_info->handle; mutex_lock(&ioc->sas_topology_mutex); list_add_tail(&port_info->list, &ioc->sas_topology); mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) { struct device *parent; mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); if (port_info->phy_info[i].identify.handle) { mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].identify.handle); port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id; } if (port_info->phy_info[i].attached.handle) { mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].attached, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].attached.handle); } /* * If we find a parent port handle this expander is * attached to another expander, else it hangs of the * HBA phys. */ 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], *index, 0); (*index)++; } return 0; out_free_port_info: kfree(port_info); out: return error;}static voidmptsas_scan_sas_topology(MPT_ADAPTER *ioc){ u32 handle = 0xFFFF; int index = 0; mptsas_probe_hba_phys(ioc, &index); while (!mptsas_probe_expander_phys(ioc, &handle, &index)) ;}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) { printk("mptsas: failed to retrieve device page\n"); 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;}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; char *ds = NULL; struct mptsas_devinfo sas_device; switch (ev->event_type) { case MPTSAS_DEL_DEVICE: 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: /* * 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); if (!phy_info) { printk("mptsas: add event for non-existant PHY.\n"); break; } if (phy_info->rphy) { printk("mptsas: trying to add existing device.\n"); break; } /* fill attached info */ phy_info->attached.handle = ev->handle; phy_info->attached.phy_id = ev->phy_id; phy_info->attached.port_id = phy_info->identify.port_id; phy_info->attached.id = ev->id; phy_info->attached.channel = ev->channel; 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); 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 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(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -