From 0b9506723826c68b50fa33e345700ddcac1bed36 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 11 Jan 2006 13:16:10 +0100 Subject: [SCSI] turn most scsi semaphores into mutexes the scsi layer is using semaphores in a mutex way, this patch converts these into using mutexes instead Signed-off-by: Arjan van de Ven Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 10bcf42cb65c..1067d77da10e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2300,10 +2301,10 @@ iscsi_xmitworker(void *data) /* * serialize Xmit worker on a per-connection basis. */ - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); if (iscsi_data_xmit(conn)) schedule_work(&conn->xmitwork); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); } #define FAILURE_BAD_HOST 1 @@ -2367,11 +2368,11 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); spin_unlock(&session->lock); - if (!in_interrupt() && !down_trylock(&conn->xmitsema)) { + if (!in_interrupt() && mutex_trylock(&conn->xmitmutex)) { spin_unlock_irq(host->host_lock); if (iscsi_data_xmit(conn)) schedule_work(&conn->xmitwork); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); spin_lock_irq(host->host_lock); } else schedule_work(&conn->xmitwork); @@ -2531,7 +2532,7 @@ iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx) goto max_recv_dlenght_alloc_fail; init_timer(&conn->tmabort_timer); - init_MUTEX(&conn->xmitsema); + mutex_init(&conn->xmitmutex); init_waitqueue_head(&conn->ehwait); return iscsi_handle(conn); @@ -2561,7 +2562,7 @@ iscsi_conn_destroy(iscsi_connh_t connh) struct iscsi_conn *conn = iscsi_ptr(connh); struct iscsi_session *session = conn->session; - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); set_bit(SUSPEND_BIT, &conn->suspend_tx); if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE && conn->sock) { struct sock *sk = conn->sock->sk; @@ -2592,7 +2593,7 @@ iscsi_conn_destroy(iscsi_connh_t connh) } spin_unlock_bh(&session->lock); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); /* * Block until all in-progress commands for this connection @@ -2796,7 +2797,7 @@ iscsi_conn_stop(iscsi_connh_t connh, int flag) set_bit(SUSPEND_BIT, &conn->suspend_rx); write_unlock_bh(&sk->sk_callback_lock); - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); spin_lock_irqsave(session->host->host_lock, flags); spin_lock(&session->lock); @@ -2878,7 +2879,7 @@ iscsi_conn_stop(iscsi_connh_t connh, int flag) conn->datadgst_en = 0; } } - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); } static int @@ -3029,12 +3030,12 @@ iscsi_eh_abort(struct scsi_cmnd *sc) * 1) connection-level failure; * 2) recovery due protocol error; */ - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); spin_lock_bh(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { if (session->state == ISCSI_STATE_TERMINATE) { spin_unlock_bh(&session->lock); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); goto failed; } spin_unlock_bh(&session->lock); @@ -3052,7 +3053,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc) * 2) session was re-open during time out of ctask. */ spin_unlock_bh(&session->lock); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); goto success; } conn->tmabort_state = TMABORT_INITIAL; @@ -3107,7 +3108,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc) conn->tmabort_state == TMABORT_SUCCESS) { conn->tmabort_state = TMABORT_INITIAL; spin_unlock_bh(&session->lock); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); goto success; } conn->tmabort_state = TMABORT_INITIAL; @@ -3116,7 +3117,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc) spin_unlock_bh(&session->lock); } } - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); /* @@ -3182,7 +3183,7 @@ failed: exit: del_timer_sync(&conn->tmabort_timer); - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); if (conn->sock) { struct sock *sk = conn->sock->sk; @@ -3190,7 +3191,7 @@ exit: iscsi_ctask_cleanup(conn, ctask); write_unlock_bh(&sk->sk_callback_lock); } - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); return rc; } @@ -3601,9 +3602,9 @@ iscsi_conn_send_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr, char *data, struct iscsi_conn *conn = iscsi_ptr(connh); int rc; - down(&conn->xmitsema); + mutex_lock(&conn->xmitmutex); rc = iscsi_conn_send_generic(conn, hdr, data, data_size); - up(&conn->xmitsema); + mutex_unlock(&conn->xmitmutex); return rc; } -- cgit v1.2.3 From 42f72aa9e5bc969a34e5989fc00e7e2d71e8a95b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 13 Jan 2006 18:05:35 -0600 Subject: [SCSI] iscsi: whitespace cleanup Remove extra whitespaces. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 1067d77da10e..49d6dd5572cb 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -687,7 +687,7 @@ iscsi_hdr_recv(struct iscsi_conn *conn) switch(conn->in.opcode) { case ISCSI_OP_LOGIN_RSP: case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_LOGOUT_RSP: + case ISCSI_OP_LOGOUT_RSP: rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)hdr); if (rc) @@ -728,12 +728,12 @@ iscsi_hdr_recv(struct iscsi_conn *conn) } spin_unlock(&session->lock); break; - case ISCSI_OP_NOOP_IN: + case ISCSI_OP_NOOP_IN: if (hdr->ttt != ISCSI_RESERVED_TAG) { rc = ISCSI_ERR_PROTO; break; } - rc = iscsi_check_assign_cmdsn(session, + rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)hdr); if (rc) break; @@ -768,7 +768,7 @@ iscsi_hdr_recv(struct iscsi_conn *conn) if (!rc && hdr->ttt != ISCSI_RESERVED_TAG) rc = iscsi_recv_pdu(iscsi_handle(conn), hdr, NULL, 0); - } else + } else rc = ISCSI_ERR_PROTO; break; case ISCSI_OP_REJECT: @@ -930,7 +930,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) sc->request_bufflen, ctask->data_offset); if (rc == -EAGAIN) return rc; - if (conn->datadgst_en) + if (conn->datadgst_en) iscsi_recv_digest_update(conn, sc->request_buffer, i); rc = 0; goto done; @@ -1025,7 +1025,7 @@ iscsi_data_recv(struct iscsi_conn *conn) conn->in.hdr = &conn->hdr; conn->senselen = (conn->data[0] << 8) | conn->data[1]; rc = iscsi_cmd_rsp(conn, conn->in.ctask); - if (!rc && conn->datadgst_en) + if (!rc && conn->datadgst_en) iscsi_recv_digest_update(conn, conn->data, conn->in.datalen); } @@ -1052,7 +1052,7 @@ iscsi_data_recv(struct iscsi_conn *conn) rc = iscsi_recv_pdu(iscsi_handle(conn), conn->in.hdr, conn->data, conn->in.datalen); - if (!rc && conn->datadgst_en && + if (!rc && conn->datadgst_en && conn->in.opcode != ISCSI_OP_LOGIN_RSP) iscsi_recv_digest_update(conn, conn->data, conn->in.datalen); @@ -1681,7 +1681,7 @@ iscsi_cmd_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, zero_data(ctask->hdr.dlength); } - iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr, + iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr, sizeof(struct iscsi_hdr)); conn->scsicmd_pdus_cnt++; } @@ -1747,7 +1747,7 @@ static inline int handle_xmstate_r_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { ctask->xmstate &= ~XMSTATE_R_HDR; - if (conn->hdrdgst_en) + if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext); if (!iscsi_sendhdr(conn, &ctask->headbuf, 0)) { BUG_ON(ctask->xmstate != XMSTATE_IDLE); @@ -1761,7 +1761,7 @@ static inline int handle_xmstate_w_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { ctask->xmstate &= ~XMSTATE_W_HDR; - if (conn->hdrdgst_en) + if (conn->hdrdgst_en) iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext); if (iscsi_sendhdr(conn, &ctask->headbuf, ctask->imm_count)) { ctask->xmstate |= XMSTATE_W_HDR; @@ -2149,7 +2149,7 @@ unsolicit_head_again: solicit_head_again: r2t = ctask->r2t; if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &r2t->headbuf, + iscsi_hdr_digest(conn, &r2t->headbuf, (u8*)r2t->dtask->hdrext); if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) { ctask->xmstate &= ~XMSTATE_SOL_DATA; -- cgit v1.2.3 From bf310b8f582bddec20c27e32ffbaf8e2c91e147c Mon Sep 17 00:00:00 2001 From: "zhenyu.z.wang@intel.com" Date: Fri, 13 Jan 2006 18:05:38 -0600 Subject: [SCSI] iscsi: data under/over flow fix We need to check the ISCSI_FLAG_DATA_* flags. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 49d6dd5572cb..550ff66ba9ec 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -357,7 +357,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct scsi_cmnd *sc = ctask->sc; conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) { int res_count = be32_to_cpu(rhdr->residual_count); if (res_count > 0 && @@ -367,9 +367,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) { + } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) { sc->resid = be32_to_cpu(rhdr->residual_count); sc->result = (DID_OK << 16) | rhdr->cmd_status; } else -- cgit v1.2.3 From 3e97c7e6cda933e3a1b518a8100d155c532a3cfc Mon Sep 17 00:00:00 2001 From: "zhenyu.z.wang@intel.com" Date: Fri, 13 Jan 2006 18:05:41 -0600 Subject: [SCSI] iscsi: host locking fix We should be taking the host_lock instead of the conn lock when checking host_busy. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 550ff66ba9ec..cd1491e52361 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2559,6 +2559,7 @@ iscsi_conn_destroy(iscsi_connh_t connh) { struct iscsi_conn *conn = iscsi_ptr(connh); struct iscsi_session *session = conn->session; + unsigned long flags; mutex_lock(&conn->xmitmutex); set_bit(SUSPEND_BIT, &conn->suspend_tx); @@ -2598,12 +2599,12 @@ iscsi_conn_destroy(iscsi_connh_t connh) * time out or fail. */ for (;;) { - spin_lock_bh(&conn->lock); + spin_lock_irqsave(session->host->host_lock, flags); if (!session->host->host_busy) { /* OK for ERL == 0 */ - spin_unlock_bh(&conn->lock); + spin_unlock_irqrestore(session->host->host_lock, flags); break; } - spin_unlock_bh(&conn->lock); + spin_unlock_irqrestore(session->host->host_lock, flags); msleep_interruptible(500); printk("conn_destroy(): host_busy %d host_failed %d\n", session->host->host_busy, session->host->host_failed); -- cgit v1.2.3 From 56851698c23430f0f291d6e50da344e6b414f3b9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 13 Jan 2006 18:05:44 -0600 Subject: [SCSI] iscsi: data digest page cache usage fix Users can write to a page while we are sending it and making digest calculations. This ends up causing us to retry the command when a digest error is later reported. By using sock_no_sendpage when data digests are calculated we can avoid a lot of (not all but it helps) the retries becuase sock_no_sendpage is not zero copy. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 16 +++++++++------- 1 file changed, 9 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 cd1491e52361..5e8b3135574c 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1318,15 +1318,15 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn) * to use tcp_sendmsg(). */ static inline int -iscsi_send(struct socket *sk, struct iscsi_buf *buf, int size, int flags) +iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) { + struct socket *sk = conn->sock; int res; if ((int)buf->sg.offset >= 0) { int offset = buf->sg.offset + buf->sent; - /* tcp_sendpage */ - res = sk->ops->sendpage(sk, buf->sg.page, offset, size, flags); + res = conn->sendpage(sk, buf->sg.page, offset, size, flags); } else { struct msghdr msg; @@ -1354,7 +1354,6 @@ iscsi_send(struct socket *sk, struct iscsi_buf *buf, int size, int flags) static inline int iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) { - struct socket *sk = conn->sock; int flags = 0; /* MSG_DONTWAIT; */ int res, size; @@ -1363,7 +1362,7 @@ iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) if (buf->sent + size != buf->sg.length || datalen) flags |= MSG_MORE; - res = iscsi_send(sk, buf, size, flags); + res = iscsi_send(conn, buf, size, flags); debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res); if (res >= 0) { conn->txdata_octets += res; @@ -1394,7 +1393,6 @@ static inline int iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, int *count, int *sent) { - struct socket *sk = conn->sock; int flags = 0; /* MSG_DONTWAIT; */ int res, size; @@ -1405,7 +1403,7 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, if (buf->sent + size != buf->sg.length || *count != size) flags |= MSG_MORE; - res = iscsi_send(sk, buf, size, flags); + res = iscsi_send(conn, buf, size, flags); debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n", size, buf->sent, *count, *sent, res); if (res >= 0) { @@ -2713,6 +2711,8 @@ iscsi_conn_bind(iscsi_sessionh_t sessionh, iscsi_connh_t connh, */ iscsi_conn_set_callbacks(conn); + conn->sendpage = conn->sock->ops->sendpage; + /* * set receive state machine into initial state */ @@ -3467,6 +3467,8 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param, if (conn->data_rx_tfm) crypto_free_tfm(conn->data_rx_tfm); } + conn->sendpage = conn->datadgst_en ? + sock_no_sendpage : conn->sock->ops->sendpage; break; case ISCSI_PARAM_INITIAL_R2T_EN: session->initial_r2t_en = value; -- cgit v1.2.3 From 7cae5159dd2623300cf9820865bfbf6dcdb7c1b9 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 13 Jan 2006 18:05:47 -0600 Subject: [SCSI] iscsi: add high mem support From Mike Christie and FUJITA Tomonori : We cannot use page_address becuase some pages could be highmem. Instead, we can use sock_no_sendpage which does kmap for us. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 84 +++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 54 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 5e8b3135574c..0acc4b235d9b 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -87,35 +87,32 @@ iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size) { sg_init_one(&ibuf->sg, (u8 *)vbuf, size); ibuf->sent = 0; + ibuf->use_sendmsg = 0; } static inline void iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) { - ibuf->sg.page = (void*)vbuf; - ibuf->sg.offset = (unsigned int)-1; + ibuf->sg.page = virt_to_page(vbuf); + ibuf->sg.offset = offset_in_page(vbuf); ibuf->sg.length = size; ibuf->sent = 0; -} - -static inline void* -iscsi_buf_iov_base(struct iscsi_buf *ibuf) -{ - return (char*)ibuf->sg.page + ibuf->sent; + ibuf->use_sendmsg = 1; } static inline void iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) { + ibuf->sg.page = sg->page; + ibuf->sg.offset = sg->offset; + ibuf->sg.length = sg->length; /* * Fastpath: sg element fits into single page */ - if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) { - ibuf->sg.page = sg->page; - ibuf->sg.offset = sg->offset; - ibuf->sg.length = sg->length; - } else - iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length); + if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) + ibuf->use_sendmsg = 0; + else + ibuf->use_sendmsg = 1; ibuf->sent = 0; } @@ -1311,35 +1308,25 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn) * @buf: buffer to write from * @size: actual size to write * @flags: socket's flags - * - * Notes: - * depending on buffer will use tcp_sendpage() or tcp_sendmsg(). - * buf->sg.offset == -1 tells us that buffer is non S/G and forces - * to use tcp_sendmsg(). */ static inline int iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) { struct socket *sk = conn->sock; - int res; - - if ((int)buf->sg.offset >= 0) { - int offset = buf->sg.offset + buf->sent; - - res = conn->sendpage(sk, buf->sg.page, offset, size, flags); - } else { - struct msghdr msg; - - buf->iov.iov_base = iscsi_buf_iov_base(buf); - buf->iov.iov_len = size; - - memset(&msg, 0, sizeof(struct msghdr)); - - /* tcp_sendmsg */ - res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size); - } + int offset = buf->sg.offset + buf->sent; - return res; + /* + * if we got use_sg=0 or are sending something we kmallocd + * then we did not have to do kmap (kmap returns page_address) + * + * if we got use_sg > 0, but had to drop down, we do not + * set clustering so this should only happen for that + * slab case. + */ + if (buf->use_sendmsg) + return sock_no_sendpage(sk, buf->sg.page, offset, size, flags); + else + return conn->sendpage(sk, buf->sg.page, offset, size, flags); } /** @@ -1431,19 +1418,6 @@ iscsi_data_digest_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ctask->digest_count = 4; } -static inline void -iscsi_buf_data_digest_update(struct iscsi_conn *conn, struct iscsi_buf *buf) -{ - struct scatterlist sg; - - if (buf->sg.offset != -1) - crypto_digest_update(conn->data_tx_tfm, &buf->sg, 1); - else { - sg_init_one(&sg, (char *)buf->sg.page, buf->sg.length); - crypto_digest_update(conn->data_tx_tfm, &sg, 1); - } -} - static inline int iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_buf *buf, uint32_t *digest, int final) @@ -1806,7 +1780,8 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) return -EAGAIN; } if (conn->datadgst_en) - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, + &ctask->sendbuf.sg, 1); if (!ctask->imm_count) break; @@ -1891,7 +1866,8 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) * so pass it */ if (conn->datadgst_en && ctask->sent - start > 0) - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, + &ctask->sendbuf.sg, 1); if (!ctask->data_count) break; @@ -1969,7 +1945,7 @@ solicit_again: BUG_ON(r2t->data_count < 0); if (conn->datadgst_en) - iscsi_buf_data_digest_update(conn, &r2t->sendbuf); + crypto_digest_update(conn->data_tx_tfm, &r2t->sendbuf.sg, 1); if (r2t->data_count) { BUG_ON(ctask->sc->use_sg == 0); @@ -2051,7 +2027,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (conn->datadgst_en) { - iscsi_buf_data_digest_update(conn, &ctask->sendbuf); + crypto_digest_update(conn->data_tx_tfm, &ctask->sendbuf.sg, 1); /* imm data? */ if (!dtask) { if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf, -- cgit v1.2.3 From 7b8631b53bea286b68847a939b87135198335b66 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 13 Jan 2006 18:05:50 -0600 Subject: [SCSI] iscsi: seperate iscsi interface from setup functions This is the second version of the patch to address Christoph's comments. Instead of doing the lib, I just kept everything in scsi_trnapsort_iscsi.c like the FC and SPI class. This was becuase the driver model and sysfs class is tied to the session and connection setup so separating did not buy very much at this time. The reason for this patch was becuase HW iscsi LLDs like qla4xxx cannot use the iscsi class becuase the scsi_host was tied to the interface and class code. This patch just seperates the session from scsi host so that LLDs that allocate the host per some resource like pci device can still use the class. This is also fixes a couple refcount bugs that can be triggered when users have a sysfs file open, close the session, then read or write to the file. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 118 ++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 48 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0acc4b235d9b..e31d350e6b67 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2435,17 +2435,20 @@ iscsi_pool_free(struct iscsi_queue *q, void **items) kfree(items); } -static iscsi_connh_t -iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx) +static struct iscsi_cls_conn * +iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx) { - struct iscsi_session *session = iscsi_ptr(sessionh); - struct iscsi_conn *conn = NULL; + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + struct iscsi_conn *conn; + struct iscsi_cls_conn *cls_conn; - conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL); - if (conn == NULL) - goto conn_alloc_fail; - memset(conn, 0, sizeof(struct iscsi_conn)); + cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata), + conn_idx); + if (!cls_conn) + return NULL; + conn = cls_conn->dd_data; + memset(conn, 0, sizeof(struct iscsi_conn)); conn->c_stage = ISCSI_CONN_INITIAL_STAGE; conn->in_progress = IN_PROGRESS_WAIT_HEADER; conn->id = conn_idx; @@ -2507,7 +2510,7 @@ iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx) mutex_init(&conn->xmitmutex); init_waitqueue_head(&conn->ehwait); - return iscsi_handle(conn); + return cls_conn; max_recv_dlenght_alloc_fail: spin_lock_bh(&session->lock); @@ -2523,15 +2526,14 @@ immqueue_alloc_fail: writequeue_alloc_fail: kfifo_free(conn->xmitqueue); xmitqueue_alloc_fail: - kfree(conn); -conn_alloc_fail: - return iscsi_handle(NULL); + iscsi_destroy_conn(cls_conn); + return NULL; } static void -iscsi_conn_destroy(iscsi_connh_t connh) +iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn) { - struct iscsi_conn *conn = iscsi_ptr(connh); + struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; unsigned long flags; @@ -2626,7 +2628,8 @@ iscsi_conn_destroy(iscsi_connh_t connh) kfifo_free(conn->writequeue); kfifo_free(conn->immqueue); kfifo_free(conn->mgmtqueue); - kfree(conn); + + iscsi_destroy_conn(cls_conn); } static int @@ -3257,17 +3260,23 @@ static struct scsi_host_template iscsi_sht = { .this_id = -1, }; -static iscsi_sessionh_t -iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host) +static struct iscsi_transport iscsi_tcp_transport; + +static struct Scsi_Host * +iscsi_session_create(struct scsi_transport_template *scsit, + uint32_t initial_cmdsn) { - int cmd_i; + struct Scsi_Host *shost; struct iscsi_session *session; + int cmd_i; - session = iscsi_hostdata(host->hostdata); - memset(session, 0, sizeof(struct iscsi_session)); + shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport); + if (!shost) + return NULL; - session->host = host; - session->id = host->host_no; + session = iscsi_hostdata(shost->hostdata); + memset(session, 0, sizeof(struct iscsi_session)); + session->host = shost; session->state = ISCSI_STATE_LOGGED_IN; session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; session->cmds_max = ISCSI_XMIT_CMDS_MAX; @@ -3311,7 +3320,7 @@ iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host) if (iscsi_r2tpool_alloc(session)) goto r2tpool_alloc_fail; - return iscsi_handle(session); + return shost; r2tpool_alloc_fail: for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) @@ -3321,15 +3330,15 @@ immdata_alloc_fail: mgmtpool_alloc_fail: iscsi_pool_free(&session->cmdpool, (void**)session->cmds); cmdpool_alloc_fail: - return iscsi_handle(NULL); + return NULL; } static void -iscsi_session_destroy(iscsi_sessionh_t sessionh) +iscsi_session_destroy(struct Scsi_Host *shost) { + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); int cmd_i; struct iscsi_data_task *dtask, *n; - struct iscsi_session *session = iscsi_ptr(sessionh); for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; @@ -3345,6 +3354,8 @@ iscsi_session_destroy(iscsi_sessionh_t sessionh) iscsi_r2tpool_free(session); iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + + iscsi_transport_destroy_session(shost); } static int @@ -3493,25 +3504,12 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param, } static int -iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param, - uint32_t *value) +iscsi_session_get_param(struct Scsi_Host *shost, + enum iscsi_param param, uint32_t *value) { - struct iscsi_conn *conn = iscsi_ptr(connh); - struct iscsi_session *session = conn->session; + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = conn->hdrdgst_en; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = conn->datadgst_en; - break; case ISCSI_PARAM_INITIAL_R2T_EN: *value = session->initial_r2t_en; break; @@ -3549,6 +3547,31 @@ iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param, return 0; } +static int +iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value) +{ + struct iscsi_conn *conn = data; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + *value = conn->max_recv_dlength; + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + *value = conn->max_xmit_dlength; + break; + case ISCSI_PARAM_HDRDGST_EN: + *value = conn->hdrdgst_en; + break; + case ISCSI_PARAM_DATADGST_EN: + *value = conn->datadgst_en; + break; + default: + return ISCSI_ERR_PARAM_NOT_FOUND; + } + + return 0; +} + static void iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats) { @@ -3593,6 +3616,7 @@ static struct iscsi_transport iscsi_tcp_transport = { | CAP_DATADGST, .host_template = &iscsi_sht, .hostdata_size = sizeof(struct iscsi_session), + .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, .create_session = iscsi_session_create, @@ -3601,7 +3625,8 @@ static struct iscsi_transport iscsi_tcp_transport = { .bind_conn = iscsi_conn_bind, .destroy_conn = iscsi_conn_destroy, .set_param = iscsi_conn_set_param, - .get_param = iscsi_conn_get_param, + .get_conn_param = iscsi_conn_get_param, + .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, .stop_conn = iscsi_conn_stop, .send_pdu = iscsi_conn_send_pdu, @@ -3611,8 +3636,6 @@ static struct iscsi_transport iscsi_tcp_transport = { static int __init iscsi_tcp_init(void) { - int error; - if (iscsi_max_lun < 1) { printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun); return -EINVAL; @@ -3625,11 +3648,10 @@ iscsi_tcp_init(void) if (!taskcache) return -ENOMEM; - error = iscsi_register_transport(&iscsi_tcp_transport); - if (error) + if (!iscsi_register_transport(&iscsi_tcp_transport)) kmem_cache_destroy(taskcache); - return error; + return 0; } static void __exit -- cgit v1.2.3 From 55e3299d9eca01fb2351c5d37e222872b7c6e0af Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 13 Jan 2006 18:05:53 -0600 Subject: [SCSI] iscsi: fix 4k stack iscsi setups When we run the xmit code from queuecomand the stack trace gets too deep. The patch runs the xmit code from the scsi_host work queue. This fixes 4k stack and xfs support and should fix the st and sg stack usage bugs. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index e31d350e6b67..4e4b1061a5e9 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -525,7 +525,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) __kfifo_put(ctask->r2tqueue, (void*)&r2t, sizeof(void*)); __kfifo_put(conn->writequeue, (void*)&ctask, sizeof(void*)); - schedule_work(&conn->xmitwork); + scsi_queue_work(session->host, &conn->xmitwork); conn->r2t_pdus_cnt++; spin_unlock(&session->lock); @@ -1267,7 +1267,7 @@ iscsi_write_space(struct sock *sk) conn->old_write_space(sk); debug_tcp("iscsi_write_space: cid %d\n", conn->id); clear_bit(SUSPEND_BIT, &conn->suspend_tx); - schedule_work(&conn->xmitwork); + scsi_queue_work(conn->session->host, &conn->xmitwork); } static void @@ -2275,7 +2275,7 @@ iscsi_xmitworker(void *data) */ mutex_lock(&conn->xmitmutex); if (iscsi_data_xmit(conn)) - schedule_work(&conn->xmitwork); + scsi_queue_work(conn->session->host, &conn->xmitwork); mutex_unlock(&conn->xmitmutex); } @@ -2340,15 +2340,7 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); spin_unlock(&session->lock); - if (!in_interrupt() && mutex_trylock(&conn->xmitmutex)) { - spin_unlock_irq(host->host_lock); - if (iscsi_data_xmit(conn)) - schedule_work(&conn->xmitwork); - mutex_unlock(&conn->xmitmutex); - spin_lock_irq(host->host_lock); - } else - schedule_work(&conn->xmitwork); - + scsi_queue_work(host, &conn->xmitwork); return 0; reject: @@ -2942,8 +2934,7 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, else __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); - schedule_work(&conn->xmitwork); - + scsi_queue_work(session->host, &conn->xmitwork); return 0; } -- cgit v1.2.3 From a1e80c20e1ac751dbdd88dee989e9a19c22c4a84 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Fri, 13 Jan 2006 18:05:56 -0600 Subject: [SCSI] iscsi: use pageslab From: FUJITA Tomonori and zhenyu.z.wang@intel.com: We cannot handle filesystems like XFS becuase of the pages they are sending us. We had thought page_count could be used to work around this, but the correct test is for PageSlab. The proper solution is to figure out what type of pages filesystems can use so we do not have to add tests like this or handle it in the block layer for all network block drivers but the issue still has not been resolved on fs-devel so we are sending this patch as a temporary fix. This is last patch just in case it is Nakd with the explanation that we need to push the correct fix through fs-devel, mm or the block layer. The rest of the patchset can live without the patch, but the driver will not work with filesystems like XFS. Signed-off-by: Alex Aizman Signed-off-by: Dmitry Yusupov Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/iscsi_tcp.c') diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 4e4b1061a5e9..1b495afe6d17 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -109,7 +109,7 @@ iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) /* * Fastpath: sg element fits into single page */ - if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) + if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page)) ibuf->use_sendmsg = 0; else ibuf->use_sendmsg = 1; -- cgit v1.2.3