[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>
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index ca22ddf..9815a1a 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -102,7 +102,8 @@
 	return 0;
 }
 
-int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag)
+int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
+			     struct scsi_lun *lun, u64 tag)
 {
 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 	struct tgt_event ev;
@@ -110,6 +111,7 @@
 
 	memset(&ev, 0, sizeof(ev));
 	ev.p.cmd_req.host_no = shost->host_no;
+	ev.p.cmd_req.itn_id = itn_id;
 	ev.p.cmd_req.data_len = cmd->request_bufflen;
 	memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
 	memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
@@ -127,7 +129,7 @@
 	return err;
 }
 
-int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag)
 {
 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 	struct tgt_event ev;
@@ -135,6 +137,7 @@
 
 	memset(&ev, 0, sizeof(ev));
 	ev.p.cmd_done.host_no = shost->host_no;
+	ev.p.cmd_done.itn_id = itn_id;
 	ev.p.cmd_done.tag = tag;
 	ev.p.cmd_done.result = cmd->result;
 
@@ -149,14 +152,15 @@
 	return err;
 }
 
-int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
-				  struct scsi_lun *scsilun, void *data)
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function,
+				  u64 tag, struct scsi_lun *scsilun, void *data)
 {
 	struct tgt_event ev;
 	int err;
 
 	memset(&ev, 0, sizeof(ev));
 	ev.p.tsk_mgmt_req.host_no = host_no;
+	ev.p.tsk_mgmt_req.itn_id = itn_id;
 	ev.p.tsk_mgmt_req.function = function;
 	ev.p.tsk_mgmt_req.tag = tag;
 	memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
@@ -172,6 +176,29 @@
 	return err;
 }
 
+int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id,
+					  int function, char *initiator_id)
+{
+	struct tgt_event ev;
+	int err;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.p.it_nexus_req.host_no = host_no;
+	ev.p.it_nexus_req.function = function;
+	ev.p.it_nexus_req.itn_id = itn_id;
+	if (initiator_id)
+		strncpy(ev.p.it_nexus_req.initiator_id, initiator_id,
+			sizeof(ev.p.it_nexus_req.initiator_id));
+
+	dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id);
+
+	err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev);
+	if (err)
+		eprintk("tx buf is full, could not send\n");
+
+	return err;
+}
+
 static int event_recv_msg(struct tgt_event *ev)
 {
 	int err = 0;
@@ -179,6 +206,7 @@
 	switch (ev->hdr.type) {
 	case TGT_UEVENT_CMD_RSP:
 		err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
+					   ev->p.cmd_rsp.itn_id,
 					   ev->p.cmd_rsp.result,
 					   ev->p.cmd_rsp.tag,
 					   ev->p.cmd_rsp.uaddr,
@@ -189,9 +217,15 @@
 		break;
 	case TGT_UEVENT_TSK_MGMT_RSP:
 		err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
+					       ev->p.tsk_mgmt_rsp.itn_id,
 					       ev->p.tsk_mgmt_rsp.mid,
 					       ev->p.tsk_mgmt_rsp.result);
 		break;
+	case TGT_UEVENT_IT_NEXUS_RSP:
+		err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no,
+						   ev->p.it_nexus_rsp.itn_id,
+						   ev->p.it_nexus_rsp.result);
+		break;
 	default:
 		eprintk("unknown type %d\n", ev->hdr.type);
 		err = -EINVAL;