diff options
author | FUJITA Tomonori <tomof@acm.org> | 2007-07-11 02:08:17 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:37:50 -0400 |
commit | 2c47f9efbedbe5749b6bb16e59bc11d6e460855f (patch) | |
tree | bfc1a2154f67c3aa45f92e586678ffc37e5f80eb /drivers/scsi | |
parent | aebd5e476ecc8ceb53577b20f2a352ff4ceffd8d (diff) |
[SCSI] tgt: add I_T nexus support
tgt uses scsi_host as I_T nexus. This works for ibmvstgt because it
creates one scsi_host for one initiator. However, other target drivers
don't work like that.
This adds I_T nexus support, which enable one scsi_host to handle
multiple initiators. New scsi_tgt_it_nexus_create/destroy functions
are expected be called transport classes. For example, ibmvstgt
creates an initiator remote port, then the srp transport calls
tgt_it_nexus_create. tgt doesn't manages I_T nexus, instead it tells
tgtd, user-space daemon, to create a new I_T nexus.
On the receiving the response from tgtd, tgt calls
shost->transportt->it_nexus_response. transports should notify a
lld. The srp transport uses it_nexus_response callback in
srp_function_template to do that.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_tgt_if.c | 42 | ||||
-rw-r--r-- | drivers/scsi/scsi_tgt_lib.c | 83 | ||||
-rw-r--r-- | drivers/scsi/scsi_tgt_priv.h | 22 |
3 files changed, 122 insertions, 25 deletions
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index ca22ddf81746..9815a1a2db24 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c | |||
@@ -102,7 +102,8 @@ static int tgt_uspace_send_event(u32 type, struct tgt_event *p) | |||
102 | return 0; | 102 | return 0; |
103 | } | 103 | } |
104 | 104 | ||
105 | int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag) | 105 | int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id, |
106 | struct scsi_lun *lun, u64 tag) | ||
106 | { | 107 | { |
107 | struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); | 108 | struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); |
108 | struct tgt_event ev; | 109 | struct tgt_event ev; |
@@ -110,6 +111,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta | |||
110 | 111 | ||
111 | memset(&ev, 0, sizeof(ev)); | 112 | memset(&ev, 0, sizeof(ev)); |
112 | ev.p.cmd_req.host_no = shost->host_no; | 113 | ev.p.cmd_req.host_no = shost->host_no; |
114 | ev.p.cmd_req.itn_id = itn_id; | ||
113 | ev.p.cmd_req.data_len = cmd->request_bufflen; | 115 | ev.p.cmd_req.data_len = cmd->request_bufflen; |
114 | memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); | 116 | memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); |
115 | memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); | 117 | memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); |
@@ -127,7 +129,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta | |||
127 | return err; | 129 | return err; |
128 | } | 130 | } |
129 | 131 | ||
130 | int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) | 132 | int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag) |
131 | { | 133 | { |
132 | struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); | 134 | struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); |
133 | struct tgt_event ev; | 135 | struct tgt_event ev; |
@@ -135,6 +137,7 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) | |||
135 | 137 | ||
136 | memset(&ev, 0, sizeof(ev)); | 138 | memset(&ev, 0, sizeof(ev)); |
137 | ev.p.cmd_done.host_no = shost->host_no; | 139 | ev.p.cmd_done.host_no = shost->host_no; |
140 | ev.p.cmd_done.itn_id = itn_id; | ||
138 | ev.p.cmd_done.tag = tag; | 141 | ev.p.cmd_done.tag = tag; |
139 | ev.p.cmd_done.result = cmd->result; | 142 | ev.p.cmd_done.result = cmd->result; |
140 | 143 | ||
@@ -149,14 +152,15 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) | |||
149 | return err; | 152 | return err; |
150 | } | 153 | } |
151 | 154 | ||
152 | int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, | 155 | int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function, |
153 | struct scsi_lun *scsilun, void *data) | 156 | u64 tag, struct scsi_lun *scsilun, void *data) |
154 | { | 157 | { |
155 | struct tgt_event ev; | 158 | struct tgt_event ev; |
156 | int err; | 159 | int err; |
157 | 160 | ||
158 | memset(&ev, 0, sizeof(ev)); | 161 | memset(&ev, 0, sizeof(ev)); |
159 | ev.p.tsk_mgmt_req.host_no = host_no; | 162 | ev.p.tsk_mgmt_req.host_no = host_no; |
163 | ev.p.tsk_mgmt_req.itn_id = itn_id; | ||
160 | ev.p.tsk_mgmt_req.function = function; | 164 | ev.p.tsk_mgmt_req.function = function; |
161 | ev.p.tsk_mgmt_req.tag = tag; | 165 | ev.p.tsk_mgmt_req.tag = tag; |
162 | memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); | 166 | memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); |
@@ -172,6 +176,29 @@ int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, | |||
172 | return err; | 176 | return err; |
173 | } | 177 | } |
174 | 178 | ||
179 | int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id, | ||
180 | int function, char *initiator_id) | ||
181 | { | ||
182 | struct tgt_event ev; | ||
183 | int err; | ||
184 | |||
185 | memset(&ev, 0, sizeof(ev)); | ||
186 | ev.p.it_nexus_req.host_no = host_no; | ||
187 | ev.p.it_nexus_req.function = function; | ||
188 | ev.p.it_nexus_req.itn_id = itn_id; | ||
189 | if (initiator_id) | ||
190 | strncpy(ev.p.it_nexus_req.initiator_id, initiator_id, | ||
191 | sizeof(ev.p.it_nexus_req.initiator_id)); | ||
192 | |||
193 | dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id); | ||
194 | |||
195 | err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev); | ||
196 | if (err) | ||
197 | eprintk("tx buf is full, could not send\n"); | ||
198 | |||
199 | return err; | ||
200 | } | ||
201 | |||
175 | static int event_recv_msg(struct tgt_event *ev) | 202 | static int event_recv_msg(struct tgt_event *ev) |
176 | { | 203 | { |
177 | int err = 0; | 204 | int err = 0; |
@@ -179,6 +206,7 @@ static int event_recv_msg(struct tgt_event *ev) | |||
179 | switch (ev->hdr.type) { | 206 | switch (ev->hdr.type) { |
180 | case TGT_UEVENT_CMD_RSP: | 207 | case TGT_UEVENT_CMD_RSP: |
181 | err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, | 208 | err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, |
209 | ev->p.cmd_rsp.itn_id, | ||
182 | ev->p.cmd_rsp.result, | 210 | ev->p.cmd_rsp.result, |
183 | ev->p.cmd_rsp.tag, | 211 | ev->p.cmd_rsp.tag, |
184 | ev->p.cmd_rsp.uaddr, | 212 | ev->p.cmd_rsp.uaddr, |
@@ -189,9 +217,15 @@ static int event_recv_msg(struct tgt_event *ev) | |||
189 | break; | 217 | break; |
190 | case TGT_UEVENT_TSK_MGMT_RSP: | 218 | case TGT_UEVENT_TSK_MGMT_RSP: |
191 | err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, | 219 | err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, |
220 | ev->p.tsk_mgmt_rsp.itn_id, | ||
192 | ev->p.tsk_mgmt_rsp.mid, | 221 | ev->p.tsk_mgmt_rsp.mid, |
193 | ev->p.tsk_mgmt_rsp.result); | 222 | ev->p.tsk_mgmt_rsp.result); |
194 | break; | 223 | break; |
224 | case TGT_UEVENT_IT_NEXUS_RSP: | ||
225 | err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no, | ||
226 | ev->p.it_nexus_rsp.itn_id, | ||
227 | ev->p.it_nexus_rsp.result); | ||
228 | break; | ||
195 | default: | 229 | default: |
196 | eprintk("unknown type %d\n", ev->hdr.type); | 230 | eprintk("unknown type %d\n", ev->hdr.type); |
197 | err = -EINVAL; | 231 | err = -EINVAL; |
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index 371b69c110bc..fa79e54722db 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <scsi/scsi_cmnd.h> | 27 | #include <scsi/scsi_cmnd.h> |
28 | #include <scsi/scsi_device.h> | 28 | #include <scsi/scsi_device.h> |
29 | #include <scsi/scsi_host.h> | 29 | #include <scsi/scsi_host.h> |
30 | #include <scsi/scsi_transport.h> | ||
30 | #include <scsi/scsi_tgt.h> | 31 | #include <scsi/scsi_tgt.h> |
31 | 32 | ||
32 | #include "scsi_tgt_priv.h" | 33 | #include "scsi_tgt_priv.h" |
@@ -46,6 +47,7 @@ struct scsi_tgt_cmd { | |||
46 | 47 | ||
47 | struct list_head hash_list; | 48 | struct list_head hash_list; |
48 | struct request *rq; | 49 | struct request *rq; |
50 | u64 itn_id; | ||
49 | u64 tag; | 51 | u64 tag; |
50 | }; | 52 | }; |
51 | 53 | ||
@@ -185,12 +187,13 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) | |||
185 | } | 187 | } |
186 | 188 | ||
187 | static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, | 189 | static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, |
188 | u64 tag) | 190 | u64 itn_id, u64 tag) |
189 | { | 191 | { |
190 | struct scsi_tgt_queuedata *qdata = rq->q->queuedata; | 192 | struct scsi_tgt_queuedata *qdata = rq->q->queuedata; |
191 | unsigned long flags; | 193 | unsigned long flags; |
192 | struct list_head *head; | 194 | struct list_head *head; |
193 | 195 | ||
196 | tcmd->itn_id = itn_id; | ||
194 | tcmd->tag = tag; | 197 | tcmd->tag = tag; |
195 | tcmd->bio = NULL; | 198 | tcmd->bio = NULL; |
196 | INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); | 199 | INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); |
@@ -301,14 +304,14 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host); | |||
301 | * @scsilun: scsi lun | 304 | * @scsilun: scsi lun |
302 | * @tag: unique value to identify this command for tmf | 305 | * @tag: unique value to identify this command for tmf |
303 | */ | 306 | */ |
304 | int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun, | 307 | int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id, |
305 | u64 tag) | 308 | struct scsi_lun *scsilun, u64 tag) |
306 | { | 309 | { |
307 | struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; | 310 | struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; |
308 | int err; | 311 | int err; |
309 | 312 | ||
310 | init_scsi_tgt_cmd(cmd->request, tcmd, tag); | 313 | init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag); |
311 | err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag); | 314 | err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag); |
312 | if (err) | 315 | if (err) |
313 | cmd_hashlist_del(cmd); | 316 | cmd_hashlist_del(cmd); |
314 | 317 | ||
@@ -326,7 +329,7 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) | |||
326 | 329 | ||
327 | dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); | 330 | dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); |
328 | 331 | ||
329 | scsi_tgt_uspace_send_status(cmd, tcmd->tag); | 332 | scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); |
330 | 333 | ||
331 | if (cmd->request_buffer) | 334 | if (cmd->request_buffer) |
332 | scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); | 335 | scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); |
@@ -459,7 +462,7 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) | |||
459 | return rq; | 462 | return rq; |
460 | } | 463 | } |
461 | 464 | ||
462 | int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, | 465 | int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, |
463 | unsigned long uaddr, u32 len, unsigned long sense_uaddr, | 466 | unsigned long uaddr, u32 len, unsigned long sense_uaddr, |
464 | u32 sense_len, u8 rw) | 467 | u32 sense_len, u8 rw) |
465 | { | 468 | { |
@@ -541,21 +544,22 @@ done: | |||
541 | return err; | 544 | return err; |
542 | } | 545 | } |
543 | 546 | ||
544 | int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag, | 547 | int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id, |
545 | struct scsi_lun *scsilun, void *data) | 548 | int function, u64 tag, struct scsi_lun *scsilun, |
549 | void *data) | ||
546 | { | 550 | { |
547 | int err; | 551 | int err; |
548 | 552 | ||
549 | /* TODO: need to retry if this fails. */ | 553 | /* TODO: need to retry if this fails. */ |
550 | err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function, | 554 | err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id, |
551 | tag, scsilun, data); | 555 | function, tag, scsilun, data); |
552 | if (err < 0) | 556 | if (err < 0) |
553 | eprintk("The task management request lost!\n"); | 557 | eprintk("The task management request lost!\n"); |
554 | return err; | 558 | return err; |
555 | } | 559 | } |
556 | EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); | 560 | EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); |
557 | 561 | ||
558 | int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) | 562 | int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result) |
559 | { | 563 | { |
560 | struct Scsi_Host *shost; | 564 | struct Scsi_Host *shost; |
561 | int err = -EINVAL; | 565 | int err = -EINVAL; |
@@ -573,7 +577,60 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) | |||
573 | goto done; | 577 | goto done; |
574 | } | 578 | } |
575 | 579 | ||
576 | err = shost->hostt->tsk_mgmt_response(mid, result); | 580 | err = shost->hostt->tsk_mgmt_response(shost, itn_id, mid, result); |
581 | done: | ||
582 | scsi_host_put(shost); | ||
583 | return err; | ||
584 | } | ||
585 | |||
586 | int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, | ||
587 | char *initiator) | ||
588 | { | ||
589 | int err; | ||
590 | |||
591 | /* TODO: need to retry if this fails. */ | ||
592 | err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0, | ||
593 | initiator); | ||
594 | if (err < 0) | ||
595 | eprintk("The i_t_neuxs request lost, %d %llx!\n", | ||
596 | shost->host_no, (unsigned long long)itn_id); | ||
597 | return err; | ||
598 | } | ||
599 | EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create); | ||
600 | |||
601 | int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) | ||
602 | { | ||
603 | int err; | ||
604 | |||
605 | /* TODO: need to retry if this fails. */ | ||
606 | err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, | ||
607 | itn_id, 1, NULL); | ||
608 | if (err < 0) | ||
609 | eprintk("The i_t_neuxs request lost, %d %llx!\n", | ||
610 | shost->host_no, (unsigned long long)itn_id); | ||
611 | return err; | ||
612 | } | ||
613 | EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy); | ||
614 | |||
615 | int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result) | ||
616 | { | ||
617 | struct Scsi_Host *shost; | ||
618 | int err = -EINVAL; | ||
619 | |||
620 | dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); | ||
621 | |||
622 | shost = scsi_host_lookup(host_no); | ||
623 | if (IS_ERR(shost)) { | ||
624 | printk(KERN_ERR "Could not find host no %d\n", host_no); | ||
625 | return err; | ||
626 | } | ||
627 | |||
628 | if (!shost->uspace_req_q) { | ||
629 | printk(KERN_ERR "Not target scsi host %d\n", host_no); | ||
630 | goto done; | ||
631 | } | ||
632 | |||
633 | err = shost->transportt->it_nexus_response(shost, itn_id, result); | ||
577 | done: | 634 | done: |
578 | scsi_host_put(shost); | 635 | scsi_host_put(shost); |
579 | return err; | 636 | return err; |
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h index e9e6db1c417f..cb92888948f9 100644 --- a/drivers/scsi/scsi_tgt_priv.h +++ b/drivers/scsi/scsi_tgt_priv.h | |||
@@ -15,12 +15,18 @@ do { \ | |||
15 | extern void scsi_tgt_if_exit(void); | 15 | extern void scsi_tgt_if_exit(void); |
16 | extern int scsi_tgt_if_init(void); | 16 | extern int scsi_tgt_if_init(void); |
17 | 17 | ||
18 | extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, | 18 | extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id, |
19 | u64 tag); | 19 | struct scsi_lun *lun, u64 tag); |
20 | extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); | 20 | extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id, |
21 | extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, | 21 | u64 tag); |
22 | unsigned long uaddr, u32 len, unsigned long sense_uaddr, | 22 | extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag, |
23 | u32 sense_len, u8 rw); | 23 | unsigned long uaddr, u32 len, |
24 | extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, | 24 | unsigned long sense_uaddr, u32 sense_len, u8 rw); |
25 | extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id, | ||
26 | int function, u64 tag, | ||
25 | struct scsi_lun *scsilun, void *data); | 27 | struct scsi_lun *scsilun, void *data); |
26 | extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result); | 28 | extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id, |
29 | u64 mid, int result); | ||
30 | extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id, | ||
31 | int function, char *initiator); | ||
32 | extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result); | ||