diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 70 |
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 | ||
67 | static int smp_execute_task(struct domain_device *dev, void *req, int req_size, | 67 | static 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 | ||
154 | static 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 | ||
156 | static inline void *alloc_smp_req(int size) | 167 | static 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 | ||
2133 | int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | 2144 | void 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; | 2188 | out: |
2189 | bsg_job_done(job, ret, reslen); | ||
2186 | } | 2190 | } |