diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2011-07-25 14:48:50 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:36:21 -0400 |
commit | 90eeb01a038e5fec0efdea4df008f3c18f67b82c (patch) | |
tree | 9977dd9000374e1162f56934efcf0e5b8c7c7155 | |
parent | 6ac73e8cb02e65abeb2f8d43f0fe48e485444b44 (diff) |
[SCSI] iscsi class: add bsg support to iscsi class
This patch adds bsg support to the iscsi class. There is only
1 request, the host vendor one, supported. It is expected that
this would be used for things like flash updates.
This patch is made over this one
http://marc.info/?l=linux-scsi&m=131149780020992&w=2
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/Kconfig | 1 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 114 | ||||
-rw-r--r-- | include/scsi/scsi_bsg_iscsi.h | 110 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 7 |
4 files changed, 230 insertions, 2 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8d9dae89f06..4a79b9d8615 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -309,6 +309,7 @@ config SCSI_FC_TGT_ATTRS | |||
309 | config SCSI_ISCSI_ATTRS | 309 | config SCSI_ISCSI_ATTRS |
310 | tristate "iSCSI Transport Attributes" | 310 | tristate "iSCSI Transport Attributes" |
311 | depends on SCSI && NET | 311 | depends on SCSI && NET |
312 | select BLK_DEV_BSGLIB | ||
312 | help | 313 | help |
313 | If you wish to export transport-specific information about | 314 | If you wish to export transport-specific information about |
314 | each attached iSCSI device to sysfs, say Y. | 315 | each attached iSCSI device to sysfs, say Y. |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 13f90515ff6..cde679f1b01 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/bsg-lib.h> | ||
26 | #include <net/tcp.h> | 27 | #include <net/tcp.h> |
27 | #include <scsi/scsi.h> | 28 | #include <scsi/scsi.h> |
28 | #include <scsi/scsi_host.h> | 29 | #include <scsi/scsi_host.h> |
@@ -31,6 +32,7 @@ | |||
31 | #include <scsi/scsi_transport_iscsi.h> | 32 | #include <scsi/scsi_transport_iscsi.h> |
32 | #include <scsi/iscsi_if.h> | 33 | #include <scsi/iscsi_if.h> |
33 | #include <scsi/scsi_cmnd.h> | 34 | #include <scsi/scsi_cmnd.h> |
35 | #include <scsi/scsi_bsg_iscsi.h> | ||
34 | 36 | ||
35 | #define ISCSI_TRANSPORT_VERSION "2.0-870" | 37 | #define ISCSI_TRANSPORT_VERSION "2.0-870" |
36 | 38 | ||
@@ -447,6 +449,99 @@ void iscsi_destroy_iface(struct iscsi_iface *iface) | |||
447 | } | 449 | } |
448 | EXPORT_SYMBOL_GPL(iscsi_destroy_iface); | 450 | EXPORT_SYMBOL_GPL(iscsi_destroy_iface); |
449 | 451 | ||
452 | /* | ||
453 | * BSG support | ||
454 | */ | ||
455 | /** | ||
456 | * iscsi_bsg_host_dispatch - Dispatch command to LLD. | ||
457 | * @job: bsg job to be processed | ||
458 | */ | ||
459 | static int iscsi_bsg_host_dispatch(struct bsg_job *job) | ||
460 | { | ||
461 | struct Scsi_Host *shost = iscsi_job_to_shost(job); | ||
462 | struct iscsi_bsg_request *req = job->request; | ||
463 | struct iscsi_bsg_reply *reply = job->reply; | ||
464 | struct iscsi_internal *i = to_iscsi_internal(shost->transportt); | ||
465 | int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ | ||
466 | int ret; | ||
467 | |||
468 | /* check if we have the msgcode value at least */ | ||
469 | if (job->request_len < sizeof(uint32_t)) { | ||
470 | ret = -ENOMSG; | ||
471 | goto fail_host_msg; | ||
472 | } | ||
473 | |||
474 | /* Validate the host command */ | ||
475 | switch (req->msgcode) { | ||
476 | case ISCSI_BSG_HST_VENDOR: | ||
477 | cmdlen += sizeof(struct iscsi_bsg_host_vendor); | ||
478 | if ((shost->hostt->vendor_id == 0L) || | ||
479 | (req->rqst_data.h_vendor.vendor_id != | ||
480 | shost->hostt->vendor_id)) { | ||
481 | ret = -ESRCH; | ||
482 | goto fail_host_msg; | ||
483 | } | ||
484 | break; | ||
485 | default: | ||
486 | ret = -EBADR; | ||
487 | goto fail_host_msg; | ||
488 | } | ||
489 | |||
490 | /* check if we really have all the request data needed */ | ||
491 | if (job->request_len < cmdlen) { | ||
492 | ret = -ENOMSG; | ||
493 | goto fail_host_msg; | ||
494 | } | ||
495 | |||
496 | ret = i->iscsi_transport->bsg_request(job); | ||
497 | if (!ret) | ||
498 | return 0; | ||
499 | |||
500 | fail_host_msg: | ||
501 | /* return the errno failure code as the only status */ | ||
502 | BUG_ON(job->reply_len < sizeof(uint32_t)); | ||
503 | reply->reply_payload_rcv_len = 0; | ||
504 | reply->result = ret; | ||
505 | job->reply_len = sizeof(uint32_t); | ||
506 | bsg_job_done(job, ret, 0); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * iscsi_bsg_host_add - Create and add the bsg hooks to receive requests | ||
512 | * @shost: shost for iscsi_host | ||
513 | * @cls_host: iscsi_cls_host adding the structures to | ||
514 | */ | ||
515 | static int | ||
516 | iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost) | ||
517 | { | ||
518 | struct device *dev = &shost->shost_gendev; | ||
519 | struct iscsi_internal *i = to_iscsi_internal(shost->transportt); | ||
520 | struct request_queue *q; | ||
521 | char bsg_name[20]; | ||
522 | int ret; | ||
523 | |||
524 | if (!i->iscsi_transport->bsg_request) | ||
525 | return -ENOTSUPP; | ||
526 | |||
527 | snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no); | ||
528 | |||
529 | q = __scsi_alloc_queue(shost, bsg_request_fn); | ||
530 | if (!q) | ||
531 | return -ENOMEM; | ||
532 | |||
533 | ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0); | ||
534 | if (ret) { | ||
535 | shost_printk(KERN_ERR, shost, "bsg interface failed to " | ||
536 | "initialize - no request queue\n"); | ||
537 | blk_cleanup_queue(q); | ||
538 | return ret; | ||
539 | } | ||
540 | |||
541 | ihost->bsg_q = q; | ||
542 | return 0; | ||
543 | } | ||
544 | |||
450 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | 545 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, |
451 | struct device *cdev) | 546 | struct device *cdev) |
452 | { | 547 | { |
@@ -456,13 +551,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | |||
456 | memset(ihost, 0, sizeof(*ihost)); | 551 | memset(ihost, 0, sizeof(*ihost)); |
457 | atomic_set(&ihost->nr_scans, 0); | 552 | atomic_set(&ihost->nr_scans, 0); |
458 | mutex_init(&ihost->mutex); | 553 | mutex_init(&ihost->mutex); |
554 | |||
555 | iscsi_bsg_host_add(shost, ihost); | ||
556 | /* ignore any bsg add error - we just can't do sgio */ | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int iscsi_remove_host(struct transport_container *tc, | ||
562 | struct device *dev, struct device *cdev) | ||
563 | { | ||
564 | struct Scsi_Host *shost = dev_to_shost(dev); | ||
565 | struct iscsi_cls_host *ihost = shost->shost_data; | ||
566 | |||
567 | if (ihost->bsg_q) { | ||
568 | bsg_remove_queue(ihost->bsg_q); | ||
569 | blk_cleanup_queue(ihost->bsg_q); | ||
570 | } | ||
459 | return 0; | 571 | return 0; |
460 | } | 572 | } |
461 | 573 | ||
462 | static DECLARE_TRANSPORT_CLASS(iscsi_host_class, | 574 | static DECLARE_TRANSPORT_CLASS(iscsi_host_class, |
463 | "iscsi_host", | 575 | "iscsi_host", |
464 | iscsi_setup_host, | 576 | iscsi_setup_host, |
465 | NULL, | 577 | iscsi_remove_host, |
466 | NULL); | 578 | NULL); |
467 | 579 | ||
468 | static DECLARE_TRANSPORT_CLASS(iscsi_session_class, | 580 | static DECLARE_TRANSPORT_CLASS(iscsi_session_class, |
diff --git a/include/scsi/scsi_bsg_iscsi.h b/include/scsi/scsi_bsg_iscsi.h new file mode 100644 index 00000000000..fd5689d4c05 --- /dev/null +++ b/include/scsi/scsi_bsg_iscsi.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * iSCSI Transport BSG Interface | ||
3 | * | ||
4 | * Copyright (C) 2009 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_ISCSI_H | ||
23 | #define SCSI_BSG_ISCSI_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 | * iSCSI Transport SGIO v4 BSG Message Support | ||
33 | */ | ||
34 | |||
35 | /* Default BSG request timeout (in seconds) */ | ||
36 | #define ISCSI_DEFAULT_BSG_TIMEOUT (10 * HZ) | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Request Message Codes supported by the iSCSI Transport | ||
41 | */ | ||
42 | |||
43 | /* define the class masks for the message codes */ | ||
44 | #define ISCSI_BSG_CLS_MASK 0xF0000000 /* find object class */ | ||
45 | #define ISCSI_BSG_HST_MASK 0x80000000 /* iscsi host class */ | ||
46 | |||
47 | /* iscsi host Message Codes */ | ||
48 | #define ISCSI_BSG_HST_VENDOR (ISCSI_BSG_HST_MASK | 0x000000FF) | ||
49 | |||
50 | |||
51 | /* | ||
52 | * iSCSI Host Messages | ||
53 | */ | ||
54 | |||
55 | /* ISCSI_BSG_HST_VENDOR : */ | ||
56 | |||
57 | /* Request: | ||
58 | * Note: When specifying vendor_id, be sure to read the Vendor Type and ID | ||
59 | * formatting requirements specified in scsi_netlink.h | ||
60 | */ | ||
61 | struct iscsi_bsg_host_vendor { | ||
62 | /* | ||
63 | * Identifies the vendor that the message is formatted for. This | ||
64 | * should be the recipient of the message. | ||
65 | */ | ||
66 | uint64_t vendor_id; | ||
67 | |||
68 | /* start of vendor command area */ | ||
69 | uint32_t vendor_cmd[0]; | ||
70 | }; | ||
71 | |||
72 | /* Response: | ||
73 | */ | ||
74 | struct iscsi_bsg_host_vendor_reply { | ||
75 | /* start of vendor response area */ | ||
76 | uint32_t vendor_rsp[0]; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /* request (CDB) structure of the sg_io_v4 */ | ||
81 | struct iscsi_bsg_request { | ||
82 | uint32_t msgcode; | ||
83 | union { | ||
84 | struct iscsi_bsg_host_vendor h_vendor; | ||
85 | } rqst_data; | ||
86 | } __attribute__((packed)); | ||
87 | |||
88 | |||
89 | /* response (request sense data) structure of the sg_io_v4 */ | ||
90 | struct iscsi_bsg_reply { | ||
91 | /* | ||
92 | * The completion result. Result exists in two forms: | ||
93 | * if negative, it is an -Exxx system errno value. There will | ||
94 | * be no further reply information supplied. | ||
95 | * else, it's the 4-byte scsi error result, with driver, host, | ||
96 | * msg and status fields. The per-msgcode reply structure | ||
97 | * will contain valid data. | ||
98 | */ | ||
99 | uint32_t result; | ||
100 | |||
101 | /* If there was reply_payload, how much was recevied ? */ | ||
102 | uint32_t reply_payload_rcv_len; | ||
103 | |||
104 | union { | ||
105 | struct iscsi_bsg_host_vendor_reply vendor_reply; | ||
106 | } reply_data; | ||
107 | }; | ||
108 | |||
109 | |||
110 | #endif /* SCSI_BSG_ISCSI_H */ | ||
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 77e6dd60fb4..4a3edeeae8f 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -38,6 +38,7 @@ struct iscsi_conn; | |||
38 | struct iscsi_task; | 38 | struct iscsi_task; |
39 | struct sockaddr; | 39 | struct sockaddr; |
40 | struct iscsi_iface; | 40 | struct iscsi_iface; |
41 | struct bsg_job; | ||
41 | 42 | ||
42 | /** | 43 | /** |
43 | * struct iscsi_transport - iSCSI Transport template | 44 | * struct iscsi_transport - iSCSI Transport template |
@@ -141,9 +142,9 @@ struct iscsi_transport { | |||
141 | enum iscsi_param_type param_type, | 142 | enum iscsi_param_type param_type, |
142 | int param, char *buf); | 143 | int param, char *buf); |
143 | mode_t (*attr_is_visible)(int param_type, int param); | 144 | mode_t (*attr_is_visible)(int param_type, int param); |
145 | int (*bsg_request)(struct bsg_job *job); | ||
144 | }; | 146 | }; |
145 | 147 | ||
146 | |||
147 | /* | 148 | /* |
148 | * transport registration upcalls | 149 | * transport registration upcalls |
149 | */ | 150 | */ |
@@ -227,8 +228,12 @@ struct iscsi_cls_session { | |||
227 | struct iscsi_cls_host { | 228 | struct iscsi_cls_host { |
228 | atomic_t nr_scans; | 229 | atomic_t nr_scans; |
229 | struct mutex mutex; | 230 | struct mutex mutex; |
231 | struct request_queue *bsg_q; | ||
230 | }; | 232 | }; |
231 | 233 | ||
234 | #define iscsi_job_to_shost(_job) \ | ||
235 | dev_to_shost(_job->dev) | ||
236 | |||
232 | extern void iscsi_host_for_each_session(struct Scsi_Host *shost, | 237 | extern void iscsi_host_for_each_session(struct Scsi_Host *shost, |
233 | void (*fn)(struct iscsi_cls_session *)); | 238 | void (*fn)(struct iscsi_cls_session *)); |
234 | 239 | ||