This patch adds support for SAS Management Protocol (SMP) passthrough support via bsg. Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> --- drivers/message/fusion/mptsas.c | 121 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 121 insertions(+), 0 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 1d2d03f..e5645ad 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1327,11 +1327,132 @@ mptsas_get_bay_identifier(struct sas_rphy *rphy) 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; + SmpPassthroughReply_t *smprep; + struct request *rsp = req->next_rq; + int ret, flagsLength; + unsigned long timeleft; + char *psge; + dma_addr_t dma_addr_in, dma_addr_out; + + if (!rsp) { + printk("%s: the smp response space is missing\n", __FUNCTION__); + return -EINVAL; + } + + /* do we need to support multiple segments? */ + if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { + printk("%s: multiple segments req %u %u, rsp %u %u\n", + __FUNCTION__, req->bio->bi_vcnt, req->data_len, + rsp->bio->bi_vcnt, rsp->data_len); + return -EINVAL; + } + + /* can we use this? */ + 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 = req->data_len - 4; + smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH; + + if (rphy) + memcpy(&smpreq->SASAddress, &rphy->identify.sas_address, + sizeof(smpreq->SASAddress)); + 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) + memcpy(&smpreq->SASAddress, + &(port_info->phy_info[0].phy->identify.sas_address), + sizeof(smpreq->SASAddress)); + mutex_unlock(&ioc->sas_topology_mutex); + } + + dma_addr_in = dma_addr_out = 0; + + 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 |= (rsp->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("%s: smp timeout!\n", __FUNCTION__); + /* On timeout reset the board */ + mpt_HardResetHandler(ioc, CAN_SLEEP); + ret = -ETIMEDOUT; + goto unmap; + } + mf = NULL; + + /* a reply frame is expected */ + if (!(ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID)) { + printk("%s: the smp response invalid!\n", __FUNCTION__); + ret = -ENXIO; + } + + smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; +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; -- 1.4.4.4 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html