From 0801c242a33426fddc005c2f559a3d2fa6fca7eb Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:12 -0500 Subject: [SCSI] libiscsi, iscsi_tcp, ib_iser : add sw iscsi host get/set params helpers iscsid and udev need to key off the hw address being used so add some helpers for iser and iscsi tcp. Also convert them Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index c9a3abf9e7b..9a42fc074b7 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2181,6 +2181,7 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, + .host_param_mask = ISCSI_HOST_HWADDRESS, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, @@ -2197,6 +2198,9 @@ static struct iscsi_transport iscsi_tcp_transport = { .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, .stop_conn = iscsi_tcp_conn_stop, + /* iscsi host params */ + .get_host_param = iscsi_host_get_param, + .set_host_param = iscsi_host_set_param, /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, -- cgit v1.2.3 From 8ad5781ae9702a8f95cfdf30967752e4297613ee Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:13 -0500 Subject: [SCSI] iscsi class, qla4xxx, iscsi_tcp, ib_iser: export/set initiator name For iscsi root boot, software iscsi needs to know what the BIOS/OF initiator used for the initiator name so this puts it in sysfs for userspace to be able to pick up. For hw iscsi, it is nice to see what the card is using. This patch adds the new param, and hooks in qla4xxx, iscsi_tcp, and ib_iser. Signed-off-by: Mike Christie Cc: Roland Dreier Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 9a42fc074b7..8201e6c4d8a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2181,7 +2181,8 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, - .host_param_mask = ISCSI_HOST_HWADDRESS, + .host_param_mask = ISCSI_HOST_HWADDRESS | + ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, -- cgit v1.2.3 From d473cc7f15f64ab8a90c3d7288ef30f46785d8d5 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:14 -0500 Subject: [SCSI] iscsi: Some fixes in preparation for bidirectional support - exp_datasn This patch fixes handling of expected datasn/r2tsn as received from target. It is done according to: T10 rfc3720 section 3.2.2.3. Data Sequencing. . unify expected datasn/r2tsn into one counter . calculate than check expected datasn/r2tsn. On error print a message and fail the request. (TODO use iscsi retransmits) . remove the FIXME ;) . avoid zero length memset Signed-off-by: Boaz Harrosh Signed-off-by: Benny Halevy Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8201e6c4d8a..17fc79c408a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -229,10 +229,13 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) if (tcp_conn->in.datalen == 0) return 0; - if (ctask->datasn != datasn) + if (tcp_ctask->exp_datasn != datasn) { + debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n", + __FUNCTION__, tcp_ctask->exp_datasn, datasn); return ISCSI_ERR_DATASN; + } - ctask->datasn++; + tcp_ctask->exp_datasn++; tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length) @@ -365,15 +368,16 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return ISCSI_ERR_DATALEN; } - if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn) + if (tcp_ctask->exp_datasn != r2tsn){ + debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n", + __FUNCTION__, tcp_ctask->exp_datasn, r2tsn); return ISCSI_ERR_R2TSN; + } rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); if (rc) return rc; - /* FIXME: use R2TSN to detect missing R2T */ - /* fill-in new R2T associated with the task */ spin_lock(&session->lock); if (!ctask->sc || ctask->mtask || @@ -414,7 +418,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) iscsi_solicit_data_init(conn, ctask, r2t); - tcp_ctask->exp_r2tsn = r2tsn + 1; + tcp_ctask->exp_datasn = r2tsn + 1; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); tcp_ctask->xmstate |= XMSTATE_SOL_HDR; list_move_tail(&ctask->running, &conn->xmitqueue); @@ -1284,10 +1288,10 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) tcp_ctask->sent = 0; tcp_ctask->sg_count = 0; + tcp_ctask->exp_datasn = 0; if (sc->sc_data_direction == DMA_TO_DEVICE) { tcp_ctask->xmstate = XMSTATE_W_HDR; - tcp_ctask->exp_r2tsn = 0; BUG_ON(ctask->total_length == 0); if (sc->use_sg) { -- cgit v1.2.3 From 857ae0bdb72999936a28ce621e38e2e288c485da Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:15 -0500 Subject: [SCSI] iscsi: Some fixes in preparation for bidirectional support - total_length - Remove shadow of request length from struct iscsi_cmd_task. - change all users to use scsi_cmnd->request_bufflen directly (With bidi we will use scsi-ml API to retrieve in/out length) Signed-off-by: Boaz Harrosh Signed-off-by: Benny Halevy Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 17fc79c408a..b2827d112cb 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -216,6 +216,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; struct iscsi_session *session = conn->session; + struct scsi_cmnd *sc = ctask->sc; int datasn = be32_to_cpu(rhdr->datasn); rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); @@ -238,12 +239,14 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn++; tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); - if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length) + if (tcp_ctask->data_offset + tcp_conn->in.datalen > sc->request_bufflen) { + debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", + __FUNCTION__, tcp_ctask->data_offset, + tcp_conn->in.datalen, sc->request_bufflen); return ISCSI_ERR_DATA_OFFSET; + } if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) { - struct scsi_cmnd *sc = ctask->sc; - conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) { int res_count = be32_to_cpu(rhdr->residual_count); @@ -405,11 +408,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length, session->max_burst); r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > ctask->total_length) { + if (r2t->data_offset + r2t->data_length > ctask->sc->request_bufflen) { spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " "offset %u and total length %d\n", r2t->data_length, - r2t->data_offset, ctask->total_length); + r2t->data_offset, ctask->sc->request_bufflen); return ISCSI_ERR_DATALEN; } @@ -604,7 +607,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; int buf_left = buf_size - (tcp_conn->data_copied + offset); - int size = min(tcp_conn->in.copy, buf_left); + unsigned size = min(tcp_conn->in.copy, buf_left); int rc; size = min(size, ctask->data_count); @@ -613,7 +616,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, size, tcp_conn->in.offset, tcp_conn->in.copied); BUG_ON(size <= 0); - BUG_ON(tcp_ctask->sent + size > ctask->total_length); + BUG_ON(tcp_ctask->sent + size > ctask->sc->request_bufflen); rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, (char*)buf + (offset + tcp_conn->data_copied), size); @@ -1292,7 +1295,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) if (sc->sc_data_direction == DMA_TO_DEVICE) { tcp_ctask->xmstate = XMSTATE_W_HDR; - BUG_ON(ctask->total_length == 0); + BUG_ON(sc->request_bufflen == 0); if (sc->use_sg) { struct scatterlist *sg = sc->request_buffer; @@ -1309,7 +1312,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) } debug_scsi("cmd [itt 0x%x total %d imm_data %d " "unsol count %d, unsol offset %d]\n", - ctask->itt, ctask->total_length, ctask->imm_count, + ctask->itt, sc->request_bufflen, ctask->imm_count, ctask->unsol_count, ctask->unsol_offset); } else tcp_ctask->xmstate = XMSTATE_R_HDR; -- cgit v1.2.3 From b2c6416736b847b91950bd43cc5153e11a1f83ee Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:16 -0500 Subject: [SCSI] iscsi class, iscsi_tcp, ib_iser: add sysfs chap file The attached patches add sysfs files for the chap settings to the iscsi transport class, iscsi_tcp and ib_iser. This is needed for software iscsi because there are times when iscsid can die and it will need to reread the values it was using. And it is needed by qla4xxx for basic management opertaions. This patch does not hook in qla4xxx yet, because I am not sure the mbx command to use. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b2827d112cb..1e722f5aabd 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2186,8 +2186,9 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_EXP_STATSN | ISCSI_PERSISTENT_PORT | ISCSI_PERSISTENT_ADDRESS | - ISCSI_TARGET_NAME | - ISCSI_TPGT, + ISCSI_TARGET_NAME | ISCSI_TPGT | + ISCSI_USERNAME | ISCSI_PASSWORD | + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_sht, -- cgit v1.2.3 From 218432c68085d6c2b04df57daaf105d2ffa2aa61 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:17 -0500 Subject: [SCSI] iscsi tcp: fix iscsi xmit state machine If iscsi_tcp partially sends a header, it would recalculate the header size and readd the size of the digest (if header digests are used).This would cause us to send sizeof(digest) extra bytes when we sent the rest of the header. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 258 ++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 113 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1e722f5aabd..0afdca2224c 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -109,7 +109,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, struct iscsi_tcp_conn *tcp_conn = conn->dd_data; crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); - buf->sg.length = tcp_conn->hdr_size; + buf->sg.length += sizeof(u32); } static inline int @@ -423,7 +423,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn = r2tsn + 1; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); - tcp_ctask->xmstate |= XMSTATE_SOL_HDR; + tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT; list_move_tail(&ctask->running, &conn->xmitqueue); scsi_queue_work(session->host, &conn->xmitwork); @@ -1284,41 +1284,10 @@ static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask, static void iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) { - struct scsi_cmnd *sc = ctask->sc; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); - - tcp_ctask->sent = 0; - tcp_ctask->sg_count = 0; - tcp_ctask->exp_datasn = 0; - - if (sc->sc_data_direction == DMA_TO_DEVICE) { - tcp_ctask->xmstate = XMSTATE_W_HDR; - BUG_ON(sc->request_bufflen == 0); - - if (sc->use_sg) { - struct scatterlist *sg = sc->request_buffer; - - iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg); - tcp_ctask->sg = sg + 1; - tcp_ctask->bad_sg = sg + sc->use_sg; - } else { - iscsi_buf_init_iov(&tcp_ctask->sendbuf, - sc->request_buffer, - sc->request_bufflen); - tcp_ctask->sg = NULL; - tcp_ctask->bad_sg = NULL; - } - debug_scsi("cmd [itt 0x%x total %d imm_data %d " - "unsol count %d, unsol offset %d]\n", - ctask->itt, sc->request_bufflen, ctask->imm_count, - ctask->unsol_count, ctask->unsol_offset); - } else - tcp_ctask->xmstate = XMSTATE_R_HDR; - - iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, - sizeof(struct iscsi_hdr)); + tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT; } /** @@ -1331,9 +1300,11 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) * call it again later, or recover. '0' return code means successful * xmit. * - * Management xmit state machine consists of two states: - * IN_PROGRESS_IMM_HEAD - PDU Header xmit in progress - * IN_PROGRESS_IMM_DATA - PDU Data xmit in progress + * Management xmit state machine consists of these states: + * XMSTATE_IMM_HDR_INIT - calculate digest of PDU Header + * XMSTATE_IMM_HDR - PDU Header xmit in progress + * XMSTATE_IMM_DATA - PDU Data xmit in progress + * XMSTATE_IDLE - management PDU is done **/ static int iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) @@ -1344,23 +1315,34 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", conn->id, tcp_mtask->xmstate, mtask->itt); - if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) { - tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR; - if (mtask->data_count) + if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) { + iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, + sizeof(struct iscsi_hdr)); + + if (mtask->data_count) { tcp_mtask->xmstate |= XMSTATE_IMM_DATA; + iscsi_buf_init_iov(&tcp_mtask->sendbuf, + (char*)mtask->data, + mtask->data_count); + } + if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && conn->stop_stage != STOP_CONN_RECOVER && conn->hdrdgst_en) iscsi_hdr_digest(conn, &tcp_mtask->headbuf, (u8*)tcp_mtask->hdrext); + + tcp_mtask->sent = 0; + tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR_INIT; + tcp_mtask->xmstate |= XMSTATE_IMM_HDR; + } + + if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) { rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf, mtask->data_count); - if (rc) { - tcp_mtask->xmstate |= XMSTATE_IMM_HDR; - if (mtask->data_count) - tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA; + if (rc) return rc; - } + tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR; } if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) { @@ -1394,55 +1376,75 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) return 0; } -static inline int -iscsi_send_read_hdr(struct iscsi_conn *conn, - struct iscsi_tcp_cmd_task *tcp_ctask) +static int +iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { - int rc; + struct scsi_cmnd *sc = ctask->sc; + struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + int rc = 0; - tcp_ctask->xmstate &= ~XMSTATE_R_HDR; - if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &tcp_ctask->headbuf, - (u8*)tcp_ctask->hdrext); - rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0); - if (!rc) { - BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE); - return 0; /* wait for Data-In */ - } - tcp_ctask->xmstate |= XMSTATE_R_HDR; - return rc; -} + if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_INIT) { + tcp_ctask->sent = 0; + tcp_ctask->sg_count = 0; + tcp_ctask->exp_datasn = 0; + + if (sc->sc_data_direction == DMA_TO_DEVICE) { + if (sc->use_sg) { + struct scatterlist *sg = sc->request_buffer; + + iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg); + tcp_ctask->sg = sg + 1; + tcp_ctask->bad_sg = sg + sc->use_sg; + } else { + iscsi_buf_init_iov(&tcp_ctask->sendbuf, + sc->request_buffer, + sc->request_bufflen); + tcp_ctask->sg = NULL; + tcp_ctask->bad_sg = NULL; + } -static inline int -iscsi_send_write_hdr(struct iscsi_conn *conn, - struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - int rc; + debug_scsi("cmd [itt 0x%x total %d imm_data %d " + "unsol count %d, unsol offset %d]\n", + ctask->itt, sc->request_bufflen, + ctask->imm_count, ctask->unsol_count, + ctask->unsol_offset); + } - tcp_ctask->xmstate &= ~XMSTATE_W_HDR; - if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &tcp_ctask->headbuf, - (u8*)tcp_ctask->hdrext); - rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); - if (rc) { - tcp_ctask->xmstate |= XMSTATE_W_HDR; - return rc; + iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, + sizeof(struct iscsi_hdr)); + + if (conn->hdrdgst_en) + iscsi_hdr_digest(conn, &tcp_ctask->headbuf, + (u8*)tcp_ctask->hdrext); + tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT; + tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT; } - if (ctask->imm_count) { - tcp_ctask->xmstate |= XMSTATE_IMM_DATA; - iscsi_set_padding(tcp_ctask, ctask->imm_count); + if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_XMIT) { + rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); + if (rc) + return rc; + tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_XMIT; + + if (sc->sc_data_direction != DMA_TO_DEVICE) + return 0; + + if (ctask->imm_count) { + tcp_ctask->xmstate |= XMSTATE_IMM_DATA; + iscsi_set_padding(tcp_ctask, ctask->imm_count); - if (ctask->conn->datadgst_en) { - iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask); - tcp_ctask->immdigest = 0; + if (ctask->conn->datadgst_en) { + iscsi_data_digest_init(ctask->conn->dd_data, + tcp_ctask); + tcp_ctask->immdigest = 0; + } } - } - if (ctask->unsol_count) - tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT; - return 0; + if (ctask->unsol_count) + tcp_ctask->xmstate |= + XMSTATE_UNS_HDR | XMSTATE_UNS_INIT; + } + return rc; } static int @@ -1631,9 +1633,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn, struct iscsi_data_task *dtask; int left, rc; - if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) { - tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; - tcp_ctask->xmstate |= XMSTATE_SOL_DATA; + if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) { if (!tcp_ctask->r2t) { spin_lock_bh(&session->lock); __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, @@ -1647,12 +1647,19 @@ send_hdr: if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &r2t->headbuf, (u8*)dtask->hdrext); + tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR_INIT; + tcp_ctask->xmstate |= XMSTATE_SOL_HDR; + } + + if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) { + r2t = tcp_ctask->r2t; + dtask = &r2t->dtask; + rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count); - if (rc) { - tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA; - tcp_ctask->xmstate |= XMSTATE_SOL_HDR; + if (rc) return rc; - } + tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; + tcp_ctask->xmstate |= XMSTATE_SOL_DATA; if (conn->datadgst_en) { iscsi_data_digest_init(conn->dd_data, tcp_ctask); @@ -1684,8 +1691,6 @@ send_hdr: left = r2t->data_length - r2t->sent; if (left) { iscsi_solicit_data_cont(conn, ctask, r2t, left); - tcp_ctask->xmstate |= XMSTATE_SOL_DATA; - tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; goto send_hdr; } @@ -1700,8 +1705,6 @@ send_hdr: if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { tcp_ctask->r2t = r2t; - tcp_ctask->xmstate |= XMSTATE_SOL_DATA; - tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR; spin_unlock_bh(&session->lock); goto send_hdr; } @@ -1710,6 +1713,46 @@ send_hdr: return 0; } +/** + * iscsi_tcp_ctask_xmit - xmit normal PDU task + * @conn: iscsi connection + * @ctask: iscsi command task + * + * Notes: + * The function can return -EAGAIN in which case caller must + * call it again later, or recover. '0' return code means successful + * xmit. + * The function is devided to logical helpers (above) for the different + * xmit stages. + * + *iscsi_send_cmd_hdr() + * XMSTATE_CMD_HDR_INIT - prepare Header and Data buffers Calculate + * Header Digest + * XMSTATE_CMD_HDR_XMIT - Transmit header in progress + * + *iscsi_send_padding + * XMSTATE_W_PAD - Prepare and send pading + * XMSTATE_W_RESEND_PAD - retry send pading + * + *iscsi_send_digest + * XMSTATE_W_RESEND_DATA_DIGEST - Finalize and send Data Digest + * XMSTATE_W_RESEND_DATA_DIGEST - retry sending digest + * + *iscsi_send_unsol_hdr + * XMSTATE_UNS_INIT - prepare un-solicit data header and digest + * XMSTATE_UNS_HDR - send un-solicit header + * + *iscsi_send_unsol_pdu + * XMSTATE_UNS_DATA - send un-solicit data in progress + * + *iscsi_send_sol_pdu + * XMSTATE_SOL_HDR_INIT - solicit data header and digest initialize + * XMSTATE_SOL_HDR - send solicit header + * XMSTATE_SOL_DATA - send solicit data + * + *iscsi_tcp_ctask_xmit + * XMSTATE_IMM_DATA - xmit managment data (??) + **/ static int iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { @@ -1725,14 +1768,11 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) if (ctask->mtask) return rc; - if (tcp_ctask->xmstate & XMSTATE_R_HDR) - return iscsi_send_read_hdr(conn, tcp_ctask); - - if (tcp_ctask->xmstate & XMSTATE_W_HDR) { - rc = iscsi_send_write_hdr(conn, ctask); - if (rc) - return rc; - } + rc = iscsi_send_cmd_hdr(conn, ctask); + if (rc) + return rc; + if (ctask->sc->sc_data_direction != DMA_TO_DEVICE) + return 0; if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) { rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, @@ -1913,15 +1953,7 @@ iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, char *data, uint32_t data_size) { struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; - - iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, - sizeof(struct iscsi_hdr)); - tcp_mtask->xmstate = XMSTATE_IMM_HDR; - tcp_mtask->sent = 0; - - if (mtask->data_count) - iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data, - mtask->data_count); + tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; } static int -- cgit v1.2.3 From 77a23c21aaa723f6b0ffc4a701be8c8e5a32346d Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:18 -0500 Subject: [SCSI] libiscsi: fix iscsi cmdsn allocation The cmdsn allocation and pdu transmit code can race, and we can end up sending a pdu with cmdsn 10 before a pdu with 5. The target will then fail the connection/session. This patch fixes the problem by delaying the cmdsn allocation until we are about to send the pdu. This also removes the xmitmutex. We were using the connection xmitmutex during error handling to handle races with mtask and ctask cleanup and completion. For ctasks we now have nice refcounting and for the mtask, if we hit the case where the mtask timesout and it is floating around somewhere in the driver, we end up dropping the session. And to handle session level cleanup, we use the xmit suspend bit along with scsi_flush_queue and the session lock to make sure that the xmit thread is not possibly transmitting a task while we are trying to kill it. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0afdca2224c..8edcfddc0ba 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -211,7 +210,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) static int iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { - int rc; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; @@ -219,9 +217,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct scsi_cmnd *sc = ctask->sc; int datasn = be32_to_cpu(rhdr->datasn); - rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (rc) - return rc; + iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); /* * setup Data-In byte counter (gets decremented..) */ @@ -377,12 +373,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return ISCSI_ERR_R2TSN; } - rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (rc) - return rc; - /* fill-in new R2T associated with the task */ spin_lock(&session->lock); + iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); + if (!ctask->sc || ctask->mtask || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " @@ -1762,12 +1756,6 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", conn->id, tcp_ctask->xmstate, ctask->itt); - /* - * serialize with TMF AbortTask - */ - if (ctask->mtask) - return rc; - rc = iscsi_send_cmd_hdr(conn, ctask); if (rc) return rc; @@ -1949,8 +1937,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* called with host lock */ static void -iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, - char *data, uint32_t data_size) +iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) { struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT; @@ -2073,22 +2060,15 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, switch(param) { case ISCSI_PARAM_CONN_PORT: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } inet = inet_sk(tcp_conn->sock->sk); len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); - mutex_unlock(&conn->xmitmutex); break; case ISCSI_PARAM_CONN_ADDRESS: - mutex_lock(&conn->xmitmutex); - if (!tcp_conn->sock) { - mutex_unlock(&conn->xmitmutex); + if (!tcp_conn->sock) return -EINVAL; - } sk = tcp_conn->sock->sk; if (sk->sk_family == PF_INET) { @@ -2099,7 +2079,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, np = inet6_sk(sk); len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); } - mutex_unlock(&conn->xmitmutex); break; default: return iscsi_conn_get_param(cls_conn, param, buf); -- cgit v1.2.3 From 1548271ece9e9312fd5feb41fd58773b56a71d39 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:19 -0500 Subject: [SCSI] libiscsi: make can_queue configurable This patch allows us to set can_queue and cmds_per_lun from userspace when we create the session/host. From there we can set it on a per target basis. The patch fully converts iscsi_tcp, but only hooks up ib_iser for cmd_per_lun since it currently has a lots of preallocations based on can_queue. Signed-off-by: Mike Christie Cc: Roland Dreier Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8edcfddc0ba..eca4d611dd4 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2114,6 +2114,7 @@ iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) static struct iscsi_cls_session * iscsi_tcp_session_create(struct iscsi_transport *iscsit, struct scsi_transport_template *scsit, + uint16_t cmds_max, uint16_t qdepth, uint32_t initial_cmdsn, uint32_t *hostno) { struct iscsi_cls_session *cls_session; @@ -2121,7 +2122,7 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, uint32_t hn; int cmd_i; - cls_session = iscsi_session_setup(iscsit, scsit, + cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth, sizeof(struct iscsi_tcp_cmd_task), sizeof(struct iscsi_tcp_mgmt_task), initial_cmdsn, &hn); @@ -2164,7 +2165,7 @@ static struct scsi_host_template iscsi_sht = { .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, - .can_queue = ISCSI_XMIT_CMDS_MAX - 1, + .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, .sg_tablesize = ISCSI_SG_TABLESIZE, .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, -- cgit v1.2.3 From dbdb016d92603619d972082167c10b8c74e605cc Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:20 -0500 Subject: [SCSI] iscsi_tcp: fix handling of data buffer padding If we got the padding, data and header in different skbs, we were not handling the padding correctly because we attributed it to the data's skb. This resulted in the initiator reading from pad bytes + skb offset instead of the correct offset. If you could not connect with the open solaris target, this will fix the lock up problem you were hitting. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 61 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index eca4d611dd4..6eaa2e3a925 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -896,11 +896,27 @@ more: } } - if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV) { + if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV && + tcp_conn->in.copy) { uint32_t recv_digest; debug_tcp("extra data_recv offset %d copy %d\n", tcp_conn->in.offset, tcp_conn->in.copy); + + if (!tcp_conn->data_copied) { + if (tcp_conn->in.padding) { + debug_tcp("padding -> %d\n", + tcp_conn->in.padding); + memset(pad, 0, tcp_conn->in.padding); + sg_init_one(&sg, pad, tcp_conn->in.padding); + crypto_hash_update(&tcp_conn->rx_hash, + &sg, sg.length); + } + crypto_hash_final(&tcp_conn->rx_hash, + (u8 *) &tcp_conn->in.datadgst); + debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst); + } + rc = iscsi_tcp_copy(conn, sizeof(uint32_t)); if (rc) { if (rc == -EAGAIN) @@ -925,8 +941,7 @@ more: } if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV && - tcp_conn->in.copy) { - + tcp_conn->in.copy) { debug_tcp("data_recv offset %d copy %d\n", tcp_conn->in.offset, tcp_conn->in.copy); @@ -937,24 +952,32 @@ more: iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } - tcp_conn->in.copy -= tcp_conn->in.padding; - tcp_conn->in.offset += tcp_conn->in.padding; - if (conn->datadgst_en) { - if (tcp_conn->in.padding) { - debug_tcp("padding -> %d\n", - tcp_conn->in.padding); - memset(pad, 0, tcp_conn->in.padding); - sg_init_one(&sg, pad, tcp_conn->in.padding); - crypto_hash_update(&tcp_conn->rx_hash, - &sg, sg.length); - } - crypto_hash_final(&tcp_conn->rx_hash, - (u8 *) &tcp_conn->in.datadgst); - debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst); + + if (tcp_conn->in.padding) + tcp_conn->in_progress = IN_PROGRESS_PAD_RECV; + else if (conn->datadgst_en) tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV; - tcp_conn->data_copied = 0; - } else + else + tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; + tcp_conn->data_copied = 0; + } + + if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV && + tcp_conn->in.copy) { + int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied, + tcp_conn->in.copy); + + tcp_conn->in.copy -= copylen; + tcp_conn->in.offset += copylen; + tcp_conn->data_copied += copylen; + + if (tcp_conn->data_copied != tcp_conn->in.padding) + tcp_conn->in_progress = IN_PROGRESS_PAD_RECV; + else if (conn->datadgst_en) + tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV; + else tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; + tcp_conn->data_copied = 0; } debug_tcp("f, processed %d from out of %d padding %d\n", -- cgit v1.2.3 From d1d81c01f4bdd50577d9f89aa4a8e6344f63aa70 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:21 -0500 Subject: [SCSI] iscsi_tcp: remove DMA alignment restriction Add a slave_configure function to iSCSI TCP to remove any DMA alignment restriction. This permits the use of direct IO from arbitrary addresses. Signed-off-by: Pete Wyckoff Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 6eaa2e3a925..4e9f0d9a55e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -2184,6 +2185,12 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) iscsi_session_teardown(cls_session); } +static int iscsi_tcp_slave_configure(struct scsi_device *sdev) +{ + blk_queue_dma_alignment(sdev->request_queue, 0); + return 0; +} + static struct scsi_host_template iscsi_sht = { .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, @@ -2195,6 +2202,7 @@ static struct scsi_host_template iscsi_sht = { .eh_abort_handler = iscsi_eh_abort, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, + .slave_configure = iscsi_tcp_slave_configure, .proc_name = "iscsi_tcp", .this_id = -1, }; -- cgit v1.2.3 From 4e7aba73f9f6e9fe6d3fa10d3fd63cd4882ba3d0 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:23 -0500 Subject: [SCSI] iscsi_tcp: fix fd leak This patch should fix the file descriptor leak problem. A quick look through the kernel shows that users of sockfd_lookup use sockfd_put to release their handle. We were using sock_release which from the comments and code look like it does not release the get() on the file from the lookup. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4e9f0d9a55e..7ce177e30a5 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1878,7 +1879,7 @@ iscsi_tcp_release_conn(struct iscsi_conn *conn) iscsi_conn_restore_callbacks(tcp_conn); sock_put(tcp_conn->sock->sk); - sock_release(tcp_conn->sock); + sockfd_put(tcp_conn->sock); tcp_conn->sock = NULL; conn->recv_lock = NULL; } -- cgit v1.2.3 From 2223696192c687f2853e42b7c1e0d3ef002081fd Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:24 -0500 Subject: [SCSI] iscsi class, qla4xxx, iscsi_tcp: export local address This patch exports the local address for the session. For qla4xxx this is the ip of the hba's port. For software this is the src addr of the socket. Signed-off-by: Mike Christie Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 127 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 98 insertions(+), 29 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7ce177e30a5..da66fb524b5 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1870,18 +1870,22 @@ tcp_conn_alloc_fail: static void iscsi_tcp_release_conn(struct iscsi_conn *conn) { + struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct socket *sock = tcp_conn->sock; - if (!tcp_conn->sock) + if (!sock) return; - sock_hold(tcp_conn->sock->sk); + sock_hold(sock->sk); iscsi_conn_restore_callbacks(tcp_conn); - sock_put(tcp_conn->sock->sk); + sock_put(sock->sk); - sockfd_put(tcp_conn->sock); + spin_lock_bh(&session->lock); tcp_conn->sock = NULL; conn->recv_lock = NULL; + spin_unlock_bh(&session->lock); + sockfd_put(sock); } static void @@ -1912,6 +1916,46 @@ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) tcp_conn->hdr_size = sizeof(struct iscsi_hdr); } +static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, + char *buf, int *port, + int (*getname)(struct socket *, struct sockaddr *, + int *addrlen)) +{ + struct sockaddr_storage *addr; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + int rc = 0, len; + + addr = kmalloc(GFP_KERNEL, sizeof(*addr)); + if (!addr) + return -ENOMEM; + + if (getname(sock, (struct sockaddr *) addr, &len)) { + rc = -ENODEV; + goto free_addr; + } + + switch (addr->ss_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + spin_lock_bh(&conn->session->lock); + sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); + *port = be16_to_cpu(sin->sin_port); + spin_unlock_bh(&conn->session->lock); + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + spin_lock_bh(&conn->session->lock); + sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr)); + *port = be16_to_cpu(sin6->sin6_port); + spin_unlock_bh(&conn->session->lock); + break; + } +free_addr: + kfree(addr); + return rc; +} + static int iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, @@ -1929,10 +1973,24 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); return -EEXIST; } + /* + * copy these values now because if we drop the session + * userspace may still want to query the values since we will + * be using them for the reconnect + */ + err = iscsi_tcp_get_addr(conn, sock, conn->portal_address, + &conn->portal_port, kernel_getpeername); + if (err) + goto free_socket; + + err = iscsi_tcp_get_addr(conn, sock, conn->local_address, + &conn->local_port, kernel_getsockname); + if (err) + goto free_socket; err = iscsi_conn_bind(cls_session, cls_conn, is_leading); if (err) - return err; + goto free_socket; /* bind iSCSI connection and socket */ tcp_conn->sock = sock; @@ -1956,8 +2014,11 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, * set receive state machine into initial state */ tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; - return 0; + +free_socket: + sockfd_put(sock); + return err; } /* called with host lock */ @@ -2077,33 +2138,18 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, char *buf) { struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct inet_sock *inet; - struct ipv6_pinfo *np; - struct sock *sk; int len; switch(param) { case ISCSI_PARAM_CONN_PORT: - if (!tcp_conn->sock) - return -EINVAL; - - inet = inet_sk(tcp_conn->sock->sk); - len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); + spin_lock_bh(&conn->session->lock); + len = sprintf(buf, "%hu\n", conn->portal_port); + spin_unlock_bh(&conn->session->lock); break; case ISCSI_PARAM_CONN_ADDRESS: - if (!tcp_conn->sock) - return -EINVAL; - - sk = tcp_conn->sock->sk; - if (sk->sk_family == PF_INET) { - inet = inet_sk(sk); - len = sprintf(buf, NIPQUAD_FMT "\n", - NIPQUAD(inet->daddr)); - } else { - np = inet6_sk(sk); - len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr)); - } + spin_lock_bh(&conn->session->lock); + len = sprintf(buf, "%s\n", conn->portal_address); + spin_unlock_bh(&conn->session->lock); break; default: return iscsi_conn_get_param(cls_conn, param, buf); @@ -2112,6 +2158,29 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, return len; } +static int +iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, + char *buf) +{ + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + int len; + + switch (param) { + case ISCSI_HOST_PARAM_IPADDRESS: + spin_lock_bh(&session->lock); + if (!session->leadconn) + len = -ENODEV; + else + len = sprintf(buf, "%s\n", + session->leadconn->local_address); + spin_unlock_bh(&session->lock); + break; + default: + return iscsi_host_get_param(shost, param, buf); + } + return len; +} + static void iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { @@ -2233,7 +2302,7 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, - .host_param_mask = ISCSI_HOST_HWADDRESS | + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), @@ -2252,7 +2321,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .start_conn = iscsi_conn_start, .stop_conn = iscsi_tcp_conn_stop, /* iscsi host params */ - .get_host_param = iscsi_host_get_param, + .get_host_param = iscsi_tcp_host_get_param, .set_host_param = iscsi_host_set_param, /* IO */ .send_pdu = iscsi_conn_send_pdu, -- cgit v1.2.3 From d8196ed2181b4595eaf464a5bcbddb6c28649a39 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 30 May 2007 12:57:25 -0500 Subject: [SCSI] iscsi class, iscsi_tcp, iser, qla4xxx: add netdevname sysfs attr iSCSI must support software iscsi (iscsi_tcp, iser), hardware iscsi (qla4xxx), and partial offload (broadcom). To be able to allow each stack or driver or port (virtual or physical) to be able to log into the same target portal we use the initiator tuple [[HWADDRESS | NETDEVNAME], INITIATOR_NAME] and the target tuple [TARGETNAME, CONN_ADDRESS, CONN_PORT] to id a session. This patch adds the netdev name, which is used by software iscsi when it binds a session to a netdevice using the SO_BINDTODEVICE sock opt. It cannot use HWADDRESS because if someone did vlans then the same netdevice will have the same mac and the initiator,target id will not be unique. Signed-off-by: Mike Christie Cc: Roland Dreier Cc: David C Somayajulu Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index da66fb524b5..d5a6527b3b3 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2303,7 +2303,8 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_USERNAME | ISCSI_PASSWORD | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | - ISCSI_HOST_INITIATOR_NAME, + ISCSI_HOST_INITIATOR_NAME | + ISCSI_HOST_NETDEV_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, -- cgit v1.2.3 From 1c13899154f6f93e8c9ff3e981a90d5f21df2d6b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 14 Jun 2007 22:13:17 +0900 Subject: [SCSI] iscsi_tcp: convert to use the data buffer accessors - remove the unnecessary map_single path. - convert to use the new accessors for the sg lists and the parameters. TODO: use scsi_for_each_sg(). Signed-off-by: FUJITA Tomonori Acked-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 117 +++++++++++++++-------------------------------- 1 file changed, 38 insertions(+), 79 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index d5a6527b3b3..aebcd5fcdc5 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -237,10 +237,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn++; tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); - if (tcp_ctask->data_offset + tcp_conn->in.datalen > sc->request_bufflen) { + if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) { debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", __FUNCTION__, tcp_ctask->data_offset, - tcp_conn->in.datalen, sc->request_bufflen); + tcp_conn->in.datalen, scsi_bufflen(sc)); return ISCSI_ERR_DATA_OFFSET; } @@ -250,14 +250,14 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int res_count = be32_to_cpu(rhdr->residual_count); if (res_count > 0 && - res_count <= sc->request_bufflen) { - sc->resid = res_count; + res_count <= scsi_bufflen(sc)) { + scsi_set_resid(sc, res_count); sc->result = (DID_OK << 16) | rhdr->cmd_status; } else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) { - sc->resid = be32_to_cpu(rhdr->residual_count); + scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); sc->result = (DID_OK << 16) | rhdr->cmd_status; } else sc->result = (DID_OK << 16) | rhdr->cmd_status; @@ -285,6 +285,8 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, { struct iscsi_data *hdr; struct scsi_cmnd *sc = ctask->sc; + int i, sg_count = 0; + struct scatterlist *sg; hdr = &r2t->dtask.hdr; memset(hdr, 0, sizeof(struct iscsi_data)); @@ -312,39 +314,30 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr, sizeof(struct iscsi_hdr)); - if (sc->use_sg) { - int i, sg_count = 0; - struct scatterlist *sg = sc->request_buffer; - - r2t->sg = NULL; - for (i = 0; i < sc->use_sg; i++, sg += 1) { - /* FIXME: prefetch ? */ - if (sg_count + sg->length > r2t->data_offset) { - int page_offset; + sg = scsi_sglist(sc); + r2t->sg = NULL; + for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) { + /* FIXME: prefetch ? */ + if (sg_count + sg->length > r2t->data_offset) { + int page_offset; - /* sg page found! */ + /* sg page found! */ - /* offset within this page */ - page_offset = r2t->data_offset - sg_count; + /* offset within this page */ + page_offset = r2t->data_offset - sg_count; - /* fill in this buffer */ - iscsi_buf_init_sg(&r2t->sendbuf, sg); - r2t->sendbuf.sg.offset += page_offset; - r2t->sendbuf.sg.length -= page_offset; + /* fill in this buffer */ + iscsi_buf_init_sg(&r2t->sendbuf, sg); + r2t->sendbuf.sg.offset += page_offset; + r2t->sendbuf.sg.length -= page_offset; - /* xmit logic will continue with next one */ - r2t->sg = sg + 1; - break; - } - sg_count += sg->length; + /* xmit logic will continue with next one */ + r2t->sg = sg + 1; + break; } - BUG_ON(r2t->sg == NULL); - } else { - iscsi_buf_init_iov(&r2t->sendbuf, - (char*)sc->request_buffer + r2t->data_offset, - r2t->data_count); - r2t->sg = NULL; + sg_count += sg->length; } + BUG_ON(r2t->sg == NULL); } /** @@ -404,11 +397,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length, session->max_burst); r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > ctask->sc->request_bufflen) { + if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " "offset %u and total length %d\n", r2t->data_length, - r2t->data_offset, ctask->sc->request_bufflen); + r2t->data_offset, scsi_bufflen(ctask->sc)); return ISCSI_ERR_DATALEN; } @@ -612,7 +605,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, size, tcp_conn->in.offset, tcp_conn->in.copied); BUG_ON(size <= 0); - BUG_ON(tcp_ctask->sent + size > ctask->sc->request_bufflen); + BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc)); rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, (char*)buf + (offset + tcp_conn->data_copied), size); @@ -710,25 +703,8 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) BUG_ON((void*)ctask != sc->SCp.ptr); - /* - * copying Data-In into the Scsi_Cmnd - */ - if (!sc->use_sg) { - i = ctask->data_count; - rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer, - sc->request_bufflen, - tcp_ctask->data_offset); - if (rc == -EAGAIN) - return rc; - if (conn->datadgst_en) - iscsi_recv_digest_update(tcp_conn, sc->request_buffer, - i); - rc = 0; - goto done; - } - offset = tcp_ctask->data_offset; - sg = sc->request_buffer; + sg = scsi_sglist(sc); if (tcp_ctask->data_offset) for (i = 0; i < tcp_ctask->sg_count; i++) @@ -737,7 +713,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) if (offset < 0) offset = 0; - for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) { + for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) { char *dest; dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0); @@ -782,7 +758,6 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) } BUG_ON(ctask->data_count); -done: /* check for non-exceptional status */ if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) { debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n", @@ -1241,7 +1216,6 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_r2t_info *r2t, int left) { struct iscsi_data *hdr; - struct scsi_cmnd *sc = ctask->sc; int new_offset; hdr = &r2t->dtask.hdr; @@ -1271,15 +1245,8 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, if (iscsi_buf_left(&r2t->sendbuf)) return; - if (sc->use_sg) { - iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg); - r2t->sg += 1; - } else { - iscsi_buf_init_iov(&r2t->sendbuf, - (char*)sc->request_buffer + new_offset, - r2t->data_count); - r2t->sg = NULL; - } + iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg); + r2t->sg += 1; } static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask, @@ -1408,23 +1375,15 @@ iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn = 0; if (sc->sc_data_direction == DMA_TO_DEVICE) { - if (sc->use_sg) { - struct scatterlist *sg = sc->request_buffer; - - iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg); - tcp_ctask->sg = sg + 1; - tcp_ctask->bad_sg = sg + sc->use_sg; - } else { - iscsi_buf_init_iov(&tcp_ctask->sendbuf, - sc->request_buffer, - sc->request_bufflen); - tcp_ctask->sg = NULL; - tcp_ctask->bad_sg = NULL; - } + struct scatterlist *sg = scsi_sglist(sc); + + iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg); + tcp_ctask->sg = sg + 1; + tcp_ctask->bad_sg = sg + scsi_sg_count(sc); debug_scsi("cmd [itt 0x%x total %d imm_data %d " "unsol count %d, unsol offset %d]\n", - ctask->itt, sc->request_bufflen, + ctask->itt, scsi_bufflen(sc), ctask->imm_count, ctask->unsol_count, ctask->unsol_offset); } -- cgit v1.2.3