diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2007-12-13 12:43:23 -0600 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 18:28:23 -0600 |
commit | 004d6530f83bee43a55b51bb5960db96e7ae0ffa (patch) | |
tree | a7bb6ffb3e6e89ca6ee9b164d5f19899a0c100dd /drivers/scsi/libiscsi.c | |
parent | 7207fea452cfdd2d4e2f4419e2c31f570edbade3 (diff) | |
download | lwn-004d6530f83bee43a55b51bb5960db96e7ae0ffa.tar.gz lwn-004d6530f83bee43a55b51bb5960db96e7ae0ffa.zip |
[SCSI] iscsi_tcp, libiscsi: initial AHS Support
at libiscsi generic code
- currently code assumes a storage space of pdu header is allocated
at llds ctask and is pointed to by iscsi_cmd_task->hdr. Here I add
a hdr_max field pertaining to that storage, and an hdr_len that
accumulates the current use of the pdu-header.
- Add an iscsi_next_hdr() inline which returns the next free space
to write new Header at. Also iscsi_next_hdr() is used to retrieve
the address at which to write the header-digest.
- Add iscsi_add_hdr(length). What the user do is calls iscsi_next_hdr()
for address of the new header, than calls iscsi_add_hdr(length) with
the size of the new header. iscsi_add_hdr() will check if space is
available and update to the new size. length must be padded according
to standard.
- Add 2 padding inline helpers thanks to Olaf. Current patch does not
use them but Following patches will.
Also moved definition of ISCSI_PAD_LEN to iscsi_proto.h which had
PAD_WORD_LEN that was never used anywhere.
- Let iscsi_prep_scsi_cmd_pdu() signal an Error return since now it is
possible that it will fail.
- I was tired of yet again writing a "this is a digest" comment next to
sizeof(__u32) so I defined a new ISCSI_DIGEST_SIZE. Now I don't need
any comments. Changed all places that used sizeof(__u32) or "4" in
connection to a digest.
iscsi_tcp specific code
- At struct iscsi_tcp_cmd_task allocate maximum space allowed in
standard for all headers following the iscsi_cmd header. and mark
it so in iscsi_tcp_session_create()
- At iscsi_send_cmd_hdr() retrieve the correct headers size and
write header digest at iscsi_next_hdr().
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Olaf Kirch <olaf.kirch@oracle.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 0beb4c620962..0d7914fd8ef3 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -37,6 +37,9 @@ #include <scsi/scsi_transport_iscsi.h> #include <scsi/libiscsi.h> +static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, + int err); + struct iscsi_session * class_to_transport_session(struct iscsi_cls_session *cls_session) { @@ -122,6 +125,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, } EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); +static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) +{ + unsigned exp_len = ctask->hdr_len + len; + + if (exp_len > ctask->hdr_max) { + WARN_ON(1); + return -EINVAL; + } + + WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ + ctask->hdr_len = exp_len; + return 0; +} + /** * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu * @ctask: iscsi cmd task @@ -129,13 +146,19 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set * fields like dlength or final based on how much data it sends */ -static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) { struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; struct iscsi_cmd *hdr = ctask->hdr; struct scsi_cmnd *sc = ctask->sc; + unsigned hdrlength; + int rc; + ctask->hdr_len = 0; + rc = iscsi_add_hdr(ctask, sizeof(*hdr)); + if (rc) + return rc; hdr->opcode = ISCSI_OP_SCSI_CMD; hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); @@ -199,6 +222,15 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->flags |= ISCSI_FLAG_CMD_READ; } + /* calculate size of additional header segments (AHSs) */ + hdrlength = ctask->hdr_len - sizeof(*hdr); + + WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); + hdrlength /= ISCSI_PAD_LEN; + + WARN_ON(hdrlength >= 256); + hdr->hlength = hdrlength & 0xFF; + conn->scsicmd_pdus_cnt++; debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " @@ -206,6 +238,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); + return 0; } /** @@ -744,7 +777,10 @@ check_mgmt: conn->ctask = list_entry(conn->xmitqueue.next, struct iscsi_cmd_task, running); - iscsi_prep_scsi_cmd_pdu(conn->ctask); + if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { + fail_command(conn, conn->ctask, DID_ABORT << 16); + continue; + } conn->session->tt->init_cmd_task(conn->ctask); conn->ctask->state = ISCSI_TASK_RUNNING; list_move_tail(conn->xmitqueue.next, &conn->run_list); @@ -1534,6 +1570,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (cmd_task_size) ctask->dd_data = &ctask[1]; ctask->itt = cmd_i; + ctask->hdr_max = sizeof(struct iscsi_cmd); INIT_LIST_HEAD(&ctask->running); } |