Skip to content

Commit

Permalink
scsi: scsi_transport_sas: switch to bsg-lib for SMP passthrough
Browse files Browse the repository at this point in the history
Simplify the SMP passthrough code by switching it to the generic bsg-lib
helpers that abstract away the details of the request code, and gets
drivers out of seeing struct scsi_request.

For the libsas host SMP code there is a small behavior difference in
that we now always clear the residual len for successful commands,
similar to the three other SMP handler implementations.  Given that
there is no partial command handling in the host SMP handler this should
not matter in practice.

[mkp: typos and checkpatch fixes]

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Johannes Thumshirn <[email protected]>
Signed-off-by: Martin K. Petersen <[email protected]>
  • Loading branch information
Christoph Hellwig authored and martinkpetersen committed Aug 30, 2017
1 parent eaa79a6 commit 651a013
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 380 deletions.
79 changes: 37 additions & 42 deletions drivers/message/fusion/mptsas.c
Original file line number Diff line number Diff line change
Expand Up @@ -2210,33 +2210,26 @@ 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)
static void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
struct sas_rphy *rphy)
{
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, __func__);
return -EINVAL;
}
unsigned int reslen = 0;
int ret = -EINVAL;

/* do we need to support multiple segments? */
if (bio_multiple_segments(req->bio) ||
bio_multiple_segments(rsp->bio)) {
if (job->request_payload.sg_cnt > 1 ||
job->reply_payload.sg_cnt > 1) {
printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
ioc->name, __func__, blk_rq_bytes(req), blk_rq_bytes(rsp));
return -EINVAL;
ioc->name, __func__, job->request_payload.payload_len,
job->reply_payload.payload_len);
goto out;
}

ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
Expand All @@ -2252,7 +2245,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
smpreq = (SmpPassthroughRequest_t *)mf;
memset(smpreq, 0, sizeof(*smpreq));

smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
smpreq->RequestDataLength =
cpu_to_le16(job->request_payload.payload_len - 4);
smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;

if (rphy)
Expand All @@ -2278,13 +2272,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_DIRECTION)
<< MPI_SGE_FLAGS_SHIFT;
flagsLength |= (blk_rq_bytes(req) - 4);

dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(ioc->pcidev, dma_addr_out))
if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list,
1, PCI_DMA_BIDIRECTIONAL))
goto put_mf;
ioc->add_sge(psge, flagsLength, dma_addr_out);

flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4);
ioc->add_sge(psge, flagsLength,
sg_dma_address(job->request_payload.sg_list));
psge += ioc->SGE_size;

/* response */
Expand All @@ -2294,12 +2289,13 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
MPI_SGE_FLAGS_END_OF_BUFFER;

flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
flagsLength |= blk_rq_bytes(rsp) + 4;
dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
if (pci_dma_mapping_error(ioc->pcidev, dma_addr_in))
goto unmap;
ioc->add_sge(psge, flagsLength, dma_addr_in);

if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list,
1, PCI_DMA_BIDIRECTIONAL))
goto unmap_out;
flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4;
ioc->add_sge(psge, flagsLength,
sg_dma_address(job->reply_payload.sg_list));

INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
Expand All @@ -2310,42 +2306,41 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
mpt_free_msg_frame(ioc, mf);
mf = NULL;
if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
goto unmap;
goto unmap_in;
if (!timeleft)
mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
goto unmap;
goto unmap_in;
}
mf = NULL;

if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
SmpPassthroughReply_t *smprep;

smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
memcpy(scsi_req(req)->sense, smprep, sizeof(*smprep));
scsi_req(req)->sense_len = sizeof(*smprep);
scsi_req(req)->resid_len = 0;
scsi_req(rsp)->resid_len -= smprep->ResponseDataLength;
memcpy(job->reply, smprep, sizeof(*smprep));
job->reply_len = sizeof(*smprep);
reslen = smprep->ResponseDataLength;
} else {
printk(MYIOC_s_ERR_FMT
"%s: smp passthru reply failed to be returned\n",
ioc->name, __func__);
ret = -ENXIO;
}
unmap:
if (dma_addr_out)
pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
PCI_DMA_BIDIRECTIONAL);
if (dma_addr_in)
pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
PCI_DMA_BIDIRECTIONAL);

