📄 mptsas.c
字号:
vdevice->lun = sdev->lun; /* * Exposing hidden raid components */ if (mptscsih_is_phys_disk(ioc, p->phy_info[i].attached.channel, p->phy_info[i].attached.id)) sdev->no_uld_attach = 1; mutex_unlock(&ioc->sas_topology_mutex); goto out; } } mutex_unlock(&ioc->sas_topology_mutex); kfree(vdevice); return -ENXIO; out: vdevice->vtarget->num_luns++; sdev->hostdata = vdevice; return 0;}static intmptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){ VirtDevice *vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) { SCpnt->result = DID_NO_CONNECT << 16; done(SCpnt); return 0; }// scsi_print_command(SCpnt); return mptscsih_qcmd(SCpnt,done);}static struct scsi_host_template mptsas_driver_template = { .module = THIS_MODULE, .proc_name = "mptsas", .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, .queuecommand = mptsas_qcmd, .target_alloc = mptsas_target_alloc, .slave_alloc = mptsas_slave_alloc, .slave_configure = mptsas_slave_configure, .target_destroy = mptsas_target_destroy, .slave_destroy = mptscsih_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, .eh_bus_reset_handler = mptscsih_bus_reset, .eh_host_reset_handler = mptscsih_host_reset, .bios_param = mptscsih_bios_param, .can_queue = MPT_FC_CAN_QUEUE, .this_id = -1, .sg_tablesize = MPT_SCSI_SG_DEPTH, .max_sectors = 8192, .cmd_per_lun = 7, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = mptscsih_host_attrs,};static int mptsas_get_linkerrors(struct sas_phy *phy){ MPT_ADAPTER *ioc = phy_to_ioc(phy); ConfigExtendedPageHeader_t hdr; CONFIGPARMS cfg; SasPhyPage1_t *buffer; dma_addr_t dma_handle; int error; /* FIXME: only have link errors on local phys */ if (!scsi_is_sas_phy_local(phy)) return -EINVAL; hdr.PageVersion = MPI_SASPHY1_PAGEVERSION; hdr.ExtPageLength = 0; hdr.PageNumber = 1 /* page number 1*/; hdr.Reserved1 = 0; hdr.Reserved2 = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; cfg.cfghdr.ehdr = &hdr; cfg.physAddr = -1; cfg.pageAddr = phy->identify.phy_identifier; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; /* read */ cfg.timeout = 10; error = mpt_config(ioc, &cfg); if (error) return error; if (!hdr.ExtPageLength) return -ENXIO; buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, &dma_handle); if (!buffer) return -ENOMEM; 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_phy_pg1(ioc, buffer); phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount); phy->running_disparity_error_count = le32_to_cpu(buffer->RunningDisparityErrorCount); phy->loss_of_dword_sync_count = le32_to_cpu(buffer->LossDwordSynchCount); phy->phy_reset_problem_count = le32_to_cpu(buffer->PhyResetProblemCount); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); return error;}static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply){ ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; if (reply != NULL) { ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; memcpy(ioc->sas_mgmt.reply, reply, min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); } complete(&ioc->sas_mgmt.done); return 1;}static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset){ MPT_ADAPTER *ioc = phy_to_ioc(phy); SasIoUnitControlRequest_t *req; SasIoUnitControlReply_t *reply; MPT_FRAME_HDR *mf; MPIHeader_t *hdr; unsigned long timeleft; int error = -ERESTARTSYS; /* FIXME: fusion doesn't allow non-local phy reset */ if (!scsi_is_sas_phy_local(phy)) return -EINVAL; /* not implemented for expanders */ if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) return -ENXIO; if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex)) goto out; mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); if (!mf) { error = -ENOMEM; goto out_unlock; } hdr = (MPIHeader_t *) mf; req = (SasIoUnitControlRequest_t *)mf; memset(req, 0, sizeof(SasIoUnitControlRequest_t)); req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; req->MsgContext = hdr->MsgContext; req->Operation = hard_reset ? MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; req->PhyNum = phy->identify.phy_identifier; mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); if (!timeleft) { /* On timeout reset the board */ mpt_free_msg_frame(ioc, mf); mpt_HardResetHandler(ioc, CAN_SLEEP); error = -ETIMEDOUT; goto out_unlock; } /* a reply frame is expected */ if ((ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) == 0) { error = -ENXIO; goto out_unlock; } /* process the completed Reply Message Frame */ reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo); error = -ENXIO; goto out_unlock; } error = 0; out_unlock: mutex_unlock(&ioc->sas_mgmt.mutex); out: return error;}static intmptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier){ MPT_ADAPTER *ioc = rphy_to_ioc(rphy); int i, error; struct mptsas_portinfo *p; struct mptsas_enclosure enclosure_info; u64 enclosure_handle; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address == rphy->identify.sas_address) { enclosure_handle = p->phy_info[i]. attached.handle_enclosure; goto found_info; } } } mutex_unlock(&ioc->sas_topology_mutex); return -ENXIO; found_info: mutex_unlock(&ioc->sas_topology_mutex); memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); if (!error) *identifier = enclosure_info.enclosure_logical_id; return error;}static intmptsas_get_bay_identifier(struct sas_rphy *rphy){ MPT_ADAPTER *ioc = rphy_to_ioc(rphy); struct mptsas_portinfo *p; int i, rc; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(p, &ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { if (p->phy_info[i].attached.sas_address == rphy->identify.sas_address) { rc = p->phy_info[i].attached.slot; goto out; } } } rc = -ENXIO; out: mutex_unlock(&ioc->sas_topology_mutex); return rc;}static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct request *req){ MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc; MPT_FRAME_HDR *mf; SmpPassthroughRequest_t *smpreq; struct request *rsp = req->next_rq; int ret; int flagsLength; unsigned long timeleft; char *psge; dma_addr_t dma_addr_in = 0; dma_addr_t dma_addr_out = 0; u64 sas_address = 0; if (!rsp) { printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n", ioc->name, __FUNCTION__); return -EINVAL; } /* do we need to support multiple segments? */ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len, rsp->bio->bi_vcnt, rsp->data_len); return -EINVAL; } ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex); if (ret) goto out; mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); if (!mf) { ret = -ENOMEM; goto out_unlock; } smpreq = (SmpPassthroughRequest_t *)mf; memset(smpreq, 0, sizeof(*smpreq)); smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4); smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; if (rphy) sas_address = rphy->identify.sas_address; else { struct mptsas_portinfo *port_info; mutex_lock(&ioc->sas_topology_mutex); port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle); if (port_info && port_info->phy_info) sas_address = port_info->phy_info[0].phy->identify.sas_address; mutex_unlock(&ioc->sas_topology_mutex); } *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address); psge = (char *) (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4)); /* request */ flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT; flagsLength |= (req->data_len - 4); dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio), req->data_len, PCI_DMA_BIDIRECTIONAL); if (!dma_addr_out) goto put_mf; mpt_add_sge(psge, flagsLength, dma_addr_out); psge += (sizeof(u32) + sizeof(dma_addr_t)); /* response */ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= rsp->data_len + 4; dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio), rsp->data_len, PCI_DMA_BIDIRECTIONAL); if (!dma_addr_in) goto unmap; mpt_add_sge(psge, flagsLength, dma_addr_in); mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ); if (!timeleft) { printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__); /* On timeout reset the board */ mpt_HardResetHandler(ioc, CAN_SLEEP); ret = -ETIMEDOUT; goto unmap; } mf = NULL; if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) { SmpPassthroughReply_t *smprep; smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", ioc->name, __FUNCTION__); ret = -ENXIO; }unmap: if (dma_addr_out) pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len, PCI_DMA_BIDIRECTIONAL); if (dma_addr_in) pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len, PCI_DMA_BIDIRECTIONAL);put_mf: if (mf) mpt_free_msg_frame(ioc, mf);out_unlock: mutex_unlock(&ioc->sas_mgmt.mutex);out: return ret;}static struct sas_function_template mptsas_transport_functions = { .get_linkerrors = mptsas_get_linkerrors, .get_enclosure_identifier = mptsas_get_enclosure_identifier, .get_bay_identifier = mptsas_get_bay_identifier, .phy_reset = mptsas_phy_reset, .smp_handler = mptsas_smp_handler,};static struct scsi_transport_template *mptsas_transport_template;static intmptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info){ ConfigExtendedPageHeader_t hdr; CONFIGPARMS cfg; SasIOUnitPage0_t *buffer; dma_addr_t dma_handle; int error, i; hdr.PageVersion = MPI_SASIOUNITPAGE0_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_IO_UNIT; cfg.cfghdr.ehdr = &hdr; cfg.physAddr = -1; cfg.pageAddr = 0; 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; port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } ioc->nvdata_version_persistent = le16_to_cpu(buffer->NvdataVersionPersistent); ioc->nvdata_version_default = le16_to_cpu(buffer->NvdataVersionDefault); for (i = 0; i < port_info->num_phys; i++) { mptsas_print_phy_data(ioc, &buffer->PhyData[i]); port_info->phy_info[i].phy_id = i; port_info->phy_info[i].port_id = buffer->PhyData[i].Port; port_info->phy_info[i].negotiated_link_rate = buffer->PhyData[i].NegotiatedLinkRate; port_info->phy_info[i].portinfo = port_info; port_info->phy_info[i].handle = le16_to_cpu(buffer->PhyData[i].ControllerDevHandle); } out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); out: return error;}static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -