Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

FUJITA Tomonori and committed by
James Bottomley
2c47f9ef aebd5e47

+161 -37
+38 -4
drivers/scsi/scsi_tgt_if.c
··· 102 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 108 struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); 108 109 struct tgt_event ev; ··· 111 110 112 111 memset(&ev, 0, sizeof(ev)); 113 112 ev.p.cmd_req.host_no = shost->host_no; 113 + ev.p.cmd_req.itn_id = itn_id; 114 114 ev.p.cmd_req.data_len = cmd->request_bufflen; 115 115 memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); 116 116 memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); ··· 129 127 return err; 130 128 } 131 129 132 - int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag) 130 + int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag) 133 131 { 134 132 struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); 135 133 struct tgt_event ev; ··· 137 135 138 136 memset(&ev, 0, sizeof(ev)); 139 137 ev.p.cmd_done.host_no = shost->host_no; 138 + ev.p.cmd_done.itn_id = itn_id; 140 139 ev.p.cmd_done.tag = tag; 141 140 ev.p.cmd_done.result = cmd->result; 142 141 ··· 152 149 return err; 153 150 } 154 151 155 - int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, 156 - struct scsi_lun *scsilun, void *data) 152 + int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function, 153 + u64 tag, struct scsi_lun *scsilun, void *data) 157 154 { 158 155 struct tgt_event ev; 159 156 int err; 160 157 161 158 memset(&ev, 0, sizeof(ev)); 162 159 ev.p.tsk_mgmt_req.host_no = host_no; 160 + ev.p.tsk_mgmt_req.itn_id = itn_id; 163 161 ev.p.tsk_mgmt_req.function = function; 164 162 ev.p.tsk_mgmt_req.tag = tag; 165 163 memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); ··· 176 172 return err; 177 173 } 178 174 175 + int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id, 176 + int function, char *initiator_id) 177 + { 178 + struct tgt_event ev; 179 + int err; 180 + 181 + memset(&ev, 0, sizeof(ev)); 182 + ev.p.it_nexus_req.host_no = host_no; 183 + ev.p.it_nexus_req.function = function; 184 + ev.p.it_nexus_req.itn_id = itn_id; 185 + if (initiator_id) 186 + strncpy(ev.p.it_nexus_req.initiator_id, initiator_id, 187 + sizeof(ev.p.it_nexus_req.initiator_id)); 188 + 189 + dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id); 190 + 191 + err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev); 192 + if (err) 193 + eprintk("tx buf is full, could not send\n"); 194 + 195 + return err; 196 + } 197 + 179 198 static int event_recv_msg(struct tgt_event *ev) 180 199 { 181 200 int err = 0; ··· 206 179 switch (ev->hdr.type) { 207 180 case TGT_UEVENT_CMD_RSP: 208 181 err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, 182 + ev->p.cmd_rsp.itn_id, 209 183 ev->p.cmd_rsp.result, 210 184 ev->p.cmd_rsp.tag, 211 185 ev->p.cmd_rsp.uaddr, ··· 217 189 break; 218 190 case TGT_UEVENT_TSK_MGMT_RSP: 219 191 err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, 192 + ev->p.tsk_mgmt_rsp.itn_id, 220 193 ev->p.tsk_mgmt_rsp.mid, 221 194 ev->p.tsk_mgmt_rsp.result); 195 + break; 196 + case TGT_UEVENT_IT_NEXUS_RSP: 197 + err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no, 198 + ev->p.it_nexus_rsp.itn_id, 199 + ev->p.it_nexus_rsp.result); 222 200 break; 223 201 default: 224 202 eprintk("unknown type %d\n", ev->hdr.type);
+70 -13
drivers/scsi/scsi_tgt_lib.c
··· 27 27 #include <scsi/scsi_cmnd.h> 28 28 #include <scsi/scsi_device.h> 29 29 #include <scsi/scsi_host.h> 30 + #include <scsi/scsi_transport.h> 30 31 #include <scsi/scsi_tgt.h> 31 32 32 33 #include "scsi_tgt_priv.h" ··· 47 46 48 47 struct list_head hash_list; 49 48 struct request *rq; 49 + u64 itn_id; 50 50 u64 tag; 51 51 }; 52 52 ··· 187 185 } 188 186 189 187 static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, 190 - u64 tag) 188 + u64 itn_id, u64 tag) 191 189 { 192 190 struct scsi_tgt_queuedata *qdata = rq->q->queuedata; 193 191 unsigned long flags; 194 192 struct list_head *head; 195 193 194 + tcmd->itn_id = itn_id; 196 195 tcmd->tag = tag; 197 196 tcmd->bio = NULL; 198 197 INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); ··· 304 301 * @scsilun: scsi lun 305 302 * @tag: unique value to identify this command for tmf 306 303 */ 307 - int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun, 308 - u64 tag) 304 + int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id, 305 + struct scsi_lun *scsilun, u64 tag) 309 306 { 310 307 struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; 311 308 int err; 312 309 313 - init_scsi_tgt_cmd(cmd->request, tcmd, tag); 314 - err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag); 310 + init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag); 311 + err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag); 315 312 if (err) 316 313 cmd_hashlist_del(cmd); 317 314 ··· 329 326 330 327 dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); 331 328 332 - scsi_tgt_uspace_send_status(cmd, tcmd->tag); 329 + scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); 333 330 334 331 if (cmd->request_buffer) 335 332 scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); ··· 462 459 return rq; 463 460 } 464 461 465 - int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, 462 + int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, 466 463 unsigned long uaddr, u32 len, unsigned long sense_uaddr, 467 464 u32 sense_len, u8 rw) 468 465 { ··· 544 541 return err; 545 542 } 546 543 547 - int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag, 548 - struct scsi_lun *scsilun, void *data) 544 + int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id, 545 + int function, u64 tag, struct scsi_lun *scsilun, 546 + void *data) 549 547 { 550 548 int err; 551 549 552 550 /* TODO: need to retry if this fails. */ 553 - err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function, 554 - tag, scsilun, data); 551 + err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id, 552 + function, tag, scsilun, data); 555 553 if (err < 0) 556 554 eprintk("The task management request lost!\n"); 557 555 return err; 558 556 } 559 557 EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); 560 558 561 - int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result) 559 + int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result) 562 560 { 563 561 struct Scsi_Host *shost; 564 562 int err = -EINVAL; ··· 577 573 goto done; 578 574 } 579 575 580 - err = shost->hostt->tsk_mgmt_response(mid, result); 576 + err = shost->hostt->tsk_mgmt_response(shost, itn_id, mid, result); 577 + done: 578 + scsi_host_put(shost); 579 + return err; 580 + } 581 + 582 + int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, 583 + char *initiator) 584 + { 585 + int err; 586 + 587 + /* TODO: need to retry if this fails. */ 588 + err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0, 589 + initiator); 590 + if (err < 0) 591 + eprintk("The i_t_neuxs request lost, %d %llx!\n", 592 + shost->host_no, (unsigned long long)itn_id); 593 + return err; 594 + } 595 + EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create); 596 + 597 + int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) 598 + { 599 + int err; 600 + 601 + /* TODO: need to retry if this fails. */ 602 + err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, 603 + itn_id, 1, NULL); 604 + if (err < 0) 605 + eprintk("The i_t_neuxs request lost, %d %llx!\n", 606 + shost->host_no, (unsigned long long)itn_id); 607 + return err; 608 + } 609 + EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy); 610 + 611 + int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result) 612 + { 613 + struct Scsi_Host *shost; 614 + int err = -EINVAL; 615 + 616 + dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); 617 + 618 + shost = scsi_host_lookup(host_no); 619 + if (IS_ERR(shost)) { 620 + printk(KERN_ERR "Could not find host no %d\n", host_no); 621 + return err; 622 + } 623 + 624 + if (!shost->uspace_req_q) { 625 + printk(KERN_ERR "Not target scsi host %d\n", host_no); 626 + goto done; 627 + } 628 + 629 + err = shost->transportt->it_nexus_response(shost, itn_id, result); 581 630 done: 582 631 scsi_host_put(shost); 583 632 return err;
+14 -8
drivers/scsi/scsi_tgt_priv.h
··· 15 15 extern void scsi_tgt_if_exit(void); 16 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, 19 - u64 tag); 20 - extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag); 21 - extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag, 22 - unsigned long uaddr, u32 len, unsigned long sense_uaddr, 23 - u32 sense_len, u8 rw); 24 - extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag, 18 + extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id, 19 + struct scsi_lun *lun, u64 tag); 20 + extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id, 21 + u64 tag); 22 + extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag, 23 + unsigned long uaddr, u32 len, 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 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);
+1 -1
include/scsi/scsi_host.h
··· 146 146 void (*done)(struct scsi_cmnd *)); 147 147 148 148 /* Used as callback for the completion of task management request. */ 149 - int (* tsk_mgmt_response)(u64 mid, int result); 149 + int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64 mid, int result); 150 150 151 151 /* 152 152 * This is an error handling strategy routine. You don't need to
+5 -3
include/scsi/scsi_tgt.h
··· 11 11 extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *); 12 12 extern int scsi_tgt_alloc_queue(struct Scsi_Host *); 13 13 extern void scsi_tgt_free_queue(struct Scsi_Host *); 14 - extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64); 15 - extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *, 16 - void *); 14 + extern int scsi_tgt_queue_command(struct scsi_cmnd *, u64, struct scsi_lun *, u64); 15 + extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, u64, int, u64, 16 + struct scsi_lun *, void *); 17 17 extern struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *, 18 18 enum dma_data_direction, gfp_t); 19 19 extern void scsi_host_put_command(struct Scsi_Host *, struct scsi_cmnd *); 20 + extern int scsi_tgt_it_nexus_create(struct Scsi_Host *, u64, char *); 21 + extern int scsi_tgt_it_nexus_destroy(struct Scsi_Host *, u64);
+27 -8
include/scsi/scsi_tgt_if.h
··· 23 23 #define __SCSI_TARGET_IF_H 24 24 25 25 /* user -> kernel */ 26 - #define TGT_UEVENT_CMD_RSP 0x0001 27 - #define TGT_UEVENT_TSK_MGMT_RSP 0x0002 26 + #define TGT_UEVENT_CMD_RSP 0x0001 27 + #define TGT_UEVENT_IT_NEXUS_RSP 0x0002 28 + #define TGT_UEVENT_TSK_MGMT_RSP 0x0003 28 29 29 30 /* kernel -> user */ 30 - #define TGT_KEVENT_CMD_REQ 0x1001 31 - #define TGT_KEVENT_CMD_DONE 0x1002 32 - #define TGT_KEVENT_TSK_MGMT_REQ 0x1003 31 + #define TGT_KEVENT_CMD_REQ 0x1001 32 + #define TGT_KEVENT_CMD_DONE 0x1002 33 + #define TGT_KEVENT_IT_NEXUS_REQ 0x1003 34 + #define TGT_KEVENT_TSK_MGMT_REQ 0x1004 33 35 34 36 struct tgt_event_hdr { 35 37 uint16_t version; ··· 48 46 struct { 49 47 int host_no; 50 48 int result; 49 + aligned_u64 itn_id; 51 50 aligned_u64 tag; 52 51 aligned_u64 uaddr; 53 52 aligned_u64 sense_uaddr; ··· 58 55 } cmd_rsp; 59 56 struct { 60 57 int host_no; 61 - aligned_u64 mid; 62 58 int result; 59 + aligned_u64 itn_id; 60 + aligned_u64 mid; 63 61 } tsk_mgmt_rsp; 64 - 62 + struct { 63 + __s32 host_no; 64 + __s32 result; 65 + aligned_u64 itn_id; 66 + __u32 function; 67 + } it_nexus_rsp; 65 68 66 69 /* kernel -> user */ 67 70 struct { 68 71 int host_no; 69 72 uint32_t data_len; 73 + aligned_u64 itn_id; 70 74 uint8_t scb[16]; 71 75 uint8_t lun[8]; 72 76 int attribute; ··· 81 71 } cmd_req; 82 72 struct { 83 73 int host_no; 84 - aligned_u64 tag; 85 74 int result; 75 + aligned_u64 itn_id; 76 + aligned_u64 tag; 86 77 } cmd_done; 87 78 struct { 88 79 int host_no; 89 80 int function; 81 + aligned_u64 itn_id; 90 82 aligned_u64 tag; 91 83 uint8_t lun[8]; 92 84 aligned_u64 mid; 93 85 } tsk_mgmt_req; 86 + struct { 87 + __s32 host_no; 88 + __u32 function; 89 + aligned_u64 itn_id; 90 + __u32 max_cmds; 91 + __u8 initiator_id[16]; 92 + } it_nexus_req; 94 93 } p; 95 94 } __attribute__ ((aligned (sizeof(uint64_t)))); 96 95
+6
include/scsi/scsi_transport.h
··· 65 65 * EH_NOT_HANDLED Begin normal error recovery 66 66 */ 67 67 enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); 68 + 69 + /* 70 + * Used as callback for the completion of i_t_nexus request 71 + * for target drivers. 72 + */ 73 + int (* it_nexus_response)(struct Scsi_Host *, u64, int); 68 74 }; 69 75 70 76 #define transport_class_to_shost(tc) \