diff options
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 @@ | |||
37 | #include <scsi/scsi_transport_iscsi.h> | 37 | #include <scsi/scsi_transport_iscsi.h> |
38 | #include <scsi/libiscsi.h> | 38 | #include <scsi/libiscsi.h> |
39 | 39 | ||
40 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | ||
41 | int err); | ||
42 | |||
40 | struct iscsi_session * | 43 | struct iscsi_session * |
41 | class_to_transport_session(struct iscsi_cls_session *cls_session) | 44 | class_to_transport_session(struct iscsi_cls_session *cls_session) |
42 | { | 45 | { |
@@ -122,6 +125,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | |||
122 | } | 125 | } |
123 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); | 126 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); |
124 | 127 | ||
128 | static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) | ||
129 | { | ||
130 | unsigned exp_len = ctask->hdr_len + len; | ||
131 | |||
132 | if (exp_len > ctask->hdr_max) { | ||
133 | WARN_ON(1); | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ | ||
138 | ctask->hdr_len = exp_len; | ||
139 | return 0; | ||
140 | } | ||
141 | |||
125 | /** | 142 | /** |
126 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 143 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
127 | * @ctask: iscsi cmd task | 144 | * @ctask: iscsi cmd task |
@@ -129,13 +146,19 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); | |||
129 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set | 146 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set |
130 | * fields like dlength or final based on how much data it sends | 147 | * fields like dlength or final based on how much data it sends |
131 | */ | 148 | */ |
132 | static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | 149 | static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) |
133 | { | 150 | { |
134 | struct iscsi_conn *conn = ctask->conn; | 151 | struct iscsi_conn *conn = ctask->conn; |
135 | struct iscsi_session *session = conn->session; | 152 | struct iscsi_session *session = conn->session; |
136 | struct iscsi_cmd *hdr = ctask->hdr; | 153 | struct iscsi_cmd *hdr = ctask->hdr; |
137 | struct scsi_cmnd *sc = ctask->sc; | 154 | struct scsi_cmnd *sc = ctask->sc; |
155 | unsigned hdrlength; | ||
156 | int rc; | ||
138 | 157 | ||
158 | ctask->hdr_len = 0; | ||
159 | rc = iscsi_add_hdr(ctask, sizeof(*hdr)); | ||
160 | if (rc) | ||
161 | return rc; | ||
139 | hdr->opcode = ISCSI_OP_SCSI_CMD; | 162 | hdr->opcode = ISCSI_OP_SCSI_CMD; |
140 | hdr->flags = ISCSI_ATTR_SIMPLE; | 163 | hdr->flags = ISCSI_ATTR_SIMPLE; |
141 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 164 | 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) | |||
199 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 222 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
200 | } | 223 | } |
201 | 224 | ||
225 | /* calculate size of additional header segments (AHSs) */ | ||
226 | hdrlength = ctask->hdr_len - sizeof(*hdr); | ||
227 | |||
228 | WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); | ||
229 | hdrlength /= ISCSI_PAD_LEN; | ||
230 | |||
231 | WARN_ON(hdrlength >= 256); | ||
232 | hdr->hlength = hdrlength & 0xFF; | ||
233 | |||
202 | conn->scsicmd_pdus_cnt++; | 234 | conn->scsicmd_pdus_cnt++; |
203 | 235 | ||
204 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | 236 | 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) | |||
206 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 238 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", |
207 | conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), | 239 | conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), |
208 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 240 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
241 | return 0; | ||
209 | } | 242 | } |
210 | 243 | ||
211 | /** | 244 | /** |
@@ -744,7 +777,10 @@ check_mgmt: | |||
744 | 777 | ||
745 | conn->ctask = list_entry(conn->xmitqueue.next, | 778 | conn->ctask = list_entry(conn->xmitqueue.next, |
746 | struct iscsi_cmd_task, running); | 779 | struct iscsi_cmd_task, running); |
747 | iscsi_prep_scsi_cmd_pdu(conn->ctask); | 780 | if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { |
781 | fail_command(conn, conn->ctask, DID_ABORT << 16); | ||
782 | continue; | ||
783 | } | ||
748 | conn->session->tt->init_cmd_task(conn->ctask); | 784 | conn->session->tt->init_cmd_task(conn->ctask); |
749 | conn->ctask->state = ISCSI_TASK_RUNNING; | 785 | conn->ctask->state = ISCSI_TASK_RUNNING; |
750 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 786 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
@@ -1534,6 +1570,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1534 | if (cmd_task_size) | 1570 | if (cmd_task_size) |
1535 | ctask->dd_data = &ctask[1]; | 1571 | ctask->dd_data = &ctask[1]; |
1536 | ctask->itt = cmd_i; | 1572 | ctask->itt = cmd_i; |
1573 | ctask->hdr_max = sizeof(struct iscsi_cmd); | ||
1537 | INIT_LIST_HEAD(&ctask->running); | 1574 | INIT_LIST_HEAD(&ctask->running); |
1538 | } | 1575 | } |
1539 | 1576 | ||