📄 mptsas.c
字号:
ConfigExtendedPageHeader_t hdr; CONFIGPARMS cfg; SasExpanderPage0_t *buffer; dma_addr_t dma_handle; int error; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 0; hdr.Reserved1 = 0; hdr.Reserved2 = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; cfg.cfghdr.ehdr = &hdr; cfg.physAddr = -1; cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ cfg.timeout = 10; memset(port_info, 0, sizeof(struct mptsas_portinfo)); error = mpt_config(ioc, &cfg); if (error) goto out; if (!hdr.ExtPageLength) { error = -ENXIO; goto out; } buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, &dma_handle); if (!buffer) { error = -ENOMEM; goto out; } cfg.physAddr = dma_handle; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); if (error) goto out_free_consistent; /* save config data */ port_info->num_phys = buffer->NumPhys; port_info->handle = le16_to_cpu(buffer->DevHandle); port_info->phy_info = kcalloc(port_info->num_phys, sizeof(struct mptsas_phyinfo),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); out: return error;}static intmptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, u32 form, u32 form_specific){ ConfigExtendedPageHeader_t hdr; CONFIGPARMS cfg; SasExpanderPage1_t *buffer; dma_addr_t dma_handle; int error=0; if (ioc->sas_discovery_runtime && mptsas_is_end_device(&phy_info->attached)) goto out; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 1; hdr.Reserved1 = 0; hdr.Reserved2 = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; cfg.cfghdr.ehdr = &hdr; cfg.physAddr = -1; cfg.pageAddr = form + form_specific; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ cfg.timeout = 10; error = mpt_config(ioc, &cfg); if (error) goto out; if (!hdr.ExtPageLength) { error = -ENXIO; goto out; } buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, &dma_handle); if (!buffer) { error = -ENOMEM; goto out; } cfg.physAddr = dma_handle; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; error = mpt_config(ioc, &cfg); if (error) goto out_free_consistent; mptsas_print_expander_pg1(buffer); /* save config data */ phy_info->phy_id = buffer->PhyIdentifier; phy_info->port_id = buffer->PhysicalPort; phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; phy_info->hw_link_rate = buffer->HwLinkRate; phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); out: return error;}static voidmptsas_parse_device_info(struct sas_identify *identify, struct mptsas_devinfo *device_info){ u16 protocols; identify->sas_address = device_info->sas_address; identify->phy_identifier = device_info->phy_id; /* * Fill in Phy Initiator Port Protocol. * Bits 6:3, more than one bit can be set, fall through cases. */ protocols = device_info->device_info & 0x78; identify->initiator_port_protocols = 0; if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) identify->initiator_port_protocols |= SAS_PROTOCOL_STP; if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; /* * Fill in Phy Target Port Protocol. * Bits 10:7, more than one bit can be set, fall through cases. */ protocols = device_info->device_info & 0x780; identify->target_port_protocols = 0; if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) identify->target_port_protocols |= SAS_PROTOCOL_SSP; if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) identify->target_port_protocols |= SAS_PROTOCOL_STP; if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) identify->target_port_protocols |= SAS_PROTOCOL_SMP; if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) identify->target_port_protocols |= SAS_PROTOCOL_SATA; /* * 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){ MPT_ADAPTER *ioc; struct sas_phy *phy; int error; if (!dev) return -ENODEV; if (!phy_info->phy) { phy = sas_phy_alloc(dev, index); if (!phy) return -ENOMEM; } else phy = phy_info->phy; 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 (!phy_info->phy) { 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) && (!phy_info->rphy)) { struct sas_rphy *rphy; struct sas_identify identify; ioc = phy_to_ioc(phy_info->phy); /* * Let the hotplug_work thread handle processing * the adding/removing of devices that occur * after start of day. */ if (ioc->sas_discovery_runtime && mptsas_is_end_device(&phy_info->attached)) return 0; mptsas_parse_device_info(&identify, &phy_info->attached); switch (identify.device_type) { case SAS_END_DEVICE: rphy = sas_end_device_alloc(phy); break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: rphy = sas_expander_alloc(phy, identify.device_type); break; default: rphy = NULL; break; } if (!rphy) return 0; /* non-fatal: an rphy can be added later */ rphy->identify = identify; 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){ struct mptsas_portinfo *port_info, *hba; u32 handle = 0xFFFF; int error = -ENOMEM, i; hba = kzalloc(sizeof(*port_info), GFP_KERNEL); if (! hba) goto out; error = mptsas_sas_io_unit_pg0(ioc, hba); if (error) goto out_free_port_info; mutex_lock(&ioc->sas_topology_mutex); port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); if (!port_info) { port_info = hba; list_add_tail(&port_info->list, &ioc->sas_topology); } else { port_info->handle = hba->handle; for (i = 0; i < hba->num_phys; i++) port_info->phy_info[i].negotiated_link_rate = hba->phy_info[i].negotiated_link_rate; if (hba->phy_info) kfree(hba->phy_info); kfree(hba); hba = NULL; } mutex_unlock(&ioc->sas_topology_mutex); ioc->num_ports = port_info->num_phys; 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], ioc->sas_index, 1); ioc->sas_index++; } return 0; out_free_port_info: if (hba) kfree(hba); out: return error;}static intmptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle){ struct mptsas_portinfo *port_info, *p, *ex; int error = -ENOMEM, i, j; ex = kzalloc(sizeof(*port_info), GFP_KERNEL); if (!ex) goto out; error = mptsas_sas_expander_pg0(ioc, ex, (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); if (error) goto out_free_port_info; *handle = ex->handle; mutex_lock(&ioc->sas_topology_mutex); port_info = mptsas_find_portinfo_by_handle(ioc, *handle); if (!port_info) { port_info = ex; list_add_tail(&port_info->list, &ioc->sas_topology); } else { port_info->handle = ex->handle; if (ex->phy_info) kfree(ex->phy_info); kfree(ex); ex = NULL; } 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); port_info->phy_info[i].attached.phy_id = port_info->phy_info[i].phy_id; } /* * If we find a parent port handle this expander is * attached to another expander, else it hangs of the * HBA phys.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -