aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_expander.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2017-08-25 11:37:41 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2017-08-29 21:51:45 -0400
commit651a013649943710a900551ec6e03d2084e1a65a (patch)
tree14a92a3104c919eb439970de5471643b6f915ffc /drivers/scsi/libsas/sas_expander.c
parenteaa79a6cd733e1f978613a5fcf5f7c1cdb38eb2a (diff)
scsi: scsi_transport_sas: switch to bsg-lib for SMP passthrough
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 <hch@lst.de> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
-rw-r--r--drivers/scsi/libsas/sas_expander.c70
1 files changed, 37 insertions, 33 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 570b2cb2da43..6b4fd2375178 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -64,8 +64,8 @@ static void smp_task_done(struct sas_task *task)
64/* Give it some long enough timeout. In seconds. */ 64/* Give it some long enough timeout. In seconds. */
65#define SMP_TIMEOUT 10 65#define SMP_TIMEOUT 10
66 66
67static int smp_execute_task(struct domain_device *dev, void *req, int req_size, 67static int smp_execute_task_sg(struct domain_device *dev,
68 void *resp, int resp_size) 68 struct scatterlist *req, struct scatterlist *resp)
69{ 69{
70 int res, retry; 70 int res, retry;
71 struct sas_task *task = NULL; 71 struct sas_task *task = NULL;
@@ -86,8 +86,8 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
86 } 86 }
87 task->dev = dev; 87 task->dev = dev;
88 task->task_proto = dev->tproto; 88 task->task_proto = dev->tproto;
89 sg_init_one(&task->smp_task.smp_req, req, req_size); 89 task->smp_task.smp_req = *req;
90 sg_init_one(&task->smp_task.smp_resp, resp, resp_size); 90 task->smp_task.smp_resp = *resp;
91 91
92 task->task_done = smp_task_done; 92 task->task_done = smp_task_done;
93 93
@@ -151,6 +151,17 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
151 return res; 151 return res;
152} 152}
153 153
154static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
155 void *resp, int resp_size)
156{
157 struct scatterlist req_sg;
158 struct scatterlist resp_sg;
159
160 sg_init_one(&req_sg, req, req_size);
161 sg_init_one(&resp_sg, resp, resp_size);
162 return smp_execute_task_sg(dev, &req_sg, &resp_sg);
163}
164
154/* ---------- Allocations ---------- */ 165/* ---------- Allocations ---------- */
155 166
156static inline void *alloc_smp_req(int size) 167static inline void *alloc_smp_req(int size)
@@ -2130,57 +2141,50 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
2130 return res; 2141 return res;
2131} 2142}
2132 2143
2133int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, 2144void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
2134 struct request *req) 2145 struct sas_rphy *rphy)
2135{ 2146{
2136 struct domain_device *dev; 2147 struct domain_device *dev;
2137 int ret, type; 2148 unsigned int reslen = 0;
2138 struct request *rsp = req->next_rq; 2149 int ret = -EINVAL;
2139
2140 if (!rsp) {
2141 printk("%s: space for a smp response is missing\n",
2142 __func__);
2143 return -EINVAL;
2144 }
2145 2150
2146 /* no rphy means no smp target support (ie aic94xx host) */ 2151 /* no rphy means no smp target support (ie aic94xx host) */
2147 if (!rphy) 2152 if (!rphy)
2148 return sas_smp_host_handler(shost, req, rsp); 2153 return sas_smp_host_handler(job, shost);
2149
2150 type = rphy->identify.device_type;
2151 2154
2152 if (type != SAS_EDGE_EXPANDER_DEVICE && 2155 switch (rphy->identify.device_type) {
2153 type != SAS_FANOUT_EXPANDER_DEVICE) { 2156 case SAS_EDGE_EXPANDER_DEVICE:
2157 case SAS_FANOUT_EXPANDER_DEVICE:
2158 break;
2159 default:
2154 printk("%s: can we send a smp request to a device?\n", 2160 printk("%s: can we send a smp request to a device?\n",
2155 __func__); 2161 __func__);
2156 return -EINVAL; 2162 goto out;
2157 } 2163 }
2158 2164
2159 dev = sas_find_dev_by_rphy(rphy); 2165 dev = sas_find_dev_by_rphy(rphy);
2160 if (!dev) { 2166 if (!dev) {
2161 printk("%s: fail to find a domain_device?\n", __func__); 2167 printk("%s: fail to find a domain_device?\n", __func__);
2162 return -EINVAL; 2168 goto out;
2163 } 2169 }
2164 2170
2165 /* do we need to support multiple segments? */ 2171 /* do we need to support multiple segments? */
2166 if (bio_multiple_segments(req->bio) || 2172 if (job->request_payload.sg_cnt > 1 ||
2167 bio_multiple_segments(rsp->bio)) { 2173 job->reply_payload.sg_cnt > 1) {
2168 printk("%s: multiple segments req %u, rsp %u\n", 2174 printk("%s: multiple segments req %u, rsp %u\n",
2169 __func__, blk_rq_bytes(req), blk_rq_bytes(rsp)); 2175 __func__, job->request_payload.payload_len,
2170 return -EINVAL; 2176 job->reply_payload.payload_len);
2177 goto out;
2171 } 2178 }
2172 2179
2173 ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req), 2180 ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
2174 bio_data(rsp->bio), blk_rq_bytes(rsp)); 2181 job->reply_payload.sg_list);
2175 if (ret > 0) { 2182 if (ret > 0) {
2176 /* positive number is the untransferred residual */ 2183 /* positive number is the untransferred residual */
2177 scsi_req(rsp)->resid_len = ret; 2184 reslen = ret;
2178 scsi_req(req)->resid_len = 0;
2179 ret = 0; 2185 ret = 0;
2180 } else if (ret == 0) {
2181 scsi_req(rsp)->resid_len = 0;
2182 scsi_req(req)->resid_len = 0;
2183 } 2186 }
2184 2187
2185 return ret; 2188out:
2189 bsg_job_done(job, ret, reslen);
2186} 2190}