unmap_in:
dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1,
PCI_DMA_BIDIRECTIONAL);
unmap_out:
dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1,
PCI_DMA_BIDIRECTIONAL);
put_mf:
if (mf)
mpt_free_msg_frame(ioc, mf);
out_unlock:
CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
mutex_unlock(&ioc->sas_mgmt.mutex);
out:
return ret;
bsg_job_done(job, ret, reslen);
}

static struct sas_function_template mptsas_transport_functions = {
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/libsas/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ config SCSI_SAS_LIBSAS
tristate "SAS Domain Transport Attributes"
depends on SCSI
select SCSI_SAS_ATTRS
select BLK_DEV_BSGLIB
help
This provides transport specific helpers for SAS drivers which
use the domain device construct (like the aic94xxx).
Expand Down
70 changes: 37 additions & 33 deletions drivers/scsi/libsas/sas_expander.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ static void smp_task_done(struct sas_task *task)
/* Give it some long enough timeout. In seconds. */
#define SMP_TIMEOUT 10

static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
void *resp, int resp_size)
static int smp_execute_task_sg(struct domain_device *dev,
struct scatterlist *req, struct scatterlist *resp)
{
int res, retry;
struct sas_task *task = NULL;
Expand All @@ -86,8 +86,8 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
}
task->dev = dev;
task->task_proto = dev->tproto;
sg_init_one(&task->smp_task.smp_req, req, req_size);
sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
task->smp_task.smp_req = *req;
task->smp_task.smp_resp = *resp;

task->task_done = smp_task_done;

Expand Down Expand Up @@ -151,6 +151,17 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
return res;
}

static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
void *resp, int resp_size)
{
struct scatterlist req_sg;
struct scatterlist resp_sg;

sg_init_one(&req_sg, req, req_size);
sg_init_one(&resp_sg, resp, resp_size);
return smp_execute_task_sg(dev, &req_sg, &resp_sg);
}

/* ---------- Allocations ---------- */

static inline void *alloc_smp_req(int size)
Expand Down Expand Up @@ -2130,57 +2141,50 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
return res;
}

int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
struct request *req)
void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
struct sas_rphy *rphy)
{
struct domain_device *dev;
int ret, type;
struct request *rsp = req->next_rq;

if (!rsp) {
printk("%s: space for a smp response is missing\n",
__func__);
return -EINVAL;
}
unsigned int reslen = 0;
int ret = -EINVAL;

/* no rphy means no smp target support (ie aic94xx host) */
if (!rphy)
return sas_smp_host_handler(shost, req, rsp);

type = rphy->identify.device_type;
return sas_smp_host_handler(job, shost);

if (type != SAS_EDGE_EXPANDER_DEVICE &&
type != SAS_FANOUT_EXPANDER_DEVICE) {
switch (rphy->identify.device_type) {
case SAS_EDGE_EXPANDER_DEVICE:
case SAS_FANOUT_EXPANDER_DEVICE:
break;
default:
printk("%s: can we send a smp request to a device?\n",
__func__);
return -EINVAL;
goto out;
}

dev = sas_find_dev_by_rphy(rphy);
if (!dev) {
printk("%s: fail to find a domain_device?\n", __func__);
return -EINVAL;
goto out;
}

/* do we need to support multiple segments? */
if (bio_multiple_segments(req->bio) ||
bio_multiple_segments(rsp->bio)) {
if (job->request_payload.sg_cnt > 1 ||
job->reply_payload.sg_cnt > 1) {
printk("%s: multiple segments req %u, rsp %u\n",
__func__, blk_rq_bytes(req), blk_rq_bytes(rsp));
return -EINVAL;
__func__, job->request_payload.payload_len,
job->reply_payload.payload_len);
goto out;
}

ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req),
bio_data(rsp->bio), blk_rq_bytes(rsp));
ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
job->reply_payload.sg_list);
if (ret > 0) {
/* positive number is the untransferred residual */
scsi_req(rsp)->resid_len = ret;
scsi_req(req)->resid_len = 0;
reslen = ret;
ret = 0;
} else if (ret == 0) {
scsi_req(rsp)->resid_len = 0;
scsi_req(req)->resid_len = 0;
}

return ret;
out:
bsg_job_done(job, ret, reslen);
}
Loading

0 comments on commit 651a013

Please sign in to comment.