#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_transport_iscsi.h>
+#include "scsi_transport_iscsi.h"
#include "iscsi_tcp.h"
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
- buf->sg.length = tcp_conn->hdr_size;
+ crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
+ buf->sg.length += sizeof(u32);
}
static inline int
if (unlikely(!sc))
return;
- tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
+ tcp_ctask->xmstate = XMSTATE_IDLE;
tcp_ctask->r2t = NULL;
}
tcp_ctask->exp_datasn++;
tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
- if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
+ if (tcp_ctask->data_offset + tcp_conn->in.datalen > sc->request_bufflen) {
+ debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ __FUNCTION__, tcp_ctask->data_offset,
+ tcp_conn->in.datalen, sc->request_bufflen);
return ISCSI_ERR_DATA_OFFSET;
+ }
if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
spin_lock(&session->lock);
iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (!ctask->sc || ctask->mtask ||
- session->state != ISCSI_STATE_LOGGED_IN) {
+ if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
"recovery...\n", ctask->itt);
spin_unlock(&session->lock);
r2t->data_length, session->max_burst);
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+ if (r2t->data_offset + r2t->data_length > ctask->sc->request_bufflen) {
spin_unlock(&session->lock);
printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
"offset %u and total length %d\n", r2t->data_length,
- r2t->data_offset, ctask->total_length);
+ r2t->data_offset, ctask->sc->request_bufflen);
return ISCSI_ERR_DATALEN;
}
tcp_ctask->exp_datasn = r2tsn + 1;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
- set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
- list_move_tail(&ctask->running, &conn->xmitqueue);
-
- scsi_queue_work(session->host, &conn->xmitwork);
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT;
conn->r2t_pdus_cnt++;
+
+ iscsi_requeue_ctask(ctask);
spin_unlock(&session->lock);
return 0;
sg_init_one(&sg, (u8 *)hdr,
sizeof(struct iscsi_hdr) + ahslen);
- crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
+ crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+ (u8 *)&cdgst);
rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
ahslen);
if (cdgst != rdgst) {
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int buf_left = buf_size - (tcp_conn->data_copied + offset);
- int size = min(tcp_conn->in.copy, buf_left);
+ unsigned size = min(tcp_conn->in.copy, buf_left);
int rc;
size = min(size, ctask->data_count);
size, tcp_conn->in.offset, tcp_conn->in.copied);
BUG_ON(size <= 0);
- BUG_ON(tcp_ctask->sent + size > ctask->total_length);
+ BUG_ON(tcp_ctask->sent + size > ctask->sc->request_bufflen);
rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
(char*)buf + (offset + tcp_conn->data_copied), size);
}
static inline void
-partial_sg_digest_update(struct crypto_tfm *tfm, struct scatterlist *sg,
+partial_sg_digest_update(struct hash_desc *desc, 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(tfm, &temp, 1);
+ crypto_hash_update(desc, &temp, length);
}
static void
struct scatterlist tmp;
sg_init_one(&tmp, buf, len);
- crypto_digest_update(tcp_conn->rx_tfm, &tmp, 1);
+ crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
}
static int iscsi_scsi_data_in(struct iscsi_conn *conn)
if (!rc) {
if (conn->datadgst_en) {
if (!offset)
- crypto_digest_update(
- tcp_conn->rx_tfm,
- &sg[i], 1);
+ crypto_hash_update(
+ &tcp_conn->rx_hash,
+ &sg[i], sg[i].length);
else
partial_sg_digest_update(
- tcp_conn->rx_tfm,
+ &tcp_conn->rx_hash,
&sg[i],
sg[i].offset + offset,
sg[i].length - offset);
/*
* data-in is complete, but buffer not...
*/
- partial_sg_digest_update(tcp_conn->rx_tfm,
- &sg[i],
- sg[i].offset, sg[i].length-rc);
+ partial_sg_digest_update(&tcp_conn->rx_hash,
+ &sg[i],
+ sg[i].offset,
+ sg[i].length-rc);
rc = 0;
break;
}
rc = iscsi_tcp_hdr_recv(conn);
if (!rc && tcp_conn->in.datalen) {
if (conn->datadgst_en)
- crypto_digest_init(tcp_conn->rx_tfm);
+ crypto_hash_init(&tcp_conn->rx_hash);
tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
} else if (rc) {
iscsi_conn_failure(conn, rc);
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->rx_tfm,
- &sg, 1);
+ crypto_hash_update(&tcp_conn->rx_hash,
+ &sg, sg.length);
}
- crypto_digest_final(tcp_conn->rx_tfm,
+ crypto_hash_final(&tcp_conn->rx_hash,
(u8 *) &tcp_conn->in.datadgst);
debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
}
iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_tcp_cmd_task *tcp_ctask)
{
- crypto_digest_init(tcp_conn->tx_tfm);
+ crypto_hash_init(&tcp_conn->tx_hash);
tcp_ctask->digest_count = 4;
}
tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
- set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate |= XMSTATE_W_PAD;
}
/**
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
- tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
+ tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT;
}
/**
* xmit.
*
* Management xmit state machine consists of these states:
- * XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
- * XMSTATE_BIT_IMM_HDR - PDU Header xmit in progress
- * XMSTATE_BIT_IMM_DATA - PDU Data xmit in progress
- * XMSTATE_VALUE_IDLE - management PDU is done
+ * XMSTATE_IMM_HDR_INIT - calculate digest of PDU Header
+ * XMSTATE_IMM_HDR - PDU Header xmit in progress
+ * XMSTATE_IMM_DATA - PDU Data xmit in progress
+ * XMSTATE_IDLE - management PDU is done
**/
static int
iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
conn->id, tcp_mtask->xmstate, mtask->itt);
- if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) {
iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
sizeof(struct iscsi_hdr));
if (mtask->data_count) {
- set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
+ tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
iscsi_buf_init_iov(&tcp_mtask->sendbuf,
(char*)mtask->data,
mtask->data_count);
(u8*)tcp_mtask->hdrext);
tcp_mtask->sent = 0;
- clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
- set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR_INIT;
+ tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
}
- if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
mtask->data_count);
if (rc)
return rc;
- clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
}
- if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
+ if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) {
BUG_ON(!mtask->data_count);
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
/* FIXME: implement.
* Virtual buffer could be spreaded across multiple pages...
*/
rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
&mtask->data_count, &tcp_mtask->sent);
if (rc) {
- set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
+ tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
return rc;
}
} while (mtask->data_count);
}
- BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
+ BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock_bh(&session->lock);
- iscsi_free_mgmt_task(conn, mtask);
+ list_del(&conn->mtask->running);
+ __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
+ sizeof(void*));
spin_unlock_bh(&session->lock);
}
return 0;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int rc = 0;
- if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_INIT) {
tcp_ctask->sent = 0;
tcp_ctask->sg_count = 0;
tcp_ctask->exp_datasn = 0;
}
iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
- sizeof(struct iscsi_hdr));
+ sizeof(struct iscsi_hdr));
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext);
- clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
- set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT;
}
- if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_XMIT) {
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
if (rc)
return rc;
- clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_XMIT;
if (sc->sc_data_direction != DMA_TO_DEVICE)
return 0;
if (ctask->imm_count) {
- set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
iscsi_set_padding(tcp_ctask, ctask->imm_count);
if (ctask->conn->datadgst_en) {
}
}
- if (ctask->unsol_count) {
- set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
- set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
- }
+ if (ctask->unsol_count)
+ tcp_ctask->xmstate |=
+ XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
}
return rc;
}
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int sent = 0, rc;
- if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
+ 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->tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
- } else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
+ crypto_hash_update(&tcp_conn->tx_hash,
+ &tcp_ctask->sendbuf.sg,
+ tcp_ctask->sendbuf.sg.length);
+ } else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
return 0;
- clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
- clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
+ 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);
+ tcp_ctask->pad_count, ctask->itt);
rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
&sent);
if (rc) {
debug_scsi("padding send failed %d\n", rc);
- set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_PAD;
}
return rc;
}
tcp_ctask = ctask->dd_data;
tcp_conn = conn->dd_data;
- if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
- crypto_digest_final(tcp_conn->tx_tfm, (u8*)digest);
+ if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
+ crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
iscsi_buf_init_iov(buf, (char*)digest, 4);
}
- clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
-
+ 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,
else {
debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
*digest, ctask->itt);
- set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_DATA_DIGEST;
}
return rc;
}
rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
*sent = *sent + buf_sent;
if (buf_sent && conn->datadgst_en)
- partial_sg_digest_update(tcp_conn->tx_tfm,
+ partial_sg_digest_update(&tcp_conn->tx_hash,
&sendbuf->sg, sendbuf->sg.offset + offset,
buf_sent);
if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
struct iscsi_data_task *dtask;
int rc;
- set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
- if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
+ tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
+ if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
dtask = &tcp_ctask->unsol_dtask;
iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)dtask->hdrext);
- clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
iscsi_set_padding(tcp_ctask, ctask->data_count);
}
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
if (rc) {
- clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
- set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
+ tcp_ctask->xmstate |= XMSTATE_UNS_HDR;
return rc;
}
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int rc;
- if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
+ 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;
}
- if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
int start = tcp_ctask->sent;
ctask->unsol_count -= tcp_ctask->sent - start;
if (rc)
return rc;
- clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
/*
* Done with the Data-Out. Next, check if we need
* to send another unsolicited Data-Out.
*/
if (ctask->unsol_count) {
debug_scsi("sending more uns\n");
- set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
goto send_hdr;
}
}
struct iscsi_data_task *dtask;
int left, rc;
- if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) {
if (!tcp_ctask->r2t) {
spin_lock_bh(&session->lock);
__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &r2t->headbuf,
(u8*)dtask->hdrext);
- clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
- set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
}
- if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
r2t = tcp_ctask->r2t;
dtask = &r2t->dtask;
rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
if (rc)
return rc;
- clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
- set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
if (conn->datadgst_en) {
iscsi_data_digest_init(conn->dd_data, tcp_ctask);
r2t->sent);
}
- if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
r2t = tcp_ctask->r2t;
dtask = &r2t->dtask;
&dtask->digestbuf, &dtask->digest);
if (rc)
return rc;
- clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
/*
* Done with this Data-Out. Next, check if we have
* xmit stages.
*
*iscsi_send_cmd_hdr()
- * XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
- * Header Digest
- * XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
+ * XMSTATE_CMD_HDR_INIT - prepare Header and Data buffers Calculate
+ * Header Digest
+ * XMSTATE_CMD_HDR_XMIT - Transmit header in progress
*
*iscsi_send_padding
- * XMSTATE_BIT_W_PAD - Prepare and send pading
- * XMSTATE_BIT_W_RESEND_PAD - retry send pading
+ * XMSTATE_W_PAD - Prepare and send pading
+ * XMSTATE_W_RESEND_PAD - retry send pading
*
*iscsi_send_digest
- * XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
- * XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - retry sending digest
*
*iscsi_send_unsol_hdr
- * XMSTATE_BIT_UNS_INIT - prepare un-solicit data header and digest
- * XMSTATE_BIT_UNS_HDR - send un-solicit header
+ * XMSTATE_UNS_INIT - prepare un-solicit data header and digest
+ * XMSTATE_UNS_HDR - send un-solicit header
*
*iscsi_send_unsol_pdu
- * XMSTATE_BIT_UNS_DATA - send un-solicit data in progress
+ * XMSTATE_UNS_DATA - send un-solicit data in progress
*
*iscsi_send_sol_pdu
- * XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
- * XMSTATE_BIT_SOL_HDR - send solicit header
- * XMSTATE_BIT_SOL_DATA - send solicit data
+ * XMSTATE_SOL_HDR_INIT - solicit data header and digest initialize
+ * XMSTATE_SOL_HDR - send solicit header
+ * XMSTATE_SOL_DATA - send solicit data
*
*iscsi_tcp_ctask_xmit
- * XMSTATE_BIT_IMM_DATA - xmit managment data (??)
+ * XMSTATE_IMM_DATA - xmit managment data (??)
**/
static int
iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
return 0;
- if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
+ if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
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;
- clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
+ tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
}
rc = iscsi_send_unsol_pdu(conn, ctask);
if (rc)
return rc;
- return iscsi_send_sol_pdu(conn, ctask);
+ rc = iscsi_send_sol_pdu(conn, ctask);
+ if (rc)
+ return rc;
+
+ return rc;
}
static struct iscsi_cls_conn *
/* 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) {
+ tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->tx_hash.flags = 0;
+ if (IS_ERR(tcp_conn->tx_hash.tfm)) {
printk(KERN_ERR "Could not create connection due to crc32c "
- "loading error. Make sure the crc32c module is "
- "built as a module or into the kernel.\n");
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->tx_hash.tfm));
goto free_tcp_conn;
}
- tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c", 0);
- if (!tcp_conn->rx_tfm) {
+ tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->rx_hash.flags = 0;
+ if (IS_ERR(tcp_conn->rx_hash.tfm)) {
printk(KERN_ERR "Could not create connection due to crc32c "
- "loading error. Make sure the crc32c module is "
- "built as a module or into the kernel.\n");
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->rx_hash.tfm));
goto free_tx_tfm;
}
return cls_conn;
free_tx_tfm:
- crypto_free_tfm(tcp_conn->tx_tfm);
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
free_tcp_conn:
kfree(tcp_conn);
tcp_conn_alloc_fail:
iscsi_tcp_release_conn(conn);
iscsi_conn_teardown(cls_conn);
- if (tcp_conn->tx_tfm)
- crypto_free_tfm(tcp_conn->tx_tfm);
- if (tcp_conn->rx_tfm)
- crypto_free_tfm(tcp_conn->rx_tfm);
+ if (tcp_conn->tx_hash.tfm)
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
+ if (tcp_conn->rx_hash.tfm)
+ crypto_free_hash(tcp_conn->rx_hash.tfm);
kfree(tcp_conn);
}
struct sockaddr_in *sin;
int rc = 0, len;
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+ addr = kmalloc(GFP_KERNEL, sizeof(*addr));
if (!addr)
return -ENOMEM;
/* called with host lock */
static void
-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size)
+iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
{
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
- tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
+ tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT;
}
static int
stats->custom[2].value = conn->eh_abort_cnt;
}
-static int iscsi_tcp_setup_tasks(struct iscsi_session *session)
+static struct iscsi_cls_session *
+iscsi_tcp_session_create(struct iscsi_transport *iscsit,
+ struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
+ uint32_t initial_cmdsn, uint32_t *hostno)
{
+ struct iscsi_cls_session *cls_session;
+ struct iscsi_session *session;
+ uint32_t hn;
int cmd_i;
+ cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth,
+ sizeof(struct iscsi_tcp_cmd_task),
+ sizeof(struct iscsi_tcp_mgmt_task),
+ initial_cmdsn, &hn);
+ if (!cls_session)
+ return NULL;
+ *hostno = hn;
+
+ session = class_to_transport_session(cls_session);
for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
mtask->hdr = &tcp_mtask->hdr;
}
- if (iscsi_r2tpool_alloc(session))
- return -ENOMEM;
-
- return 0;
-}
-
-/*
- * iscsi_tcp_session_create2 is a KABI work around. For the new version
- * we pass in the session and default device queue depth.
- */
-static struct iscsi_cls_session *
-iscsi_tcp_session_create2(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- uint16_t cmds_max, uint16_t qdepth,
- uint32_t initial_cmdsn, uint32_t *hostno)
-{
- struct iscsi_cls_session *cls_session;
- uint32_t hn;
-
- cls_session = iscsi_session_setup2(iscsit, scsit, cmds_max, qdepth,
- sizeof(struct iscsi_tcp_cmd_task),
- sizeof(struct iscsi_tcp_mgmt_task),
- initial_cmdsn, &hn);
- if (!cls_session)
- return NULL;
- *hostno = hn;
-
- if (iscsi_tcp_setup_tasks(class_to_transport_session(cls_session)))
- goto task_setup_fail;
-
- return cls_session;
-
-task_setup_fail:
- iscsi_session_teardown(cls_session);
- return NULL;
-}
-
-static struct iscsi_cls_session *
-iscsi_tcp_session_create(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- uint32_t initial_cmdsn, uint32_t *hostno)
-{
- struct iscsi_cls_session *cls_session;
- uint32_t hn;
-
- cls_session = iscsi_session_setup2(iscsit, scsit, ISCSI_XMIT_CMDS_MAX,
- ISCSI_DEF_CMD_PER_LUN,
- sizeof(struct iscsi_tcp_cmd_task),
- sizeof(struct iscsi_tcp_mgmt_task),
- initial_cmdsn, &hn);
- if (!cls_session)
- return NULL;
- *hostno = hn;
-
- if (iscsi_tcp_setup_tasks(class_to_transport_session(cls_session)))
- goto task_setup_fail;
+ if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
+ goto r2tpool_alloc_fail;
return cls_session;
-task_setup_fail:
+r2tpool_alloc_fail:
iscsi_session_teardown(cls_session);
return NULL;
}
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
- .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
+ .eh_device_reset_handler= iscsi_eh_device_reset,
.eh_host_reset_handler = iscsi_eh_host_reset,
.use_clustering = DISABLE_CLUSTERING,
- .slave_configure = iscsi_tcp_slave_configure,
+ .slave_configure = iscsi_tcp_slave_configure,
.proc_name = "iscsi_tcp",
.this_id = -1,
};
ISCSI_TARGET_NAME | ISCSI_TPGT |
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
- ISCSI_PING_TMO | ISCSI_RECV_TMO,
+ ISCSI_FAST_ABORT,
.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
ISCSI_HOST_INITIATOR_NAME |
ISCSI_HOST_NETDEV_NAME,
.max_cmd_len = ISCSI_TCP_MAX_CMD_LEN,
/* session management */
.create_session = iscsi_tcp_session_create,
- .create_session2 = iscsi_tcp_session_create2,
.destroy_session = iscsi_tcp_session_destroy,
/* connection management */
.create_conn = iscsi_tcp_conn_create,
#ifndef ISCSI_TCP_H
#define ISCSI_TCP_H
-#include <scsi/libiscsi.h>
+#include "libiscsi.h"
/* Socket's Receive state machine */
#define IN_PROGRESS_WAIT_HEADER 0x0
#define IN_PROGRESS_PAD_RECV 0x4
/* xmit state machine */
-#define XMSTATE_VALUE_IDLE 0
-#define XMSTATE_BIT_CMD_HDR_INIT 0
-#define XMSTATE_BIT_CMD_HDR_XMIT 1
-#define XMSTATE_BIT_IMM_HDR 2
-#define XMSTATE_BIT_IMM_DATA 3
-#define XMSTATE_BIT_UNS_INIT 4
-#define XMSTATE_BIT_UNS_HDR 5
-#define XMSTATE_BIT_UNS_DATA 6
-#define XMSTATE_BIT_SOL_HDR 7
-#define XMSTATE_BIT_SOL_DATA 8
-#define XMSTATE_BIT_W_PAD 9
-#define XMSTATE_BIT_W_RESEND_PAD 10
-#define XMSTATE_BIT_W_RESEND_DATA_DIGEST 11
-#define XMSTATE_BIT_IMM_HDR_INIT 12
-#define XMSTATE_BIT_SOL_HDR_INIT 13
+#define XMSTATE_IDLE 0x0
+#define XMSTATE_CMD_HDR_INIT 0x1
+#define XMSTATE_CMD_HDR_XMIT 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 XMSTATE_IMM_HDR_INIT 0x1000
+#define XMSTATE_SOL_HDR_INIT 0x2000
#define ISCSI_PAD_LEN 4
#define ISCSI_SG_TABLESIZE SG_ALL
#define ISCSI_TCP_MAX_CMD_LEN 16
+struct crypto_hash;
struct socket;
/* Socket connection recieve helper */
void (*old_write_space)(struct sock *);
/* data and header digests */
- struct crypto_tfm *tx_tfm; /* CRC32C (Tx) */
- struct crypto_tfm *rx_tfm; /* CRC32C (Rx) */
+ struct hash_desc tx_hash; /* CRC32C (Tx) */
+ struct hash_desc rx_hash; /* CRC32C (Rx) */
/* MIB custom statistics */
uint32_t sendpage_failures_cnt;
struct iscsi_tcp_mgmt_task {
struct iscsi_hdr hdr;
char hdrext[sizeof(__u32)]; /* Header-Digest */
- unsigned long xmstate; /* mgmt xmit progress */
+ int xmstate; /* mgmt xmit progress */
struct iscsi_buf headbuf; /* header buffer */
struct iscsi_buf sendbuf; /* in progress buffer */
int sent;
int pad_count; /* padded bytes */
struct iscsi_buf headbuf; /* header buf (xmit) */
struct iscsi_buf sendbuf; /* in progress buffer*/
- unsigned long xmstate; /* xmit xtate machine */
+ int xmstate; /* xmit xtate machine */
int sent;
struct scatterlist *sg; /* per-cmd SG list */
struct scatterlist *bad_sg; /* assert statement */
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/types.h>
-#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
-#include <scsi/iscsi_proto.h>
#include <scsi/scsi_transport.h>
-#include <scsi/scsi_transport_iscsi.h>
-#include <scsi/libiscsi.h>
+#include "iscsi_proto.h"
+#include "scsi_transport_iscsi.h"
+#include "libiscsi.h"
struct iscsi_session *
class_to_transport_session(struct iscsi_cls_session *cls_session)
* xmit thread
*/
if (!list_empty(&session->leadconn->xmitqueue) ||
- __kfifo_len(session->leadconn->mgmtqueue))
+ !list_empty(&session->leadconn->mgmtqueue))
scsi_queue_work(session->host,
&session->leadconn->xmitwork);
}
}
EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
-int iscsi_check_assign_cmdsn(struct iscsi_session *session,
- struct iscsi_nopin *hdr)
-{
- iscsi_update_cmdsn(session, hdr);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
-
void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
struct iscsi_data *hdr)
{
ctask->unsol_datasn = 0;
if (session->imm_data_en) {
- if (ctask->total_length >= session->first_burst)
+ if (sc->request_bufflen >= session->first_burst)
ctask->imm_count = min(session->first_burst,
conn->max_xmit_dlength);
else
- ctask->imm_count = min(ctask->total_length,
+ ctask->imm_count = min(sc->request_bufflen,
conn->max_xmit_dlength);
hton24(ctask->hdr->dlength, ctask->imm_count);
} else
zero_data(ctask->hdr->dlength);
if (!session->initial_r2t_en) {
- ctask->unsol_count = min(session->first_burst,
- ctask->total_length) - ctask->imm_count;
+ ctask->unsol_count = min((session->first_burst),
+ (sc->request_bufflen)) - ctask->imm_count;
ctask->unsol_offset = ctask->imm_count;
}
/* No unsolicit Data-Out's */
ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
} else {
- /*
- * this has been moved to the iscsi_tcp mode upstream
- * since it is only used there
- */
- ctask->datasn = 0;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
zero_data(hdr->dlength);
conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
}
-EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
/**
* iscsi_complete_command - return command back to scsi-ml
iscsi_complete_command(ctask);
}
-/**
- * iscsi_free_mgmt_task - return mgmt task back to pool
- * @conn: iscsi connection
- * @mtask: mtask
- *
- * Must be called with session lock.
- */
-void iscsi_free_mgmt_task(struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask)
-{
- list_del_init(&mtask->running);
- if (conn->login_mtask == mtask)
- return;
-
- if (conn->ping_mtask == mtask)
- conn->ping_mtask = NULL;
- __kfifo_put(conn->session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*));
-}
-EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
-
-static struct iscsi_mgmt_task *
-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
-{
- struct iscsi_session *session = conn->session;
- struct iscsi_mgmt_task *mtask;
-
- if (session->state == ISCSI_STATE_TERMINATE)
- return NULL;
-
- if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
- hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
- /*
- * Login and Text are sent serially, in
- * request-followed-by-response sequence.
- * Same mtask can be used. Same ITT must be used.
- * Note that login_mtask is preallocated at conn_create().
- */
- mtask = conn->login_mtask;
- else {
- BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
- BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
- if (!__kfifo_get(session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*)))
- return NULL;
- }
-
- if (data_size) {
- memcpy(mtask->data, data, data_size);
- mtask->data_count = data_size;
- } else
- mtask->data_count = 0;
-
- INIT_LIST_HEAD(&mtask->running);
- memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
- __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
- return mtask;
-}
-
-int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_session *session = conn->session;
- int err = 0;
-
- spin_lock_bh(&session->lock);
- if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) {
- err = -EPERM;
- spin_unlock_bh(&session->lock);
- return err;
- }
- spin_unlock_bh(&session->lock);
- scsi_queue_work(session->host, &conn->xmitwork);
- return 0;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
-
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
* iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
* then completes the command and task.
**/
-static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_cmd_task *ctask, char *data,
int datalen)
{
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
}
+ if (sc->sc_data_direction == DMA_TO_DEVICE)
+ goto out;
+
if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
conn->scsirsp_pdus_cnt++;
__iscsi_put_ctask(ctask);
- return 0;
}
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
conn->tmfrsp_pdus_cnt++;
- if (conn->tmabort_state != TMABORT_INITIAL)
+ if (conn->tmf_state != TMF_QUEUED)
return;
if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
- conn->tmabort_state = TMABORT_SUCCESS;
+ conn->tmf_state = TMF_SUCCESS;
else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
- conn->tmabort_state = TMABORT_NOT_FOUND;
+ conn->tmf_state = TMF_NOT_FOUND;
else
- conn->tmabort_state = TMABORT_FAILED;
+ conn->tmf_state = TMF_FAILED;
wake_up(&conn->ehwait);
}
-static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
-{
- struct iscsi_nopout hdr;
- struct iscsi_mgmt_task *mtask;
-
- if (!rhdr && conn->ping_mtask)
- return;
-
- memset(&hdr, 0, sizeof(struct iscsi_nopout));
- hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
- hdr.flags = ISCSI_FLAG_CMD_FINAL;
-
- if (rhdr) {
- memcpy(hdr.lun, rhdr->lun, 8);
- hdr.ttt = rhdr->ttt;
- hdr.itt = RESERVED_ITT;
- } else
- hdr.ttt = RESERVED_ITT;
-
- mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
- if (!mtask) {
- printk(KERN_ERR "Could not send nopout\n");
- return;
- }
-
- /* only track our nops */
- if (!rhdr) {
- conn->ping_mtask = mtask;
- conn->last_ping = jiffies;
- }
- scsi_queue_work(conn->session->host, &conn->xmitwork);
-}
-
static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
char *data, int datalen)
{
struct iscsi_mgmt_task *mtask;
uint32_t itt;
- conn->last_recv = jiffies;
if (hdr->itt != RESERVED_ITT)
itt = get_itt(hdr->itt);
else
*/
if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
rc = ISCSI_ERR_CONN_FAILED;
- iscsi_free_mgmt_task(conn, mtask);
+ list_del_init(&mtask->running);
+ if (conn->login_mtask != mtask)
+ __kfifo_put(session->mgmtpool.queue,
+ (void*)&mtask, sizeof(void*));
break;
case ISCSI_OP_SCSI_TMFUNC_RSP:
if (datalen) {
}
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- if (conn->ping_mtask != mtask) {
- /*
- * If this is not in response to one of our
- * nops then it must be from userspace.
- */
- if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
- datalen))
- rc = ISCSI_ERR_CONN_FAILED;
- }
- iscsi_free_mgmt_task(conn, mtask);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
+ list_del_init(&mtask->running);
+ __kfifo_put(session->mgmtpool.queue,
+ (void*)&mtask, sizeof(void*));
break;
default:
rc = ISCSI_ERR_BAD_OPCODE;
if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
- iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
+ rc = ISCSI_ERR_CONN_FAILED;
break;
case ISCSI_OP_REJECT:
rc = iscsi_handle_reject(conn, hdr, data, datalen);
}
if (session->tt->init_mgmt_task)
- session->tt->init_mgmt_task(conn, mtask, mtask->data,
- mtask->data_count);
+ session->tt->init_mgmt_task(conn, mtask);
debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
- hdr->opcode, hdr->itt, mtask->data_count);
+ hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
+ mtask->data_count);
}
static int iscsi_xmit_mtask(struct iscsi_conn *conn)
static int iscsi_xmit_ctask(struct iscsi_conn *conn)
{
struct iscsi_cmd_task *ctask = conn->ctask;
- int rc = 0;
-
- /*
- * serialize with TMF AbortTask
- */
- if (ctask->state == ISCSI_TASK_ABORTING)
- goto done;
+ int rc;
__iscsi_get_ctask(ctask);
spin_unlock_bh(&conn->session->lock);
rc = conn->session->tt->xmit_cmd_task(conn, ctask);
spin_lock_bh(&conn->session->lock);
__iscsi_put_ctask(ctask);
-
-done:
if (!rc)
/* done with this ctask */
conn->ctask = NULL;
return rc;
}
+/**
+ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
+ * @ctask: ctask to requeue
+ *
+ * LLDs that need to run a ctask from the session workqueue should call
+ * this. The session lock must be held.
+ */
+void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_conn *conn = ctask->conn;
+
+ list_move_tail(&ctask->running, &conn->requeue);
+ scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
+
/**
* iscsi_data_xmit - xmit any command into the scheduled connection
* @conn: iscsi connection
* overflow us with nop-ins
*/
check_mgmt:
- while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
- sizeof(void*))) {
+ while (!list_empty(&conn->mgmtqueue)) {
+ conn->mtask = list_entry(conn->mgmtqueue.next,
+ struct iscsi_mgmt_task, running);
iscsi_prep_mtask(conn, conn->mtask);
- list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
+ list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
}
- /* process command queue */
+ /* process pending command queue */
while (!list_empty(&conn->xmitqueue)) {
- /*
- * iscsi tcp may readd the task to the xmitqueue to send
- * write data
- */
+ if (conn->tmf_state == TMF_QUEUED)
+ break;
+
conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
- switch (conn->ctask->state) {
- case ISCSI_TASK_ABORTING:
- break;
- case ISCSI_TASK_PENDING:
- iscsi_prep_scsi_cmd_pdu(conn->ctask);
- conn->session->tt->init_cmd_task(conn->ctask);
- /* fall through */
- default:
- conn->ctask->state = ISCSI_TASK_RUNNING;
- break;
- }
+ iscsi_prep_scsi_cmd_pdu(conn->ctask);
+ conn->session->tt->init_cmd_task(conn->ctask);
+ conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list);
-
rc = iscsi_xmit_ctask(conn);
if (rc)
goto again;
* we need to check the mgmt queue for nops that need to
* be sent to aviod starvation
*/
- if (__kfifo_len(conn->mgmtqueue))
+ if (!list_empty(&conn->mgmtqueue))
+ goto check_mgmt;
+ }
+
+ while (!list_empty(&conn->requeue)) {
+ if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
+ break;
+
+ conn->ctask = list_entry(conn->requeue.next,
+ struct iscsi_cmd_task, running);
+ conn->ctask->state = ISCSI_TASK_RUNNING;
+ list_move_tail(conn->requeue.next, &conn->run_list);
+ rc = iscsi_xmit_ctask(conn);
+ if (rc)
+ goto again;
+ if (!list_empty(&conn->mgmtqueue))
goto check_mgmt;
}
spin_unlock_bh(&conn->session->lock);
return rc;
}
-static void iscsi_xmitworker(void *data)
+static void iscsi_xmitworker(struct work_struct *work)
{
- struct iscsi_conn *conn = data;
+ struct iscsi_conn *conn =
+ container_of(work, struct iscsi_conn, xmitwork);
int rc;
/*
* serialize Xmit worker on a per-connection basis.
atomic_set(&ctask->refcount, 1);
ctask->state = ISCSI_TASK_PENDING;
- ctask->mtask = NULL;
ctask->conn = conn;
ctask->sc = sc;
- ctask->total_length = sc->request_bufflen;
INIT_LIST_HEAD(&ctask->running);
list_add_tail(&ctask->running, &conn->xmitqueue);
}
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
+static struct iscsi_mgmt_task *
+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size)
+{
+ struct iscsi_session *session = conn->session;
+ struct iscsi_mgmt_task *mtask;
+
+ if (session->state == ISCSI_STATE_TERMINATE)
+ return NULL;
+
+ if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
+ hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+ /*
+ * Login and Text are sent serially, in
+ * request-followed-by-response sequence.
+ * Same mtask can be used. Same ITT must be used.
+ * Note that login_mtask is preallocated at conn_create().
+ */
+ mtask = conn->login_mtask;
+ else {
+ BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+ BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+
+ if (!__kfifo_get(session->mgmtpool.queue,
+ (void*)&mtask, sizeof(void*)))
+ return NULL;
+ }
+
+ if (data_size) {
+ memcpy(mtask->data, data, data_size);
+ mtask->data_count = data_size;
+ } else
+ mtask->data_count = 0;
+
+ memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
+ INIT_LIST_HEAD(&mtask->running);
+ list_add_tail(&mtask->running, &conn->mgmtqueue);
+ return mtask;
+}
+
+int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+ int err = 0;
+
+ spin_lock_bh(&session->lock);
+ if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+ err = -EPERM;
+ spin_unlock_bh(&session->lock);
+ scsi_queue_work(session->host, &conn->xmitwork);
+ return err;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
+
void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{
struct iscsi_session *session = class_to_transport_session(cls_session);
- struct iscsi_conn *conn = session->leadconn;
spin_lock_bh(&session->lock);
if (session->state != ISCSI_STATE_LOGGED_IN) {
session->state = ISCSI_STATE_RECOVERY_FAILED;
- if (conn)
- wake_up(&conn->ehwait);
+ if (session->leadconn)
+ wake_up(&session->leadconn->ehwait);
}
spin_unlock_bh(&session->lock);
}
struct Scsi_Host *host = sc->device->host;
struct iscsi_session *session = iscsi_hostdata(host->hostdata);
struct iscsi_conn *conn = session->leadconn;
- int fail_session = 0;
spin_lock_bh(&session->lock);
if (session->state == ISCSI_STATE_TERMINATE) {
return FAILED;
}
- if (sc->SCp.phase == session->age) {
- debug_scsi("failing connection CID %d due to SCSI host reset\n",
- conn->id);
- fail_session = 1;
- }
spin_unlock_bh(&session->lock);
/*
* we drop the lock here but the leadconn cannot be destoyed while
* we are in the scsi eh
*/
- if (fail_session)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
debug_scsi("iscsi_eh_host_reset wait for relogin\n");
wait_event_interruptible(conn->ehwait,
}
EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
-static void iscsi_tmabort_timedout(unsigned long data)
+static void iscsi_tmf_timedout(unsigned long data)
{
- struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
- struct iscsi_conn *conn = ctask->conn;
+ struct iscsi_conn *conn = (struct iscsi_conn *)data;
struct iscsi_session *session = conn->session;
spin_lock(&session->lock);
- if (conn->tmabort_state == TMABORT_INITIAL) {
- conn->tmabort_state = TMABORT_TIMEDOUT;
- debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
- ctask->sc, ctask->itt);
+ if (conn->tmf_state == TMF_QUEUED) {
+ conn->tmf_state = TMF_TIMEDOUT;
+ debug_scsi("tmf timedout\n");
/* unblock eh_abort() */
wake_up(&conn->ehwait);
}
spin_unlock(&session->lock);
}
-static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
- struct iscsi_cmd_task *ctask)
+static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
+ struct iscsi_tm *hdr, int age)
{
- struct iscsi_conn *conn = ctask->conn;
struct iscsi_session *session = conn->session;
- struct iscsi_tm *hdr = &conn->tmhdr;
-
- /*
- * ctask timed out but session is OK requests must be serialized.
- */
- memset(hdr, 0, sizeof(struct iscsi_tm));
- hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
- hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
- hdr->rtt = ctask->hdr->itt;
- hdr->refcmdsn = ctask->hdr->cmdsn;
+ struct iscsi_mgmt_task *mtask;
- ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
- NULL, 0);
- if (!ctask->mtask) {
+ mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+ NULL, 0);
+ if (!mtask) {
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock)
- debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
+ spin_lock_bh(&session->lock);
+ debug_scsi("tmf exec failure\n");
return -EPERM;
}
- ctask->state = ISCSI_TASK_ABORTING;
-
- debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
+ conn->tmfcmd_pdus_cnt++;
+ conn->tmf_timer.expires = 30 * HZ + jiffies;
+ conn->tmf_timer.function = iscsi_tmf_timedout;
+ conn->tmf_timer.data = (unsigned long)conn;
+ add_timer(&conn->tmf_timer);
+ debug_scsi("tmf set timeout\n");
- if (conn->tmabort_state == TMABORT_INITIAL) {
- conn->tmfcmd_pdus_cnt++;
- conn->tmabort_timer.expires = 20*HZ + jiffies;
- conn->tmabort_timer.function = iscsi_tmabort_timedout;
- conn->tmabort_timer.data = (unsigned long)ctask;
- add_timer(&conn->tmabort_timer);
- debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
- }
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
scsi_queue_work(session->host, &conn->xmitwork);
/*
* block eh thread until:
*
- * 1) abort response
- * 2) abort timeout
+ * 1) tmf response
+ * 2) tmf timeout
* 3) session is terminated or restarted or userspace has
* given up on recovery
*/
- wait_event_interruptible(conn->ehwait,
- sc->SCp.phase != session->age ||
+ wait_event_interruptible(conn->ehwait, age != session->age ||
session->state != ISCSI_STATE_LOGGED_IN ||
- conn->tmabort_state != TMABORT_INITIAL);
+ conn->tmf_state != TMF_QUEUED);
if (signal_pending(current))
flush_signals(current);
- del_timer_sync(&conn->tmabort_timer);
+ del_timer_sync(&conn->tmf_timer);
+
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
- return 0;
-}
-
-/*
- * session lock must be held
- */
-static struct iscsi_mgmt_task *
-iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
-{
- int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
- struct iscsi_mgmt_task *task;
-
- debug_scsi("searching %d tasks\n", nr_tasks);
-
- for (i = 0; i < nr_tasks; i++) {
- __kfifo_get(fifo, (void*)&task, sizeof(void*));
- debug_scsi("check task %u\n", task->itt);
-
- if (task->itt == itt) {
- debug_scsi("matched task\n");
- return task;
- }
+ /* if the session drops it will clean up the mtask */
+ if (age != session->age ||
+ session->state != ISCSI_STATE_LOGGED_IN)
+ return -ENOTCONN;
- __kfifo_put(fifo, (void*)&task, sizeof(void*));
+ if (!list_empty(&mtask->running)) {
+ list_del_init(&mtask->running);
+ __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+ sizeof(void*));
}
- return NULL;
-}
-
-static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
-{
- struct iscsi_conn *conn = ctask->conn;
- struct iscsi_session *session = conn->session;
-
- if (!ctask->mtask)
- return -EINVAL;
-
- if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
- list_del(&ctask->mtask->running);
- __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
- sizeof(void*));
- ctask->mtask = NULL;
return 0;
}
conn->session->queued_cmdsn--;
else
conn->session->tt->cleanup_cmd_task(conn, ctask);
- iscsi_ctask_mtask_cleanup(ctask);
sc->result = err;
sc->resid = sc->request_bufflen;
__iscsi_put_ctask(ctask);
}
+/*
+ * Fail commands. session lock held and recv side suspended and xmit
+ * thread flushed
+ */
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
+{
+ struct iscsi_cmd_task *ctask, *tmp;
+
+ if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
+ conn->ctask = NULL;
+
+ /* flush pending */
+ list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
+ if (lun == ctask->sc->device->lun || lun == -1) {
+ debug_scsi("failing pending sc %p itt 0x%x\n",
+ ctask->sc, ctask->itt);
+ fail_command(conn, ctask, DID_BUS_BUSY << 16);
+ }
+ }
+
+ list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
+ if (lun == ctask->sc->device->lun || lun == -1) {
+ debug_scsi("failing requeued sc %p itt 0x%x\n",
+ ctask->sc, ctask->itt);
+ fail_command(conn, ctask, DID_BUS_BUSY << 16);
+ }
+ }
+
+ /* fail all other running */
+ list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
+ if (lun == ctask->sc->device->lun || lun == -1) {
+ debug_scsi("failing in progress sc %p itt 0x%x\n",
+ ctask->sc, ctask->itt);
+ fail_command(conn, ctask, DID_BUS_BUSY << 16);
+ }
+ }
+}
+
static void iscsi_suspend_tx(struct iscsi_conn *conn)
{
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
scsi_queue_work(conn->session->host, &conn->xmitwork);
}
-static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
-{
- struct iscsi_cls_session *cls_session;
- struct iscsi_session *session;
- struct iscsi_conn *conn;
- enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
-
- cls_session = starget_to_session(scsi_target(scmd->device));
- session = class_to_transport_session(cls_session);
-
- debug_scsi("scsi cmd %p timedout\n", scmd);
-
- spin_lock(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN) {
- /*
- * We are probably in the middle of iscsi recovery so let
- * that complete and handle the error.
- */
- rc = EH_RESET_TIMER;
- goto done;
- }
-
- conn = session->leadconn;
- if (!conn) {
- /* In the middle of shuting down */
- rc = EH_RESET_TIMER;
- goto done;
- }
-
- if (!conn->recv_timeout && !conn->ping_timeout)
- goto done;
- /*
- * if the ping timedout then we are in the middle of cleaning up
- * and can let the iscsi eh handle it
- */
- if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
- (conn->ping_timeout * HZ), jiffies))
- rc = EH_RESET_TIMER;
- /*
- * if we are about to check the transport then give the command
- * more time
- */
- else if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
- jiffies))
- rc = EH_RESET_TIMER;
- /* if in the middle of checking the transport then give us more time */
- else if (conn->ping_mtask)
- rc = EH_RESET_TIMER;
-done:
- spin_unlock(&session->lock);
- debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
- return rc;
-}
-
-static void iscsi_check_transport_timeouts(unsigned long data)
+static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
+ struct iscsi_tm *hdr)
{
- struct iscsi_conn *conn = (struct iscsi_conn *)data;
- struct iscsi_session *session = conn->session;
- unsigned long timeout, next_timeout = 0, last_recv;
-
- spin_lock(&session->lock);
- if (session->state != ISCSI_STATE_LOGGED_IN)
- goto done;
-
- timeout = conn->recv_timeout;
- if (!timeout)
- goto done;
-
- timeout *= HZ;
- last_recv = conn->last_recv;
- if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
- jiffies)) {
- printk(KERN_ERR "ping timeout of %d secs expired, "
- "last rx %lu, last ping %lu, now %lu\n",
- conn->ping_timeout, last_recv,
- conn->last_ping, jiffies);
- spin_unlock(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- return;
- }
-
- if (time_before_eq(last_recv + timeout, jiffies)) {
- if (time_before_eq(conn->last_ping, last_recv)) {
- /* send a ping to try to provoke some traffic */
- debug_scsi("Sending nopout as ping on conn %p\n", conn);
- iscsi_send_nopout(conn, NULL);
- }
- next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
- } else
- next_timeout = last_recv + timeout;
-
- debug_scsi("Setting next tmo %lu\n", next_timeout);
- mod_timer(&conn->transport_timer, next_timeout);
-done:
- spin_unlock(&session->lock);
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+ hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+ hdr->rtt = ctask->hdr->itt;
+ hdr->refcmdsn = ctask->hdr->cmdsn;
}
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
struct Scsi_Host *host = sc->device->host;
struct iscsi_session *session = iscsi_hostdata(host->hostdata);
- struct iscsi_cmd_task *ctask;
struct iscsi_conn *conn;
- int rc;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_tm *hdr;
+ int rc, age;
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
return SUCCESS;
}
- ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
- conn = ctask->conn;
-
- conn->eh_abort_cnt++;
- debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
-
/*
* If we are not logged in or we have started a new session
* then let the host reset code handle this
*/
- if (session->state != ISCSI_STATE_LOGGED_IN ||
- sc->SCp.phase != session->age)
- goto failed;
+ if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
+ sc->SCp.phase != session->age) {
+ spin_unlock_bh(&session->lock);
+ mutex_unlock(&session->eh_mutex);
+ return FAILED;
+ }
+
+ conn = session->leadconn;
+ conn->eh_abort_cnt++;
+ age = session->age;
+
+ ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+ debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
/* ctask completed before time out */
if (!ctask->sc) {
goto success;
}
- /* what should we do here ? */
- if (conn->ctask == ctask) {
- printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. "
- "Failing abort\n", sc, ctask->itt);
- goto failed;
- }
-
if (ctask->state == ISCSI_TASK_PENDING) {
fail_command(conn, ctask, DID_ABORT << 16);
goto success;
}
- conn->tmabort_state = TMABORT_INITIAL;
- rc = iscsi_exec_abort_task(sc, ctask);
- if (rc || sc->SCp.phase != session->age ||
- session->state != ISCSI_STATE_LOGGED_IN)
+ /* only have one tmf outstanding at a time */
+ if (conn->tmf_state != TMF_INITIAL)
goto failed;
- iscsi_ctask_mtask_cleanup(ctask);
+ conn->tmf_state = TMF_QUEUED;
- switch (conn->tmabort_state) {
- case TMABORT_SUCCESS:
+ hdr = &conn->tmhdr;
+ iscsi_prep_abort_task_pdu(ctask, hdr);
+
+ if (iscsi_exec_task_mgmt_fn(conn, hdr, age)) {
+ rc = FAILED;
+ goto failed;
+ }
+
+ switch (conn->tmf_state) {
+ case TMF_SUCCESS:
spin_unlock_bh(&session->lock);
iscsi_suspend_tx(conn);
/*
write_lock_bh(conn->recv_lock);
spin_lock(&session->lock);
fail_command(conn, ctask, DID_ABORT << 16);
+ conn->tmf_state = TMF_INITIAL;
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
iscsi_start_tx(conn);
goto success_unlocked;
- case TMABORT_NOT_FOUND:
- if (!ctask->sc) {
+ case TMF_TIMEDOUT:
+ spin_unlock_bh(&session->lock);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ goto failed_unlocked;
+ case TMF_NOT_FOUND:
+ if (!sc->SCp.ptr) {
+ conn->tmf_state = TMF_INITIAL;
/* ctask completed before tmf abort response */
debug_scsi("sc completed while abort in progress\n");
goto success;
}
/* fall through */
default:
- /* timedout or failed */
- spin_unlock_bh(&session->lock);
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- goto failed_unlocked;
+ conn->tmf_state = TMF_INITIAL;
+ goto failed;
}
success:
failed:
spin_unlock_bh(&session->lock);
failed_unlocked:
- debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+ debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
+ ctask ? ctask->itt : 0);
mutex_unlock(&session->eh_mutex);
return FAILED;
}
EXPORT_SYMBOL_GPL(iscsi_eh_abort);
+static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
+{
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+ hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+ hdr->rtt = ISCSI_RESERVED_TAG;
+}
+
+int iscsi_eh_device_reset(struct scsi_cmnd *sc)
+{
+ struct Scsi_Host *host = sc->device->host;
+ struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+ struct iscsi_conn *conn;
+ struct iscsi_tm *hdr;
+ int rc = FAILED;
+
+ debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
+
+ mutex_lock(&session->eh_mutex);
+ spin_lock_bh(&session->lock);
+ /*
+ * Just check if we are not logged in. We cannot check for
+ * the phase because the reset could come from a ioctl.
+ */
+ if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+ goto unlock;
+ conn = session->leadconn;
+
+ /* only have one tmf outstanding at a time */
+ if (conn->tmf_state != TMF_INITIAL)
+ goto unlock;
+ conn->tmf_state = TMF_QUEUED;
+
+ hdr = &conn->tmhdr;
+ iscsi_prep_lun_reset_pdu(sc, hdr);
+
+ if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age)) {
+ rc = FAILED;
+ goto unlock;
+ }
+
+ switch (conn->tmf_state) {
+ case TMF_SUCCESS:
+ break;
+ case TMF_TIMEDOUT:
+ spin_unlock_bh(&session->lock);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ goto done;
+ default:
+ conn->tmf_state = TMF_INITIAL;
+ goto unlock;
+ }
+
+ rc = SUCCESS;
+ spin_unlock_bh(&session->lock);
+
+ iscsi_suspend_tx(conn);
+ /* need to grab the recv lock then session lock */
+ write_lock_bh(conn->recv_lock);
+ spin_lock(&session->lock);
+ fail_all_commands(conn, sc->device->lun);
+ conn->tmf_state = TMF_INITIAL;
+ spin_unlock(&session->lock);
+ write_unlock_bh(conn->recv_lock);
+
+ iscsi_start_tx(conn);
+ goto done;
+
+unlock:
+ spin_unlock_bh(&session->lock);
+done:
+ debug_scsi("iscsi_eh_device_reset %s\n",
+ rc == SUCCESS ? "SUCCESS" : "FAILED");
+ mutex_unlock(&session->eh_mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
+
int
iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
{
#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
-static struct iscsi_cls_session *
-__iscsi_session_setup(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- uint16_t cmds_max, uint16_t qdepth,
- int cmd_task_size, int mgmt_task_size,
- uint32_t initial_cmdsn, uint32_t *hostno)
+/**
+ * iscsi_session_setup - create iscsi cls session and host and session
+ * @scsit: scsi transport template
+ * @iscsit: iscsi transport template
+ * @cmds_max: scsi host can queue
+ * @qdepth: scsi host cmds per lun
+ * @cmd_task_size: LLD ctask private data size
+ * @mgmt_task_size: LLD mtask private data size
+ * @initial_cmdsn: initial CmdSN
+ * @hostno: host no allocated
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+struct iscsi_cls_session *
+iscsi_session_setup(struct iscsi_transport *iscsit,
+ struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
+ int cmd_task_size, int mgmt_task_size,
+ uint32_t initial_cmdsn, uint32_t *hostno)
{
struct Scsi_Host *shost;
struct iscsi_session *session;
if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
if (qdepth != 0)
printk(KERN_ERR "iscsi: invalid queue depth of %d. "
- "Queue depth must be between 1 and %d.\n",
- qdepth, ISCSI_MAX_CMD_PER_LUN);
- qdepth = ISCSI_DEF_CMD_PER_LUN;
+ "Queue depth must be between 1 and %d.\n",
+ qdepth, ISCSI_MAX_CMD_PER_LUN);
+ qdepth = ISCSI_DEF_CMD_PER_LUN;
}
if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
printk(KERN_ERR "iscsi: invalid can_queue of %d. "
"can_queue must be a power of 2 and between "
"2 and %d - setting to %d.\n", cmds_max,
- ISCSI_MGMT_ITT_OFFSET, ISCSI_XMIT_CMDS_MAX);
- cmds_max = ISCSI_XMIT_CMDS_MAX;
+ ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX);
+ cmds_max = ISCSI_DEF_XMIT_CMDS_MAX;
}
shost = scsi_host_alloc(iscsit->host_template,
shost->max_cmd_len = iscsit->max_cmd_len;
shost->transportt = scsit;
shost->transportt->create_work_queue = 1;
- shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
*hostno = shost->host_no;
session = iscsi_hostdata(shost->hostdata);
scsi_host_put(shost);
return NULL;
}
-
-/**
- * iscsi_session_setup - create iscsi cls session and host and session
- * @scsit: scsi transport template
- * @iscsit: iscsi transport template
- * @cmd_task_size: LLD ctask private data size
- * @mgmt_task_size: LLD mtask private data size
- * @initial_cmdsn: initial CmdSN
- * @hostno: host no allocated
- *
- * This can be used by software iscsi_transports that allocate
- * a session per scsi host.
- **/
-struct iscsi_cls_session *
-iscsi_session_setup(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- int cmd_task_size, int mgmt_task_size,
- uint32_t initial_cmdsn, uint32_t *hostno)
-{
- return __iscsi_session_setup(iscsit, scsit, ISCSI_XMIT_CMDS_MAX,
- ISCSI_DEF_CMD_PER_LUN,
- cmd_task_size, mgmt_task_size,
- initial_cmdsn, hostno);
-}
EXPORT_SYMBOL_GPL(iscsi_session_setup);
-/*
- * This is a KABI work around. This new version takes the defaults
- * session queue depth and default device queue depth.
- */
-/**
- * iscsi_session_setup - create iscsi cls session and host and session
- * @scsit: scsi transport template
- * @iscsit: iscsi transport template
- * @cmds_max: session queue depth
- * @qdepth: default device queue depth
- * @cmd_task_size: LLD ctask private data size
- * @mgmt_task_size: LLD mtask private data size
- * @initial_cmdsn: initial CmdSN
- * @hostno: host no allocated
- *
- * This can be used by software iscsi_transports that allocate
- * a session per scsi host.
- **/
-struct iscsi_cls_session *
-iscsi_session_setup2(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- uint16_t cmds_max, uint16_t qdepth,
- int cmd_task_size, int mgmt_task_size,
- uint32_t initial_cmdsn, uint32_t *hostno)
-{
- return __iscsi_session_setup(iscsit, scsit, cmds_max, qdepth,
- cmd_task_size, mgmt_task_size,
- initial_cmdsn, hostno);
-}
-EXPORT_SYMBOL_GPL(iscsi_session_setup2);
-
/**
* iscsi_session_teardown - destroy session, host, and cls_session
* shost: scsi host
conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
conn->id = conn_idx;
conn->exp_statsn = 0;
- conn->tmabort_state = TMABORT_INITIAL;
-
- init_timer(&conn->transport_timer);
- conn->transport_timer.data = (unsigned long)conn;
- conn->transport_timer.function = iscsi_check_transport_timeouts;
-
+ conn->tmf_state = TMF_INITIAL;
INIT_LIST_HEAD(&conn->run_list);
INIT_LIST_HEAD(&conn->mgmt_run_list);
+ INIT_LIST_HEAD(&conn->mgmtqueue);
INIT_LIST_HEAD(&conn->xmitqueue);
-
- /* initialize general immediate & non-immediate PDU commands queue */
- conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
- goto mgmtqueue_alloc_fail;
-
- INIT_WORK(&conn->xmitwork, iscsi_xmitworker, conn);
+ INIT_LIST_HEAD(&conn->requeue);
+ INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
/* allocate login_mtask used for the login/text sequences */
spin_lock_bh(&session->lock);
goto login_mtask_data_alloc_fail;
conn->login_mtask->data = conn->data = data;
- init_timer(&conn->tmabort_timer);
- /*
- * RHEL5.0 iscsi_tcp tried to ise the xmitmutex to serialize
- * access to the connection during sysfs access and teardown
- * and setup, but the code did not actually protect the access
- * due to a bug. So incase somone uses a new libiscsi with old
- * iscsi_tcp, we init this and those weirdos would get the old
- * broken behavior.
- *
- * TODO: Do I have to support such weirdness for KABI?
- */
- mutex_init(&conn->xmitmutex);
+ init_timer(&conn->tmf_timer);
init_waitqueue_head(&conn->ehwait);
return cls_conn;
__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
sizeof(void*));
login_mtask_alloc_fail:
- kfifo_free(conn->mgmtqueue);
-mgmtqueue_alloc_fail:
iscsi_destroy_conn(cls_conn);
return NULL;
}
struct iscsi_session *session = conn->session;
unsigned long flags;
- del_timer_sync(&conn->transport_timer);
-
spin_lock_bh(&session->lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
/*
}
/* flush queued up work because we free the connection below */
- scsi_flush_work(session->host);
+ iscsi_suspend_tx(conn);
spin_lock_bh(&session->lock);
kfree(conn->data);
session->leadconn = NULL;
spin_unlock_bh(&session->lock);
- kfifo_free(conn->mgmtqueue);
-
iscsi_destroy_conn(cls_conn);
}
EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
return -EINVAL;
}
- if (conn->ping_timeout && !conn->recv_timeout) {
- printk(KERN_ERR "iscsi: invalid recv timeout of zero. "
- "Using 5 seconds\n.");
- conn->recv_timeout = 5;
- }
-
- if (conn->recv_timeout && !conn->ping_timeout) {
- printk(KERN_ERR "iscsi: invalid ping timeout of zero. "
- "Using 5 seconds.\n");
- conn->ping_timeout = 5;
- }
-
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
session->queued_cmdsn = session->cmdsn;
- conn->last_recv = jiffies;
- conn->last_ping = jiffies;
- if (conn->recv_timeout && conn->ping_timeout)
- mod_timer(&conn->transport_timer,
- jiffies + (conn->recv_timeout * HZ));
-
switch(conn->stop_stage) {
case STOP_CONN_RECOVER:
/*
* commands after successful recovery
*/
conn->stop_stage = 0;
- conn->tmabort_state = TMABORT_INITIAL;
+ conn->tmf_state = TMF_INITIAL;
session->age++;
spin_unlock_bh(&session->lock);
struct iscsi_mgmt_task *mtask, *tmp;
/* handle pending */
- while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
+ list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
- iscsi_free_mgmt_task(conn, mtask);
+ list_del_init(&mtask->running);
+ if (mtask == conn->login_mtask)
+ continue;
+ __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+ sizeof(void*));
}
/* handle running */
list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
- iscsi_free_mgmt_task(conn, mtask);
- }
+ list_del_init(&mtask->running);
- conn->mtask = NULL;
-}
-
-/* Fail commands. Mutex and session lock held and recv side suspended */
-static void fail_all_commands(struct iscsi_conn *conn)
-{
- struct iscsi_cmd_task *ctask, *tmp;
-
- /* flush pending */
- list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
- debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
- ctask->itt);
- fail_command(conn, ctask, DID_BUS_BUSY << 16);
- }
-
- /* fail all other running */
- list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
- debug_scsi("failing in progress sc %p itt 0x%x\n",
- ctask->sc, ctask->itt);
- fail_command(conn, ctask, DID_BUS_BUSY << 16);
+ if (mtask == conn->login_mtask)
+ continue;
+ __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+ sizeof(void*));
}
- conn->ctask = NULL;
+ conn->mtask = NULL;
}
static void iscsi_start_session_recovery(struct iscsi_session *session,
{
int old_stop_stage;
- del_timer_sync(&conn->transport_timer);
-
mutex_lock(&session->eh_mutex);
spin_lock_bh(&session->lock);
if (conn->stop_stage == STOP_CONN_TERM) {
* flush queues.
*/
spin_lock_bh(&session->lock);
- fail_all_commands(conn);
+ fail_all_commands(conn, -1);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
mutex_unlock(&session->eh_mutex);
uint32_t value;
switch(param) {
- case ISCSI_PARAM_PING_TMO:
- sscanf(buf, "%d", &conn->ping_timeout);
- break;
- case ISCSI_PARAM_RECV_TMO:
- sscanf(buf, "%d", &conn->recv_timeout);
+ case ISCSI_PARAM_FAST_ABORT:
+ sscanf(buf, "%d", &session->fast_abort);
break;
case ISCSI_PARAM_MAX_RECV_DLENGTH:
sscanf(buf, "%d", &conn->max_recv_dlength);
int len;
switch(param) {
+ case ISCSI_PARAM_FAST_ABORT:
+ len = sprintf(buf, "%d\n", session->fast_abort);
+ break;
case ISCSI_PARAM_INITIAL_R2T_EN:
len = sprintf(buf, "%d\n", session->initial_r2t_en);
break;
int len;
switch(param) {
- case ISCSI_PARAM_PING_TMO:
- len = sprintf(buf, "%u\n", conn->ping_timeout);
- break;
- case ISCSI_PARAM_RECV_TMO:
- len = sprintf(buf, "%u\n", conn->recv_timeout);
- break;
case ISCSI_PARAM_MAX_RECV_DLENGTH:
len = sprintf(buf, "%u\n", conn->max_recv_dlength);
break;
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport.h>
-#include <scsi/scsi_transport_iscsi.h>
-#include <scsi/iscsi_if.h>
+#include "scsi_transport_iscsi.h"
+#include "iscsi_if.h"
-#define ISCSI_SESSION_ATTRS 15
-#define ISCSI_CONN_ATTRS 13
+#define ISCSI_SESSION_ATTRS 16
+#define ISCSI_CONN_ATTRS 11
#define ISCSI_HOST_ATTRS 4
-#define ISCSI_TRANSPORT_VERSION "2.0-724"
+#define ISCSI_TRANSPORT_VERSION "2.0-865"
struct iscsi_internal {
int daemon_pid;
return 0;
}
-static void session_recovery_timedout(void *data)
+static void session_recovery_timedout(struct work_struct *work)
{
- struct iscsi_cls_session *session = data;
+ struct iscsi_cls_session *session =
+ container_of(work, struct iscsi_cls_session,
+ recovery_work.work);
dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed "
"out after %d secs\n", session->recovery_tmo);
session->transport = transport;
session->recovery_tmo = 120;
- INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
+ INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
INIT_LIST_HEAD(&session->host_list);
INIT_LIST_HEAD(&session->sess_list);
unsigned long flags;
uint32_t hostno;
- if ((!ev->u.c_session.cmds_max && !ev->u.c_session.queue_depth) ||
- !transport->create_session2)
- session = transport->create_session(transport, &priv->t,
- ev->u.c_session.initial_cmdsn,
- &hostno);
- else
- session = transport->create_session2(transport, &priv->t,
- ev->u.c_session.cmds_max,
- ev->u.c_session.queue_depth,
- ev->u.c_session.initial_cmdsn,
- &hostno);
+ session = transport->create_session(transport, &priv->t,
+ ev->u.c_session.cmds_max,
+ ev->u.c_session.queue_depth,
+ ev->u.c_session.initial_cmdsn,
+ &hostno);
if (!session)
return -ENOMEM;
iscsi_tgt_dscvr(struct iscsi_transport *transport,
struct iscsi_uevent *ev)
{
+ struct Scsi_Host *shost;
struct sockaddr *dst_addr;
+ int err;
if (!transport->tgt_dscvr)
return -EINVAL;
+ shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "target discovery could not find host no %u\n",
+ ev->u.tgt_dscvr.host_no);
+ return -ENODEV;
+ }
+
+
dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
- return transport->tgt_dscvr(ev->u.tgt_dscvr.type,
- ev->u.tgt_dscvr.host_no,
- ev->u.tgt_dscvr.enable, dst_addr);
+ err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
+ ev->u.tgt_dscvr.enable, dst_addr);
+ scsi_host_put(shost);
+ return err;
}
static int
iscsi_set_host_param(struct iscsi_transport *transport,
- struct iscsi_uevent *ev)
+ struct iscsi_uevent *ev)
{
char *data = (char*)ev + sizeof(*ev);
struct Scsi_Host *shost;
err = iscsi_set_host_param(transport, ev);
break;
default:
- err = -EINVAL;
+ err = -ENOSYS;
break;
}
iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
-iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
-iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
#define iscsi_cdev_to_session(_cdev) \
iscsi_dev_to_session(_cdev->dev)
iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
+iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 1);
#define iscsi_priv_session_attr_show(field, format) \
static ssize_t \
count++; \
} while (0)
+
#define SETUP_SESSION_RD_ATTR(field, param_flag) \
do { \
if (tt->param_mask & param_flag) { \
SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
-
BUG_ON(count > ISCSI_HOST_ATTRS);
priv->host_attrs[count] = NULL;
count = 0;
SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
- SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
- SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
BUG_ON(count > ISCSI_CONN_ATTRS);
priv->conn_attrs[count] = NULL;
SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
+ SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
BUG_ON(count > ISCSI_SESSION_ATTRS);
goto unregister_conn_class;
nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
- THIS_MODULE);
+ NULL, THIS_MODULE);
if (!nls) {
err = -ENOBUFS;
goto unregister_session_class;
#ifndef ISCSI_IF_H
#define ISCSI_IF_H
-#include <scsi/iscsi_proto.h>
+#include <iscsi_proto.h>
#define UEVENT_BASE 10
#define KEVENT_BASE 100
ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
-#ifndef __GENKSYMS__
ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
-#endif
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
/* messages u -> k */
struct msg_create_session {
uint32_t initial_cmdsn;
-#ifndef __GENKSYMS__
uint16_t cmds_max;
uint16_t queue_depth;
-#endif
} c_session;
struct msg_destroy_session {
uint32_t sid;
*/
uint32_t enable;
} tgt_dscvr;
-#ifndef __GENKSYMS__
struct msg_set_host_param {
uint32_t host_no;
uint32_t param; /* enum iscsi_host_param */
uint32_t len;
} set_host_param;
-#endif
} u;
union {
/* messages k -> u */
ISCSI_PARAM_CONN_PORT,
ISCSI_PARAM_CONN_ADDRESS,
- /* must always be last */
- ISCSI_PARAM_MAX,
-
-#ifndef __GENKSYMS__
- /* no one uses ISCSI_PARAM_MAX */
- ISCSI_PARAM_USERNAME = ISCSI_PARAM_MAX,
+ ISCSI_PARAM_USERNAME,
ISCSI_PARAM_USERNAME_IN,
ISCSI_PARAM_PASSWORD,
ISCSI_PARAM_PASSWORD_IN,
- /*
- * These tmf timers are not yet used in RHEL, but come before the ping
- * ones upstream so they are being brought in to maintain ordering.
- */
ISCSI_PARAM_FAST_ABORT,
- ISCSI_PARAM_ABORT_TMO,
- ISCSI_PARAM_LU_RESET_TMO,
- ISCSI_PARAM_HOST_RESET_TMO,
-
- ISCSI_PARAM_PING_TMO,
- ISCSI_PARAM_RECV_TMO,
-
-#endif
+ /* must always be last */
+ ISCSI_PARAM_MAX,
};
#define ISCSI_MAX_RECV_DLENGTH (1 << ISCSI_PARAM_MAX_RECV_DLENGTH)
#define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD)
#define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN)
#define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT)
-#define ISCSI_ABORT_TMO (1 << ISCSI_PARAM_ABORT_TMO)
-#define ISCSI_LU_RESET_TMO (1 << ISCSI_PARAM_LU_RESET_TMO)
-#define ISCSI_HOST_RESET_TMO (1 << ISCSI_PARAM_HOST_RESET_TMO)
-#define ISCSI_PING_TMO (1 << ISCSI_PARAM_PING_TMO)
-#define ISCSI_RECV_TMO (1 << ISCSI_PARAM_RECV_TMO)
/* iSCSI HBA params */
enum iscsi_host_param {
* These flags describes reason of stop_conn() call
*/
#define STOP_CONN_TERM 0x1
-#define STOP_CONN_SUSPEND 0x2
#define STOP_CONN_RECOVER 0x3
#define ISCSI_STATS_CUSTOM_MAX 32
}
#define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;}
+/*
+ * If running svn modules we may need to define these.
+ * This should not go upstream since this is already properly defined there
+ */
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
/* initiator tags; opaque for target */
typedef uint32_t __bitwise__ itt_t;
/* below makes sense only for initiator that created this tag */
uint8_t hlength; /* AHSs total length */
uint8_t dlength[3]; /* Data length */
uint8_t lun[8];
-
-#ifndef __GENKSYMS__
itt_t itt; /* Initiator Task Tag, opaque for target */
-#else
- __be32 itt;
-#endif
__be32 ttt; /* Target Task Tag */
__be32 statsn;
__be32 exp_statsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 data_length;
__be32 cmdsn;
__be32 exp_statsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd1;
__be32 statsn;
__be32 exp_cmdsn;
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 cmdsn;
__be32 exp_statsn;
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
-
-#ifndef __GENKSYMS__
- itt_t rtt; /* Reference Task Tag */
-#else
- __be32 rtt;
-#endif
+ itt_t rtt; /* Reference Task Tag */
__be32 cmdsn;
__be32 exp_statsn;
__be32 refcmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
-#ifndef __GENKSYMS__
itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
-
-#ifndef __GENKSYMS__
- itt_t rtt; /* Reference Task Tag */
-#else
- __be32 rtt
-#endif
+ itt_t rtt; /* Reference Task Tag */
__be32 statsn;
__be32 exp_cmdsn;
__be32 max_cmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
__be32 ttt; /* Target Transfer Tag */
__be32 statsn;
__be32 exp_cmdsn;
uint8_t rsvd3;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
itt_t itt;
-#else
- __be32 itt;
-#endif
__be32 ttt;
__be32 rsvd4;
__be32 exp_statsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t lun[8];
-#ifndef __GENKSYMS__
- itt_t itt;
-#else
- __be32 itt;
-#endif
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
-#ifndef __GENKSYMS__
- itt_t itt;
-#else
- __be32 itt;
-#endif
+ itt_t itt;
__be32 ttt;
__be32 cmdsn;
__be32 exp_statsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd4[8];
-#ifndef __GENKSYMS__
- itt_t itt;
-#else
- __be32 itt;
-#endif
+ itt_t itt;
__be32 ttt;
__be32 statsn;
__be32 exp_cmdsn;
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
__be16 rsvd3;
__be32 cmdsn;
uint8_t dlength[3];
uint8_t isid[6]; /* Initiator Session ID */
__be16 tsih; /* Target Session Handle */
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd3;
__be32 statsn;
__be32 exp_cmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd2[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be16 cid;
uint8_t rsvd3[2];
__be32 cmdsn;
uint8_t hlength;
uint8_t dlength[3];
uint8_t rsvd3[8];
-#ifndef __GENKSYMS__
- itt_t itt; /* Initiator Task Tag */
-#else
- __be32 itt;
-#endif
+ itt_t itt; /* Initiator Task Tag */
__be32 rsvd4;
__be32 statsn;
__be32 exp_cmdsn;
uint8_t opcode;
uint8_t flags;
uint8_t rsvd2[14];
-#ifndef __GENKSYMS__
- itt_t itt;
-#else
- __be32 itt;
-#endif
+ itt_t itt;
__be32 begrun;
__be32 runlength;
__be32 exp_statsn;
#define VALUE_MAXLEN 255
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
-#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192
-
#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192
#define ISCSI_MIN_MAX_RECV_SEG_LEN 512
#define ISCSI_MAX_MAX_RECV_SEG_LEN 16777215
#define ISCSI_MIN_MAX_BURST_LEN 512
#define ISCSI_MAX_MAX_BURST_LEN 16777215
+#define ISCSI_DEF_TIME2WAIT 2
+
/************************* RFC 3720 End *****************************/
#endif /* ISCSI_PROTO_H */
#include <linux/types.h>
#include <linux/mutex.h>
-#include <scsi/iscsi_proto.h>
-#include <scsi/iscsi_if.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include "iscsi_proto.h"
+#include "iscsi_if.h"
struct scsi_transport_template;
struct scsi_device;
#define debug_scsi(fmt...)
#endif
-#define ISCSI_XMIT_CMDS_MAX 256 /* must be power of 2 */
+#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */
#define ISCSI_MGMT_CMDS_MAX 16 /* must be power of 2 */
-#define ISCSI_CONN_MAX 1
-
-#define ISCSI_ADDRESS_BUF_LEN 64
#define ISCSI_MGMT_ITT_OFFSET 0xa00
#define ISCSI_MAX_CMD_PER_LUN 128
/* Task Mgmt states */
-#define TMABORT_INITIAL 0x0
-#define TMABORT_SUCCESS 0x1
-#define TMABORT_FAILED 0x2
-#define TMABORT_TIMEDOUT 0x3
-#define TMABORT_NOT_FOUND 0x4
+enum {
+ TMF_INITIAL,
+ TMF_QUEUED,
+ TMF_SUCCESS,
+ TMF_FAILED,
+ TMF_TIMEDOUT,
+ TMF_NOT_FOUND,
+};
/* Connection suspend "bit" */
#define ISCSI_SUSPEND_BIT 1
#define ISCSI_AGE_SHIFT 28
#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
+#define ISCSI_ADDRESS_BUF_LEN 64
+
struct iscsi_mgmt_task {
/*
* Becuae LLDs allocate their hdr differently, this is a pointer to
*/
struct iscsi_hdr *hdr;
char *data; /* mgmt payload */
- int data_count; /* counts data to be sent */
+ unsigned data_count; /* counts data to be sent */
uint32_t itt; /* this ITT */
void *dd_data; /* driver/transport data */
struct list_head running;
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
-#ifndef __GENKSYMS__
- ISCSI_TASK_ABORTING,
-#endif
};
struct iscsi_cmd_task {
*/
struct iscsi_cmd *hdr;
int itt; /* this ITT */
- int datasn; /* DataSN */
uint32_t unsol_datasn;
- int imm_count; /* imm-data (bytes) */
- int unsol_count; /* unsolicited (bytes)*/
+ unsigned imm_count; /* imm-data (bytes) */
+ unsigned unsol_count; /* unsolicited (bytes)*/
/* offset in unsolicited stream (bytes); */
- int unsol_offset;
- int data_count; /* remaining Data-Out */
+ unsigned unsol_offset;
+ unsigned data_count; /* remaining Data-Out */
struct scsi_cmnd *sc; /* associated SCSI cmd*/
- int total_length;
struct iscsi_conn *conn; /* used connection */
- struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
/* state set/tested under session->lock */
int state;
/* control data */
int id; /* CID */
- struct list_head item; /* maintains list of conns */
int c_stage; /* connection state */
/*
* Preallocated buffer for pdus that have data but do not
struct iscsi_cmd_task *ctask; /* xmit ctask in progress */
/* xmit */
- struct kfifo *immqueue; /* immediate xmit queue */
- struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
+ struct list_head mgmtqueue; /* mgmt (control) xmit queue */
struct list_head mgmt_run_list; /* list of control tasks */
struct list_head xmitqueue; /* data-path cmd queue */
struct list_head run_list; /* list of cmds in progress */
+ struct list_head requeue; /* tasks needing another run */
struct work_struct xmitwork; /* per-conn. xmit workqueue */
- /*
- * serializes connection xmit, access to kfifos:
- * xmitqueue, immqueue, mgmtqueue
- */
- struct mutex xmitmutex;
-
unsigned long suspend_tx; /* suspend Tx */
unsigned long suspend_rx; /* suspend Rx */
/* abort */
wait_queue_head_t ehwait; /* used in eh_abort() */
struct iscsi_tm tmhdr;
- struct timer_list tmabort_timer;
- int tmabort_state; /* see TMABORT_INITIAL, etc.*/
+ struct timer_list tmf_timer;
+ int tmf_state; /* see TMF_INITIAL, etc.*/
/* negotiated params */
- int max_recv_dlength; /* initiator_max_recv_dsl*/
- int max_xmit_dlength; /* target_max_recv_dsl */
+ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
+ unsigned max_xmit_dlength; /* target_max_recv_dsl */
int hdrdgst_en;
int datadgst_en;
int ifmarker_en;
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
+ /* remote portal currently connected to */
+ int portal_port;
+ char portal_address[ISCSI_ADDRESS_BUF_LEN];
+ /* local address */
+ int local_port;
+ char local_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
/* custom statistics */
uint32_t eh_abort_cnt;
-#ifndef __GENKSYMS__
- /* remote portal currently connected to */
- int portal_port;
- char portal_address[ISCSI_ADDRESS_BUF_LEN];
- /* local address */
- int local_port;
- char local_address[ISCSI_ADDRESS_BUF_LEN];
-
- struct timer_list transport_timer;
- unsigned long last_recv;
- unsigned long last_ping;
- int ping_timeout;
- int recv_timeout;
- struct iscsi_mgmt_task *ping_mtask;
-#endif
};
struct iscsi_queue {
};
struct iscsi_session {
+ /*
+ * Syncs up the scsi eh thread with the iscsi eh thread when sending
+ * task management functions. This must be taken before the session
+ * and recv lock.
+ */
+ struct mutex eh_mutex;
+
/* iSCSI session-wide sequencing */
uint32_t cmdsn;
uint32_t exp_cmdsn;
uint32_t max_cmdsn;
+ /* This tracks the reqs queued into the initiator */
+ uint32_t queued_cmdsn;
+
/* configuration */
int initial_r2t_en;
- int max_r2t;
+ unsigned max_r2t;
int imm_data_en;
- int first_burst;
- int max_burst;
+ unsigned first_burst;
+ unsigned max_burst;
int time2wait;
int time2retain;
int pdu_inorder_en;
int dataseq_inorder_en;
int erl;
+ int fast_abort;
int tpgt;
+ char *username;
+ char *username_in;
+ char *password;
+ char *password_in;
char *targetname;
-
+ char *initiatorname;
+ /* hw address or netdev iscsi connection is bound to */
+ char *hwaddress;
+ char *netdev;
/* control data */
struct iscsi_transport *tt;
struct Scsi_Host *host;
* - mgmtpool, *
* - r2tpool */
int state; /* session state */
- struct list_head item;
int age; /* counts session re-opens */
- struct list_head connections; /* list of connections */
int cmds_max; /* size of cmds array */
struct iscsi_cmd_task **cmds; /* Original Cmds arr */
struct iscsi_queue cmdpool; /* PDU's pool */
int mgmtpool_max; /* size of mgmt array */
struct iscsi_mgmt_task **mgmt_cmds; /* Original mgmt arr */
struct iscsi_queue mgmtpool; /* Mgmt PDU's pool */
-#ifndef __GENKSYMS__
- /* This tracks the reqs queued into the initiator */
- uint32_t queued_cmdsn;
- /*
- * Syncs up the scsi eh thread with the iscsi eh thread when sending
- * task management functions. This must be taken before the session
- * and recv lock.
- */
- struct mutex eh_mutex;
-
- char *username;
- char *username_in;
- char *password;
- char *password_in;
- char *initiatorname;
- /* hw address or netdev iscsi connection is bound to */
- char *hwaddress;
- char *netdev;
-#endif
};
/*
extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth);
extern int iscsi_eh_abort(struct scsi_cmnd *sc);
extern int iscsi_eh_host_reset(struct scsi_cmnd *sc);
+extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
extern int iscsi_queuecommand(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *));
+
/*
* iSCSI host helpers.
*/
*/
extern struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
- int, int, uint32_t, uint32_t *);
-extern struct iscsi_cls_session *
-iscsi_session_setup2(struct iscsi_transport *, struct scsi_transport_template *,
- uint16_t, uint16_t, int, int, uint32_t, uint32_t *);
+ uint16_t, uint16_t, int, int, uint32_t, uint32_t *);
extern void iscsi_session_teardown(struct iscsi_cls_session *);
extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
/*
* pdu and task processing
*/
-extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
- struct iscsi_nopin *);
+extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
struct iscsi_data *hdr);
extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
char *, int);
extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *,
uint32_t *);
-extern void iscsi_free_mgmt_task(struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask);
-extern void iscsi_update_cmdsn(struct iscsi_session *,
- struct iscsi_nopin *);;
+extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask);
/*
* generic helpers
#define SCSI_TRANSPORT_ISCSI_H
#include <linux/device.h>
-#include <scsi/iscsi_if.h>
+#include "iscsi_if.h"
struct scsi_transport_template;
struct iscsi_transport;
char *name;
unsigned int caps;
/* LLD sets this to indicate what values it can export to sysfs */
- unsigned int param_mask;
+ uint64_t param_mask;
+ uint64_t host_param_mask;
struct scsi_host_template *host_template;
/* LLD connection data size */
int conndata_size;
unsigned int max_conn;
unsigned int max_cmd_len;
struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
- struct scsi_transport_template *t, uint32_t sn, uint32_t *hn);
+ struct scsi_transport_template *t, uint16_t, uint16_t,
+ uint32_t sn, uint32_t *hn);
void (*destroy_session) (struct iscsi_cls_session *session);
struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
uint32_t cid);
enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
enum iscsi_param param, char *buf);
+ int (*get_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+ int (*set_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size);
void (*get_stats) (struct iscsi_cls_conn *conn,
struct iscsi_stats *stats);
void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
void (*init_mgmt_task) (struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size);
+ struct iscsi_mgmt_task *mtask);
int (*xmit_cmd_task) (struct iscsi_conn *conn,
struct iscsi_cmd_task *ctask);
void (*cleanup_cmd_task) (struct iscsi_conn *conn,
uint64_t *ep_handle);
int (*ep_poll) (uint64_t ep_handle, int timeout_ms);
void (*ep_disconnect) (uint64_t ep_handle);
- int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no,
+ int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
uint32_t enable, struct sockaddr *dst_addr);
-#ifndef __GENKSYMS__
- uint64_t host_param_mask;
- int (*get_host_param) (struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf);
- int (*set_host_param) (struct Scsi_Host *shost,
- enum iscsi_host_param param, char *buf,
- int buflen);
- struct iscsi_cls_session *(*create_session2) (struct iscsi_transport *i,
- struct scsi_transport_template *t, uint16_t cmds_max,
- uint16_t qdepth, uint32_t sn, uint32_t *hn);
-#endif
};
/*
/* recovery fields */
int recovery_tmo;
- struct work_struct recovery_work;
+ struct delayed_work recovery_work;
int target_id;