📄 mptsas.c
字号:
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) { error = sas_phy_add(phy); if (error) { sas_phy_free(phy); goto out; } phy_info->phy = phy; } if (!phy_info->attached.handle || !phy_info->port_details) goto out; port = mptsas_get_port(phy_info); ioc = phy_to_ioc(phy_info->phy); if (phy_info->sas_port_add_phy) { if (!port) { port = sas_port_alloc_num(dev); if (!port) { error = -ENOMEM; goto out; } error = sas_port_add(port); if (error) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); goto out; } mptsas_set_port(ioc, phy_info, port); dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_alloc: port=%p dev=%p port_id=%d\n", ioc->name, port, dev, port->port_identifier)); } dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n", ioc->name, phy_info->phy_id)); sas_port_add_phy(port, phy_info->phy); phy_info->sas_port_add_phy = 0; } if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; struct device *parent; struct sas_identify identify; parent = dev->parent->parent; /* * 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)) goto out; mptsas_parse_device_info(&identify, &phy_info->attached); if (scsi_is_host_device(parent)) { struct mptsas_portinfo *port_info; int i; mutex_lock(&ioc->sas_topology_mutex); port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) if (port_info->phy_info[i].identify.sas_address == identify.sas_address) { sas_port_mark_backlink(port); goto out; } } else if (scsi_is_sas_rphy(parent)) { struct sas_rphy *parent_rphy = dev_to_rphy(parent); if (identify.sas_address == parent_rphy->identify.sas_address) { sas_port_mark_backlink(port); goto out; } } switch (identify.device_type) { case SAS_END_DEVICE: rphy = sas_end_device_alloc(port); break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: rphy = sas_expander_alloc(port, identify.device_type); break; default: rphy = NULL; break; } if (!rphy) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); goto out; } rphy->identify = identify; error = sas_rphy_add(rphy); if (error) { dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "%s: exit at line=%d\n", ioc->name, __FUNCTION__, __LINE__)); sas_rphy_free(rphy); goto out; } mptsas_set_rphy(ioc, phy_info, rphy); } out: return error;}static intmptsas_probe_hba_phys(MPT_ADAPTER *ioc){ struct mptsas_portinfo *port_info, *hba; 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; mptsas_sas_io_unit_pg1(ioc); mutex_lock(&ioc->sas_topology_mutex); ioc->handle = hba->phy_info[0].handle; port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); if (!port_info) { port_info = hba; list_add_tail(&port_info->list, &ioc->sas_topology); } else { for (i = 0; i < hba->num_phys; i++) { port_info->phy_info[i].negotiated_link_rate = hba->phy_info[i].negotiated_link_rate; port_info->phy_info[i].handle = hba->phy_info[i].handle; port_info->phy_info[i].port_id = hba->phy_info[i].port_id; } kfree(hba->phy_info); kfree(hba); hba = NULL; } 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_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].handle); port_info->phy_info[i].identify.phy_id = port_info->phy_info[i].phy_id = i; 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_setup_wide_ports(ioc, port_info); for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(&ioc->sh->shost_gendev, &port_info->phy_info[i], ioc->sas_index, 1); return 0; out_free_port_info: kfree(hba); out: return error;}static intmptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle){ struct mptsas_portinfo *port_info, *p, *ex; struct device *parent; struct sas_rphy *rphy; 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->phy_info[0].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 { for (i = 0; i < ex->num_phys; i++) { port_info->phy_info[i].handle = ex->phy_info[i].handle; port_info->phy_info[i].port_id = ex->phy_info[i].port_id; } kfree(ex->phy_info); kfree(ex); ex = NULL; } mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) { 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; } } parent = &ioc->sh->shost_gendev; for (i = 0; i < port_info->num_phys; i++) { 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) continue; rphy = mptsas_get_rphy(&p->phy_info[j]); parent = &rphy->dev; } } mutex_unlock(&ioc->sas_topology_mutex); } mptsas_setup_wide_ports(ioc, port_info); for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(parent, &port_info->phy_info[i], ioc->sas_index, 0); return 0; out_free_port_info: if (ex) { 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; struct mptsas_phyinfo *phy_info; struct sas_port * port; int i; u64 expander_sas_address; 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->phy_info[0].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; expander_sas_address = port_info->phy_info[0].identify.sas_address; /* * Delete rphys in the parent that point * to this expander. The transport layer will * cleanup all the children. */ phy_info = parent->phy_info; for (i = 0; i < parent->num_phys; i++, phy_info++) { port = mptsas_get_port(phy_info); if (!port) continue; if (phy_info->attached.sas_address != expander_sas_address) continue; dsaswideprintk(ioc, dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT "delete port (%d)\n", ioc->name, port->port_identifier)); sas_port_delete(port); mptsas_port_delete(ioc, phy_info->port_details); } next_port: phy_info = port_info->phy_info; for (i = 0; i < port_info->num_phys; i++, phy_info++) mptsas_port_delete(ioc, phy_info->port_details); list_del(&port_info->list); kfree(port_info->phy_info); kfree(port_info); } /* * Free this memory allocated from inside * mptsas_sas_expander_pg0 */ 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->ir_firmware) goto out; 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, MPTSAS_RAID_CHANNEL, 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 *(Mutex UNLOCKED) */static void__mptsas_discovery_work(MPT_ADAPTER *ioc){ u32 handle = 0xFFFF; 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;}/* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders *(Mutex LOCKED) */static voidmptsas_discovery_work(struct work_struct *work){ struct mptsas_discovery_event *ev = container_of(work, struct mptsas_discovery_event, work); MPT_ADAPTER *ioc = ev->ioc; mutex_lock(&ioc->sas_discovery_mutex); __mptsas_discovery_work(ioc); mutex_unlock(&ioc->sas_discovery_mutex); kfree(ev);}static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address){ struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; int i; 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)) continue; if (port_info->phy_info[i].attached.sas_address != sas_address) continue; 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, u8 channel, u8 id){ struct mptsas_portinfo *port_info; struct mptsas_phyinfo *phy_info = NULL; int i; 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_i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -