iscsi bugfixes
Subsystems (4)
These patches fix several bugs in iscsi_tcp and libiscsi including:
- support for targets that do not obey max burst length for r2ts
- Lots of data and head digests fixes.
- Lots of fixes for partial IO handling.
- Fix for when IO needs padding.
- Fix for when the recv soft irq completes a command but the xmit thread has not yet filly cleaned itself up.
The patches were made over scsi-rc-fixes, but patch against scsi-rc-fixes or scsi-misc. These are all bug fixes so if we send patches upstream again these would qualify. Since I am sending them so late in the 2.6.18 cylce, I know there is a slim chance so if they are merged into scsi-misc it is fine.
PATCH 1/12 libiscsi, iscsi_tcp, iscsi_iser: check that burst lengths are valid.
From: Mike Christie <[email protected]>
iSCSI RFC states that the first burst length must be smaller than the max burst length. We currently assume targets will be good, but that may not be the case, so this patch adds a check.
This patch also moves the unsol data out offset to the lib so the LLDs do not have to track it.
--- drivers/infiniband/ulp/iser/iscsi_iser.c | 18 ++++-------------- drivers/infiniband/ulp/iser/iscsi_iser.h | 1 - drivers/scsi/iscsi_tcp.c | 30 +++++++----------------------- drivers/scsi/iscsi_tcp.h | 1 - drivers/scsi/libiscsi.c | 25 +++++++++++++++++-------- include/scsi/libiscsi.h | 5 +++-- 6 files changed, 31 insertions(+), 49 deletions(-)
drivers/infiniband/ulp/iser/iscsi_iser.c +4 -14
@@ -141,18 +141,11 @@ iscsi_iser_cmd_init(struct iscsi_cmd_tasif (sc->sc_data_direction ==DMA_TO_DEVICE ) {BUG_ON (ctask->total_length ==0 ); -/* bytes to be sent via RDMA operations */ - iser_ctask->rdma_data_count = ctask->total_length - - ctask->imm_count - - ctask->unsol_count; -debug_scsi ("cmd [itt %x total %d imm %d unsol_data %d " -"rdma_data %d]\n" , +debug_scsi ("cmd [itt %x total %d imm %d unsol_data %d\n" , ctask->itt, ctask->total_length, ctask->imm_count, - ctask->unsol_count, iser_ctask->rdma_data_count); - }else -/* bytes to be sent via RDMA operations */ - iser_ctask->rdma_data_count = ctask->total_length; + ctask->unsol_count); + }iser_ctask_rdma_init (iser_ctask); }
@@ -196,13 +189,10 @@ iscsi_iser_ctask_xmit_unsol_data(struct {struct iscsi_data hdr;int error =0 ; -struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;/* Send data-out PDUs while there's still unsolicited data to send */ while (ctask->unsol_count >0 ) { -iscsi_prep_unsolicit_data_pdu (ctask, &hdr, - iser_ctask->rdma_data_count); - +iscsi_prep_unsolicit_data_pdu (ctask, &hdr);debug_scsi ("Sending data-out: itt 0x%x, data count %d\n" , hdr.itt, ctask->data_count);
drivers/infiniband/ulp/iser/iscsi_iser.h +0 -1
@@ -257,7 +257,6 @@ struct iscsi_iser_conn {struct iscsi_iser_cmd_task {struct iser_desc desc;struct iscsi_iser_conn *iser_conn; -int rdma_data_count;/* RDMA bytes */ enum iser_task_status status;int command_sent;/* set if command sent */ int dir[ISER_DIRS_NUM ];/* set if dir use*/
drivers/scsi/iscsi_tcp.c +7 -23
@@ -1264,19 +1264,6 @@ iscsi_solicit_data_cont(struct iscsi_con r2t->data_count); } -static void -iscsi_unsolicit_data_init (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) -{ -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_data_task *dtask; - - dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask; -iscsi_prep_unsolicit_data_pdu (ctask, &dtask->hdr, - tcp_ctask->r2t_data_count); -iscsi_buf_init_iov (&tcp_ctask->headbuf, (char *)&dtask->hdr, -sizeof (struct iscsi_hdr )); -} -/** * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * @conn: iscsi connection
@@ -1326,14 +1313,11 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_taskif (ctask->unsol_count) tcp_ctask->xmstate |=XMSTATE_UNS_HDR |XMSTATE_UNS_INIT ; - tcp_ctask->r2t_data_count = ctask->total_length - - ctask->imm_count - - ctask->unsol_count; -debug_scsi ("cmd [itt 0x%x total %d imm %d imm_data %d " -"r2t_data %d]\n" , +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->unsol_count, tcp_ctask->r2t_data_count); + ctask->unsol_count, ctask->unsol_offset); }else tcp_ctask->xmstate =XMSTATE_R_HDR ;
@@ -1531,8 +1515,10 @@ handle_xmstate_uns_hdr(struct iscsi_conn tcp_ctask->xmstate |=XMSTATE_UNS_DATA ;if (tcp_ctask->xmstate &XMSTATE_UNS_INIT ) { -iscsi_unsolicit_data_init (conn, ctask); - dtask = tcp_ctask->dtask; + dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask; +iscsi_prep_unsolicit_data_pdu (ctask, &dtask->hdr); +iscsi_buf_init_iov (&tcp_ctask->headbuf, (char *)&dtask->hdr, +sizeof (struct iscsi_hdr ));if (conn->hdrdgst_en)iscsi_hdr_digest (conn, &tcp_ctask->headbuf, (u8 *)dtask->hdrext);
@@ -1720,7 +1706,6 @@ data_out_done:* Done with this R2T. Check if there are more * outstanding R2Ts ready to be processed. */ -BUG_ON (tcp_ctask->r2t_data_count - r2t->data_length <0 );if (conn->datadgst_en) { rc =iscsi_digest_final_send (conn, ctask, &dtask->digestbuf, &dtask->digest,1 );
@@ -1732,7 +1717,6 @@ data_out_done:debug_tcp ("r2t done dout digest 0x%x\n" , dtask->digest); } - tcp_ctask->r2t_data_count -= r2t->data_length; tcp_ctask->r2t =NULL ;spin_lock_bh (&session->lock);__kfifo_put (tcp_ctask->r2tpool.queue, (void *)&r2t,sizeof (void *));
drivers/scsi/iscsi_tcp.h +0 -1
@@ -157,7 +157,6 @@ struct iscsi_tcp_cmd_task {struct scatterlist *bad_sg;/* assert statement */ int sg_count;/* SG's to process */ uint32_t exp_r2tsn; -int r2t_data_count;/* R2T Data-Out bytes */ int data_offset;struct iscsi_r2t_info *r2t;/* in progress R2T */ struct iscsi_queue r2tpool;
drivers/scsi/libiscsi.c +17 -8
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_seEXPORT_SYMBOL_GPL (iscsi_check_assign_cmdsn);void iscsi_prep_unsolicit_data_pdu (struct iscsi_cmd_task *ctask, -struct iscsi_data *hdr, -int transport_data_cnt) +struct iscsi_data *hdr) {struct iscsi_conn *conn = ctask->conn;
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struc hdr->itt = ctask->hdr->itt; hdr->exp_statsn =cpu_to_be32 (conn->exp_statsn); - - hdr->offset =cpu_to_be32 (ctask->total_length - - transport_data_cnt - - ctask->unsol_count); + hdr->offset =cpu_to_be32 (ctask->unsol_offset);if (ctask->unsol_count > conn->max_xmit_dlength) {hton24 (hdr->dlength, conn->max_xmit_dlength); ctask->data_count = conn->max_xmit_dlength; + ctask->unsol_offset += ctask->data_count; hdr->flags =0 ; }else {hton24 (hdr->dlength, ctask->unsol_count);
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(strumemcpy (hdr->cdb, sc->cmnd, sc->cmd_len);memset (&hdr->cdb[sc->cmd_len],0 ,MAX_COMMAND_SIZE - sc->cmd_len); + ctask->data_count =0 ;if (sc->sc_data_direction ==DMA_TO_DEVICE ) { hdr->flags |=ISCSI_FLAG_CMD_WRITE ;/*
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(stru*/ ctask->imm_count =0 ; ctask->unsol_count =0 ; + ctask->unsol_offset =0 ; ctask->unsol_datasn =0 ;if (session->imm_data_en) {
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(stru }else zero_data (ctask->hdr->dlength); -if (!session->initial_r2t_en) +if (!session->initial_r2t_en) { ctask->unsol_count =min (session->first_burst, ctask->total_length) - ctask->imm_count; + ctask->unsol_offset = ctask->imm_count; + } +if (!ctask->unsol_count)/* No unsolicit Data-Out's */ ctask->hdr->flags |=ISCSI_FLAG_CMD_FINAL ;
@@ -1520,11 +1522,18 @@ int iscsi_conn_start(struct iscsi_cls_costruct iscsi_conn *conn = cls_conn->dd_data;struct iscsi_session *session = conn->session; -if (session ==NULL ) { +if (!session) {printk (KERN_ERR "iscsi: can't start unbound connection\n" );return -EPERM ; } +if (session->first_burst > session->max_burst) { +printk ("iscsi: invalid burst lengths: " +"first_burst %d max_burst %d\n" , + session->first_burst, session->max_burst); +return -EINVAL ; + } +spin_lock_bh (&session->lock); conn->c_stage =ISCSI_CONN_STARTED ; session->state =ISCSI_STATE_LOGGED_IN ;
include/scsi/libiscsi.h +3 -2
@@ -102,6 +102,8 @@ struct iscsi_cmd_task {uint32_t unsol_datasn;int imm_count;/* imm-data (bytes) */ int unsol_count;/* unsolicited (bytes)*/ +/* offset in unsolicited stream (bytes); */ +int unsol_offset;int data_count;/* remaining Data-Out */ struct scsi_cmnd *sc;/* associated SCSI cmd*/ int total_length;
@@ -290,8 +292,7 @@ extern int iscsi_conn_get_param(struct iextern int iscsi_check_assign_cmdsn (struct iscsi_session *,struct iscsi_nopin *);extern void iscsi_prep_unsolicit_data_pdu (struct iscsi_cmd_task *, -struct iscsi_data *hdr, -int transport_data_cnt); +struct iscsi_data *hdr);extern int iscsi_conn_send_pdu (struct iscsi_cls_conn *,struct iscsi_hdr *,char *,uint32_t ); extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *,
Signature · 1 line
1.4.1.1
PATCH 2/12 add refcouting around ctask usage in main IO patch
From: Mike Christie <[email protected]>
It is possible that a ctask could be completing and getting cleaned up at the same time, we are finishing up the last data transfer. This could then result in the data transfer code using stale or invalid values. This patch adds a refcount to the ctask. When the count goes to zero then we know the transmit thread and recv thread or softirq are not touching it and we can safely release it.
The eh should not need to grab a reference because it only cleans up a task if it has both the xmit mutex and recv lock (or recv side suspended).
--- drivers/scsi/libiscsi.c | 59 ++++++++++++++++++++++++++++++++++++++++------- include/scsi/libiscsi.h | 1 + 2 files changed, 51 insertions(+), 9 deletions(-)
drivers/scsi/libiscsi.c +50 -9
@@ -179,16 +179,15 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pd/** * iscsi_complete_command - return command back to scsi-ml -* @session: iscsi session * @ctask: iscsi cmd task * * Must be called with session lock. * This function returns the scsi command to scsi-ml and returns * the cmd task to the pool of available cmd tasks. */ -static void iscsi_complete_command (struct iscsi_session *session, -struct iscsi_cmd_task *ctask) +static void iscsi_complete_command (struct iscsi_cmd_task *ctask) { +struct iscsi_session *session = ctask->conn->session;struct scsi_cmnd *sc = ctask->sc; ctask->state =ISCSI_TASK_COMPLETED ;
@@ -198,6 +197,35 @@ static void iscsi_complete_command(struc sc->scsi_done (sc); } +static void __iscsi_get_ctask (struct iscsi_cmd_task *ctask) +{ +atomic_inc (&ctask->refcount); +} + +static void iscsi_get_ctask (struct iscsi_cmd_task *ctask) +{ +spin_lock_bh (&ctask->conn->session->lock); +__iscsi_get_ctask (ctask); +spin_unlock_bh (&ctask->conn->session->lock); +} + +static void __iscsi_put_ctask (struct iscsi_cmd_task *ctask) +{ +struct iscsi_conn *conn = ctask->conn; + +if (atomic_dec_and_test (&ctask->refcount)) { + conn->session->tt->cleanup_cmd_task (conn, ctask); +iscsi_complete_command (ctask); + } +} + +static void iscsi_put_ctask (struct iscsi_cmd_task *ctask) +{ +spin_lock_bh (&ctask->conn->session->lock); +__iscsi_put_ctask (ctask); +spin_unlock_bh (&ctask->conn->session->lock); +} +/** * iscsi_cmd_rsp - SCSI Command Response processing * @conn: iscsi connection
@@ -274,7 +302,7 @@ out: (long)sc, sc->result, ctask->itt); conn->scsirsp_pdus_cnt++; -iscsi_complete_command (conn->session, ctask); +__iscsi_put_ctask (ctask);return rc; }
@@ -338,7 +366,7 @@ int __iscsi_complete_pdu(struct iscsi_coBUG_ON ((void *)ctask != ctask->sc->SCp.ptr);if (hdr->flags &ISCSI_FLAG_DATA_STATUS ) { conn->scsirsp_pdus_cnt++; -iscsi_complete_command (session, ctask); +__iscsi_put_ctask (ctask); }break ;case ISCSI_OP_R2T :
@@ -563,7 +591,9 @@ static int iscsi_data_xmit(struct iscsi_BUG_ON (conn->ctask && conn->mtask);if (conn->ctask) { +iscsi_get_ctask (conn->ctask); rc = tt->xmit_cmd_task (conn, conn->ctask); +iscsi_put_ctask (conn->ctask);if (rc) goto again;/* done with this in-progress ctask */
@@ -604,12 +634,19 @@ static int iscsi_data_xmit(struct iscsi_ struct iscsi_cmd_task, running); conn->ctask->state =ISCSI_TASK_RUNNING ;list_move_tail (conn->xmitqueue.next, &conn->run_list); +__iscsi_get_ctask (conn->ctask);spin_unlock_bh (&conn->session->lock); rc = tt->xmit_cmd_task (conn, conn->ctask);if (rc) goto again; +spin_lock_bh (&conn->session->lock); +__iscsi_put_ctask (conn->ctask); +if (rc) { +spin_unlock_bh (&conn->session->lock); + goto again; + } }spin_unlock_bh (&conn->session->lock);/* done with this ctask */
@@ -659,6 +696,7 @@ enum {FAILURE_SESSION_FAILED ,FAILURE_SESSION_FREED ,FAILURE_WINDOW_CLOSED , +FAILURE_OOM ,FAILURE_SESSION_TERMINATE ,FAILURE_SESSION_IN_RECOVERY , FAILURE_SESSION_RECOVERY_TIMEOUT,
@@ -717,10 +755,15 @@ int iscsi_queuecommand(struct scsi_cmnd conn = session->leadconn; -__kfifo_get (session->cmdpool.queue, (void *)&ctask,sizeof (void *)); +if (!__kfifo_get (session->cmdpool.queue, (void *)&ctask, +sizeof (void *))) { + reason =FAILURE_OOM ; + goto reject; + } sc->SCp.phase = session->age; sc->SCp.ptr = (char *)ctask; +atomic_set (&ctask->refcount,1 ); ctask->state =ISCSI_TASK_PENDING ; ctask->mtask =NULL ; ctask->conn = conn;
@@ -1057,13 +1100,11 @@ static void fail_command(struct iscsi_co sc = ctask->sc;if (!sc)return ; - - conn->session->tt->cleanup_cmd_task (conn, ctask);iscsi_ctask_mtask_cleanup (ctask); sc->result = err; sc->resid = sc->request_bufflen; -iscsi_complete_command (conn->session, ctask); +__iscsi_put_ctask (ctask); }int iscsi_eh_abort (struct scsi_cmnd *sc)
include/scsi/libiscsi.h +1 -0
@@ -112,6 +112,7 @@ struct iscsi_cmd_task {/* state set/tested under session->lock */ int state; +atomic_t refcount;struct list_head running;/* running cmd list */ void *dd_data;/* driver/transport data */ };
Signature · 1 line
1.4.1.1
PATCH 3/12 attempt to complete r2t with data len greater than max burst
From: Mike Christie <[email protected]>
A couple targets like string bean and MDS, send r2ts with a data len greater than the max burst we agreed to. We were being strict in our enforcing of the iscsi rfc in that code path, but there is no driver limitation that prevents us from fullfilling the request. To allow those targets to work we will ignore the max_burst length and send as much data as the target asks for assuming it has consciously decided to override its max burst length.
--- drivers/scsi/iscsi_tcp.c | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-)
drivers/scsi/iscsi_tcp.c +14 -3
@@ -358,8 +358,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, sint r2tsn =be32_to_cpu (rhdr->r2tsn);int rc; -if (tcp_conn->in.datalen) +if (tcp_conn->in.datalen) { +printk (KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n" , + tcp_conn->in.datalen);return ISCSI_ERR_DATALEN ; + }if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)return ISCSI_ERR_R2TSN ;
@@ -385,15 +388,23 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s r2t->exp_statsn = rhdr->statsn; r2t->data_length =be32_to_cpu (rhdr->data_length); -if (r2t->data_length ==0 || - r2t->data_length > session->max_burst) { +if (r2t->data_length ==0 ) { +printk (KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n" );spin_unlock (&session->lock);return ISCSI_ERR_DATALEN ; } +if (r2t->data_length > session->max_burst) +debug_scsi ("invalid R2T with data len %u and max burst %u." +"Attempting to execute request.\n" , + 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) {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);return ISCSI_ERR_DATALEN ; }
Signature · 1 line
1.4.1.1
PATCH 4/12 iscsi_tcp: fix padding, data digests, and IO at weird offsets
From: Mike Christie <[email protected]>
iscsi_tcp calculates padding by using the expected transfer length. This has the problem where if we have immediate data = no and initial R2T = yes, and the transfer length ended up needing padding then we send:
1. header
2. padding which should have gone after data
3. data
Besides this bug, we also assume the target will always ask for nice transfer lengths and the first burst length will always be a nice value. As far as I can tell form the RFC this is not a requirement. It would be silly to do this, but if someone did it we will end doing bad things.
Finally the last bug in that bit of code is in our handling of the recalculation of data digests when we do not send a whole iscsi_buf in one try. The bug here is that we call crypto_digest_final on a iscsi_sendpage error, then when we send the rest of the iscsi_buf, we doiscsi_data_digest_init and this causes the previous data digest to be lost.
And to make matters worse, some of these bugs are replicated over and over and over again for immediate data, solicited data and unsolicited data. So the attached patch made over the iscsi git tree (see kernel.org/git for details) which I updated today to include the patches I said I merged, consolidates the sending of data, padding and digests and calculation of data digests and fixes the above bugs.
--- drivers/scsi/iscsi_tcp.c | 636 +++++++++++++++++----------------------------- drivers/scsi/iscsi_tcp.h | 33 +- drivers/scsi/libiscsi.c | 37 ++- 3 files changed, 286 insertions(+), 420 deletions(-)
drivers/scsi/iscsi_tcp.c +241 -395
@@ -281,7 +281,6 @@ iscsi_solicit_data_init(struct iscsi_con {struct iscsi_data *hdr;struct scsi_cmnd *sc = ctask->sc; -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; hdr = &r2t->dtask.hdr;memset (hdr,0 ,sizeof (struct iscsi_data ));
@@ -336,10 +335,12 @@ iscsi_solicit_data_init(struct iscsi_con sg_count += sg->length; }BUG_ON (r2t->sg ==NULL ); - }else -iscsi_buf_init_iov (&tcp_ctask->sendbuf, + }else { +iscsi_buf_init_iov (&r2t->sendbuf, (char *)sc->request_buffer + r2t->data_offset, r2t->data_count); + r2t->sg =NULL ; + } }/**
@@ -503,7 +504,6 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *co goto copy_hdr;spin_lock (&session->lock); -iscsi_tcp_cleanup_ctask (conn, tcp_conn->in.ctask); rc =__iscsi_complete_pdu (conn, hdr,NULL ,0 );spin_unlock (&session->lock);break ;
@@ -676,15 +676,15 @@ iscsi_tcp_copy(struct iscsi_conn *conn) }static inline void -partial_sg_digest_update (struct iscsi_tcp_conn *tcp_conn, -struct scatterlist *sg,int offset,int length) +partial_sg_digest_update (struct crypto_tfm *tfm,struct scatterlist *sg, +int offset,int length) {struct scatterlist temp;memcpy (&temp, sg,sizeof (struct scatterlist )); temp.offset = offset; temp.length = length; -crypto_digest_update (tcp_conn->data_rx_tfm, &temp,1 ); +crypto_digest_update (tfm, &temp,1 ); } static void
@@ -751,7 +751,8 @@ static int iscsi_scsi_data_in(struct isc tcp_conn->data_rx_tfm, &sg[i], 1); else - partial_sg_digest_update(tcp_conn, +partial_sg_digest_update ( + tcp_conn->data_rx_tfm, &sg[i], sg[i].offset + offset, sg[i].length - offset);
@@ -765,7 +766,8 @@ static int iscsi_scsi_data_in(struct isc/* * data-in is complete, but buffer not... */ -partial_sg_digest_update (tcp_conn, &sg[i], +partial_sg_digest_update (tcp_conn->data_rx_tfm, + &sg[i], sg[i].offset, sg[i].length-rc); rc =0 ;break ;
@@ -783,7 +785,6 @@ done: (long )sc, sc->result, ctask->itt, tcp_conn->in.hdr->flags);spin_lock (&conn->session->lock); -iscsi_tcp_cleanup_ctask (conn, ctask);__iscsi_complete_pdu (conn, tcp_conn->in.hdr,NULL ,0 );spin_unlock (&conn->session->lock); }
@@ -803,9 +804,6 @@ iscsi_data_recv(struct iscsi_conn *conn) rc =iscsi_scsi_data_in (conn);break ;case ISCSI_OP_SCSI_CMD_RSP : -spin_lock (&conn->session->lock); -iscsi_tcp_cleanup_ctask (conn, tcp_conn->in.ctask); -spin_unlock (&conn->session->lock);case ISCSI_OP_TEXT_RSP :case ISCSI_OP_LOGIN_RSP :case ISCSI_OP_ASYNC_EVENT :
@@ -1188,37 +1186,12 @@ iscsi_sendpage(struct iscsi_conn *conn,static inline void iscsi_data_digest_init (struct iscsi_tcp_conn *tcp_conn, -struct iscsi_cmd_task *ctask) +struct iscsi_tcp_cmd_task *tcp_ctask) { -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - -BUG_ON (!tcp_conn->data_tx_tfm);crypto_digest_init (tcp_conn->data_tx_tfm); tcp_ctask->digest_count =4 ; } -static int -iscsi_digest_final_send (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask, -struct iscsi_buf *buf,uint32_t *digest,int final) -{ -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_tcp_conn *tcp_conn = conn->dd_data; -int rc =0 ; -int sent =0 ; - -if (final) -crypto_digest_final (tcp_conn->data_tx_tfm, (u8 *)digest); - -iscsi_buf_init_iov (buf, (char *)digest,4 ); - rc =iscsi_sendpage (conn, buf, &tcp_ctask->digest_count, &sent); -if (rc) { - tcp_ctask->datadigest = *digest; - tcp_ctask->xmstate |=XMSTATE_DATA_DIGEST ; - }else - tcp_ctask->digest_count =4 ; -return rc; -} -/** * iscsi_solicit_data_cont - initialize next Data-Out * @conn: iscsi connection
@@ -1236,7 +1209,6 @@ static void iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_r2t_info *r2t, int left) { - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_data *hdr;struct scsi_cmnd *sc = ctask->sc;int new_offset;
@@ -1265,14 +1237,30 @@ iscsi_solicit_data_cont(struct iscsi_coniscsi_buf_init_iov (&r2t->headbuf, (char *)hdr,sizeof (struct iscsi_hdr )); -if (sc->use_sg && !iscsi_buf_left (&r2t->sendbuf)) { -BUG_ON (tcp_ctask->bad_sg == r2t->sg); +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 (&tcp_ctask->sendbuf, + }else { +iscsi_buf_init_iov (&r2t->sendbuf, (char *)sc->request_buffer + new_offset, r2t->data_count); + r2t->sg =NULL ; + } +} + +static void iscsi_set_padding (struct iscsi_tcp_cmd_task *tcp_ctask, +unsigned long len) +{ + tcp_ctask->pad_count = len & (ISCSI_PAD_LEN -1 ); +if (!tcp_ctask->pad_count) +return ; + + tcp_ctask->pad_count =ISCSI_PAD_LEN - tcp_ctask->pad_count; +debug_scsi ("write padding %d bytes\n" , tcp_ctask->pad_count); + tcp_ctask->xmstate |=XMSTATE_W_PAD ; }/**
@@ -1300,31 +1288,16 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_taskif (sc->use_sg) {struct scatterlist *sg = sc->request_buffer; -iscsi_buf_init_sg (&tcp_ctask->sendbuf, - &sg[tcp_ctask->sg_count++]); - tcp_ctask->sg = sg; +iscsi_buf_init_sg (&tcp_ctask->sendbuf, sg); + tcp_ctask->sg = sg +1 ; tcp_ctask->bad_sg = sg + sc->use_sg; - }else + }else {iscsi_buf_init_iov (&tcp_ctask->sendbuf, sc->request_buffer, sc->request_bufflen); - -if (ctask->imm_count) - tcp_ctask->xmstate |=XMSTATE_IMM_DATA ; - - tcp_ctask->pad_count = ctask->total_length & (ISCSI_PAD_LEN -1 ); -if (tcp_ctask->pad_count) { - tcp_ctask->pad_count =ISCSI_PAD_LEN - - tcp_ctask->pad_count; -debug_scsi ("write padding %d bytes\n" , - tcp_ctask->pad_count); - tcp_ctask->xmstate |=XMSTATE_W_PAD ; + tcp_ctask->sg =NULL ; + tcp_ctask->bad_sg =NULL ; } - -if (ctask->unsol_count) - tcp_ctask->xmstate |=XMSTATE_UNS_HDR | -XMSTATE_UNS_INIT ; - 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,
@@ -1410,8 +1383,8 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn * }static inline int -handle_xmstate_r_hdr (struct iscsi_conn *conn, -struct iscsi_tcp_cmd_task *tcp_ctask) +iscsi_send_read_hdr (struct iscsi_conn *conn, +struct iscsi_tcp_cmd_task *tcp_ctask) {int rc;
@@ -1429,7 +1402,7 @@ handle_xmstate_r_hdr(struct iscsi_conn * }static inline int -handle_xmstate_w_hdr (struct iscsi_conn *conn, +iscsi_send_write_hdr (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) {struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
@@ -1440,85 +1413,125 @@ handle_xmstate_w_hdr(struct iscsi_conn *iscsi_hdr_digest (conn, &tcp_ctask->headbuf, (u8 *)tcp_ctask->hdrext); rc =iscsi_sendhdr (conn, &tcp_ctask->headbuf, ctask->imm_count); -if (rc) +if (rc) { tcp_ctask->xmstate |=XMSTATE_W_HDR ; -return rc; +return rc; + } + +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->unsol_count) + tcp_ctask->xmstate |=XMSTATE_UNS_HDR |XMSTATE_UNS_INIT ; +return 0 ; } -static inline int -handle_xmstate_data_digest (struct iscsi_conn *conn, -struct iscsi_cmd_task *ctask) +static int +iscsi_send_padding (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) {struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -int rc; +struct iscsi_tcp_conn *tcp_conn = conn->dd_data; +int sent =0 , rc; - tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST ; -debug_tcp ("resent data digest 0x%x\n" , tcp_ctask->datadigest); - rc =iscsi_digest_final_send (conn, ctask, &tcp_ctask->immbuf, - &tcp_ctask->datadigest,0 ); +if (tcp_ctask->xmstate &XMSTATE_W_PAD ) { +iscsi_buf_init_iov (&tcp_ctask->sendbuf, (char *)&tcp_ctask->pad, + tcp_ctask->pad_count); +if (conn->datadgst_en) +crypto_digest_update (tcp_conn->data_tx_tfm, + &tcp_ctask->sendbuf.sg,1 ); + }else if (!(tcp_ctask->xmstate &XMSTATE_W_RESEND_PAD )) +return 0 ; + + tcp_ctask->xmstate &= ~XMSTATE_W_PAD ; + tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_PAD ; +debug_scsi ("sending %d pad bytes for itt 0x%x\n" , + tcp_ctask->pad_count, ctask->itt); + rc =iscsi_sendpage (conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, + &sent);if (rc) { - tcp_ctask->xmstate |=XMSTATE_DATA_DIGEST ; -debug_tcp ("resent data digest 0x%x fail!\n" , - tcp_ctask->datadigest); +debug_scsi ("padding send failed %d\n" , rc); + tcp_ctask->xmstate |=XMSTATE_W_RESEND_PAD ; } -return rc; } -static inline int -handle_xmstate_imm_data (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) +static int +iscsi_send_digest (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask, +struct iscsi_buf *buf,uint32_t *digest) { -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_tcp_conn *tcp_conn = conn->dd_data; -int rc; +struct iscsi_tcp_cmd_task *tcp_ctask; +struct iscsi_tcp_conn *tcp_conn; +int rc, sent =0 ; + +if (!conn->datadgst_en) +return 0 ; -BUG_ON (!ctask->imm_count); - tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA ; + tcp_ctask = ctask->dd_data; + tcp_conn = conn->dd_data; -if (conn->datadgst_en) { -iscsi_data_digest_init (tcp_conn, ctask); - tcp_ctask->immdigest =0 ; +if (!(tcp_ctask->xmstate &XMSTATE_W_RESEND_DATA_DIGEST )) { +crypto_digest_final (tcp_conn->data_tx_tfm, (u8 *)digest); +iscsi_buf_init_iov (buf, (char *)digest,4 ); + } + tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST ; + + rc =iscsi_sendpage (conn, buf, &tcp_ctask->digest_count, &sent); +if (!rc) +debug_scsi ("sent digest 0x%x for itt 0x%x\n" , *digest, + ctask->itt); +else { +debug_scsi ("sending digest 0x%x failed for itt 0x%x!\n" , + *digest, ctask->itt); + tcp_ctask->xmstate |=XMSTATE_W_RESEND_DATA_DIGEST ; } +return rc; +} -for (;;) { - rc =iscsi_sendpage (conn, &tcp_ctask->sendbuf, - &ctask->imm_count, &tcp_ctask->sent); -if (rc) { - tcp_ctask->xmstate |=XMSTATE_IMM_DATA ; -if (conn->datadgst_en) { -crypto_digest_final (tcp_conn->data_tx_tfm, - (u8 *)&tcp_ctask->immdigest); -debug_tcp ("tx imm sendpage fail 0x%x\n" , - tcp_ctask->datadigest); - } -return rc; +static int +iscsi_send_data (struct iscsi_cmd_task *ctask,struct iscsi_buf *sendbuf, +struct scatterlist **sg,int *sent,int *count, +struct iscsi_buf *digestbuf,uint32_t *digest) +{ +struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; +struct iscsi_conn *conn = ctask->conn; +struct iscsi_tcp_conn *tcp_conn = conn->dd_data; +int rc, buf_sent, offset; + +while (*count) { + buf_sent =0 ; + offset = sendbuf->sent; + + rc =iscsi_sendpage (conn, sendbuf, count, &buf_sent); + *sent = *sent + buf_sent; +if (buf_sent && conn->datadgst_en) +partial_sg_digest_update (tcp_conn->data_tx_tfm, + &sendbuf->sg, sendbuf->sg.offset + offset, + buf_sent); +if (!iscsi_buf_left (sendbuf) && *sg != tcp_ctask->bad_sg) { +iscsi_buf_init_sg (sendbuf, *sg); + *sg = *sg +1 ; } -if (conn->datadgst_en) -crypto_digest_update (tcp_conn->data_tx_tfm, - &tcp_ctask->sendbuf.sg,1 ); -if (!ctask->imm_count) -break ; -iscsi_buf_init_sg (&tcp_ctask->sendbuf, - &tcp_ctask->sg[tcp_ctask->sg_count++]); - } - -if (conn->datadgst_en && !(tcp_ctask->xmstate &XMSTATE_W_PAD )) { - rc =iscsi_digest_final_send (conn, ctask, &tcp_ctask->immbuf, - &tcp_ctask->immdigest,1 ); -if (rc) { -debug_tcp ("sending imm digest 0x%x fail!\n" , - tcp_ctask->immdigest); +if (rc)return rc; - } -debug_tcp ("sending imm digest 0x%x\n" , tcp_ctask->immdigest); } -return 0 ; + rc =iscsi_send_padding (conn, ctask); +if (rc) +return rc; + +return iscsi_send_digest (conn, ctask, digestbuf, digest); } -static inline int -handle_xmstate_uns_hdr (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) +static int +iscsi_send_unsol_hdr (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) {struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;struct iscsi_data_task *dtask;
@@ -1526,14 +1539,21 @@ handle_xmstate_uns_hdr(struct iscsi_conn tcp_ctask->xmstate |=XMSTATE_UNS_DATA ;if (tcp_ctask->xmstate &XMSTATE_UNS_INIT ) { - dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask; + dtask = &tcp_ctask->unsol_dtask; +iscsi_prep_unsolicit_data_pdu (ctask, &dtask->hdr);iscsi_buf_init_iov (&tcp_ctask->headbuf, (char *)&dtask->hdr,sizeof (struct iscsi_hdr ));if (conn->hdrdgst_en)iscsi_hdr_digest (conn, &tcp_ctask->headbuf, (u8 *)dtask->hdrext); +if (conn->datadgst_en) { +iscsi_data_digest_init (ctask->conn->dd_data, tcp_ctask); + dtask->digest =0 ; + } + tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT ; +iscsi_set_padding (tcp_ctask, ctask->data_count); } rc =iscsi_sendhdr (conn, &tcp_ctask->headbuf, ctask->data_count);
@@ -1548,247 +1568,128 @@ handle_xmstate_uns_hdr(struct iscsi_connreturn 0 ; } -static inline int -handle_xmstate_uns_data (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) +static int +iscsi_send_unsol_pdu (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) {struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_data_task *dtask = tcp_ctask->dtask; -struct iscsi_tcp_conn *tcp_conn = conn->dd_data;int rc; -BUG_ON (!ctask->data_count); - tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA ; - -if (conn->datadgst_en) { -iscsi_data_digest_init (tcp_conn, ctask); - dtask->digest =0 ; +if (tcp_ctask->xmstate &XMSTATE_UNS_HDR ) { +BUG_ON (!ctask->unsol_count); + tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR ; +send_hdr: + rc =iscsi_send_unsol_hdr (conn, ctask); +if (rc) +return rc; } -for (;;) { +if (tcp_ctask->xmstate &XMSTATE_UNS_DATA ) { +struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;int start = tcp_ctask->sent; - rc =iscsi_sendpage (conn, &tcp_ctask->sendbuf, - &ctask->data_count, &tcp_ctask->sent); -if (rc) { - ctask->unsol_count -= tcp_ctask->sent - start; - tcp_ctask->xmstate |=XMSTATE_UNS_DATA ; -/* will continue with this ctask later.. */ -if (conn->datadgst_en) { -crypto_digest_final (tcp_conn->data_tx_tfm, - (u8 *)&dtask->digest); -debug_tcp ("tx uns data fail 0x%x\n" , - dtask->digest); - } -return rc; - } - -BUG_ON (tcp_ctask->sent > ctask->total_length); + rc =iscsi_send_data (ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, + &tcp_ctask->sent, &ctask->data_count, + &dtask->digestbuf, &dtask->digest); ctask->unsol_count -= tcp_ctask->sent - start; - +if (rc) +return rc; + tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA ;/* -* XXX:we may run here with un-initial sendbuf. -* so pass it +* Done with the Data-Out. Next, check if we need +* to send another unsolicited Data-Out. */ -if (conn->datadgst_en && tcp_ctask->sent - start >0 ) -crypto_digest_update (tcp_conn->data_tx_tfm, - &tcp_ctask->sendbuf.sg,1 ); - -if (!ctask->data_count) -break ; -iscsi_buf_init_sg (&tcp_ctask->sendbuf, - &tcp_ctask->sg[tcp_ctask->sg_count++]); - } -BUG_ON (ctask->unsol_count <0 ); - -/* -* Done with the Data-Out. Next, check if we need -* to send another unsolicited Data-Out. -*/ -if (ctask->unsol_count) { -if (conn->datadgst_en) { - rc =iscsi_digest_final_send (conn, ctask, - &dtask->digestbuf, - &dtask->digest,1 ); -if (rc) { -debug_tcp ("send uns digest 0x%x fail\n" , - dtask->digest); -return rc; - } -debug_tcp ("sending uns digest 0x%x, more uns\n" , - dtask->digest); +if (ctask->unsol_count) { +debug_scsi ("sending more uns\n" ); + tcp_ctask->xmstate |=XMSTATE_UNS_INIT ; + goto send_hdr; } - tcp_ctask->xmstate |=XMSTATE_UNS_INIT ; -return 1 ; } - -if (conn->datadgst_en && !(tcp_ctask->xmstate &XMSTATE_W_PAD )) { - rc =iscsi_digest_final_send (conn, ctask, - &dtask->digestbuf, - &dtask->digest,1 ); -if (rc) { -debug_tcp ("send last uns digest 0x%x fail\n" , - dtask->digest); -return rc; - } -debug_tcp ("sending uns digest 0x%x\n" ,dtask->digest); - } -return 0 ; } -static inline int -handle_xmstate_sol_data (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) +static int iscsi_send_sol_pdu (struct iscsi_conn *conn, +struct iscsi_cmd_task *ctask) { -struct iscsi_session *session = conn->session; -struct iscsi_tcp_conn *tcp_conn = conn->dd_data;struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_r2t_info *r2t = tcp_ctask->r2t; -struct iscsi_data_task *dtask = &r2t->dtask; +struct iscsi_session *session = conn->session; +struct iscsi_r2t_info *r2t; +struct iscsi_data_task *dtask;int left, rc; - tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA ; - tcp_ctask->dtask = dtask; - -if (conn->datadgst_en) { -iscsi_data_digest_init (tcp_conn, ctask); - dtask->digest =0 ; - } -solicit_again: -/* -* send Data-Out within this R2T sequence. -*/ -if (!r2t->data_count) - goto data_out_done; - - rc =iscsi_sendpage (conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent); -if (rc) { +if (tcp_ctask->xmstate &XMSTATE_SOL_HDR ) { + tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR ; tcp_ctask->xmstate |=XMSTATE_SOL_DATA ; -/* will continue with this ctask later.. */ -if (conn->datadgst_en) { -crypto_digest_final (tcp_conn->data_tx_tfm, - (u8 *)&dtask->digest); -debug_tcp ("r2t data send fail 0x%x\n" , dtask->digest); - } -return rc; - } +if (!tcp_ctask->r2t) +__kfifo_get (tcp_ctask->r2tqueue, (void *)&tcp_ctask->r2t, +sizeof (void *)); +send_hdr: + r2t = tcp_ctask->r2t; + dtask = &r2t->dtask; -BUG_ON (r2t->data_count <0 ); -if (conn->datadgst_en) -crypto_digest_update (tcp_conn->data_tx_tfm, &r2t->sendbuf.sg, -1 ); - -if (r2t->data_count) { -BUG_ON (ctask->sc->use_sg ==0 ); -if (!iscsi_buf_left (&r2t->sendbuf)) { -BUG_ON (tcp_ctask->bad_sg == r2t->sg); -iscsi_buf_init_sg (&r2t->sendbuf, r2t->sg); - r2t->sg +=1 ; - } - goto solicit_again; - } +if (conn->hdrdgst_en) +iscsi_hdr_digest (conn, &r2t->headbuf, + (u8 *)dtask->hdrext); -data_out_done: -/* -* Done with this Data-Out. Next, check if we have -* to send another Data-Out for this R2T. -*/ -BUG_ON (r2t->data_length - r2t->sent <0 ); - left = r2t->data_length - r2t->sent; -if (left) {if (conn->datadgst_en) { - rc =iscsi_digest_final_send (conn, ctask, - &dtask->digestbuf, - &dtask->digest,1 ); -if (rc) { -debug_tcp ("send r2t data digest 0x%x" -"fail\n" , dtask->digest); -return rc; - } -debug_tcp ("r2t data send digest 0x%x\n" , - dtask->digest); +iscsi_data_digest_init (conn->dd_data, tcp_ctask); + dtask->digest =0 ; } -iscsi_solicit_data_cont (conn, ctask, r2t, left); - tcp_ctask->xmstate |=XMSTATE_SOL_DATA ; - tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR ; -return 1 ; - } -/* -* Done with this R2T. Check if there are more -* outstanding R2Ts ready to be processed. -*/ -if (conn->datadgst_en) { - rc =iscsi_digest_final_send (conn, ctask, &dtask->digestbuf, - &dtask->digest,1 ); + rc =iscsi_sendhdr (conn, &r2t->headbuf, r2t->data_count);if (rc) { -debug_tcp ("send last r2t data digest 0x%x" -"fail\n" , dtask->digest); + tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA ; + tcp_ctask->xmstate |=XMSTATE_SOL_HDR ;return rc; } -debug_tcp ("r2t done dout digest 0x%x\n" , dtask->digest); - } - tcp_ctask->r2t =NULL ; -spin_lock_bh (&session->lock); -__kfifo_put (tcp_ctask->r2tpool.queue, (void *)&r2t,sizeof (void *)); -spin_unlock_bh (&session->lock); -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 ; -return 1 ; +iscsi_set_padding (tcp_ctask, r2t->data_count); +debug_scsi ("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n" , + r2t->solicit_datasn -1 , ctask->itt, r2t->data_count, + r2t->sent); } -return 0 ; -} +if (tcp_ctask->xmstate &XMSTATE_SOL_DATA ) { + r2t = tcp_ctask->r2t; + dtask = &r2t->dtask; -static inline int -handle_xmstate_w_pad (struct iscsi_conn *conn,struct iscsi_cmd_task *ctask) -{ -struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; -struct iscsi_tcp_conn *tcp_conn = conn->dd_data; -struct iscsi_data_task *dtask = tcp_ctask->dtask; -int sent =0 , rc; + rc =iscsi_send_data (ctask, &r2t->sendbuf, &r2t->sg, + &r2t->sent, &r2t->data_count, + &dtask->digestbuf, &dtask->digest); +if (rc) +return rc; + tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA ; - tcp_ctask->xmstate &= ~XMSTATE_W_PAD ; -iscsi_buf_init_iov (&tcp_ctask->sendbuf, (char *)&tcp_ctask->pad, - tcp_ctask->pad_count); - rc =iscsi_sendpage (conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, - &sent); -if (rc) { - tcp_ctask->xmstate |=XMSTATE_W_PAD ; -return rc; - } +/* +* Done with this Data-Out. Next, check if we have +* to send another Data-Out for this R2T. +*/ +BUG_ON (r2t->data_length - r2t->sent <0 ); + 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; + } -if (conn->datadgst_en) { -crypto_digest_update (tcp_conn->data_tx_tfm, - &tcp_ctask->sendbuf.sg,1 ); -/* imm data? */ -if (!dtask) { - rc =iscsi_digest_final_send (conn, ctask, - &tcp_ctask->immbuf, - &tcp_ctask->immdigest,1 ); -if (rc) { -debug_tcp ("send padding digest 0x%x" -"fail!\n" , tcp_ctask->immdigest); -return rc; - } -debug_tcp ("done with padding, digest 0x%x\n" , - tcp_ctask->datadigest); - }else { - rc =iscsi_digest_final_send (conn, ctask, - &dtask->digestbuf, - &dtask->digest,1 ); -if (rc) { -debug_tcp ("send padding digest 0x%x" -"fail\n" , dtask->digest); -return rc; - } -debug_tcp ("done with padding, digest 0x%x\n" , - dtask->digest); +/* +* Done with this R2T. Check if there are more +* outstanding R2Ts ready to be processed. +*/ +spin_lock_bh (&session->lock); + tcp_ctask->r2t =NULL ; +__kfifo_put (tcp_ctask->r2tpool.queue, (void *)&r2t, +sizeof (void *)); +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; } +spin_unlock_bh (&session->lock); } -return 0 ; }
@@ -1808,85 +1709,30 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *return rc;if (tcp_ctask->xmstate &XMSTATE_R_HDR ) -return handle_xmstate_r_hdr (conn, tcp_ctask); +return iscsi_send_read_hdr (conn, tcp_ctask);if (tcp_ctask->xmstate &XMSTATE_W_HDR ) { - rc =handle_xmstate_w_hdr (conn, ctask); -if (rc) -return rc; - } - -/* XXX: for data digest xmit recover */ -if (tcp_ctask->xmstate &XMSTATE_DATA_DIGEST ) { - rc =handle_xmstate_data_digest (conn, ctask); + rc =iscsi_send_write_hdr (conn, ctask);if (rc)return rc; }if (tcp_ctask->xmstate &XMSTATE_IMM_DATA ) { - rc =handle_xmstate_imm_data (conn, ctask); + rc =iscsi_send_data (ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, + &tcp_ctask->sent, &ctask->imm_count, + &tcp_ctask->immbuf, &tcp_ctask->immdigest);if (rc)return rc; + tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA ; } -if (tcp_ctask->xmstate &XMSTATE_UNS_HDR ) { -BUG_ON (!ctask->unsol_count); - tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR ; -unsolicit_head_again: - rc =handle_xmstate_uns_hdr (conn, ctask); -if (rc) -return rc; - } - -if (tcp_ctask->xmstate &XMSTATE_UNS_DATA ) { - rc =handle_xmstate_uns_data (conn, ctask); -if (rc ==1 ) - goto unsolicit_head_again; -else if (rc) -return rc; - goto done; - } - -if (tcp_ctask->xmstate &XMSTATE_SOL_HDR ) { -struct iscsi_r2t_info *r2t; - - tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR ; - tcp_ctask->xmstate |=XMSTATE_SOL_DATA ; -if (!tcp_ctask->r2t) -__kfifo_get (tcp_ctask->r2tqueue, (void *)&tcp_ctask->r2t, -sizeof (void *)); -solicit_head_again: - r2t = tcp_ctask->r2t; -if (conn->hdrdgst_en) -iscsi_hdr_digest (conn, &r2t->headbuf, - (u8 *)r2t->dtask.hdrext); - rc =iscsi_sendhdr (conn, &r2t->headbuf, r2t->data_count); -if (rc) { - tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA ; - tcp_ctask->xmstate |=XMSTATE_SOL_HDR ; -return rc; - } - -debug_scsi ("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n" , - r2t->solicit_datasn -1 , ctask->itt, r2t->data_count, - r2t->sent); - } - -if (tcp_ctask->xmstate &XMSTATE_SOL_DATA ) { - rc =handle_xmstate_sol_data (conn, ctask); -if (rc ==1 ) - goto solicit_head_again; -if (rc) -return rc; - } + rc =iscsi_send_unsol_pdu (conn, ctask); +if (rc) +return rc; -done: -/* -* Last thing to check is whether we need to send write -* padding. Note that we check for xmstate equality, not just the bit. -*/ -if (tcp_ctask->xmstate ==XMSTATE_W_PAD ) - rc =handle_xmstate_w_pad (conn, ctask); + rc =iscsi_send_sol_pdu (conn, ctask); +if (rc) +return rc;return rc; }
drivers/scsi/iscsi_tcp.h +14 -19
@@ -31,23 +31,21 @@ #define IN_PROGRESS_DATA_RECV 0x2#define IN_PROGRESS_DDIGEST_RECV 0x3/* xmit state machine */ -#define XMSTATE_IDLE 0x0 -#define XMSTATE_R_HDR 0x1 -#define XMSTATE_W_HDR 0x2 -#define XMSTATE_IMM_HDR 0x4 -#define XMSTATE_IMM_DATA 0x8 -#define XMSTATE_UNS_INIT 0x10 -#define XMSTATE_UNS_HDR 0x20 -#define XMSTATE_UNS_DATA 0x40 -#define XMSTATE_SOL_HDR 0x80 -#define XMSTATE_SOL_DATA 0x100 -#define XMSTATE_W_PAD 0x200 -#define XMSTATE_DATA_DIGEST 0x400 - -#define ISCSI_CONN_RCVBUF_MIN 262144 -#define ISCSI_CONN_SNDBUF_MIN 262144 +#define XMSTATE_IDLE 0x0 +#define XMSTATE_R_HDR 0x1 +#define XMSTATE_W_HDR 0x2 +#define XMSTATE_IMM_HDR 0x4 +#define XMSTATE_IMM_DATA 0x8 +#define XMSTATE_UNS_INIT 0x10 +#define XMSTATE_UNS_HDR 0x20 +#define XMSTATE_UNS_DATA 0x40 +#define XMSTATE_SOL_HDR 0x80 +#define XMSTATE_SOL_DATA 0x100 +#define XMSTATE_W_PAD 0x200 +#define XMSTATE_W_RESEND_PAD 0x400 +#define XMSTATE_W_RESEND_DATA_DIGEST 0x800 +#define ISCSI_PAD_LEN 4 -#define ISCSI_R2T_MAX 16#define ISCSI_SG_TABLESIZE SG_ALL#define ISCSI_TCP_MAX_CMD_LEN 16
@@ -162,13 +160,10 @@ struct iscsi_tcp_cmd_task {struct iscsi_queue r2tpool;struct kfifo *r2tqueue;struct iscsi_r2t_info **r2ts; -uint32_t datadigest;/* for recover digest */ int digest_count;uint32_t immdigest;/* for imm data */ struct iscsi_buf immbuf;/* for imm data digest */ -struct iscsi_data_task *dtask;/* data task in progress*/ struct iscsi_data_task unsol_dtask; /* unsol data task */ - int digest_offset; /* for partial buff digest */ };#endif /* ISCSI_H */
drivers/scsi/libiscsi.c +31 -6
@@ -325,6 +325,30 @@ static void iscsi_tmf_rsp(struct iscsi_cwake_up (&conn->ehwait); } +static int iscsi_handle_reject (struct iscsi_conn *conn,struct iscsi_hdr *hdr, +char *data,int datalen) +{ +struct iscsi_reject *reject = (struct iscsi_reject *)hdr; +struct iscsi_hdr rejected_pdu; +uint32_t itt; + + conn->exp_statsn =be32_to_cpu (reject->statsn) +1 ; + +if (reject->reason ==ISCSI_REASON_DATA_DIGEST_ERROR ) { +if (ntoh24 (reject->dlength) > datalen) +return ISCSI_ERR_PROTO ; + +if (ntoh24 (reject->dlength) >=sizeof (struct iscsi_hdr )) { +memcpy (&rejected_pdu, data,sizeof (struct iscsi_hdr )); + itt = rejected_pdu.itt &ISCSI_ITT_MASK ; +printk (KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " +"due to DataDigest error.\n" , itt, + rejected_pdu.opcode); + } + } +return 0 ; +} +/** * __iscsi_complete_pdu - complete pdu * @conn: iscsi conn
@@ -436,6 +460,11 @@ int __iscsi_complete_pdu(struct iscsi_cobreak ; } }else if (itt ==ISCSI_RESERVED_TAG ) { + rc =iscsi_check_assign_cmdsn (session, + (struct iscsi_nopin *)hdr); +if (rc) + goto done; +switch (opcode) {case ISCSI_OP_NOOP_IN :if (datalen) {
@@ -443,11 +472,6 @@ int __iscsi_complete_pdu(struct iscsi_cobreak ; } - rc =iscsi_check_assign_cmdsn (session, - (struct iscsi_nopin *)hdr); -if (rc) -break ; -if (hdr->ttt ==ISCSI_RESERVED_TAG )break ;
@@ -455,7 +479,8 @@ int __iscsi_complete_pdu(struct iscsi_co rc =ISCSI_ERR_CONN_FAILED ;break ;case ISCSI_OP_REJECT : -/* we need sth like iscsi_reject_rsp()*/ + rc =iscsi_handle_reject (conn, hdr, data, datalen); +break ;case ISCSI_OP_ASYNC_EVENT : conn->exp_statsn =be32_to_cpu (hdr->statsn) +1 ;/* we need sth like iscsi_async_event_rsp() */
Signature · 1 line
1.4.1.1
PATCH 5/12 scsi_tcp: rm data rx and tx tfms
From: Mike Christie <[email protected]>
We currently allocated seperate tfms for data and header digests. There is no reason for this since we can never calculate a rx header and digest at the same time. Same for sends. So this patch removes the data tfms and has the send and recv sides use the rx_tfm or tx_tfm.
I also made the connection creation code preallocate the tfms because I thought I hit a bug where I changed the digests settings during a relogin but could not allocate the tfm and then we just failed.
--- drivers/scsi/iscsi_tcp.c | 102 ++++++++++++++++------------------------------ drivers/scsi/iscsi_tcp.h | 8 +--- 2 files changed, 38 insertions(+), 72 deletions(-)
drivers/scsi/iscsi_tcp.c +36 -66
@@ -693,7 +693,7 @@ iscsi_recv_digest_update(struct iscsi_tcstruct scatterlist tmp;sg_init_one (&tmp, buf, len); -crypto_digest_update (tcp_conn->data_rx_tfm, &tmp,1 ); +crypto_digest_update (tcp_conn->rx_tfm, &tmp,1 ); }static int iscsi_scsi_data_in (struct iscsi_conn *conn)
@@ -748,11 +748,11 @@ static int iscsi_scsi_data_in(struct iscif (conn->datadgst_en) {if (!offset)crypto_digest_update ( - tcp_conn->data_rx_tfm, + tcp_conn->rx_tfm, &sg[i],1 );else partial_sg_digest_update ( - tcp_conn->data_rx_tfm, + tcp_conn->rx_tfm, &sg[i], sg[i].offset + offset, sg[i].length - offset);
@@ -766,7 +766,7 @@ static int iscsi_scsi_data_in(struct isc/* * data-in is complete, but buffer not... */ -partial_sg_digest_update (tcp_conn->data_rx_tfm, +partial_sg_digest_update (tcp_conn->rx_tfm, &sg[i], sg[i].offset, sg[i].length-rc); rc =0 ;
@@ -885,10 +885,8 @@ more:*/ rc =iscsi_tcp_hdr_recv (conn);if (!rc && tcp_conn->in.datalen) { -if (conn->datadgst_en) { -BUG_ON (!tcp_conn->data_rx_tfm); -crypto_digest_init (tcp_conn->data_rx_tfm); - } +if (conn->datadgst_en) +crypto_digest_init (tcp_conn->rx_tfm); tcp_conn->in_progress =IN_PROGRESS_DATA_RECV ; }else if (rc) {iscsi_conn_failure (conn, rc);
@@ -940,10 +938,10 @@ more: tcp_conn->in.padding);memset (pad,0 , tcp_conn->in.padding);sg_init_one (&sg, pad, tcp_conn->in.padding); -crypto_digest_update (tcp_conn->data_rx_tfm, +crypto_digest_update (tcp_conn->rx_tfm, &sg,1 ); } -crypto_digest_final (tcp_conn->data_rx_tfm, +crypto_digest_final (tcp_conn->rx_tfm, (u8 *) & tcp_conn->in.datadgst);debug_tcp ("rx digest 0x%x\n" , tcp_conn->in.datadgst); tcp_conn->in_progress =IN_PROGRESS_DDIGEST_RECV ;
@@ -1188,7 +1186,7 @@ static inline void iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn, struct iscsi_tcp_cmd_task *tcp_ctask) { - crypto_digest_init(tcp_conn->data_tx_tfm); + crypto_digest_init(tcp_conn->tx_tfm); tcp_ctask->digest_count =4 ; }
@@ -1444,7 +1442,7 @@ iscsi_send_padding(struct iscsi_conn *coiscsi_buf_init_iov (&tcp_ctask->sendbuf, (char *)&tcp_ctask->pad, tcp_ctask->pad_count);if (conn->datadgst_en) -crypto_digest_update (tcp_conn->data_tx_tfm, +crypto_digest_update (tcp_conn->tx_tfm, &tcp_ctask->sendbuf.sg,1 ); }else if (!(tcp_ctask->xmstate &XMSTATE_W_RESEND_PAD ))return 0 ;
@@ -1477,7 +1475,7 @@ iscsi_send_digest(struct iscsi_conn *con tcp_conn = conn->dd_data;if (!(tcp_ctask->xmstate &XMSTATE_W_RESEND_DATA_DIGEST )) { -crypto_digest_final (tcp_conn->data_tx_tfm, (u8 *)digest); +crypto_digest_final (tcp_conn->tx_tfm, (u8 *)digest);iscsi_buf_init_iov (buf, (char *)digest,4 ); } tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST ;
@@ -1511,7 +1509,7 @@ iscsi_send_data(struct iscsi_cmd_task *c rc =iscsi_sendpage (conn, sendbuf, count, &buf_sent); *sent = *sent + buf_sent;if (buf_sent && conn->datadgst_en) -partial_sg_digest_update (tcp_conn->data_tx_tfm, +partial_sg_digest_update (tcp_conn->tx_tfm, &sendbuf->sg, sendbuf->sg.offset + offset, buf_sent);if (!iscsi_buf_left (sendbuf) && *sg != tcp_ctask->bad_sg) {
@@ -1547,10 +1545,6 @@ iscsi_send_unsol_hdr(struct iscsi_conn *if (conn->hdrdgst_en)iscsi_hdr_digest (conn, &tcp_ctask->headbuf, (u8 *)dtask->hdrext); -if (conn->datadgst_en) { -iscsi_data_digest_init (ctask->conn->dd_data, tcp_ctask); - dtask->digest =0 ; - } tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT ;iscsi_set_padding (tcp_ctask, ctask->data_count);
@@ -1563,6 +1557,12 @@ iscsi_send_unsol_hdr(struct iscsi_conn *return rc; } +if (conn->datadgst_en) { + dtask = &tcp_ctask->unsol_dtask; +iscsi_data_digest_init (ctask->conn->dd_data, tcp_ctask); + dtask->digest =0 ; + } +debug_scsi ("uns dout [itt 0x%x dlen %d sent %d]\n" , ctask->itt, ctask->unsol_count, tcp_ctask->sent);return 0 ;
@@ -1629,12 +1629,6 @@ send_hdr:if (conn->hdrdgst_en)iscsi_hdr_digest (conn, &r2t->headbuf, (u8 *)dtask->hdrext); - -if (conn->datadgst_en) { -iscsi_data_digest_init (conn->dd_data, tcp_ctask); - dtask->digest =0 ; - } - rc =iscsi_sendhdr (conn, &r2t->headbuf, r2t->data_count);if (rc) { tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA ;
@@ -1642,6 +1636,11 @@ send_hdr:return rc; } +if (conn->datadgst_en) { +iscsi_data_digest_init (conn->dd_data, tcp_ctask); + dtask->digest =0 ; + } +iscsi_set_padding (tcp_ctask, r2t->data_count); debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n", r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
@@ -1764,8 +1763,20 @@ iscsi_tcp_conn_create(struct iscsi_cls_s/* initial operational parameters */ tcp_conn->hdr_size =sizeof (struct iscsi_hdr ); + tcp_conn->tx_tfm =crypto_alloc_tfm ("crc32c" ,0 ); +if (!tcp_conn->tx_tfm) + goto free_tcp_conn; + + tcp_conn->rx_tfm =crypto_alloc_tfm ("crc32c" ,0 ); +if (!tcp_conn->rx_tfm) + goto free_tx_tfm; +return cls_conn; +free_tx_tfm: +crypto_free_tfm (tcp_conn->tx_tfm); +free_tcp_conn: +kfree (tcp_conn); tcp_conn_alloc_fail:iscsi_conn_teardown (cls_conn);return NULL ;
@@ -1807,10 +1818,6 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_crypto_free_tfm (tcp_conn->tx_tfm);if (tcp_conn->rx_tfm)crypto_free_tfm (tcp_conn->rx_tfm); -if (tcp_conn->data_tx_tfm) -crypto_free_tfm (tcp_conn->data_tx_tfm); -if (tcp_conn->data_rx_tfm) -crypto_free_tfm (tcp_conn->data_rx_tfm); }kfree (tcp_conn);
@@ -1968,48 +1975,11 @@ iscsi_conn_set_param(struct iscsi_cls_cocase ISCSI_PARAM_HDRDGST_EN :iscsi_set_param (cls_conn, param, buf, buflen); tcp_conn->hdr_size =sizeof (struct iscsi_hdr ); -if (conn->hdrdgst_en) { +if (conn->hdrdgst_en) tcp_conn->hdr_size +=sizeof (__u32); -if (!tcp_conn->tx_tfm) - tcp_conn->tx_tfm =crypto_alloc_tfm ("crc32c" , -0 ); -if (!tcp_conn->tx_tfm) -return -ENOMEM ; -if (!tcp_conn->rx_tfm) - tcp_conn->rx_tfm =crypto_alloc_tfm ("crc32c" , -0 ); -if (!tcp_conn->rx_tfm) { -crypto_free_tfm (tcp_conn->tx_tfm); -return -ENOMEM ; - } - }else { -if (tcp_conn->tx_tfm) -crypto_free_tfm (tcp_conn->tx_tfm); -if (tcp_conn->rx_tfm) -crypto_free_tfm (tcp_conn->rx_tfm); - }break ;case ISCSI_PARAM_DATADGST_EN :iscsi_set_param (cls_conn, param, buf, buflen); -if (conn->datadgst_en) { -if (!tcp_conn->data_tx_tfm) - tcp_conn->data_tx_tfm = -crypto_alloc_tfm ("crc32c" ,0 ); -if (!tcp_conn->data_tx_tfm) -return -ENOMEM ; -if (!tcp_conn->data_rx_tfm) - tcp_conn->data_rx_tfm = -crypto_alloc_tfm ("crc32c" ,0 ); -if (!tcp_conn->data_rx_tfm) { -crypto_free_tfm (tcp_conn->data_tx_tfm); -return -ENOMEM ; - } - }else { -if (tcp_conn->data_tx_tfm) -crypto_free_tfm (tcp_conn->data_tx_tfm); -if (tcp_conn->data_rx_tfm) -crypto_free_tfm (tcp_conn->data_rx_tfm); - } tcp_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_conn->sock->ops->sendpage;break ;
drivers/scsi/iscsi_tcp.h +2 -6
@@ -81,10 +81,6 @@ struct iscsi_tcp_conn {* stop to terminate */ /* iSCSI connection-wide sequencing */ int hdr_size;/* PDU header size */ - -struct crypto_tfm *rx_tfm;/* CRC32C (Rx) */ -struct crypto_tfm *data_rx_tfm;/* CRC32C (Rx) for data */ -/* control data */ struct iscsi_tcp_recv in;/* TCP receive context */ int in_progress;/* connection state machine */
@@ -94,9 +90,9 @@ struct iscsi_tcp_conn {void (*old_state_change)(struct sock *);void (*old_write_space)(struct sock *); -/* xmit */ +/* data and header digests */ struct crypto_tfm *tx_tfm;/* CRC32C (Tx) */ -struct crypto_tfm *data_tx_tfm;/* CRC32C (Tx) for data */ +struct crypto_tfm *rx_tfm;/* CRC32C (Rx) */ /* MIB custom statistics */ uint32_t sendpage_failures_cnt;
Signature · 1 line
1.4.1.1
PATCH 6/12 iscsi_tcp: fix header resend
From: Mike Christie <[email protected]>
This patch built over the last ones fixes a bug in the partial header resend code, where we add on another 4 bytes to the send length on the resend. We want just the header plus digest.
--- drivers/scsi/iscsi_tcp.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/iscsi_tcp.c +1 -1
@@ -109,7 +109,7 @@ iscsi_hdr_digest(struct iscsi_conn *connstruct iscsi_tcp_conn *tcp_conn = conn->dd_data;crypto_digest_digest (tcp_conn->tx_tfm, &buf->sg,1 , crc); - buf->sg.length +=sizeof (uint32_t ); + buf->sg.length = tcp_conn->hdr_size; } static inline int
Signature · 1 line
1.4.1.1
PATCH 7/12 iscsi_tcp: update header size during relogin
From: Mike Christie <[email protected]>
When we relogin to a target, we have not yet negotiated digests so we must reset the hdr_size var.
--- drivers/scsi/iscsi_tcp.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/scsi/iscsi_tcp.c +2 -0
@@ -1827,9 +1827,11 @@ static void iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) {struct iscsi_conn *conn = cls_conn->dd_data; +struct iscsi_tcp_conn *tcp_conn = conn->dd_data;iscsi_conn_stop (cls_conn, flag);iscsi_tcp_release_conn (conn); + tcp_conn->hdr_size =sizeof (struct iscsi_hdr ); } static int
Signature · 1 line
1.4.1.1
PATCH 8/12 libiscsi: only check burst lengths when sending unsol data
From: Mike Christie <[email protected]>
The first burst length is only relevant if immedate data = Yes or if Initial R2T is No.
--- drivers/scsi/libiscsi.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/scsi/libiscsi.c +2 -1
@@ -1593,7 +1593,8 @@ int iscsi_conn_start(struct iscsi_cls_coreturn -EPERM ; } -if (session->first_burst > session->max_burst) { +if ((session->imm_data_en || !session->initial_r2t_en) && + session->first_burst > session->max_burst) {printk ("iscsi: invalid burst lengths: " "first_burst %d max_burst %d\n" , session->first_burst, session->max_burst);
Signature · 1 line
1.4.1.1
PATCH 9/12 iscsi_tcp: fix partial digest recv
From: Mike Christie <[email protected]>
When a digest is spread across two network buffers, we currently ignore this and try to check the digest with the partial buffer. Or course this fails. This patch has use iscsi_tcp_copy to copy the whole digest before testing it.
--- drivers/scsi/iscsi_tcp.c | 21 +++++++++++++-------- 1 files changed, 13 insertions(+), 8 deletions(-)
drivers/scsi/iscsi_tcp.c +13 -8
@@ -648,10 +648,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn ** byte counters. **/ static inline int -iscsi_tcp_copy (struct iscsi_conn *conn) +iscsi_tcp_copy (struct iscsi_conn *conn,int buf_size) {struct iscsi_tcp_conn *tcp_conn = conn->dd_data; -int buf_size = tcp_conn->in.datalen;int buf_left = buf_size - tcp_conn->data_copied;int size =min (tcp_conn->in.copy, buf_left);int rc;
@@ -812,7 +811,7 @@ iscsi_data_recv(struct iscsi_conn *conn)* Collect data segment to the connection's data * placeholder */ -if (iscsi_tcp_copy (conn)) { +if (iscsi_tcp_copy (conn, tcp_conn->in.datalen)) { rc = -EAGAIN ; goto exit; }
@@ -899,10 +898,15 @@ more:debug_tcp ("extra data_recv offset %d copy %d\n" , tcp_conn->in.offset, tcp_conn->in.copy); -skb_copy_bits (tcp_conn->in.skb, tcp_conn->in.offset, - &recv_digest,4 ); - tcp_conn->in.offset +=4 ; - tcp_conn->in.copy -=4 ; + rc =iscsi_tcp_copy (conn,sizeof (uint32_t )); +if (rc) { +if (rc == -EAGAIN ) + goto again; +iscsi_conn_failure (conn,ISCSI_ERR_CONN_FAILED ); +return 0 ; + } + +memcpy (&recv_digest, conn->data,sizeof (uint32_t ));if (recv_digest != tcp_conn->in.datadgst) { debug_tcp("iscsi_tcp: data digest error!" "0x%x != 0x%x\n", recv_digest,
@@ -942,9 +946,10 @@ more: &sg, 1); }crypto_digest_final (tcp_conn->rx_tfm, - (u8 *) & tcp_conn->in.datadgst); + (u8 *) &tcp_conn->in.datadgst);debug_tcp ("rx digest 0x%x\n" , tcp_conn->in.datadgst); tcp_conn->in_progress =IN_PROGRESS_DDIGEST_RECV ; + tcp_conn->data_copied =0 ; }else tcp_conn->in_progress =IN_PROGRESS_WAIT_HEADER ; }
Signature · 1 line
1.4.1.1
PATCH 10/12 libiscsi: check that command ptr is set before accessing it
From: Mike Christie <[email protected]>
If the scsi eh sends a TUR and the session is down we could return SCSI_ML_HOST_BUSY. scsi eh will ignore this and send ask us to abort the command and we blindly accesst the command ptr.
--- drivers/scsi/libiscsi.c | 27 ++++++++++++++++++++++----- 1 files changed, 22 insertions(+), 5 deletions(-)
drivers/scsi/libiscsi.c +22 -5
@@ -192,6 +192,8 @@ static void iscsi_complete_command(struc ctask->state =ISCSI_TASK_COMPLETED ; ctask->sc =NULL ; +/* SCSI eh reuses commands to verify us */ + sc->SCp.ptr =NULL ;list_del_init (&ctask->running);__kfifo_put (session->cmdpool.queue, (void *)&ctask,sizeof (void *)); sc->scsi_done (sc);
@@ -737,6 +739,7 @@ int iscsi_queuecommand(struct scsi_cmnd sc->scsi_done = done; sc->result =0 ; + sc->SCp.ptr =NULL ; host = sc->device->host; session =iscsi_hostdata (host->hostdata);
@@ -801,9 +804,10 @@ int iscsi_queuecommand(struct scsi_cmndlist_add_tail (&ctask->running, &conn->xmitqueue);debug_scsi ( -"ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n" , +"ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " +"win %d]\n" , sc->sc_data_direction ==DMA_TO_DEVICE ?"write" :"read" , - conn->id, (long )sc, ctask->itt, sc->request_bufflen, + conn->id, sc, sc->cmnd[0 ], ctask->itt, sc->request_bufflen, session->cmdsn, session->max_cmdsn - session->exp_cmdsn +1 );spin_unlock (&session->lock);
@@ -1134,11 +1138,24 @@ static void fail_command(struct iscsi_coint iscsi_eh_abort (struct scsi_cmnd *sc) { -struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; -struct iscsi_conn *conn = ctask->conn; -struct iscsi_session *session = conn->session; +struct iscsi_cmd_task *ctask; +struct iscsi_conn *conn; +struct iscsi_session *session;int rc; +/* +* if session was ISCSI_STATE_IN_RECOVERY then we may not have +* got the command. +*/ +if (!sc->SCp.ptr) { +debug_scsi ("sc never reached iscsi layer or it completed.\n" ); +return SUCCESS ; + } + + ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; + conn = ctask->conn; + session = conn->session; + conn->eh_abort_cnt++;debug_scsi ("aborting [sc %p itt 0x%x]\n" , sc, ctask->itt);
Signature · 1 line
1.4.1.1
PATCH 11/12 libiscsi: don't call into lld to cleanup task
From: Mike Christie <[email protected]>
In the normal IO path we should not be calling back into the LLD since the LLD will have cleaned up the task before or after calling complete pdu.
For the fail_command path we still need to do this to force the cleanup.
--- drivers/scsi/libiscsi.c | 9 ++++----- 1 files changed, 4 insertions(+), 5 deletions(-)
drivers/scsi/libiscsi.c +4 -5
@@ -213,12 +213,8 @@ static void iscsi_get_ctask(struct iscsistatic void __iscsi_put_ctask (struct iscsi_cmd_task *ctask) { -struct iscsi_conn *conn = ctask->conn; - -if (atomic_dec_and_test (&ctask->refcount)) { - conn->session->tt->cleanup_cmd_task (conn, ctask); +if (atomic_dec_and_test (&ctask->refcount))iscsi_complete_command (ctask); - } }static void iscsi_put_ctask (struct iscsi_cmd_task *ctask)
@@ -1129,10 +1125,13 @@ static void fail_command(struct iscsi_co sc = ctask->sc;if (!sc)return ; + + conn->session->tt->cleanup_cmd_task (conn, ctask);iscsi_ctask_mtask_cleanup (ctask); sc->result = err; sc->resid = sc->request_bufflen; +/* release ref from queuecommand */ __iscsi_put_ctask (ctask); }
Signature · 1 line
1.4.1.1
PATCH 12/12 iscsi class: update version
From: Mike Christie <[email protected]>
Bump version.
--- drivers/scsi/scsi_transport_iscsi.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +1 -1
@@ -34,7 +34,7 @@ #include <scsi/iscsi_if.h>#define ISCSI_SESSION_ATTRS 11#define ISCSI_CONN_ATTRS 11#define ISCSI_HOST_ATTRS 0 -#define ISCSI_TRANSPORT_VERSION "1.1-646" +#define ISCSI_TRANSPORT_VERSION "2.0-685"struct iscsi_internal {int daemon_pid;
Signature · 1 line
1.4.1.1