diff options
author | James Smart <James.Smart@Emulex.Com> | 2009-03-26 13:33:19 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-06-12 15:20:05 -0400 |
commit | 9e4f5e29610162fd426366f3b29e3cc6e575b858 (patch) | |
tree | aad7fed6b70d87bc9aae10563fa1e71535b11de9 | |
parent | e349792a385ed47390d156155b1a1e19af1bf163 (diff) |
[SCSI] FC Pass Thru support
Attached is the ELS/CT pass-thru patch for the FC Transport. The patch
creates a generic framework that lays on top of bsg and the SGIO v4 ioctl
in order to pass transaction requests to LLDD's.
The interface supports the following operations:
On an fc_host basis:
Request login to the specified N_Port_ID, creating an fc_rport.
Request logout of the specified N_Port_ID, deleting an fc_rport
Send ELS request to specified N_Port_ID w/o requiring a login, and
wait for ELS response.
Send CT request to specified N_Port_ID and wait for CT response.
Login is required, but LLDD is allowed to manage login and decide
whether it stays in place after the request is satisfied.
Vendor-Unique request. Allows a LLDD-specific request to be passed
to the LLDD, and the passing of a response back to the application.
On an fc_rport basis:
Send ELS request to nport and wait for ELS response.
Send CT request to nport and wait for CT response.
The patch also exports several headers from include/scsi such that
they can be available to user-space applications:
include/scsi/scsi.h
include/scsi/scsi_netlink.h
include/scsi/scsi_netlink_fc.h
include/scsi/scsi_bsg_fc.h
For further information, refer to the last RFC:
http://marc.info/?l=linux-scsi&m=123436574018579&w=2
Note: Documentation is still spotty and will be added later.
[bharrosh@panasas.com: update for new block API]
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | Documentation/scsi/scsi_fc_transport.txt | 14 | ||||
-rw-r--r-- | Documentation/scsi/scsi_mid_low_api.txt | 5 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 614 | ||||
-rw-r--r-- | include/Kbuild | 1 | ||||
-rw-r--r-- | include/scsi/Kbuild | 4 | ||||
-rw-r--r-- | include/scsi/scsi_bsg_fc.h | 322 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 9 | ||||
-rw-r--r-- | include/scsi/scsi_transport_fc.h | 52 |
8 files changed, 1016 insertions, 5 deletions
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt index e5b071d46619..d7f181701dc2 100644 --- a/Documentation/scsi/scsi_fc_transport.txt +++ b/Documentation/scsi/scsi_fc_transport.txt | |||
@@ -1,10 +1,11 @@ | |||
1 | SCSI FC Tansport | 1 | SCSI FC Tansport |
2 | ============================================= | 2 | ============================================= |
3 | 3 | ||
4 | Date: 4/12/2007 | 4 | Date: 11/18/2008 |
5 | Kernel Revisions for features: | 5 | Kernel Revisions for features: |
6 | rports : <<TBS>> | 6 | rports : <<TBS>> |
7 | vports : 2.6.22 (? TBD) | 7 | vports : 2.6.22 |
8 | bsg support : 2.6.30 (?TBD?) | ||
8 | 9 | ||
9 | 10 | ||
10 | Introduction | 11 | Introduction |
@@ -15,6 +16,7 @@ The FC transport can be found at: | |||
15 | drivers/scsi/scsi_transport_fc.c | 16 | drivers/scsi/scsi_transport_fc.c |
16 | include/scsi/scsi_transport_fc.h | 17 | include/scsi/scsi_transport_fc.h |
17 | include/scsi/scsi_netlink_fc.h | 18 | include/scsi/scsi_netlink_fc.h |
19 | include/scsi/scsi_bsg_fc.h | ||
18 | 20 | ||
19 | This file is found at Documentation/scsi/scsi_fc_transport.txt | 21 | This file is found at Documentation/scsi/scsi_fc_transport.txt |
20 | 22 | ||
@@ -472,6 +474,14 @@ int | |||
472 | fc_vport_terminate(struct fc_vport *vport) | 474 | fc_vport_terminate(struct fc_vport *vport) |
473 | 475 | ||
474 | 476 | ||
477 | FC BSG support (CT & ELS passthru, and more) | ||
478 | ======================================================================== | ||
479 | << To Be Supplied >> | ||
480 | |||
481 | |||
482 | |||
483 | |||
484 | |||
475 | Credits | 485 | Credits |
476 | ======= | 486 | ======= |
477 | The following people have contributed to this document: | 487 | The following people have contributed to this document: |
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index a6d5354639b2..de67229251d8 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt | |||
@@ -1271,6 +1271,11 @@ of interest: | |||
1271 | hostdata[0] - area reserved for LLD at end of struct Scsi_Host. Size | 1271 | hostdata[0] - area reserved for LLD at end of struct Scsi_Host. Size |
1272 | is set by the second argument (named 'xtr_bytes') to | 1272 | is set by the second argument (named 'xtr_bytes') to |
1273 | scsi_host_alloc() or scsi_register(). | 1273 | scsi_host_alloc() or scsi_register(). |
1274 | vendor_id - a unique value that identifies the vendor supplying | ||
1275 | the LLD for the Scsi_Host. Used most often in validating | ||
1276 | vendor-specific message requests. Value consists of an | ||
1277 | identifier type and a vendor-specific value. | ||
1278 | See scsi_netlink.h for a description of valid formats. | ||
1274 | 1279 | ||
1275 | The scsi_host structure is defined in include/scsi/scsi_host.h | 1280 | The scsi_host structure is defined in include/scsi/scsi_host.h |
1276 | 1281 | ||
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index a152f89ae51c..3f64d93b6c8b 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/netlink.h> | 35 | #include <linux/netlink.h> |
36 | #include <net/netlink.h> | 36 | #include <net/netlink.h> |
37 | #include <scsi/scsi_netlink_fc.h> | 37 | #include <scsi/scsi_netlink_fc.h> |
38 | #include <scsi/scsi_bsg_fc.h> | ||
38 | #include "scsi_priv.h" | 39 | #include "scsi_priv.h" |
39 | #include "scsi_transport_fc_internal.h" | 40 | #include "scsi_transport_fc_internal.h" |
40 | 41 | ||
@@ -43,6 +44,10 @@ static void fc_vport_sched_delete(struct work_struct *work); | |||
43 | static int fc_vport_setup(struct Scsi_Host *shost, int channel, | 44 | static int fc_vport_setup(struct Scsi_Host *shost, int channel, |
44 | struct device *pdev, struct fc_vport_identifiers *ids, | 45 | struct device *pdev, struct fc_vport_identifiers *ids, |
45 | struct fc_vport **vport); | 46 | struct fc_vport **vport); |
47 | static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *); | ||
48 | static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); | ||
49 | static void fc_bsg_remove(struct request_queue *); | ||
50 | static void fc_bsg_goose_queue(struct fc_rport *); | ||
46 | 51 | ||
47 | /* | 52 | /* |
48 | * Redefine so that we can have same named attributes in the | 53 | * Redefine so that we can have same named attributes in the |
@@ -411,13 +416,26 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, | |||
411 | return -ENOMEM; | 416 | return -ENOMEM; |
412 | } | 417 | } |
413 | 418 | ||
419 | fc_bsg_hostadd(shost, fc_host); | ||
420 | /* ignore any bsg add error - we just can't do sgio */ | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int fc_host_remove(struct transport_container *tc, struct device *dev, | ||
426 | struct device *cdev) | ||
427 | { | ||
428 | struct Scsi_Host *shost = dev_to_shost(dev); | ||
429 | struct fc_host_attrs *fc_host = shost_to_fc_host(shost); | ||
430 | |||
431 | fc_bsg_remove(fc_host->rqst_q); | ||
414 | return 0; | 432 | return 0; |
415 | } | 433 | } |
416 | 434 | ||
417 | static DECLARE_TRANSPORT_CLASS(fc_host_class, | 435 | static DECLARE_TRANSPORT_CLASS(fc_host_class, |
418 | "fc_host", | 436 | "fc_host", |
419 | fc_host_setup, | 437 | fc_host_setup, |
420 | NULL, | 438 | fc_host_remove, |
421 | NULL); | 439 | NULL); |
422 | 440 | ||
423 | /* | 441 | /* |
@@ -2375,6 +2393,7 @@ fc_rport_final_delete(struct work_struct *work) | |||
2375 | scsi_flush_work(shost); | 2393 | scsi_flush_work(shost); |
2376 | 2394 | ||
2377 | fc_terminate_rport_io(rport); | 2395 | fc_terminate_rport_io(rport); |
2396 | |||
2378 | /* | 2397 | /* |
2379 | * Cancel any outstanding timers. These should really exist | 2398 | * Cancel any outstanding timers. These should really exist |
2380 | * only when rmmod'ing the LLDD and we're asking for | 2399 | * only when rmmod'ing the LLDD and we're asking for |
@@ -2407,6 +2426,8 @@ fc_rport_final_delete(struct work_struct *work) | |||
2407 | (i->f->dev_loss_tmo_callbk)) | 2426 | (i->f->dev_loss_tmo_callbk)) |
2408 | i->f->dev_loss_tmo_callbk(rport); | 2427 | i->f->dev_loss_tmo_callbk(rport); |
2409 | 2428 | ||
2429 | fc_bsg_remove(rport->rqst_q); | ||
2430 | |||
2410 | transport_remove_device(dev); | 2431 | transport_remove_device(dev); |
2411 | device_del(dev); | 2432 | device_del(dev); |
2412 | transport_destroy_device(dev); | 2433 | transport_destroy_device(dev); |
@@ -2494,6 +2515,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
2494 | transport_add_device(dev); | 2515 | transport_add_device(dev); |
2495 | transport_configure_device(dev); | 2516 | transport_configure_device(dev); |
2496 | 2517 | ||
2518 | fc_bsg_rportadd(shost, rport); | ||
2519 | /* ignore any bsg add error - we just can't do sgio */ | ||
2520 | |||
2497 | if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { | 2521 | if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { |
2498 | /* initiate a scan of the target */ | 2522 | /* initiate a scan of the target */ |
2499 | rport->flags |= FC_RPORT_SCAN_PENDING; | 2523 | rport->flags |= FC_RPORT_SCAN_PENDING; |
@@ -2658,6 +2682,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
2658 | spin_unlock_irqrestore(shost->host_lock, | 2682 | spin_unlock_irqrestore(shost->host_lock, |
2659 | flags); | 2683 | flags); |
2660 | 2684 | ||
2685 | fc_bsg_goose_queue(rport); | ||
2686 | |||
2661 | return rport; | 2687 | return rport; |
2662 | } | 2688 | } |
2663 | } | 2689 | } |
@@ -3343,6 +3369,592 @@ fc_vport_sched_delete(struct work_struct *work) | |||
3343 | } | 3369 | } |
3344 | 3370 | ||
3345 | 3371 | ||
3372 | /* | ||
3373 | * BSG support | ||
3374 | */ | ||
3375 | |||
3376 | |||
3377 | /** | ||
3378 | * fc_destroy_bsgjob - routine to teardown/delete a fc bsg job | ||
3379 | * @job: fc_bsg_job that is to be torn down | ||
3380 | */ | ||
3381 | static void | ||
3382 | fc_destroy_bsgjob(struct fc_bsg_job *job) | ||
3383 | { | ||
3384 | unsigned long flags; | ||
3385 | |||
3386 | spin_lock_irqsave(&job->job_lock, flags); | ||
3387 | if (job->ref_cnt) { | ||
3388 | spin_unlock_irqrestore(&job->job_lock, flags); | ||
3389 | return; | ||
3390 | } | ||
3391 | spin_unlock_irqrestore(&job->job_lock, flags); | ||
3392 | |||
3393 | put_device(job->dev); /* release reference for the request */ | ||
3394 | |||
3395 | kfree(job->request_payload.sg_list); | ||
3396 | kfree(job->reply_payload.sg_list); | ||
3397 | kfree(job); | ||
3398 | } | ||
3399 | |||
3400 | |||
3401 | /** | ||
3402 | * fc_bsg_jobdone - completion routine for bsg requests that the LLD has | ||
3403 | * completed | ||
3404 | * @job: fc_bsg_job that is complete | ||
3405 | */ | ||
3406 | static void | ||
3407 | fc_bsg_jobdone(struct fc_bsg_job *job) | ||
3408 | { | ||
3409 | struct request *req = job->req; | ||
3410 | struct request *rsp = req->next_rq; | ||
3411 | unsigned long flags; | ||
3412 | int err; | ||
3413 | |||
3414 | spin_lock_irqsave(&job->job_lock, flags); | ||
3415 | job->state_flags |= FC_RQST_STATE_DONE; | ||
3416 | job->ref_cnt--; | ||
3417 | spin_unlock_irqrestore(&job->job_lock, flags); | ||
3418 | |||
3419 | err = job->req->errors = job->reply->result; | ||
3420 | if (err < 0) | ||
3421 | /* we're only returning the result field in the reply */ | ||
3422 | job->req->sense_len = sizeof(uint32_t); | ||
3423 | else | ||
3424 | job->req->sense_len = job->reply_len; | ||
3425 | |||
3426 | /* we assume all request payload was transferred, residual == 0 */ | ||
3427 | req->resid_len = 0; | ||
3428 | |||
3429 | if (rsp) { | ||
3430 | WARN_ON(job->reply->reply_payload_rcv_len > rsp->resid_len); | ||
3431 | |||
3432 | /* set reply (bidi) residual */ | ||
3433 | rsp->resid_len -= min(job->reply->reply_payload_rcv_len, | ||
3434 | rsp->resid_len); | ||
3435 | } | ||
3436 | |||
3437 | blk_end_request_all(req, err); | ||
3438 | |||
3439 | fc_destroy_bsgjob(job); | ||
3440 | } | ||
3441 | |||
3442 | |||
3443 | /** | ||
3444 | * fc_bsg_job_timeout - handler for when a bsg request timesout | ||
3445 | * @req: request that timed out | ||
3446 | */ | ||
3447 | static enum blk_eh_timer_return | ||
3448 | fc_bsg_job_timeout(struct request *req) | ||
3449 | { | ||
3450 | struct fc_bsg_job *job = (void *) req->special; | ||
3451 | struct Scsi_Host *shost = job->shost; | ||
3452 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3453 | unsigned long flags; | ||
3454 | int err = 0, done = 0; | ||
3455 | |||
3456 | if (job->rport && job->rport->port_state == FC_PORTSTATE_BLOCKED) | ||
3457 | return BLK_EH_RESET_TIMER; | ||
3458 | |||
3459 | spin_lock_irqsave(&job->job_lock, flags); | ||
3460 | if (job->state_flags & FC_RQST_STATE_DONE) | ||
3461 | done = 1; | ||
3462 | else | ||
3463 | job->ref_cnt++; | ||
3464 | spin_unlock_irqrestore(&job->job_lock, flags); | ||
3465 | |||
3466 | if (!done && i->f->bsg_timeout) { | ||
3467 | /* call LLDD to abort the i/o as it has timed out */ | ||
3468 | err = i->f->bsg_timeout(job); | ||
3469 | if (err) | ||
3470 | printk(KERN_ERR "ERROR: FC BSG request timeout - LLD " | ||
3471 | "abort failed with status %d\n", err); | ||
3472 | } | ||
3473 | |||
3474 | if (!done) { | ||
3475 | spin_lock_irqsave(&job->job_lock, flags); | ||
3476 | job->ref_cnt--; | ||
3477 | spin_unlock_irqrestore(&job->job_lock, flags); | ||
3478 | fc_destroy_bsgjob(job); | ||
3479 | } | ||
3480 | |||
3481 | /* the blk_end_sync_io() doesn't check the error */ | ||
3482 | return BLK_EH_HANDLED; | ||
3483 | } | ||
3484 | |||
3485 | |||
3486 | |||
3487 | static int | ||
3488 | fc_bsg_map_buffer(struct fc_bsg_buffer *buf, struct request *req) | ||
3489 | { | ||
3490 | size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments); | ||
3491 | |||
3492 | BUG_ON(!req->nr_phys_segments); | ||
3493 | |||
3494 | buf->sg_list = kzalloc(sz, GFP_KERNEL); | ||
3495 | if (!buf->sg_list) | ||
3496 | return -ENOMEM; | ||
3497 | sg_init_table(buf->sg_list, req->nr_phys_segments); | ||
3498 | buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list); | ||
3499 | buf->payload_len = blk_rq_bytes(req); | ||
3500 | return 0; | ||
3501 | } | ||
3502 | |||
3503 | |||
3504 | /** | ||
3505 | * fc_req_to_bsgjob - Allocate/create the fc_bsg_job structure for the | ||
3506 | * bsg request | ||
3507 | * @shost: SCSI Host corresponding to the bsg object | ||
3508 | * @rport: (optional) FC Remote Port corresponding to the bsg object | ||
3509 | * @req: BSG request that needs a job structure | ||
3510 | */ | ||
3511 | static int | ||
3512 | fc_req_to_bsgjob(struct Scsi_Host *shost, struct fc_rport *rport, | ||
3513 | struct request *req) | ||
3514 | { | ||
3515 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3516 | struct request *rsp = req->next_rq; | ||
3517 | struct fc_bsg_job *job; | ||
3518 | int ret; | ||
3519 | |||
3520 | BUG_ON(req->special); | ||
3521 | |||
3522 | job = kzalloc(sizeof(struct fc_bsg_job) + i->f->dd_bsg_size, | ||
3523 | GFP_KERNEL); | ||
3524 | if (!job) | ||
3525 | return -ENOMEM; | ||
3526 | |||
3527 | /* | ||
3528 | * Note: this is a bit silly. | ||
3529 | * The request gets formatted as a SGIO v4 ioctl request, which | ||
3530 | * then gets reformatted as a blk request, which then gets | ||
3531 | * reformatted as a fc bsg request. And on completion, we have | ||
3532 | * to wrap return results such that SGIO v4 thinks it was a scsi | ||
3533 | * status. I hope this was all worth it. | ||
3534 | */ | ||
3535 | |||
3536 | req->special = job; | ||
3537 | job->shost = shost; | ||
3538 | job->rport = rport; | ||
3539 | job->req = req; | ||
3540 | if (i->f->dd_bsg_size) | ||
3541 | job->dd_data = (void *)&job[1]; | ||
3542 | spin_lock_init(&job->job_lock); | ||
3543 | job->request = (struct fc_bsg_request *)req->cmd; | ||
3544 | job->request_len = req->cmd_len; | ||
3545 | job->reply = req->sense; | ||
3546 | job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer | ||
3547 | * allocated */ | ||
3548 | if (req->bio) { | ||
3549 | ret = fc_bsg_map_buffer(&job->request_payload, req); | ||
3550 | if (ret) | ||
3551 | goto failjob_rls_job; | ||
3552 | } | ||
3553 | if (rsp && rsp->bio) { | ||
3554 | ret = fc_bsg_map_buffer(&job->reply_payload, rsp); | ||
3555 | if (ret) | ||
3556 | goto failjob_rls_rqst_payload; | ||
3557 | } | ||
3558 | job->job_done = fc_bsg_jobdone; | ||
3559 | if (rport) | ||
3560 | job->dev = &rport->dev; | ||
3561 | else | ||
3562 | job->dev = &shost->shost_gendev; | ||
3563 | get_device(job->dev); /* take a reference for the request */ | ||
3564 | |||
3565 | job->ref_cnt = 1; | ||
3566 | |||
3567 | return 0; | ||
3568 | |||
3569 | |||
3570 | failjob_rls_rqst_payload: | ||
3571 | kfree(job->request_payload.sg_list); | ||
3572 | failjob_rls_job: | ||
3573 | kfree(job); | ||
3574 | return -ENOMEM; | ||
3575 | } | ||
3576 | |||
3577 | |||
3578 | enum fc_dispatch_result { | ||
3579 | FC_DISPATCH_BREAK, /* on return, q is locked, break from q loop */ | ||
3580 | FC_DISPATCH_LOCKED, /* on return, q is locked, continue on */ | ||
3581 | FC_DISPATCH_UNLOCKED, /* on return, q is unlocked, continue on */ | ||
3582 | }; | ||
3583 | |||
3584 | |||
3585 | /** | ||
3586 | * fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD | ||
3587 | * @shost: scsi host rport attached to | ||
3588 | * @job: bsg job to be processed | ||
3589 | */ | ||
3590 | static enum fc_dispatch_result | ||
3591 | fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost, | ||
3592 | struct fc_bsg_job *job) | ||
3593 | { | ||
3594 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3595 | int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ | ||
3596 | int ret; | ||
3597 | |||
3598 | /* Validate the host command */ | ||
3599 | switch (job->request->msgcode) { | ||
3600 | case FC_BSG_HST_ADD_RPORT: | ||
3601 | cmdlen += sizeof(struct fc_bsg_host_add_rport); | ||
3602 | break; | ||
3603 | |||
3604 | case FC_BSG_HST_DEL_RPORT: | ||
3605 | cmdlen += sizeof(struct fc_bsg_host_del_rport); | ||
3606 | break; | ||
3607 | |||
3608 | case FC_BSG_HST_ELS_NOLOGIN: | ||
3609 | cmdlen += sizeof(struct fc_bsg_host_els); | ||
3610 | /* there better be a xmt and rcv payloads */ | ||
3611 | if ((!job->request_payload.payload_len) || | ||
3612 | (!job->reply_payload.payload_len)) { | ||
3613 | ret = -EINVAL; | ||
3614 | goto fail_host_msg; | ||
3615 | } | ||
3616 | break; | ||
3617 | |||
3618 | case FC_BSG_HST_CT: | ||
3619 | cmdlen += sizeof(struct fc_bsg_host_ct); | ||
3620 | /* there better be xmt and rcv payloads */ | ||
3621 | if ((!job->request_payload.payload_len) || | ||
3622 | (!job->reply_payload.payload_len)) { | ||
3623 | ret = -EINVAL; | ||
3624 | goto fail_host_msg; | ||
3625 | } | ||
3626 | break; | ||
3627 | |||
3628 | case FC_BSG_HST_VENDOR: | ||
3629 | cmdlen += sizeof(struct fc_bsg_host_vendor); | ||
3630 | if ((shost->hostt->vendor_id == 0L) || | ||
3631 | (job->request->rqst_data.h_vendor.vendor_id != | ||
3632 | shost->hostt->vendor_id)) { | ||
3633 | ret = -ESRCH; | ||
3634 | goto fail_host_msg; | ||
3635 | } | ||
3636 | break; | ||
3637 | |||
3638 | default: | ||
3639 | ret = -EBADR; | ||
3640 | goto fail_host_msg; | ||
3641 | } | ||
3642 | |||
3643 | /* check if we really have all the request data needed */ | ||
3644 | if (job->request_len < cmdlen) { | ||
3645 | ret = -ENOMSG; | ||
3646 | goto fail_host_msg; | ||
3647 | } | ||
3648 | |||
3649 | ret = i->f->bsg_request(job); | ||
3650 | if (!ret) | ||
3651 | return FC_DISPATCH_UNLOCKED; | ||
3652 | |||
3653 | fail_host_msg: | ||
3654 | /* return the errno failure code as the only status */ | ||
3655 | BUG_ON(job->reply_len < sizeof(uint32_t)); | ||
3656 | job->reply->result = ret; | ||
3657 | job->reply_len = sizeof(uint32_t); | ||
3658 | fc_bsg_jobdone(job); | ||
3659 | return FC_DISPATCH_UNLOCKED; | ||
3660 | } | ||
3661 | |||
3662 | |||
3663 | /* | ||
3664 | * fc_bsg_goose_queue - restart rport queue in case it was stopped | ||
3665 | * @rport: rport to be restarted | ||
3666 | */ | ||
3667 | static void | ||
3668 | fc_bsg_goose_queue(struct fc_rport *rport) | ||
3669 | { | ||
3670 | int flagset; | ||
3671 | |||
3672 | if (!rport->rqst_q) | ||
3673 | return; | ||
3674 | |||
3675 | get_device(&rport->dev); | ||
3676 | |||
3677 | spin_lock(rport->rqst_q->queue_lock); | ||
3678 | flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && | ||
3679 | !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); | ||
3680 | if (flagset) | ||
3681 | queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); | ||
3682 | __blk_run_queue(rport->rqst_q); | ||
3683 | if (flagset) | ||
3684 | queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); | ||
3685 | spin_unlock(rport->rqst_q->queue_lock); | ||
3686 | |||
3687 | put_device(&rport->dev); | ||
3688 | } | ||
3689 | |||
3690 | |||
3691 | /** | ||
3692 | * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD | ||
3693 | * @shost: scsi host rport attached to | ||
3694 | * @rport: rport request destined to | ||
3695 | * @job: bsg job to be processed | ||
3696 | */ | ||
3697 | static enum fc_dispatch_result | ||
3698 | fc_bsg_rport_dispatch(struct request_queue *q, struct Scsi_Host *shost, | ||
3699 | struct fc_rport *rport, struct fc_bsg_job *job) | ||
3700 | { | ||
3701 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3702 | int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ | ||
3703 | int ret; | ||
3704 | |||
3705 | /* Validate the rport command */ | ||
3706 | switch (job->request->msgcode) { | ||
3707 | case FC_BSG_RPT_ELS: | ||
3708 | cmdlen += sizeof(struct fc_bsg_rport_els); | ||
3709 | goto check_bidi; | ||
3710 | |||
3711 | case FC_BSG_RPT_CT: | ||
3712 | cmdlen += sizeof(struct fc_bsg_rport_ct); | ||
3713 | check_bidi: | ||
3714 | /* there better be xmt and rcv payloads */ | ||
3715 | if ((!job->request_payload.payload_len) || | ||
3716 | (!job->reply_payload.payload_len)) { | ||
3717 | ret = -EINVAL; | ||
3718 | goto fail_rport_msg; | ||
3719 | } | ||
3720 | break; | ||
3721 | default: | ||
3722 | ret = -EBADR; | ||
3723 | goto fail_rport_msg; | ||
3724 | } | ||
3725 | |||
3726 | /* check if we really have all the request data needed */ | ||
3727 | if (job->request_len < cmdlen) { | ||
3728 | ret = -ENOMSG; | ||
3729 | goto fail_rport_msg; | ||
3730 | } | ||
3731 | |||
3732 | ret = i->f->bsg_request(job); | ||
3733 | if (!ret) | ||
3734 | return FC_DISPATCH_UNLOCKED; | ||
3735 | |||
3736 | fail_rport_msg: | ||
3737 | /* return the errno failure code as the only status */ | ||
3738 | BUG_ON(job->reply_len < sizeof(uint32_t)); | ||
3739 | job->reply->result = ret; | ||
3740 | job->reply_len = sizeof(uint32_t); | ||
3741 | fc_bsg_jobdone(job); | ||
3742 | return FC_DISPATCH_UNLOCKED; | ||
3743 | } | ||
3744 | |||
3745 | |||
3746 | /** | ||
3747 | * fc_bsg_request_handler - generic handler for bsg requests | ||
3748 | * @q: request queue to manage | ||
3749 | * @shost: Scsi_Host related to the bsg object | ||
3750 | * @rport: FC remote port related to the bsg object (optional) | ||
3751 | * @dev: device structure for bsg object | ||
3752 | */ | ||
3753 | static void | ||
3754 | fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, | ||
3755 | struct fc_rport *rport, struct device *dev) | ||
3756 | { | ||
3757 | struct request *req; | ||
3758 | struct fc_bsg_job *job; | ||
3759 | enum fc_dispatch_result ret; | ||
3760 | |||
3761 | if (!get_device(dev)) | ||
3762 | return; | ||
3763 | |||
3764 | while (!blk_queue_plugged(q)) { | ||
3765 | if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED)) | ||
3766 | break; | ||
3767 | |||
3768 | req = blk_fetch_request(q); | ||
3769 | if (!req) | ||
3770 | break; | ||
3771 | |||
3772 | if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { | ||
3773 | req->errors = -ENXIO; | ||
3774 | spin_unlock_irq(q->queue_lock); | ||
3775 | blk_end_request(req, -ENXIO, blk_rq_bytes(req)); | ||
3776 | spin_lock_irq(q->queue_lock); | ||
3777 | continue; | ||
3778 | } | ||
3779 | |||
3780 | spin_unlock_irq(q->queue_lock); | ||
3781 | |||
3782 | ret = fc_req_to_bsgjob(shost, rport, req); | ||
3783 | if (ret) { | ||
3784 | req->errors = ret; | ||
3785 | blk_end_request(req, ret, blk_rq_bytes(req)); | ||
3786 | spin_lock_irq(q->queue_lock); | ||
3787 | continue; | ||
3788 | } | ||
3789 | |||
3790 | job = req->special; | ||
3791 | |||
3792 | /* check if we have the msgcode value at least */ | ||
3793 | if (job->request_len < sizeof(uint32_t)) { | ||
3794 | BUG_ON(job->reply_len < sizeof(uint32_t)); | ||
3795 | job->reply->result = -ENOMSG; | ||
3796 | job->reply_len = sizeof(uint32_t); | ||
3797 | fc_bsg_jobdone(job); | ||
3798 | spin_lock_irq(q->queue_lock); | ||
3799 | continue; | ||
3800 | } | ||
3801 | |||
3802 | /* the dispatch routines will unlock the queue_lock */ | ||
3803 | if (rport) | ||
3804 | ret = fc_bsg_rport_dispatch(q, shost, rport, job); | ||
3805 | else | ||
3806 | ret = fc_bsg_host_dispatch(q, shost, job); | ||
3807 | |||
3808 | /* did dispatcher hit state that can't process any more */ | ||
3809 | if (ret == FC_DISPATCH_BREAK) | ||
3810 | break; | ||
3811 | |||
3812 | /* did dispatcher had released the lock */ | ||
3813 | if (ret == FC_DISPATCH_UNLOCKED) | ||
3814 | spin_lock_irq(q->queue_lock); | ||
3815 | } | ||
3816 | |||
3817 | spin_unlock_irq(q->queue_lock); | ||
3818 | put_device(dev); | ||
3819 | spin_lock_irq(q->queue_lock); | ||
3820 | } | ||
3821 | |||
3822 | |||
3823 | /** | ||
3824 | * fc_bsg_host_handler - handler for bsg requests for a fc host | ||
3825 | * @q: fc host request queue | ||
3826 | */ | ||
3827 | static void | ||
3828 | fc_bsg_host_handler(struct request_queue *q) | ||
3829 | { | ||
3830 | struct Scsi_Host *shost = q->queuedata; | ||
3831 | |||
3832 | fc_bsg_request_handler(q, shost, NULL, &shost->shost_gendev); | ||
3833 | } | ||
3834 | |||
3835 | |||
3836 | /** | ||
3837 | * fc_bsg_rport_handler - handler for bsg requests for a fc rport | ||
3838 | * @q: rport request queue | ||
3839 | */ | ||
3840 | static void | ||
3841 | fc_bsg_rport_handler(struct request_queue *q) | ||
3842 | { | ||
3843 | struct fc_rport *rport = q->queuedata; | ||
3844 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
3845 | |||
3846 | fc_bsg_request_handler(q, shost, rport, &rport->dev); | ||
3847 | } | ||
3848 | |||
3849 | |||
3850 | /** | ||
3851 | * fc_bsg_hostadd - Create and add the bsg hooks so we can receive requests | ||
3852 | * @shost: shost for fc_host | ||
3853 | * @fc_host: fc_host adding the structures to | ||
3854 | */ | ||
3855 | static int | ||
3856 | fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) | ||
3857 | { | ||
3858 | struct device *dev = &shost->shost_gendev; | ||
3859 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3860 | struct request_queue *q; | ||
3861 | int err; | ||
3862 | char bsg_name[BUS_ID_SIZE]; /*20*/ | ||
3863 | |||
3864 | fc_host->rqst_q = NULL; | ||
3865 | |||
3866 | if (!i->f->bsg_request) | ||
3867 | return -ENOTSUPP; | ||
3868 | |||
3869 | snprintf(bsg_name, sizeof(bsg_name), | ||
3870 | "fc_host%d", shost->host_no); | ||
3871 | |||
3872 | q = __scsi_alloc_queue(shost, fc_bsg_host_handler); | ||
3873 | if (!q) { | ||
3874 | printk(KERN_ERR "fc_host%d: bsg interface failed to " | ||
3875 | "initialize - no request queue\n", | ||
3876 | shost->host_no); | ||
3877 | return -ENOMEM; | ||
3878 | } | ||
3879 | |||
3880 | q->queuedata = shost; | ||
3881 | queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); | ||
3882 | blk_queue_rq_timed_out(q, fc_bsg_job_timeout); | ||
3883 | blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT); | ||
3884 | |||
3885 | err = bsg_register_queue(q, dev, bsg_name, NULL); | ||
3886 | if (err) { | ||
3887 | printk(KERN_ERR "fc_host%d: bsg interface failed to " | ||
3888 | "initialize - register queue\n", | ||
3889 | shost->host_no); | ||
3890 | blk_cleanup_queue(q); | ||
3891 | return err; | ||
3892 | } | ||
3893 | |||
3894 | fc_host->rqst_q = q; | ||
3895 | return 0; | ||
3896 | } | ||
3897 | |||
3898 | |||
3899 | /** | ||
3900 | * fc_bsg_rportadd - Create and add the bsg hooks so we can receive requests | ||
3901 | * @shost: shost that rport is attached to | ||
3902 | * @rport: rport that the bsg hooks are being attached to | ||
3903 | */ | ||
3904 | static int | ||
3905 | fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) | ||
3906 | { | ||
3907 | struct device *dev = &rport->dev; | ||
3908 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
3909 | struct request_queue *q; | ||
3910 | int err; | ||
3911 | |||
3912 | rport->rqst_q = NULL; | ||
3913 | |||
3914 | if (!i->f->bsg_request) | ||
3915 | return -ENOTSUPP; | ||
3916 | |||
3917 | q = __scsi_alloc_queue(shost, fc_bsg_rport_handler); | ||
3918 | if (!q) { | ||
3919 | printk(KERN_ERR "%s: bsg interface failed to " | ||
3920 | "initialize - no request queue\n", | ||
3921 | dev->kobj.name); | ||
3922 | return -ENOMEM; | ||
3923 | } | ||
3924 | |||
3925 | q->queuedata = rport; | ||
3926 | queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); | ||
3927 | blk_queue_rq_timed_out(q, fc_bsg_job_timeout); | ||
3928 | blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); | ||
3929 | |||
3930 | err = bsg_register_queue(q, dev, NULL, NULL); | ||
3931 | if (err) { | ||
3932 | printk(KERN_ERR "%s: bsg interface failed to " | ||
3933 | "initialize - register queue\n", | ||
3934 | dev->kobj.name); | ||
3935 | blk_cleanup_queue(q); | ||
3936 | return err; | ||
3937 | } | ||
3938 | |||
3939 | rport->rqst_q = q; | ||
3940 | return 0; | ||
3941 | } | ||
3942 | |||
3943 | |||
3944 | /** | ||
3945 | * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports | ||
3946 | * @q: the request_queue that is to be torn down. | ||
3947 | */ | ||
3948 | static void | ||
3949 | fc_bsg_remove(struct request_queue *q) | ||
3950 | { | ||
3951 | if (q) { | ||
3952 | bsg_unregister_queue(q); | ||
3953 | blk_cleanup_queue(q); | ||
3954 | } | ||
3955 | } | ||
3956 | |||
3957 | |||
3346 | /* Original Author: Martin Hicks */ | 3958 | /* Original Author: Martin Hicks */ |
3347 | MODULE_AUTHOR("James Smart"); | 3959 | MODULE_AUTHOR("James Smart"); |
3348 | MODULE_DESCRIPTION("FC Transport Attributes"); | 3960 | MODULE_DESCRIPTION("FC Transport Attributes"); |
diff --git a/include/Kbuild b/include/Kbuild index fe36accd4328..8d226bfa2696 100644 --- a/include/Kbuild +++ b/include/Kbuild | |||
@@ -9,3 +9,4 @@ header-y += rdma/ | |||
9 | header-y += video/ | 9 | header-y += video/ |
10 | header-y += drm/ | 10 | header-y += drm/ |
11 | header-y += xen/ | 11 | header-y += xen/ |
12 | header-y += scsi/ | ||
diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild new file mode 100644 index 000000000000..33b2750e9283 --- /dev/null +++ b/include/scsi/Kbuild | |||
@@ -0,0 +1,4 @@ | |||
1 | header-y += scsi.h | ||
2 | header-y += scsi_netlink.h | ||
3 | header-y += scsi_netlink_fc.h | ||
4 | header-y += scsi_bsg_fc.h | ||
diff --git a/include/scsi/scsi_bsg_fc.h b/include/scsi/scsi_bsg_fc.h new file mode 100644 index 000000000000..a4b233318179 --- /dev/null +++ b/include/scsi/scsi_bsg_fc.h | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * FC Transport BSG Interface | ||
3 | * | ||
4 | * Copyright (C) 2008 James Smart, Emulex Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef SCSI_BSG_FC_H | ||
23 | #define SCSI_BSG_FC_H | ||
24 | |||
25 | /* | ||
26 | * This file intended to be included by both kernel and user space | ||
27 | */ | ||
28 | |||
29 | #include <scsi/scsi.h> | ||
30 | |||
31 | /* | ||
32 | * FC Transport SGIO v4 BSG Message Support | ||
33 | */ | ||
34 | |||
35 | /* Default BSG request timeout (in seconds) */ | ||
36 | #define FC_DEFAULT_BSG_TIMEOUT (10 * HZ) | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Request Message Codes supported by the FC Transport | ||
41 | */ | ||
42 | |||
43 | /* define the class masks for the message codes */ | ||
44 | #define FC_BSG_CLS_MASK 0xF0000000 /* find object class */ | ||
45 | #define FC_BSG_HST_MASK 0x80000000 /* fc host class */ | ||
46 | #define FC_BSG_RPT_MASK 0x40000000 /* fc rport class */ | ||
47 | |||
48 | /* fc_host Message Codes */ | ||
49 | #define FC_BSG_HST_ADD_RPORT (FC_BSG_HST_MASK | 0x00000001) | ||
50 | #define FC_BSG_HST_DEL_RPORT (FC_BSG_HST_MASK | 0x00000002) | ||
51 | #define FC_BSG_HST_ELS_NOLOGIN (FC_BSG_HST_MASK | 0x00000003) | ||
52 | #define FC_BSG_HST_CT (FC_BSG_HST_MASK | 0x00000004) | ||
53 | #define FC_BSG_HST_VENDOR (FC_BSG_HST_MASK | 0x000000FF) | ||
54 | |||
55 | /* fc_rport Message Codes */ | ||
56 | #define FC_BSG_RPT_ELS (FC_BSG_RPT_MASK | 0x00000001) | ||
57 | #define FC_BSG_RPT_CT (FC_BSG_RPT_MASK | 0x00000002) | ||
58 | |||
59 | |||
60 | |||
61 | /* | ||
62 | * FC Address Identifiers in Message Structures : | ||
63 | * | ||
64 | * Whenever a command payload contains a FC Address Identifier | ||
65 | * (aka port_id), the value is effectively in big-endian | ||
66 | * order, thus the array elements are decoded as follows: | ||
67 | * element [0] is bits 23:16 of the FC Address Identifier | ||
68 | * element [1] is bits 15:8 of the FC Address Identifier | ||
69 | * element [2] is bits 7:0 of the FC Address Identifier | ||
70 | */ | ||
71 | |||
72 | |||
73 | /* | ||
74 | * FC Host Messages | ||
75 | */ | ||
76 | |||
77 | /* FC_BSG_HST_ADDR_PORT : */ | ||
78 | |||
79 | /* Request: | ||
80 | * This message requests the FC host to login to the remote port | ||
81 | * at the specified N_Port_Id. The remote port is to be enumerated | ||
82 | * with the transport upon completion of the login. | ||
83 | */ | ||
84 | struct fc_bsg_host_add_rport { | ||
85 | uint8_t reserved; | ||
86 | |||
87 | /* FC Address Identier of the remote port to login to */ | ||
88 | uint8_t port_id[3]; | ||
89 | }; | ||
90 | |||
91 | /* Response: | ||
92 | * There is no additional response data - fc_bsg_reply->result is sufficient | ||
93 | */ | ||
94 | |||
95 | |||
96 | /* FC_BSG_HST_DEL_RPORT : */ | ||
97 | |||
98 | /* Request: | ||
99 | * This message requests the FC host to remove an enumerated | ||
100 | * remote port and to terminate the login to it. | ||
101 | * | ||
102 | * Note: The driver is free to reject this request if it desires to | ||
103 | * remain logged in with the remote port. | ||
104 | */ | ||
105 | struct fc_bsg_host_del_rport { | ||
106 | uint8_t reserved; | ||
107 | |||
108 | /* FC Address Identier of the remote port to logout of */ | ||
109 | uint8_t port_id[3]; | ||
110 | }; | ||
111 | |||
112 | /* Response: | ||
113 | * There is no additional response data - fc_bsg_reply->result is sufficient | ||
114 | */ | ||
115 | |||
116 | |||
117 | /* FC_BSG_HST_ELS_NOLOGIN : */ | ||
118 | |||
119 | /* Request: | ||
120 | * This message requests the FC_Host to send an ELS to a specific | ||
121 | * N_Port_ID. The host does not need to log into the remote port, | ||
122 | * nor does it need to enumerate the rport for further traffic | ||
123 | * (although, the FC host is free to do so if it desires). | ||
124 | */ | ||
125 | struct fc_bsg_host_els { | ||
126 | /* | ||
127 | * ELS Command Code being sent (must be the same as byte 0 | ||
128 | * of the payload) | ||
129 | */ | ||
130 | uint8_t command_code; | ||
131 | |||
132 | /* FC Address Identier of the remote port to send the ELS to */ | ||
133 | uint8_t port_id[3]; | ||
134 | }; | ||
135 | |||
136 | /* Response: | ||
137 | */ | ||
138 | /* fc_bsg_ctels_reply->status values */ | ||
139 | #define FC_CTELS_STATUS_OK 0x00000000 | ||
140 | #define FC_CTELS_STATUS_REJECT 0x00000001 | ||
141 | #define FC_CTELS_STATUS_P_RJT 0x00000002 | ||
142 | #define FC_CTELS_STATUS_F_RJT 0x00000003 | ||
143 | #define FC_CTELS_STATUS_P_BSY 0x00000004 | ||
144 | #define FC_CTELS_STATUS_F_BSY 0x00000006 | ||
145 | struct fc_bsg_ctels_reply { | ||
146 | /* | ||
147 | * Note: An ELS LS_RJT may be reported in 2 ways: | ||
148 | * a) A status of FC_CTELS_STATUS_OK is returned. The caller | ||
149 | * is to look into the ELS receive payload to determine | ||
150 | * LS_ACC or LS_RJT (by contents of word 0). The reject | ||
151 | * data will be in word 1. | ||
152 | * b) A status of FC_CTELS_STATUS_REJECT is returned, The | ||
153 | * rjt_data field will contain valid data. | ||
154 | * | ||
155 | * Note: ELS LS_ACC is determined by an FC_CTELS_STATUS_OK, and | ||
156 | * the receive payload word 0 indicates LS_ACC | ||
157 | * (e.g. value is 0x02xxxxxx). | ||
158 | * | ||
159 | * Note: Similarly, a CT Reject may be reported in 2 ways: | ||
160 | * a) A status of FC_CTELS_STATUS_OK is returned. The caller | ||
161 | * is to look into the CT receive payload to determine | ||
162 | * Accept or Reject (by contents of word 2). The reject | ||
163 | * data will be in word 3. | ||
164 | * b) A status of FC_CTELS_STATUS_REJECT is returned, The | ||
165 | * rjt_data field will contain valid data. | ||
166 | * | ||
167 | * Note: x_RJT/BSY status will indicae that the rjt_data field | ||
168 | * is valid and contains the reason/explanation values. | ||
169 | */ | ||
170 | uint32_t status; /* See FC_CTELS_STATUS_xxx */ | ||
171 | |||
172 | /* valid if status is not FC_CTELS_STATUS_OK */ | ||
173 | struct { | ||
174 | uint8_t action; /* fragment_id for CT REJECT */ | ||
175 | uint8_t reason_code; | ||
176 | uint8_t reason_explanation; | ||
177 | uint8_t vendor_unique; | ||
178 | } rjt_data; | ||
179 | }; | ||
180 | |||
181 | |||
182 | /* FC_BSG_HST_CT : */ | ||
183 | |||
184 | /* Request: | ||
185 | * This message requests that a CT Request be performed with the | ||
186 | * indicated N_Port_ID. The driver is responsible for logging in with | ||
187 | * the fabric and/or N_Port_ID, etc as per FC rules. This request does | ||
188 | * not mandate that the driver must enumerate the destination in the | ||
189 | * transport. The driver is allowed to decide whether to enumerate it, | ||
190 | * and whether to tear it down after the request. | ||
191 | */ | ||
192 | struct fc_bsg_host_ct { | ||
193 | uint8_t reserved; | ||
194 | |||
195 | /* FC Address Identier of the remote port to send the ELS to */ | ||
196 | uint8_t port_id[3]; | ||
197 | |||
198 | /* | ||
199 | * We need words 0-2 of the generic preamble for the LLD's | ||
200 | */ | ||
201 | uint32_t preamble_word0; /* revision & IN_ID */ | ||
202 | uint32_t preamble_word1; /* GS_Type, GS_SubType, Options, Rsvd */ | ||
203 | uint32_t preamble_word2; /* Cmd Code, Max Size */ | ||
204 | |||
205 | }; | ||
206 | /* Response: | ||
207 | * | ||
208 | * The reply structure is an fc_bsg_ctels_reply structure | ||
209 | */ | ||
210 | |||
211 | |||
212 | /* FC_BSG_HST_VENDOR : */ | ||
213 | |||
214 | /* Request: | ||
215 | * Note: When specifying vendor_id, be sure to read the Vendor Type and ID | ||
216 | * formatting requirements specified in scsi_netlink.h | ||
217 | */ | ||
218 | struct fc_bsg_host_vendor { | ||
219 | /* | ||
220 | * Identifies the vendor that the message is formatted for. This | ||
221 | * should be the recipient of the message. | ||
222 | */ | ||
223 | uint64_t vendor_id; | ||
224 | |||
225 | /* start of vendor command area */ | ||
226 | uint32_t vendor_cmd[0]; | ||
227 | }; | ||
228 | |||
229 | /* Response: | ||
230 | */ | ||
231 | struct fc_bsg_host_vendor_reply { | ||
232 | /* start of vendor response area */ | ||
233 | uint32_t vendor_rsp[0]; | ||
234 | }; | ||
235 | |||
236 | |||
237 | |||
238 | /* | ||
239 | * FC Remote Port Messages | ||
240 | */ | ||
241 | |||
242 | /* FC_BSG_RPT_ELS : */ | ||
243 | |||
244 | /* Request: | ||
245 | * This message requests that an ELS be performed with the rport. | ||
246 | */ | ||
247 | struct fc_bsg_rport_els { | ||
248 | /* | ||
249 | * ELS Command Code being sent (must be the same as | ||
250 | * byte 0 of the payload) | ||
251 | */ | ||
252 | uint8_t els_code; | ||
253 | }; | ||
254 | |||
255 | /* Response: | ||
256 | * | ||
257 | * The reply structure is an fc_bsg_ctels_reply structure | ||
258 | */ | ||
259 | |||
260 | |||
261 | /* FC_BSG_RPT_CT : */ | ||
262 | |||
263 | /* Request: | ||
264 | * This message requests that a CT Request be performed with the rport. | ||
265 | */ | ||
266 | struct fc_bsg_rport_ct { | ||
267 | /* | ||
268 | * We need words 0-2 of the generic preamble for the LLD's | ||
269 | */ | ||
270 | uint32_t preamble_word0; /* revision & IN_ID */ | ||
271 | uint32_t preamble_word1; /* GS_Type, GS_SubType, Options, Rsvd */ | ||
272 | uint32_t preamble_word2; /* Cmd Code, Max Size */ | ||
273 | }; | ||
274 | /* Response: | ||
275 | * | ||
276 | * The reply structure is an fc_bsg_ctels_reply structure | ||
277 | */ | ||
278 | |||
279 | |||
280 | |||
281 | |||
282 | /* request (CDB) structure of the sg_io_v4 */ | ||
283 | struct fc_bsg_request { | ||
284 | uint32_t msgcode; | ||
285 | union { | ||
286 | struct fc_bsg_host_add_rport h_addrport; | ||
287 | struct fc_bsg_host_del_rport h_delrport; | ||
288 | struct fc_bsg_host_els h_els; | ||
289 | struct fc_bsg_host_ct h_ct; | ||
290 | struct fc_bsg_host_vendor h_vendor; | ||
291 | |||
292 | struct fc_bsg_rport_els r_els; | ||
293 | struct fc_bsg_rport_ct r_ct; | ||
294 | } rqst_data; | ||
295 | }; | ||
296 | |||
297 | |||
298 | /* response (request sense data) structure of the sg_io_v4 */ | ||
299 | struct fc_bsg_reply { | ||
300 | /* | ||
301 | * The completion result. Result exists in two forms: | ||
302 | * if negative, it is an -Exxx system errno value. There will | ||
303 | * be no further reply information supplied. | ||
304 | * else, it's the 4-byte scsi error result, with driver, host, | ||
305 | * msg and status fields. The per-msgcode reply structure | ||
306 | * will contain valid data. | ||
307 | */ | ||
308 | uint32_t result; | ||
309 | |||
310 | /* If there was reply_payload, how much was recevied ? */ | ||
311 | uint32_t reply_payload_rcv_len; | ||
312 | |||
313 | union { | ||
314 | struct fc_bsg_host_vendor_reply vendor_reply; | ||
315 | |||
316 | struct fc_bsg_ctels_reply ctels_reply; | ||
317 | } reply_data; | ||
318 | }; | ||
319 | |||
320 | |||
321 | #endif /* SCSI_BSG_FC_H */ | ||
322 | |||
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index d123ca84e732..b62a097b3ecb 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
@@ -478,6 +478,15 @@ struct scsi_host_template { | |||
478 | * module_init/module_exit. | 478 | * module_init/module_exit. |
479 | */ | 479 | */ |
480 | struct list_head legacy_hosts; | 480 | struct list_head legacy_hosts; |
481 | |||
482 | /* | ||
483 | * Vendor Identifier associated with the host | ||
484 | * | ||
485 | * Note: When specifying vendor_id, be sure to read the | ||
486 | * Vendor Type and ID formatting requirements specified in | ||
487 | * scsi_netlink.h | ||
488 | */ | ||
489 | u64 vendor_id; | ||
481 | }; | 490 | }; |
482 | 491 | ||
483 | /* | 492 | /* |
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 68a8d873bbd9..fc50bd64aa4e 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h | |||
@@ -33,7 +33,6 @@ | |||
33 | 33 | ||
34 | struct scsi_transport_template; | 34 | struct scsi_transport_template; |
35 | 35 | ||
36 | |||
37 | /* | 36 | /* |
38 | * FC Port definitions - Following FC HBAAPI guidelines | 37 | * FC Port definitions - Following FC HBAAPI guidelines |
39 | * | 38 | * |
@@ -352,6 +351,7 @@ struct fc_rport { /* aka fc_starget_attrs */ | |||
352 | struct delayed_work fail_io_work; | 351 | struct delayed_work fail_io_work; |
353 | struct work_struct stgt_delete_work; | 352 | struct work_struct stgt_delete_work; |
354 | struct work_struct rport_delete_work; | 353 | struct work_struct rport_delete_work; |
354 | struct request_queue *rqst_q; /* bsg support */ | ||
355 | } __attribute__((aligned(sizeof(unsigned long)))); | 355 | } __attribute__((aligned(sizeof(unsigned long)))); |
356 | 356 | ||
357 | /* bit field values for struct fc_rport "flags" field: */ | 357 | /* bit field values for struct fc_rport "flags" field: */ |
@@ -514,6 +514,9 @@ struct fc_host_attrs { | |||
514 | struct workqueue_struct *work_q; | 514 | struct workqueue_struct *work_q; |
515 | char devloss_work_q_name[20]; | 515 | char devloss_work_q_name[20]; |
516 | struct workqueue_struct *devloss_work_q; | 516 | struct workqueue_struct *devloss_work_q; |
517 | |||
518 | /* bsg support */ | ||
519 | struct request_queue *rqst_q; | ||
517 | }; | 520 | }; |
518 | 521 | ||
519 | #define shost_to_fc_host(x) \ | 522 | #define shost_to_fc_host(x) \ |
@@ -579,6 +582,47 @@ struct fc_host_attrs { | |||
579 | (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q) | 582 | (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q) |
580 | 583 | ||
581 | 584 | ||
585 | struct fc_bsg_buffer { | ||
586 | unsigned int payload_len; | ||
587 | int sg_cnt; | ||
588 | struct scatterlist *sg_list; | ||
589 | }; | ||
590 | |||
591 | /* Values for fc_bsg_job->state_flags (bitflags) */ | ||
592 | #define FC_RQST_STATE_INPROGRESS 0 | ||
593 | #define FC_RQST_STATE_DONE 1 | ||
594 | |||
595 | struct fc_bsg_job { | ||
596 | struct Scsi_Host *shost; | ||
597 | struct fc_rport *rport; | ||
598 | struct device *dev; | ||
599 | struct request *req; | ||
600 | spinlock_t job_lock; | ||
601 | unsigned int state_flags; | ||
602 | unsigned int ref_cnt; | ||
603 | void (*job_done)(struct fc_bsg_job *); | ||
604 | |||
605 | struct fc_bsg_request *request; | ||
606 | struct fc_bsg_reply *reply; | ||
607 | unsigned int request_len; | ||
608 | unsigned int reply_len; | ||
609 | /* | ||
610 | * On entry : reply_len indicates the buffer size allocated for | ||
611 | * the reply. | ||
612 | * | ||
613 | * Upon completion : the message handler must set reply_len | ||
614 | * to indicates the size of the reply to be returned to the | ||
615 | * caller. | ||
616 | */ | ||
617 | |||
618 | /* DMA payloads for the request/response */ | ||
619 | struct fc_bsg_buffer request_payload; | ||
620 | struct fc_bsg_buffer reply_payload; | ||
621 | |||
622 | void *dd_data; /* Used for driver-specific storage */ | ||
623 | }; | ||
624 | |||
625 | |||
582 | /* The functions by which the transport class and the driver communicate */ | 626 | /* The functions by which the transport class and the driver communicate */ |
583 | struct fc_function_template { | 627 | struct fc_function_template { |
584 | void (*get_rport_dev_loss_tmo)(struct fc_rport *); | 628 | void (*get_rport_dev_loss_tmo)(struct fc_rport *); |
@@ -614,9 +658,14 @@ struct fc_function_template { | |||
614 | int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int); | 658 | int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int); |
615 | int (* it_nexus_response)(struct Scsi_Host *, u64, int); | 659 | int (* it_nexus_response)(struct Scsi_Host *, u64, int); |
616 | 660 | ||
661 | /* bsg support */ | ||
662 | int (*bsg_request)(struct fc_bsg_job *); | ||
663 | int (*bsg_timeout)(struct fc_bsg_job *); | ||
664 | |||
617 | /* allocation lengths for host-specific data */ | 665 | /* allocation lengths for host-specific data */ |
618 | u32 dd_fcrport_size; | 666 | u32 dd_fcrport_size; |
619 | u32 dd_fcvport_size; | 667 | u32 dd_fcvport_size; |
668 | u32 dd_bsg_size; | ||
620 | 669 | ||
621 | /* | 670 | /* |
622 | * The driver sets these to tell the transport class it | 671 | * The driver sets these to tell the transport class it |
@@ -737,7 +786,6 @@ fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state) | |||
737 | vport->vport_state = new_state; | 786 | vport->vport_state = new_state; |
738 | } | 787 | } |
739 | 788 | ||
740 | |||
741 | struct scsi_transport_template *fc_attach_transport( | 789 | struct scsi_transport_template *fc_attach_transport( |
742 | struct fc_function_template *); | 790 | struct fc_function_template *); |
743 | void fc_release_transport(struct scsi_transport_template *); | 791 | void fc_release_transport(struct scsi_transport_template *); |