diff options
Diffstat (limited to 'drivers/scsi')
| -rw-r--r-- | drivers/scsi/libsas/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 70 | ||||
| -rw-r--r-- | drivers/scsi/libsas/sas_host_smp.c | 106 | ||||
| -rw-r--r-- | drivers/scsi/libsas/sas_internal.h | 12 | ||||
| -rw-r--r-- | drivers/scsi/mpt3sas/mpt3sas_transport.c | 230 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 118 |
6 files changed, 203 insertions, 334 deletions
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig index 9dafe64e7c7a..13739bfacc67 100644 --- a/drivers/scsi/libsas/Kconfig +++ b/drivers/scsi/libsas/Kconfig | |||
| @@ -26,6 +26,7 @@ config SCSI_SAS_LIBSAS | |||
| 26 | tristate "SAS Domain Transport Attributes" | 26 | tristate "SAS Domain Transport Attributes" |
| 27 | depends on SCSI | 27 | depends on SCSI |
| 28 | select SCSI_SAS_ATTRS | 28 | select SCSI_SAS_ATTRS |
| 29 | select BLK_DEV_BSGLIB | ||
| 29 | help | 30 | help |
| 30 | This provides transport specific helpers for SAS drivers which | 31 | This provides transport specific helpers for SAS drivers which |
| 31 | use the domain device construct (like the aic94xxx). | 32 | use the domain device construct (like the aic94xxx). |
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 | } |
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index 45cbbc44f4d7..9ead93df3a6e 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c | |||
| @@ -225,47 +225,36 @@ static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id, | |||
| 225 | resp_data[2] = SMP_RESP_FUNC_ACC; | 225 | resp_data[2] = SMP_RESP_FUNC_ACC; |
| 226 | } | 226 | } |
| 227 | 227 | ||
| 228 | int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | 228 | void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost) |
| 229 | struct request *rsp) | ||
| 230 | { | 229 | { |
| 231 | u8 *req_data = NULL, *resp_data = NULL, *buf; | ||
| 232 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | 230 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); |
| 231 | u8 *req_data, *resp_data; | ||
| 232 | unsigned int reslen = 0; | ||
| 233 | int error = -EINVAL; | 233 | int error = -EINVAL; |
| 234 | 234 | ||
| 235 | /* eight is the minimum size for request and response frames */ | 235 | /* eight is the minimum size for request and response frames */ |
| 236 | if (blk_rq_bytes(req) < 8 || blk_rq_bytes(rsp) < 8) | 236 | if (job->request_payload.payload_len < 8 || |
| 237 | job->reply_payload.payload_len < 8) | ||
| 237 | goto out; | 238 | goto out; |
| 238 | 239 | ||
| 239 | if (bio_offset(req->bio) + blk_rq_bytes(req) > PAGE_SIZE || | 240 | error = -ENOMEM; |
| 240 | bio_offset(rsp->bio) + blk_rq_bytes(rsp) > PAGE_SIZE) { | 241 | req_data = kzalloc(job->request_payload.payload_len, GFP_KERNEL); |
| 241 | shost_printk(KERN_ERR, shost, | 242 | if (!req_data) |
| 242 | "SMP request/response frame crosses page boundary"); | ||
| 243 | goto out; | 243 | goto out; |
| 244 | } | 244 | sg_copy_to_buffer(job->request_payload.sg_list, |
| 245 | 245 | job->request_payload.sg_cnt, req_data, | |
| 246 | req_data = kzalloc(blk_rq_bytes(req), GFP_KERNEL); | 246 | job->request_payload.payload_len); |
| 247 | 247 | ||
| 248 | /* make sure frame can always be built ... we copy | 248 | /* make sure frame can always be built ... we copy |
| 249 | * back only the requested length */ | 249 | * back only the requested length */ |
| 250 | resp_data = kzalloc(max(blk_rq_bytes(rsp), 128U), GFP_KERNEL); | 250 | resp_data = kzalloc(max(job->reply_payload.payload_len, 128U), |
| 251 | 251 | GFP_KERNEL); | |
| 252 | if (!req_data || !resp_data) { | 252 | if (!resp_data) |
| 253 | error = -ENOMEM; | 253 | goto out_free_req; |
| 254 | goto out; | ||
| 255 | } | ||
| 256 | |||
| 257 | local_irq_disable(); | ||
| 258 | buf = kmap_atomic(bio_page(req->bio)); | ||
| 259 | memcpy(req_data, buf, blk_rq_bytes(req)); | ||
| 260 | kunmap_atomic(buf - bio_offset(req->bio)); | ||
| 261 | local_irq_enable(); | ||
| 262 | 254 | ||
| 255 | error = -EINVAL; | ||
| 263 | if (req_data[0] != SMP_REQUEST) | 256 | if (req_data[0] != SMP_REQUEST) |
| 264 | goto out; | 257 | goto out_free_resp; |
| 265 | |||
| 266 | /* always succeeds ... even if we can't process the request | ||
| 267 | * the result is in the response frame */ | ||
| 268 | error = 0; | ||
| 269 | 258 | ||
| 270 | /* set up default don't know response */ | 259 | /* set up default don't know response */ |
| 271 | resp_data[0] = SMP_RESPONSE; | 260 | resp_data[0] = SMP_RESPONSE; |
| @@ -274,20 +263,18 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 274 | 263 | ||
| 275 | switch (req_data[1]) { | 264 | switch (req_data[1]) { |
| 276 | case SMP_REPORT_GENERAL: | 265 | case SMP_REPORT_GENERAL: |
| 277 | scsi_req(req)->resid_len -= 8; | ||
| 278 | scsi_req(rsp)->resid_len -= 32; | ||
| 279 | resp_data[2] = SMP_RESP_FUNC_ACC; | 266 | resp_data[2] = SMP_RESP_FUNC_ACC; |
| 280 | resp_data[9] = sas_ha->num_phys; | 267 | resp_data[9] = sas_ha->num_phys; |
| 268 | reslen = 32; | ||
| 281 | break; | 269 | break; |
| 282 | 270 | ||
| 283 | case SMP_REPORT_MANUF_INFO: | 271 | case SMP_REPORT_MANUF_INFO: |
| 284 | scsi_req(req)->resid_len -= 8; | ||
| 285 | scsi_req(rsp)->resid_len -= 64; | ||
| 286 | resp_data[2] = SMP_RESP_FUNC_ACC; | 272 | resp_data[2] = SMP_RESP_FUNC_ACC; |
| 287 | memcpy(resp_data + 12, shost->hostt->name, | 273 | memcpy(resp_data + 12, shost->hostt->name, |
| 288 | SAS_EXPANDER_VENDOR_ID_LEN); | 274 | SAS_EXPANDER_VENDOR_ID_LEN); |
| 289 | memcpy(resp_data + 20, "libsas virt phy", | 275 | memcpy(resp_data + 20, "libsas virt phy", |
| 290 | SAS_EXPANDER_PRODUCT_ID_LEN); | 276 | SAS_EXPANDER_PRODUCT_ID_LEN); |
| 277 | reslen = 64; | ||
| 291 | break; | 278 | break; |
| 292 | 279 | ||
| 293 | case SMP_READ_GPIO_REG: | 280 | case SMP_READ_GPIO_REG: |
| @@ -295,14 +282,10 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 295 | break; | 282 | break; |
| 296 | 283 | ||
| 297 | case SMP_DISCOVER: | 284 | case SMP_DISCOVER: |
| 298 | scsi_req(req)->resid_len -= 16; | 285 | if (job->request_payload.payload_len < 16) |
| 299 | if ((int)scsi_req(req)->resid_len < 0) { | 286 | goto out_free_resp; |
| 300 | scsi_req(req)->resid_len = 0; | ||
| 301 | error = -EINVAL; | ||
| 302 | goto out; | ||
| 303 | } | ||
| 304 | scsi_req(rsp)->resid_len -= 56; | ||
| 305 | sas_host_smp_discover(sas_ha, resp_data, req_data[9]); | 287 | sas_host_smp_discover(sas_ha, resp_data, req_data[9]); |
| 288 | reslen = 56; | ||
| 306 | break; | 289 | break; |
| 307 | 290 | ||
| 308 | case SMP_REPORT_PHY_ERR_LOG: | 291 | case SMP_REPORT_PHY_ERR_LOG: |
| @@ -311,14 +294,10 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 311 | break; | 294 | break; |
| 312 | 295 | ||
| 313 | case SMP_REPORT_PHY_SATA: | 296 | case SMP_REPORT_PHY_SATA: |
| 314 | scsi_req(req)->resid_len -= 16; | 297 | if (job->request_payload.payload_len < 16) |
| 315 | if ((int)scsi_req(req)->resid_len < 0) { | 298 | goto out_free_resp; |
| 316 | scsi_req(req)->resid_len = 0; | ||
| 317 | error = -EINVAL; | ||
| 318 | goto out; | ||
| 319 | } | ||
| 320 | scsi_req(rsp)->resid_len -= 60; | ||
| 321 | sas_report_phy_sata(sas_ha, resp_data, req_data[9]); | 299 | sas_report_phy_sata(sas_ha, resp_data, req_data[9]); |
| 300 | reslen = 60; | ||
| 322 | break; | 301 | break; |
| 323 | 302 | ||
| 324 | case SMP_REPORT_ROUTE_INFO: | 303 | case SMP_REPORT_ROUTE_INFO: |
| @@ -330,16 +309,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 330 | const int base_frame_size = 11; | 309 | const int base_frame_size = 11; |
| 331 | int to_write = req_data[4]; | 310 | int to_write = req_data[4]; |
| 332 | 311 | ||
| 333 | if (blk_rq_bytes(req) < base_frame_size + to_write * 4 || | 312 | if (job->request_payload.payload_len < |
| 334 | scsi_req(req)->resid_len < base_frame_size + to_write * 4) { | 313 | base_frame_size + to_write * 4) { |
| 335 | resp_data[2] = SMP_RESP_INV_FRM_LEN; | 314 | resp_data[2] = SMP_RESP_INV_FRM_LEN; |
| 336 | break; | 315 | break; |
| 337 | } | 316 | } |
| 338 | 317 | ||
| 339 | to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2], | 318 | to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2], |
| 340 | req_data[3], to_write, &req_data[8]); | 319 | req_data[3], to_write, &req_data[8]); |
| 341 | scsi_req(req)->resid_len -= base_frame_size + to_write * 4; | 320 | reslen = 8; |
| 342 | scsi_req(rsp)->resid_len -= 8; | ||
| 343 | break; | 321 | break; |
| 344 | } | 322 | } |
| 345 | 323 | ||
| @@ -348,16 +326,12 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 348 | break; | 326 | break; |
| 349 | 327 | ||
| 350 | case SMP_PHY_CONTROL: | 328 | case SMP_PHY_CONTROL: |
| 351 | scsi_req(req)->resid_len -= 44; | 329 | if (job->request_payload.payload_len < 44) |
| 352 | if ((int)scsi_req(req)->resid_len < 0) { | 330 | goto out_free_resp; |
| 353 | scsi_req(req)->resid_len = 0; | ||
| 354 | error = -EINVAL; | ||
| 355 | goto out; | ||
| 356 | } | ||
| 357 | scsi_req(rsp)->resid_len -= 8; | ||
| 358 | sas_phy_control(sas_ha, req_data[9], req_data[10], | 331 | sas_phy_control(sas_ha, req_data[9], req_data[10], |
| 359 | req_data[32] >> 4, req_data[33] >> 4, | 332 | req_data[32] >> 4, req_data[33] >> 4, |
| 360 | resp_data); | 333 | resp_data); |
| 334 | reslen = 8; | ||
| 361 | break; | 335 | break; |
| 362 | 336 | ||
| 363 | case SMP_PHY_TEST_FUNCTION: | 337 | case SMP_PHY_TEST_FUNCTION: |
| @@ -369,15 +343,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | |||
| 369 | break; | 343 | break; |
| 370 | } | 344 | } |
| 371 | 345 | ||
| 372 | local_irq_disable(); | 346 | sg_copy_from_buffer(job->reply_payload.sg_list, |
| 373 | buf = kmap_atomic(bio_page(rsp->bio)); | 347 | job->reply_payload.sg_cnt, resp_data, |
| 374 | memcpy(buf, resp_data, blk_rq_bytes(rsp)); | 348 | job->reply_payload.payload_len); |
| 375 | flush_kernel_dcache_page(bio_page(rsp->bio)); | ||
| 376 | kunmap_atomic(buf - bio_offset(rsp->bio)); | ||
| 377 | local_irq_enable(); | ||
| 378 | 349 | ||
| 379 | out: | 350 | error = 0; |
| 380 | kfree(req_data); | 351 | out_free_resp: |
| 381 | kfree(resp_data); | 352 | kfree(resp_data); |
| 382 | return error; | 353 | out_free_req: |
| 354 | kfree(req_data); | ||
| 355 | out: | ||
| 356 | bsg_job_done(job, error, reslen); | ||
| 383 | } | 357 | } |
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index a216c957b639..c07e08136491 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h | |||
| @@ -81,6 +81,8 @@ int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); | |||
| 81 | int sas_notify_lldd_dev_found(struct domain_device *); | 81 | int sas_notify_lldd_dev_found(struct domain_device *); |
| 82 | void sas_notify_lldd_dev_gone(struct domain_device *); | 82 | void sas_notify_lldd_dev_gone(struct domain_device *); |
| 83 | 83 | ||
| 84 | void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, | ||
| 85 | struct sas_rphy *rphy); | ||
| 84 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | 86 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, |
| 85 | enum phy_func phy_func, struct sas_phy_linkrates *); | 87 | enum phy_func phy_func, struct sas_phy_linkrates *); |
| 86 | int sas_smp_get_phy_events(struct sas_phy *phy); | 88 | int sas_smp_get_phy_events(struct sas_phy *phy); |
| @@ -98,16 +100,14 @@ void sas_hae_reset(struct work_struct *work); | |||
| 98 | void sas_free_device(struct kref *kref); | 100 | void sas_free_device(struct kref *kref); |
| 99 | 101 | ||
| 100 | #ifdef CONFIG_SCSI_SAS_HOST_SMP | 102 | #ifdef CONFIG_SCSI_SAS_HOST_SMP |
| 101 | extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, | 103 | extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); |
| 102 | struct request *rsp); | ||
| 103 | #else | 104 | #else |
| 104 | static inline int sas_smp_host_handler(struct Scsi_Host *shost, | 105 | static inline void sas_smp_host_handler(struct bsg_job *job, |
| 105 | struct request *req, | 106 | struct Scsi_Host *shost) |
| 106 | struct request *rsp) | ||
| 107 | { | 107 | { |
| 108 | shost_printk(KERN_ERR, shost, | 108 | shost_printk(KERN_ERR, shost, |
| 109 | "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); | 109 | "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); |
| 110 | return -EINVAL; | 110 | bsg_job_done(job, -EINVAL, 0); |
| 111 | } | 111 | } |
| 112 | #endif | 112 | #endif |
| 113 | 113 | ||
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index e7a7a704a315..d3940c5d079d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c | |||
| @@ -1870,6 +1870,38 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) | |||
| 1870 | return rc; | 1870 | return rc; |
| 1871 | } | 1871 | } |
| 1872 | 1872 | ||
| 1873 | static int | ||
| 1874 | _transport_map_smp_buffer(struct device *dev, struct bsg_buffer *buf, | ||
| 1875 | dma_addr_t *dma_addr, size_t *dma_len, void **p) | ||
| 1876 | { | ||
| 1877 | /* Check if the request is split across multiple segments */ | ||
| 1878 | if (buf->sg_cnt > 1) { | ||
| 1879 | *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr, | ||
| 1880 | GFP_KERNEL); | ||
| 1881 | if (!*p) | ||
| 1882 | return -ENOMEM; | ||
| 1883 | *dma_len = buf->payload_len; | ||
| 1884 | } else { | ||
| 1885 | if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL)) | ||
| 1886 | return -ENOMEM; | ||
| 1887 | *dma_addr = sg_dma_address(buf->sg_list); | ||
| 1888 | *dma_len = sg_dma_len(buf->sg_list); | ||
| 1889 | *p = NULL; | ||
| 1890 | } | ||
| 1891 | |||
| 1892 | return 0; | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | static void | ||
| 1896 | _transport_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf, | ||
| 1897 | dma_addr_t dma_addr, void *p) | ||
| 1898 | { | ||
| 1899 | if (p) | ||
| 1900 | dma_free_coherent(dev, buf->payload_len, p, dma_addr); | ||
| 1901 | else | ||
| 1902 | dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL); | ||
| 1903 | } | ||
| 1904 | |||
| 1873 | /** | 1905 | /** |
| 1874 | * _transport_smp_handler - transport portal for smp passthru | 1906 | * _transport_smp_handler - transport portal for smp passthru |
| 1875 | * @shost: shost object | 1907 | * @shost: shost object |
| @@ -1880,9 +1912,9 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) | |||
| 1880 | * Example: | 1912 | * Example: |
| 1881 | * smp_rep_general /sys/class/bsg/expander-5:0 | 1913 | * smp_rep_general /sys/class/bsg/expander-5:0 |
| 1882 | */ | 1914 | */ |
| 1883 | static int | 1915 | static void |
| 1884 | _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | 1916 | _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, |
| 1885 | struct request *req) | 1917 | struct sas_rphy *rphy) |
| 1886 | { | 1918 | { |
| 1887 | struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); | 1919 | struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); |
| 1888 | Mpi2SmpPassthroughRequest_t *mpi_request; | 1920 | Mpi2SmpPassthroughRequest_t *mpi_request; |
| @@ -1891,33 +1923,25 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1891 | u16 smid; | 1923 | u16 smid; |
| 1892 | u32 ioc_state; | 1924 | u32 ioc_state; |
| 1893 | void *psge; | 1925 | void *psge; |
| 1894 | u8 issue_reset = 0; | 1926 | dma_addr_t dma_addr_in; |
| 1895 | dma_addr_t dma_addr_in = 0; | 1927 | dma_addr_t dma_addr_out; |
| 1896 | dma_addr_t dma_addr_out = 0; | 1928 | void *addr_in = NULL; |
| 1897 | dma_addr_t pci_dma_in = 0; | 1929 | void *addr_out = NULL; |
| 1898 | dma_addr_t pci_dma_out = 0; | 1930 | size_t dma_len_in; |
| 1899 | void *pci_addr_in = NULL; | 1931 | size_t dma_len_out; |
| 1900 | void *pci_addr_out = NULL; | ||
| 1901 | u16 wait_state_count; | 1932 | u16 wait_state_count; |
| 1902 | struct request *rsp = req->next_rq; | 1933 | unsigned int reslen = 0; |
| 1903 | struct bio_vec bvec; | ||
| 1904 | struct bvec_iter iter; | ||
| 1905 | |||
| 1906 | if (!rsp) { | ||
| 1907 | pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n", | ||
| 1908 | ioc->name, __func__); | ||
| 1909 | return -EINVAL; | ||
| 1910 | } | ||
| 1911 | 1934 | ||
| 1912 | if (ioc->shost_recovery || ioc->pci_error_recovery) { | 1935 | if (ioc->shost_recovery || ioc->pci_error_recovery) { |
| 1913 | pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", | 1936 | pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", |
| 1914 | __func__, ioc->name); | 1937 | __func__, ioc->name); |
| 1915 | return -EFAULT; | 1938 | rc = -EFAULT; |
| 1939 | goto out; | ||
| 1916 | } | 1940 | } |
| 1917 | 1941 | ||
| 1918 | rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); | 1942 | rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); |
| 1919 | if (rc) | 1943 | if (rc) |
| 1920 | return rc; | 1944 | goto out; |
| 1921 | 1945 | ||
| 1922 | if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { | 1946 | if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { |
| 1923 | pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, | 1947 | pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, |
| @@ -1927,58 +1951,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1927 | } | 1951 | } |
| 1928 | ioc->transport_cmds.status = MPT3_CMD_PENDING; | 1952 | ioc->transport_cmds.status = MPT3_CMD_PENDING; |
| 1929 | 1953 | ||
| 1930 | /* Check if the request is split across multiple segments */ | 1954 | rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->request_payload, |
| 1931 | if (bio_multiple_segments(req->bio)) { | 1955 | &dma_addr_out, &dma_len_out, &addr_out); |
| 1932 | u32 offset = 0; | 1956 | if (rc) |
| 1933 | 1957 | goto out; | |
| 1934 | /* Allocate memory and copy the request */ | 1958 | if (addr_out) { |
| 1935 | pci_addr_out = pci_alloc_consistent(ioc->pdev, | 1959 | sg_copy_to_buffer(job->request_payload.sg_list, |
| 1936 | blk_rq_bytes(req), &pci_dma_out); | 1960 | job->request_payload.sg_cnt, addr_out, |
| 1937 | if (!pci_addr_out) { | 1961 | job->request_payload.payload_len); |
| 1938 | pr_info(MPT3SAS_FMT "%s(): PCI Addr out = NULL\n", | ||
| 1939 | ioc->name, __func__); | ||
| 1940 | rc = -ENOMEM; | ||
| 1941 | goto out; | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | bio_for_each_segment(bvec, req->bio, iter) { | ||
| 1945 | memcpy(pci_addr_out + offset, | ||
| 1946 | page_address(bvec.bv_page) + bvec.bv_offset, | ||
| 1947 | bvec.bv_len); | ||
| 1948 | offset += bvec.bv_len; | ||
| 1949 | } | ||
| 1950 | } else { | ||
| 1951 | dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), | ||
| 1952 | blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); | ||
| 1953 | if (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) { | ||
| 1954 | pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n", | ||
| 1955 | ioc->name, __func__); | ||
| 1956 | rc = -ENOMEM; | ||
| 1957 | goto free_pci; | ||
| 1958 | } | ||
| 1959 | } | 1962 | } |
| 1960 | 1963 | ||
| 1961 | /* Check if the response needs to be populated across | 1964 | rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->reply_payload, |
| 1962 | * multiple segments */ | 1965 | &dma_addr_in, &dma_len_in, &addr_in); |
| 1963 | if (bio_multiple_segments(rsp->bio)) { | 1966 | if (rc) |
| 1964 | pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), | 1967 | goto unmap_out; |
| 1965 | &pci_dma_in); | ||
| 1966 | if (!pci_addr_in) { | ||
| 1967 | pr_info(MPT3SAS_FMT "%s(): PCI Addr in = NULL\n", | ||
| 1968 | ioc->name, __func__); | ||
| 1969 | rc = -ENOMEM; | ||
| 1970 | goto unmap; | ||
| 1971 | } | ||
| 1972 | } else { | ||
| 1973 | dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), | ||
| 1974 | blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); | ||
| 1975 | if (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) { | ||
| 1976 | pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n", | ||
| 1977 | ioc->name, __func__); | ||
| 1978 | rc = -ENOMEM; | ||
| 1979 | goto unmap; | ||
| 1980 | } | ||
| 1981 | } | ||
| 1982 | 1968 | ||
| 1983 | wait_state_count = 0; | 1969 | wait_state_count = 0; |
| 1984 | ioc_state = mpt3sas_base_get_iocstate(ioc, 1); | 1970 | ioc_state = mpt3sas_base_get_iocstate(ioc, 1); |
| @@ -1988,7 +1974,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 1988 | "%s: failed due to ioc not operational\n", | 1974 | "%s: failed due to ioc not operational\n", |
| 1989 | ioc->name, __func__); | 1975 | ioc->name, __func__); |
| 1990 | rc = -EFAULT; | 1976 | rc = -EFAULT; |
| 1991 | goto unmap; | 1977 | goto unmap_in; |
| 1992 | } | 1978 | } |
| 1993 | ssleep(1); | 1979 | ssleep(1); |
| 1994 | ioc_state = mpt3sas_base_get_iocstate(ioc, 1); | 1980 | ioc_state = mpt3sas_base_get_iocstate(ioc, 1); |
| @@ -2005,7 +1991,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 2005 | pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", | 1991 | pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", |
| 2006 | ioc->name, __func__); | 1992 | ioc->name, __func__); |
| 2007 | rc = -EAGAIN; | 1993 | rc = -EAGAIN; |
| 2008 | goto unmap; | 1994 | goto unmap_in; |
| 2009 | } | 1995 | } |
| 2010 | 1996 | ||
| 2011 | rc = 0; | 1997 | rc = 0; |
| @@ -2018,15 +2004,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 2018 | mpi_request->SASAddress = (rphy) ? | 2004 | mpi_request->SASAddress = (rphy) ? |
| 2019 | cpu_to_le64(rphy->identify.sas_address) : | 2005 | cpu_to_le64(rphy->identify.sas_address) : |
| 2020 | cpu_to_le64(ioc->sas_hba.sas_address); | 2006 | cpu_to_le64(ioc->sas_hba.sas_address); |
| 2021 | mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); | 2007 | mpi_request->RequestDataLength = cpu_to_le16(dma_len_out - 4); |
| 2022 | psge = &mpi_request->SGL; | 2008 | psge = &mpi_request->SGL; |
| 2023 | 2009 | ||
| 2024 | if (bio_multiple_segments(req->bio)) | 2010 | ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in, |
| 2025 | ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4), | 2011 | dma_len_in - 4); |
| 2026 | pci_dma_in, (blk_rq_bytes(rsp) + 4)); | ||
| 2027 | else | ||
| 2028 | ioc->build_sg(ioc, psge, dma_addr_out, (blk_rq_bytes(req) - 4), | ||
| 2029 | dma_addr_in, (blk_rq_bytes(rsp) + 4)); | ||
| 2030 | 2012 | ||
| 2031 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT | 2013 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT |
| 2032 | "%s - sending smp request\n", ioc->name, __func__)); | 2014 | "%s - sending smp request\n", ioc->name, __func__)); |
| @@ -2040,83 +2022,51 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, | |||
| 2040 | __func__, ioc->name); | 2022 | __func__, ioc->name); |
| 2041 | _debug_dump_mf(mpi_request, | 2023 | _debug_dump_mf(mpi_request, |
| 2042 | sizeof(Mpi2SmpPassthroughRequest_t)/4); | 2024 | sizeof(Mpi2SmpPassthroughRequest_t)/4); |
| 2043 | if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) | 2025 | if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) { |
| 2044 | issue_reset = 1; | 2026 | mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); |
| 2045 | goto issue_host_reset; | 2027 | rc = -ETIMEDOUT; |
| 2028 | goto unmap_in; | ||
| 2029 | } | ||
| 2046 | } | 2030 | } |
| 2047 | 2031 | ||
| 2048 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT | 2032 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT |
| 2049 | "%s - complete\n", ioc->name, __func__)); | 2033 | "%s - complete\n", ioc->name, __func__)); |
| 2050 | 2034 | ||
| 2051 | if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) { | 2035 | if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) { |
| 2052 | |||
| 2053 | mpi_reply = ioc->transport_cmds.reply; | ||
| 2054 | |||
| 2055 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT | ||
| 2056 | "%s - reply data transfer size(%d)\n", | ||
| 2057 | ioc->name, __func__, | ||
| 2058 | le16_to_cpu(mpi_reply->ResponseDataLength))); | ||
| 2059 | |||
| 2060 | memcpy(scsi_req(req)->sense, mpi_reply, sizeof(*mpi_reply)); | ||
| 2061 | scsi_req(req)->sense_len = sizeof(*mpi_reply); | ||
| 2062 | scsi_req(req)->resid_len = 0; | ||
| 2063 | scsi_req(rsp)->resid_len -= | ||
| 2064 | le16_to_cpu(mpi_reply->ResponseDataLength); | ||
| 2065 | |||
| 2066 | /* check if the resp needs to be copied from the allocated | ||
| 2067 | * pci mem */ | ||
| 2068 | if (bio_multiple_segments(rsp->bio)) { | ||
| 2069 | u32 offset = 0; | ||
| 2070 | u32 bytes_to_copy = | ||
| 2071 | le16_to_cpu(mpi_reply->ResponseDataLength); | ||
| 2072 | bio_for_each_segment(bvec, rsp->bio, iter) { | ||
| 2073 | if (bytes_to_copy <= bvec.bv_len) { | ||
| 2074 | memcpy(page_address(bvec.bv_page) + | ||
| 2075 | bvec.bv_offset, pci_addr_in + | ||
| 2076 | offset, bytes_to_copy); | ||
| 2077 | break; | ||
| 2078 | } else { | ||
| 2079 | memcpy(page_address(bvec.bv_page) + | ||
| 2080 | bvec.bv_offset, pci_addr_in + | ||
| 2081 | offset, bvec.bv_len); | ||
| 2082 | bytes_to_copy -= bvec.bv_len; | ||
| 2083 | } | ||
| 2084 | offset += bvec.bv_len; | ||
| 2085 | } | ||
| 2086 | } | ||
| 2087 | } else { | ||
| 2088 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT | 2036 | dtransportprintk(ioc, pr_info(MPT3SAS_FMT |
| 2089 | "%s - no reply\n", ioc->name, __func__)); | 2037 | "%s - no reply\n", ioc->name, __func__)); |
| 2090 | rc = -ENXIO; | 2038 | rc = -ENXIO; |
| 2039 | goto unmap_in; | ||
| 2091 | } | 2040 | } |
| 2092 | 2041 | ||
| 2093 | issue_host_reset: | 2042 | mpi_reply = ioc->transport_cmds.reply; |
| 2094 | if (issue_reset) { | ||
| 2095 | mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER); | ||
| 2096 | rc = -ETIMEDOUT; | ||
| 2097 | } | ||
| 2098 | 2043 | ||
| 2099 | unmap: | 2044 | dtransportprintk(ioc, |
| 2100 | if (dma_addr_out) | 2045 | pr_info(MPT3SAS_FMT "%s - reply data transfer size(%d)\n", |
| 2101 | pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), | 2046 | ioc->name, __func__, |
| 2102 | PCI_DMA_BIDIRECTIONAL); | 2047 | le16_to_cpu(mpi_reply->ResponseDataLength))); |
| 2103 | if (dma_addr_in) | ||
| 2104 | pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), | ||
| 2105 | PCI_DMA_BIDIRECTIONAL); | ||
| 2106 | 2048 | ||
| 2107 | free_pci: | 2049 | memcpy(job->reply, mpi_reply, sizeof(*mpi_reply)); |
| 2108 | if (pci_addr_out) | 2050 | job->reply_len = sizeof(*mpi_reply); |
| 2109 | pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, | 2051 | reslen = le16_to_cpu(mpi_reply->ResponseDataLength); |
| 2110 | pci_dma_out); | ||
| 2111 | 2052 | ||
| 2112 | if (pci_addr_in) | 2053 | if (addr_in) { |
| 2113 | pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, | 2054 | sg_copy_to_buffer(job->reply_payload.sg_list, |
| 2114 | pci_dma_in); | 2055 | job->reply_payload.sg_cnt, addr_in, |
| 2056 | job->reply_payload.payload_len); | ||
| 2057 | } | ||
| 2115 | 2058 | ||
| 2059 | rc = 0; | ||
| 2060 | unmap_in: | ||
| 2061 | _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->reply_payload, | ||
| 2062 | dma_addr_in, addr_in); | ||
| 2063 | unmap_out: | ||
| 2064 | _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->request_payload, | ||
| 2065 | dma_addr_out, addr_out); | ||
| 2116 | out: | 2066 | out: |
| 2117 | ioc->transport_cmds.status = MPT3_CMD_NOT_USED; | 2067 | ioc->transport_cmds.status = MPT3_CMD_NOT_USED; |
| 2118 | mutex_unlock(&ioc->transport_cmds.mutex); | 2068 | mutex_unlock(&ioc->transport_cmds.mutex); |
| 2119 | return rc; | 2069 | bsg_job_done(job, rc, reslen); |
| 2120 | } | 2070 | } |
| 2121 | 2071 | ||
| 2122 | struct sas_function_template mpt3sas_transport_functions = { | 2072 | struct sas_function_template mpt3sas_transport_functions = { |
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index e2e948f1ce28..319dff970237 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
| @@ -169,39 +169,22 @@ static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev) | |||
| 169 | return rdev; | 169 | return rdev; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, | 172 | static int sas_smp_dispatch(struct bsg_job *job) |
| 173 | struct sas_rphy *rphy) | ||
| 174 | { | 173 | { |
| 175 | struct request *req; | 174 | struct Scsi_Host *shost = dev_to_shost(job->dev); |
| 176 | blk_status_t ret; | 175 | struct sas_rphy *rphy = NULL; |
| 177 | int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); | ||
| 178 | 176 | ||
| 179 | while ((req = blk_fetch_request(q)) != NULL) { | 177 | if (!scsi_is_host_device(job->dev)) |
| 180 | spin_unlock_irq(q->queue_lock); | 178 | rphy = dev_to_rphy(job->dev); |
| 181 | 179 | ||
| 182 | scsi_req(req)->resid_len = blk_rq_bytes(req); | 180 | if (!job->req->next_rq) { |
| 183 | if (req->next_rq) | 181 | dev_warn(job->dev, "space for a smp response is missing\n"); |
| 184 | scsi_req(req->next_rq)->resid_len = | 182 | bsg_job_done(job, -EINVAL, 0); |
| 185 | blk_rq_bytes(req->next_rq); | 183 | return 0; |
| 186 | handler = to_sas_internal(shost->transportt)->f->smp_handler; | ||
| 187 | ret = handler(shost, rphy, req); | ||
| 188 | scsi_req(req)->result = ret; | ||
| 189 | |||
| 190 | blk_end_request_all(req, 0); | ||
| 191 | |||
| 192 | spin_lock_irq(q->queue_lock); | ||
| 193 | } | 184 | } |
| 194 | } | ||
| 195 | 185 | ||
| 196 | static void sas_host_smp_request(struct request_queue *q) | 186 | to_sas_internal(shost->transportt)->f->smp_handler(job, shost, rphy); |
| 197 | { | 187 | return 0; |
| 198 | sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void sas_non_host_smp_request(struct request_queue *q) | ||
| 202 | { | ||
| 203 | struct sas_rphy *rphy = q->queuedata; | ||
| 204 | sas_smp_request(q, rphy_to_shost(rphy), rphy); | ||
| 205 | } | 188 | } |
| 206 | 189 | ||
| 207 | static void sas_host_release(struct device *dev) | 190 | static void sas_host_release(struct device *dev) |
| @@ -217,81 +200,36 @@ static void sas_host_release(struct device *dev) | |||
| 217 | static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) | 200 | static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) |
| 218 | { | 201 | { |
| 219 | struct request_queue *q; | 202 | struct request_queue *q; |
| 220 | int error; | ||
| 221 | struct device *dev; | ||
| 222 | char namebuf[20]; | ||
| 223 | const char *name; | ||
| 224 | void (*release)(struct device *); | ||
| 225 | 203 | ||
| 226 | if (!to_sas_internal(shost->transportt)->f->smp_handler) { | 204 | if (!to_sas_internal(shost->transportt)->f->smp_handler) { |
| 227 | printk("%s can't handle SMP requests\n", shost->hostt->name); | 205 | printk("%s can't handle SMP requests\n", shost->hostt->name); |
| 228 | return 0; | 206 | return 0; |
| 229 | } | 207 | } |
| 230 | 208 | ||
| 231 | q = blk_alloc_queue(GFP_KERNEL); | ||
| 232 | if (!q) | ||
| 233 | return -ENOMEM; | ||
| 234 | q->initialize_rq_fn = scsi_initialize_rq; | ||
| 235 | q->cmd_size = sizeof(struct scsi_request); | ||
| 236 | |||
| 237 | if (rphy) { | 209 | if (rphy) { |
| 238 | q->request_fn = sas_non_host_smp_request; | 210 | q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev), |
| 239 | dev = &rphy->dev; | 211 | sas_smp_dispatch, 0, NULL); |
| 240 | name = dev_name(dev); | 212 | if (IS_ERR(q)) |
| 241 | release = NULL; | 213 | return PTR_ERR(q); |
| 214 | rphy->q = q; | ||
| 242 | } else { | 215 | } else { |
| 243 | q->request_fn = sas_host_smp_request; | 216 | char name[20]; |
| 244 | dev = &shost->shost_gendev; | 217 | |
| 245 | snprintf(namebuf, sizeof(namebuf), | 218 | snprintf(name, sizeof(name), "sas_host%d", shost->host_no); |
| 246 | "sas_host%d", shost->host_no); | 219 | q = bsg_setup_queue(&shost->shost_gendev, name, |
| 247 | name = namebuf; | 220 | sas_smp_dispatch, 0, sas_host_release); |
| 248 | release = sas_host_release; | 221 | if (IS_ERR(q)) |
| 222 | return PTR_ERR(q); | ||
| 223 | to_sas_host_attrs(shost)->q = q; | ||
| 249 | } | 224 | } |
| 250 | error = blk_init_allocated_queue(q); | ||
| 251 | if (error) | ||
| 252 | goto out_cleanup_queue; | ||
| 253 | 225 | ||
| 254 | /* | 226 | /* |
| 255 | * by default assume old behaviour and bounce for any highmem page | 227 | * by default assume old behaviour and bounce for any highmem page |
| 256 | */ | 228 | */ |
| 257 | blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); | 229 | blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); |
| 258 | |||
| 259 | error = bsg_register_queue(q, dev, name, release); | ||
| 260 | if (error) | ||
| 261 | goto out_cleanup_queue; | ||
| 262 | |||
| 263 | if (rphy) | ||
| 264 | rphy->q = q; | ||
| 265 | else | ||
| 266 | to_sas_host_attrs(shost)->q = q; | ||
| 267 | |||
| 268 | if (rphy) | ||
| 269 | q->queuedata = rphy; | ||
| 270 | else | ||
| 271 | q->queuedata = shost; | ||
| 272 | |||
| 273 | queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); | 230 | queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); |
| 274 | queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q); | 231 | queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q); |
| 275 | return 0; | 232 | return 0; |
| 276 | |||
| 277 | out_cleanup_queue: | ||
| 278 | blk_cleanup_queue(q); | ||
| 279 | return error; | ||
| 280 | } | ||
| 281 | |||
| 282 | static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy) | ||
| 283 | { | ||
| 284 | struct request_queue *q; | ||
| 285 | |||
| 286 | if (rphy) | ||
| 287 | q = rphy->q; | ||
| 288 | else | ||
| 289 | q = to_sas_host_attrs(shost)->q; | ||
| 290 | |||
| 291 | if (!q) | ||
| 292 | return; | ||
| 293 | |||
| 294 | bsg_unregister_queue(q); | ||
| 295 | } | 233 | } |
| 296 | 234 | ||
| 297 | /* | 235 | /* |
| @@ -321,9 +259,10 @@ static int sas_host_remove(struct transport_container *tc, struct device *dev, | |||
| 321 | struct device *cdev) | 259 | struct device *cdev) |
| 322 | { | 260 | { |
| 323 | struct Scsi_Host *shost = dev_to_shost(dev); | 261 | struct Scsi_Host *shost = dev_to_shost(dev); |
| 262 | struct request_queue *q = to_sas_host_attrs(shost)->q; | ||
| 324 | 263 | ||
| 325 | sas_bsg_remove(shost, NULL); | 264 | if (q) |
| 326 | 265 | bsg_unregister_queue(q); | |
| 327 | return 0; | 266 | return 0; |
| 328 | } | 267 | } |
| 329 | 268 | ||
| @@ -1713,7 +1652,8 @@ sas_rphy_remove(struct sas_rphy *rphy) | |||
| 1713 | } | 1652 | } |
| 1714 | 1653 | ||
| 1715 | sas_rphy_unlink(rphy); | 1654 | sas_rphy_unlink(rphy); |
| 1716 | sas_bsg_remove(NULL, rphy); | 1655 | if (rphy->q) |
| 1656 | bsg_unregister_queue(rphy->q); | ||
| 1717 | transport_remove_device(dev); | 1657 | transport_remove_device(dev); |
| 1718 | device_del(dev); | 1658 | device_del(dev); |
| 1719 | } | 1659 | } |
