aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_expander.c
diff options
context:
space:
mode:
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}