Loading drivers/scsi/iscsi_tcp.c +119 −130 Original line number Original line Diff line number Diff line Loading @@ -57,13 +57,6 @@ MODULE_LICENSE("GPL"); #define debug_tcp(fmt...) #define debug_tcp(fmt...) #endif #endif #ifndef DEBUG_ASSERT #ifdef BUG_ON #undef BUG_ON #endif #define BUG_ON(expr) #endif static struct scsi_transport_template *iscsi_tcp_scsi_transport; static struct scsi_transport_template *iscsi_tcp_scsi_transport; static struct scsi_host_template iscsi_sht; static struct scsi_host_template iscsi_sht; static struct iscsi_transport iscsi_tcp_transport; static struct iscsi_transport iscsi_tcp_transport; Loading Loading @@ -498,14 +491,13 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) /* /* * must be called with session lock * must be called with session lock */ */ static void static void iscsi_tcp_cleanup_task(struct iscsi_task *task) iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) { { struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_r2t_info *r2t; struct iscsi_r2t_info *r2t; /* nothing to do for mgmt tasks */ /* nothing to do for mgmt or pending tasks */ if (!task->sc) if (!task->sc || task->state == ISCSI_TASK_PENDING) return; return; /* flush task's r2t queues */ /* flush task's r2t queues */ Loading Loading @@ -611,11 +603,11 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_task *task, static int static int iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) { { struct iscsi_r2t_info *r2t; struct iscsi_session *session = conn->session; struct iscsi_session *session = conn->session; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_info *r2t; int r2tsn = be32_to_cpu(rhdr->r2tsn); int r2tsn = be32_to_cpu(rhdr->r2tsn); int rc; int rc; Loading Loading @@ -643,7 +635,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } } rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); BUG_ON(!rc); if (!rc) { iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " "Target has sent more R2Ts than it " "negotiated for or driver has has leaked.\n"); return ISCSI_ERR_PROTO; } r2t->exp_statsn = rhdr->statsn; r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); r2t->data_length = be32_to_cpu(rhdr->data_length); Loading Loading @@ -672,9 +669,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } } r2t->ttt = rhdr->ttt; /* no flip */ r2t->ttt = rhdr->ttt; /* no flip */ r2t->solicit_datasn = 0; r2t->datasn = 0; r2t->sent = 0; iscsi_solicit_data_init(conn, task, r2t); tcp_task->exp_datasn = r2tsn + 1; tcp_task->exp_datasn = r2tsn + 1; __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); Loading Loading @@ -1199,9 +1195,9 @@ iscsi_tcp_xmit_qlen(struct iscsi_conn *conn) return segment->total_copied - segment->total_size; return segment->total_copied - segment->total_size; } } static inline int static int iscsi_tcp_flush(struct iscsi_task *task) iscsi_tcp_flush(struct iscsi_conn *conn) { { struct iscsi_conn *conn = task->conn; int rc; int rc; while (iscsi_tcp_xmit_qlen(conn)) { while (iscsi_tcp_xmit_qlen(conn)) { Loading Loading @@ -1364,14 +1360,49 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_task *task, return 1; return 1; } } static int iscsi_tcp_pdu_init(struct iscsi_task *task, unsigned int offset, unsigned int count) { struct iscsi_conn *conn = task->conn; int err = 0; iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); if (!count) return 0; if (!task->sc) iscsi_tcp_send_linear_data_prepare(conn, task->data, count); else { struct scsi_data_buffer *sdb = scsi_out(task->sc); err = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, offset, count); } if (err) { iscsi_conn_failure(conn, err); return -EIO; } return 0; } static int iscsi_tcp_pdu_alloc(struct iscsi_task *task) { struct iscsi_tcp_task *tcp_task = task->dd_data; task->hdr = &tcp_task->hdr.hdrbuf; task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; return 0; } /** /** * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * @conn: iscsi connection * @conn: iscsi connection * @task: scsi command task * @task: scsi command task * @sc: scsi command * @sc: scsi command **/ **/ static int static int iscsi_tcp_task_init(struct iscsi_task *task) iscsi_tcp_task_init(struct iscsi_task *task) { { struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_conn *conn = task->conn; struct iscsi_conn *conn = task->conn; Loading @@ -1386,40 +1417,57 @@ iscsi_tcp_task_init(struct iscsi_task *task) debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, task->itt); task->itt); /* Prepare PDU, optionally w/ immediate data */ return conn->session->tt->init_pdu(task, 0, task->data_count); iscsi_tcp_send_hdr_prep(conn, task->hdr, sizeof(*task->hdr)); /* If we have immediate data, attach a payload */ if (task->data_count) iscsi_tcp_send_linear_data_prepare(conn, task->data, task->data_count); return 0; } } BUG_ON(__kfifo_len(tcp_task->r2tqueue)); BUG_ON(__kfifo_len(tcp_task->r2tqueue)); tcp_task->sent = 0; tcp_task->exp_datasn = 0; tcp_task->exp_datasn = 0; /* Prepare PDU, optionally w/ immediate data */ /* Prepare PDU, optionally w/ immediate data */ debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", conn->id, task->itt, task->imm_count, conn->id, task->itt, task->imm_count, task->unsol_count); task->unsol_r2t.data_length); iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); if (!task->imm_count) err = conn->session->tt->init_pdu(task, 0, task->imm_count); return 0; /* If we have immediate data, attach a payload */ err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, scsi_out(sc)->table.nents, 0, task->imm_count); if (err) if (err) return err; return err; tcp_task->sent += task->imm_count; task->imm_count = 0; task->imm_count = 0; return 0; return 0; } } static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task) { struct iscsi_session *session = task->conn->session; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_r2t_info *r2t = NULL; if (iscsi_task_has_unsol_data(task)) r2t = &task->unsol_r2t; else { spin_lock_bh(&session->lock); if (tcp_task->r2t) { r2t = tcp_task->r2t; /* Continue with this R2T? */ if (r2t->data_length <= r2t->sent) { debug_scsi(" done with r2t %p\n", r2t); __kfifo_put(tcp_task->r2tpool.queue, (void *)&tcp_task->r2t, sizeof(void *)); tcp_task->r2t = r2t = NULL; } } if (r2t == NULL) { __kfifo_get(tcp_task->r2tqueue, (void *)&tcp_task->r2t, sizeof(void *)); r2t = tcp_task->r2t; } spin_unlock_bh(&session->lock); } return r2t; } /* /* * iscsi_tcp_task_xmit - xmit normal PDU task * iscsi_tcp_task_xmit - xmit normal PDU task * @task: iscsi command task * @task: iscsi command task Loading @@ -1428,109 +1476,53 @@ iscsi_tcp_task_init(struct iscsi_task *task) * -EAGAIN if there's still data in the queue, or != 0 for any other kind * -EAGAIN if there's still data in the queue, or != 0 for any other kind * of error. * of error. */ */ static int static int iscsi_tcp_task_xmit(struct iscsi_task *task) iscsi_tcp_task_xmit(struct iscsi_task *task) { { struct iscsi_conn *conn = task->conn; struct iscsi_conn *conn = task->conn; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = task->sc; struct iscsi_r2t_info *r2t; struct scsi_data_buffer *sdb; int rc = 0; int rc = 0; flush: flush: /* Flush any pending data first. */ /* Flush any pending data first. */ rc = iscsi_tcp_flush(conn); rc = session->tt->xmit_pdu(task); if (rc < 0) if (rc < 0) return rc; return rc; /* mgmt command */ /* mgmt command */ if (!sc) { if (!task->sc) { if (task->hdr->itt == RESERVED_ITT) if (task->hdr->itt == RESERVED_ITT) iscsi_put_task(task); iscsi_put_task(task); return 0; return 0; } } /* Are we done already? */ /* Are we done already? */ if (sc->sc_data_direction != DMA_TO_DEVICE) if (task->sc->sc_data_direction != DMA_TO_DEVICE) return 0; return 0; sdb = scsi_out(sc); r2t = iscsi_tcp_get_curr_r2t(task); if (task->unsol_count != 0) { struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr; /* Prepare a header for the unsolicited PDU. * The amount of data we want to send will be * in task->data_count. * FIXME: return the data count instead. */ iscsi_prep_unsolicit_data_pdu(task, hdr); debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", task->itt, tcp_task->sent, task->data_count); iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, tcp_task->sent, task->data_count); if (rc) goto fail; tcp_task->sent += task->data_count; task->unsol_count -= task->data_count; goto flush; } else { struct iscsi_session *session = conn->session; struct iscsi_r2t_info *r2t; /* All unsolicited PDUs sent. Check for solicited PDUs. */ spin_lock_bh(&session->lock); r2t = tcp_task->r2t; if (r2t != NULL) { /* Continue with this R2T? */ if (!iscsi_solicit_data_cont(conn, task, r2t)) { debug_scsi(" done with r2t %p\n", r2t); __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); tcp_task->r2t = r2t = NULL; } } if (r2t == NULL) { if (r2t == NULL) { __kfifo_get(tcp_task->r2tqueue, (void*)&tcp_task->r2t, sizeof(void*)); r2t = tcp_task->r2t; } spin_unlock_bh(&session->lock); /* Waiting for more R2Ts to arrive. */ /* Waiting for more R2Ts to arrive. */ if (r2t == NULL) { debug_tcp("no R2Ts yet\n"); debug_tcp("no R2Ts yet\n"); return 0; return 0; } } rc = conn->session->tt->alloc_pdu(task); if (rc) return rc; iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr); debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", r2t, r2t->solicit_datasn - 1, task->itt, r2t, r2t->datasn - 1, task->hdr->itt, r2t->data_offset + r2t->sent, r2t->data_count); r2t->data_offset + r2t->sent, r2t->data_count); iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent, sizeof(struct iscsi_hdr)); rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, r2t->data_offset + r2t->sent, r2t->data_count); r2t->data_count); if (rc) if (rc) goto fail; return rc; tcp_task->sent += r2t->data_count; r2t->sent += r2t->data_count; r2t->sent += r2t->data_count; goto flush; goto flush; } } return 0; fail: iscsi_conn_failure(conn, rc); return -EIO; } static struct iscsi_cls_conn * static struct iscsi_cls_conn * iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) Loading Loading @@ -1751,13 +1743,14 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; /* /* * pre-allocated x4 as much r2ts to handle race when * pre-allocated x2 as much r2ts to handle race when * target acks DataOut faster than we data_xmit() queues * target acks DataOut faster than we data_xmit() queues * could replenish r2tqueue. * could replenish r2tqueue. */ */ /* R2T pool */ /* R2T pool */ if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 4, NULL, if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 2, NULL, sizeof(struct iscsi_r2t_info))) { sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; goto r2t_alloc_fail; } } Loading Loading @@ -1891,7 +1884,6 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, struct iscsi_cls_session *cls_session; struct iscsi_cls_session *cls_session; struct iscsi_session *session; struct iscsi_session *session; struct Scsi_Host *shost; struct Scsi_Host *shost; int cmd_i; if (ep) { if (ep) { printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); Loading Loading @@ -1919,14 +1911,6 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, session = cls_session->dd_data; session = cls_session->dd_data; shost->can_queue = session->scsi_cmds_max; shost->can_queue = session->scsi_cmds_max; for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { struct iscsi_task *task = session->cmds[cmd_i]; struct iscsi_tcp_task *tcp_task = task->dd_data; task->hdr = &tcp_task->hdr.cmd_hdr; task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; } if (iscsi_r2tpool_alloc(session)) if (iscsi_r2tpool_alloc(session)) goto remove_session; goto remove_session; return cls_session; return cls_session; Loading Loading @@ -2026,9 +2010,14 @@ static struct iscsi_transport iscsi_tcp_transport = { /* IO */ /* IO */ .send_pdu = iscsi_conn_send_pdu, .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, .get_stats = iscsi_conn_get_stats, /* iscsi task/cmd helpers */ .init_task = iscsi_tcp_task_init, .init_task = iscsi_tcp_task_init, .xmit_task = iscsi_tcp_task_xmit, .xmit_task = iscsi_tcp_task_xmit, .cleanup_task = iscsi_tcp_cleanup_task, .cleanup_task = iscsi_tcp_cleanup_task, /* low level pdu helpers */ .xmit_pdu = iscsi_tcp_flush, .init_pdu = iscsi_tcp_pdu_init, .alloc_pdu = iscsi_tcp_pdu_alloc, /* recovery */ /* recovery */ .session_recovery_timedout = iscsi_session_recovery_timedout, .session_recovery_timedout = iscsi_session_recovery_timedout, }; }; Loading drivers/scsi/iscsi_tcp.h +2 −19 Original line number Original line Diff line number Diff line Loading @@ -98,25 +98,9 @@ struct iscsi_tcp_conn { ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); }; }; struct iscsi_data_task { struct iscsi_data hdr; /* PDU */ char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ }; struct iscsi_r2t_info { __be32 ttt; /* copied from R2T */ __be32 exp_statsn; /* copied from R2T */ uint32_t data_length; /* copied from R2T */ uint32_t data_offset; /* copied from R2T */ int sent; /* R2T sequence progress */ int data_count; /* DATA-Out payload progress */ int solicit_datasn; struct iscsi_data_task dtask; /* Data-Out header buf */ }; struct iscsi_tcp_task { struct iscsi_tcp_task { struct iscsi_hdr_buff { struct iscsi_hdr_buff { struct iscsi_cmd cmd_hdr; struct iscsi_hdr hdrbuf; char hdrextbuf[ISCSI_MAX_AHS_SIZE + char hdrextbuf[ISCSI_MAX_AHS_SIZE + ISCSI_DIGEST_SIZE]; ISCSI_DIGEST_SIZE]; } hdr; } hdr; Loading @@ -124,10 +108,9 @@ struct iscsi_tcp_task { int sent; int sent; uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ int data_offset; int data_offset; struct iscsi_r2t_info *r2t; /* in progress R2T */ struct iscsi_r2t_info *r2t; /* in progress solict R2T */ struct iscsi_pool r2tpool; struct iscsi_pool r2tpool; struct kfifo *r2tqueue; struct kfifo *r2tqueue; struct iscsi_data_task unsol_dtask; /* Data-Out header buf */ }; }; #endif /* ISCSI_H */ #endif /* ISCSI_H */ Loading
drivers/scsi/iscsi_tcp.c +119 −130 Original line number Original line Diff line number Diff line Loading @@ -57,13 +57,6 @@ MODULE_LICENSE("GPL"); #define debug_tcp(fmt...) #define debug_tcp(fmt...) #endif #endif #ifndef DEBUG_ASSERT #ifdef BUG_ON #undef BUG_ON #endif #define BUG_ON(expr) #endif static struct scsi_transport_template *iscsi_tcp_scsi_transport; static struct scsi_transport_template *iscsi_tcp_scsi_transport; static struct scsi_host_template iscsi_sht; static struct scsi_host_template iscsi_sht; static struct iscsi_transport iscsi_tcp_transport; static struct iscsi_transport iscsi_tcp_transport; Loading Loading @@ -498,14 +491,13 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) /* /* * must be called with session lock * must be called with session lock */ */ static void static void iscsi_tcp_cleanup_task(struct iscsi_task *task) iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) { { struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_r2t_info *r2t; struct iscsi_r2t_info *r2t; /* nothing to do for mgmt tasks */ /* nothing to do for mgmt or pending tasks */ if (!task->sc) if (!task->sc || task->state == ISCSI_TASK_PENDING) return; return; /* flush task's r2t queues */ /* flush task's r2t queues */ Loading Loading @@ -611,11 +603,11 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_task *task, static int static int iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) { { struct iscsi_r2t_info *r2t; struct iscsi_session *session = conn->session; struct iscsi_session *session = conn->session; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; struct iscsi_r2t_info *r2t; int r2tsn = be32_to_cpu(rhdr->r2tsn); int r2tsn = be32_to_cpu(rhdr->r2tsn); int rc; int rc; Loading Loading @@ -643,7 +635,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } } rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); BUG_ON(!rc); if (!rc) { iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " "Target has sent more R2Ts than it " "negotiated for or driver has has leaked.\n"); return ISCSI_ERR_PROTO; } r2t->exp_statsn = rhdr->statsn; r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); r2t->data_length = be32_to_cpu(rhdr->data_length); Loading Loading @@ -672,9 +669,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) } } r2t->ttt = rhdr->ttt; /* no flip */ r2t->ttt = rhdr->ttt; /* no flip */ r2t->solicit_datasn = 0; r2t->datasn = 0; r2t->sent = 0; iscsi_solicit_data_init(conn, task, r2t); tcp_task->exp_datasn = r2tsn + 1; tcp_task->exp_datasn = r2tsn + 1; __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); Loading Loading @@ -1199,9 +1195,9 @@ iscsi_tcp_xmit_qlen(struct iscsi_conn *conn) return segment->total_copied - segment->total_size; return segment->total_copied - segment->total_size; } } static inline int static int iscsi_tcp_flush(struct iscsi_task *task) iscsi_tcp_flush(struct iscsi_conn *conn) { { struct iscsi_conn *conn = task->conn; int rc; int rc; while (iscsi_tcp_xmit_qlen(conn)) { while (iscsi_tcp_xmit_qlen(conn)) { Loading Loading @@ -1364,14 +1360,49 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_task *task, return 1; return 1; } } static int iscsi_tcp_pdu_init(struct iscsi_task *task, unsigned int offset, unsigned int count) { struct iscsi_conn *conn = task->conn; int err = 0; iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); if (!count) return 0; if (!task->sc) iscsi_tcp_send_linear_data_prepare(conn, task->data, count); else { struct scsi_data_buffer *sdb = scsi_out(task->sc); err = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, offset, count); } if (err) { iscsi_conn_failure(conn, err); return -EIO; } return 0; } static int iscsi_tcp_pdu_alloc(struct iscsi_task *task) { struct iscsi_tcp_task *tcp_task = task->dd_data; task->hdr = &tcp_task->hdr.hdrbuf; task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; return 0; } /** /** * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * @conn: iscsi connection * @conn: iscsi connection * @task: scsi command task * @task: scsi command task * @sc: scsi command * @sc: scsi command **/ **/ static int static int iscsi_tcp_task_init(struct iscsi_task *task) iscsi_tcp_task_init(struct iscsi_task *task) { { struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_conn *conn = task->conn; struct iscsi_conn *conn = task->conn; Loading @@ -1386,40 +1417,57 @@ iscsi_tcp_task_init(struct iscsi_task *task) debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, task->itt); task->itt); /* Prepare PDU, optionally w/ immediate data */ return conn->session->tt->init_pdu(task, 0, task->data_count); iscsi_tcp_send_hdr_prep(conn, task->hdr, sizeof(*task->hdr)); /* If we have immediate data, attach a payload */ if (task->data_count) iscsi_tcp_send_linear_data_prepare(conn, task->data, task->data_count); return 0; } } BUG_ON(__kfifo_len(tcp_task->r2tqueue)); BUG_ON(__kfifo_len(tcp_task->r2tqueue)); tcp_task->sent = 0; tcp_task->exp_datasn = 0; tcp_task->exp_datasn = 0; /* Prepare PDU, optionally w/ immediate data */ /* Prepare PDU, optionally w/ immediate data */ debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", conn->id, task->itt, task->imm_count, conn->id, task->itt, task->imm_count, task->unsol_count); task->unsol_r2t.data_length); iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); if (!task->imm_count) err = conn->session->tt->init_pdu(task, 0, task->imm_count); return 0; /* If we have immediate data, attach a payload */ err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, scsi_out(sc)->table.nents, 0, task->imm_count); if (err) if (err) return err; return err; tcp_task->sent += task->imm_count; task->imm_count = 0; task->imm_count = 0; return 0; return 0; } } static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task) { struct iscsi_session *session = task->conn->session; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_r2t_info *r2t = NULL; if (iscsi_task_has_unsol_data(task)) r2t = &task->unsol_r2t; else { spin_lock_bh(&session->lock); if (tcp_task->r2t) { r2t = tcp_task->r2t; /* Continue with this R2T? */ if (r2t->data_length <= r2t->sent) { debug_scsi(" done with r2t %p\n", r2t); __kfifo_put(tcp_task->r2tpool.queue, (void *)&tcp_task->r2t, sizeof(void *)); tcp_task->r2t = r2t = NULL; } } if (r2t == NULL) { __kfifo_get(tcp_task->r2tqueue, (void *)&tcp_task->r2t, sizeof(void *)); r2t = tcp_task->r2t; } spin_unlock_bh(&session->lock); } return r2t; } /* /* * iscsi_tcp_task_xmit - xmit normal PDU task * iscsi_tcp_task_xmit - xmit normal PDU task * @task: iscsi command task * @task: iscsi command task Loading @@ -1428,109 +1476,53 @@ iscsi_tcp_task_init(struct iscsi_task *task) * -EAGAIN if there's still data in the queue, or != 0 for any other kind * -EAGAIN if there's still data in the queue, or != 0 for any other kind * of error. * of error. */ */ static int static int iscsi_tcp_task_xmit(struct iscsi_task *task) iscsi_tcp_task_xmit(struct iscsi_task *task) { { struct iscsi_conn *conn = task->conn; struct iscsi_conn *conn = task->conn; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = task->sc; struct iscsi_r2t_info *r2t; struct scsi_data_buffer *sdb; int rc = 0; int rc = 0; flush: flush: /* Flush any pending data first. */ /* Flush any pending data first. */ rc = iscsi_tcp_flush(conn); rc = session->tt->xmit_pdu(task); if (rc < 0) if (rc < 0) return rc; return rc; /* mgmt command */ /* mgmt command */ if (!sc) { if (!task->sc) { if (task->hdr->itt == RESERVED_ITT) if (task->hdr->itt == RESERVED_ITT) iscsi_put_task(task); iscsi_put_task(task); return 0; return 0; } } /* Are we done already? */ /* Are we done already? */ if (sc->sc_data_direction != DMA_TO_DEVICE) if (task->sc->sc_data_direction != DMA_TO_DEVICE) return 0; return 0; sdb = scsi_out(sc); r2t = iscsi_tcp_get_curr_r2t(task); if (task->unsol_count != 0) { struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr; /* Prepare a header for the unsolicited PDU. * The amount of data we want to send will be * in task->data_count. * FIXME: return the data count instead. */ iscsi_prep_unsolicit_data_pdu(task, hdr); debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", task->itt, tcp_task->sent, task->data_count); iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, tcp_task->sent, task->data_count); if (rc) goto fail; tcp_task->sent += task->data_count; task->unsol_count -= task->data_count; goto flush; } else { struct iscsi_session *session = conn->session; struct iscsi_r2t_info *r2t; /* All unsolicited PDUs sent. Check for solicited PDUs. */ spin_lock_bh(&session->lock); r2t = tcp_task->r2t; if (r2t != NULL) { /* Continue with this R2T? */ if (!iscsi_solicit_data_cont(conn, task, r2t)) { debug_scsi(" done with r2t %p\n", r2t); __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); tcp_task->r2t = r2t = NULL; } } if (r2t == NULL) { if (r2t == NULL) { __kfifo_get(tcp_task->r2tqueue, (void*)&tcp_task->r2t, sizeof(void*)); r2t = tcp_task->r2t; } spin_unlock_bh(&session->lock); /* Waiting for more R2Ts to arrive. */ /* Waiting for more R2Ts to arrive. */ if (r2t == NULL) { debug_tcp("no R2Ts yet\n"); debug_tcp("no R2Ts yet\n"); return 0; return 0; } } rc = conn->session->tt->alloc_pdu(task); if (rc) return rc; iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr); debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", r2t, r2t->solicit_datasn - 1, task->itt, r2t, r2t->datasn - 1, task->hdr->itt, r2t->data_offset + r2t->sent, r2t->data_count); r2t->data_offset + r2t->sent, r2t->data_count); iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent, sizeof(struct iscsi_hdr)); rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, sdb->table.nents, r2t->data_offset + r2t->sent, r2t->data_count); r2t->data_count); if (rc) if (rc) goto fail; return rc; tcp_task->sent += r2t->data_count; r2t->sent += r2t->data_count; r2t->sent += r2t->data_count; goto flush; goto flush; } } return 0; fail: iscsi_conn_failure(conn, rc); return -EIO; } static struct iscsi_cls_conn * static struct iscsi_cls_conn * iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) Loading Loading @@ -1751,13 +1743,14 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; /* /* * pre-allocated x4 as much r2ts to handle race when * pre-allocated x2 as much r2ts to handle race when * target acks DataOut faster than we data_xmit() queues * target acks DataOut faster than we data_xmit() queues * could replenish r2tqueue. * could replenish r2tqueue. */ */ /* R2T pool */ /* R2T pool */ if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 4, NULL, if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 2, NULL, sizeof(struct iscsi_r2t_info))) { sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; goto r2t_alloc_fail; } } Loading Loading @@ -1891,7 +1884,6 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, struct iscsi_cls_session *cls_session; struct iscsi_cls_session *cls_session; struct iscsi_session *session; struct iscsi_session *session; struct Scsi_Host *shost; struct Scsi_Host *shost; int cmd_i; if (ep) { if (ep) { printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); Loading Loading @@ -1919,14 +1911,6 @@ iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, session = cls_session->dd_data; session = cls_session->dd_data; shost->can_queue = session->scsi_cmds_max; shost->can_queue = session->scsi_cmds_max; for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { struct iscsi_task *task = session->cmds[cmd_i]; struct iscsi_tcp_task *tcp_task = task->dd_data; task->hdr = &tcp_task->hdr.cmd_hdr; task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; } if (iscsi_r2tpool_alloc(session)) if (iscsi_r2tpool_alloc(session)) goto remove_session; goto remove_session; return cls_session; return cls_session; Loading Loading @@ -2026,9 +2010,14 @@ static struct iscsi_transport iscsi_tcp_transport = { /* IO */ /* IO */ .send_pdu = iscsi_conn_send_pdu, .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, .get_stats = iscsi_conn_get_stats, /* iscsi task/cmd helpers */ .init_task = iscsi_tcp_task_init, .init_task = iscsi_tcp_task_init, .xmit_task = iscsi_tcp_task_xmit, .xmit_task = iscsi_tcp_task_xmit, .cleanup_task = iscsi_tcp_cleanup_task, .cleanup_task = iscsi_tcp_cleanup_task, /* low level pdu helpers */ .xmit_pdu = iscsi_tcp_flush, .init_pdu = iscsi_tcp_pdu_init, .alloc_pdu = iscsi_tcp_pdu_alloc, /* recovery */ /* recovery */ .session_recovery_timedout = iscsi_session_recovery_timedout, .session_recovery_timedout = iscsi_session_recovery_timedout, }; }; Loading
drivers/scsi/iscsi_tcp.h +2 −19 Original line number Original line Diff line number Diff line Loading @@ -98,25 +98,9 @@ struct iscsi_tcp_conn { ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); }; }; struct iscsi_data_task { struct iscsi_data hdr; /* PDU */ char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ }; struct iscsi_r2t_info { __be32 ttt; /* copied from R2T */ __be32 exp_statsn; /* copied from R2T */ uint32_t data_length; /* copied from R2T */ uint32_t data_offset; /* copied from R2T */ int sent; /* R2T sequence progress */ int data_count; /* DATA-Out payload progress */ int solicit_datasn; struct iscsi_data_task dtask; /* Data-Out header buf */ }; struct iscsi_tcp_task { struct iscsi_tcp_task { struct iscsi_hdr_buff { struct iscsi_hdr_buff { struct iscsi_cmd cmd_hdr; struct iscsi_hdr hdrbuf; char hdrextbuf[ISCSI_MAX_AHS_SIZE + char hdrextbuf[ISCSI_MAX_AHS_SIZE + ISCSI_DIGEST_SIZE]; ISCSI_DIGEST_SIZE]; } hdr; } hdr; Loading @@ -124,10 +108,9 @@ struct iscsi_tcp_task { int sent; int sent; uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ int data_offset; int data_offset; struct iscsi_r2t_info *r2t; /* in progress R2T */ struct iscsi_r2t_info *r2t; /* in progress solict R2T */ struct iscsi_pool r2tpool; struct iscsi_pool r2tpool; struct kfifo *r2tqueue; struct kfifo *r2tqueue; struct iscsi_data_task unsol_dtask; /* Data-Out header buf */ }; }; #endif /* ISCSI_H */ #endif /* ISCSI_H */