diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index bdd7de7da39a..010c1b9b178c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -137,6 +137,70 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) | |||
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | 139 | ||
140 | /* | ||
141 | * make an extended cdb AHS | ||
142 | */ | ||
143 | static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | ||
144 | { | ||
145 | struct scsi_cmnd *cmd = ctask->sc; | ||
146 | unsigned rlen, pad_len; | ||
147 | unsigned short ahslength; | ||
148 | struct iscsi_ecdb_ahdr *ecdb_ahdr; | ||
149 | int rc; | ||
150 | |||
151 | ecdb_ahdr = iscsi_next_hdr(ctask); | ||
152 | rlen = cmd->cmd_len - ISCSI_CDB_SIZE; | ||
153 | |||
154 | BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); | ||
155 | ahslength = rlen + sizeof(ecdb_ahdr->reserved); | ||
156 | |||
157 | pad_len = iscsi_padding(rlen); | ||
158 | |||
159 | rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) + | ||
160 | sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); | ||
161 | if (rc) | ||
162 | return rc; | ||
163 | |||
164 | if (pad_len) | ||
165 | memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len); | ||
166 | |||
167 | ecdb_ahdr->ahslength = cpu_to_be16(ahslength); | ||
168 | ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB; | ||
169 | ecdb_ahdr->reserved = 0; | ||
170 | memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen); | ||
171 | |||
172 | debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " | ||
173 | "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", | ||
174 | cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | ||
180 | { | ||
181 | struct scsi_cmnd *sc = ctask->sc; | ||
182 | struct iscsi_rlength_ahdr *rlen_ahdr; | ||
183 | int rc; | ||
184 | |||
185 | rlen_ahdr = iscsi_next_hdr(ctask); | ||
186 | rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); | ||
187 | if (rc) | ||
188 | return rc; | ||
189 | |||
190 | rlen_ahdr->ahslength = | ||
191 | cpu_to_be16(sizeof(rlen_ahdr->read_length) + | ||
192 | sizeof(rlen_ahdr->reserved)); | ||
193 | rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; | ||
194 | rlen_ahdr->reserved = 0; | ||
195 | rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); | ||
196 | |||
197 | debug_scsi("bidi-in rlen_ahdr->read_length(%d) " | ||
198 | "rlen_ahdr->ahslength(%d)\n", | ||
199 | be32_to_cpu(rlen_ahdr->read_length), | ||
200 | be16_to_cpu(rlen_ahdr->ahslength)); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
140 | /** | 204 | /** |
141 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 205 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
142 | * @ctask: iscsi cmd task | 206 | * @ctask: iscsi cmd task |
@@ -150,7 +214,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
150 | struct iscsi_session *session = conn->session; | 214 | struct iscsi_session *session = conn->session; |
151 | struct iscsi_cmd *hdr = ctask->hdr; | 215 | struct iscsi_cmd *hdr = ctask->hdr; |
152 | struct scsi_cmnd *sc = ctask->sc; | 216 | struct scsi_cmnd *sc = ctask->sc; |
153 | unsigned hdrlength; | 217 | unsigned hdrlength, cmd_len; |
154 | int rc; | 218 | int rc; |
155 | 219 | ||
156 | ctask->hdr_len = 0; | 220 | ctask->hdr_len = 0; |
@@ -161,17 +225,30 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
161 | hdr->flags = ISCSI_ATTR_SIMPLE; | 225 | hdr->flags = ISCSI_ATTR_SIMPLE; |
162 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 226 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
163 | hdr->itt = build_itt(ctask->itt, session->age); | 227 | hdr->itt = build_itt(ctask->itt, session->age); |
164 | hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); | ||
165 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 228 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
166 | session->cmdsn++; | 229 | session->cmdsn++; |
167 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 230 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
168 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); | 231 | cmd_len = sc->cmd_len; |
169 | if (sc->cmd_len < MAX_COMMAND_SIZE) | 232 | if (cmd_len < ISCSI_CDB_SIZE) |
170 | memset(&hdr->cdb[sc->cmd_len], 0, | 233 | memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); |
171 | MAX_COMMAND_SIZE - sc->cmd_len); | 234 | else if (cmd_len > ISCSI_CDB_SIZE) { |
235 | rc = iscsi_prep_ecdb_ahs(ctask); | ||
236 | if (rc) | ||
237 | return rc; | ||
238 | cmd_len = ISCSI_CDB_SIZE; | ||
239 | } | ||
240 | memcpy(hdr->cdb, sc->cmnd, cmd_len); | ||
172 | 241 | ||
173 | ctask->imm_count = 0; | 242 | ctask->imm_count = 0; |
243 | if (scsi_bidi_cmnd(sc)) { | ||
244 | hdr->flags |= ISCSI_FLAG_CMD_READ; | ||
245 | rc = iscsi_prep_bidi_ahs(ctask); | ||
246 | if (rc) | ||
247 | return rc; | ||
248 | } | ||
174 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 249 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
250 | unsigned out_len = scsi_out(sc)->length; | ||
251 | hdr->data_length = cpu_to_be32(out_len); | ||
175 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 252 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
176 | /* | 253 | /* |
177 | * Write counters: | 254 | * Write counters: |
@@ -192,19 +269,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
192 | ctask->unsol_datasn = 0; | 269 | ctask->unsol_datasn = 0; |
193 | 270 | ||
194 | if (session->imm_data_en) { | 271 | if (session->imm_data_en) { |
195 | if (scsi_bufflen(sc) >= session->first_burst) | 272 | if (out_len >= session->first_burst) |
196 | ctask->imm_count = min(session->first_burst, | 273 | ctask->imm_count = min(session->first_burst, |
197 | conn->max_xmit_dlength); | 274 | conn->max_xmit_dlength); |
198 | else | 275 | else |
199 | ctask->imm_count = min(scsi_bufflen(sc), | 276 | ctask->imm_count = min(out_len, |
200 | conn->max_xmit_dlength); | 277 | conn->max_xmit_dlength); |
201 | hton24(hdr->dlength, ctask->imm_count); | 278 | hton24(hdr->dlength, ctask->imm_count); |
202 | } else | 279 | } else |
203 | zero_data(hdr->dlength); | 280 | zero_data(hdr->dlength); |
204 | 281 | ||
205 | if (!session->initial_r2t_en) { | 282 | if (!session->initial_r2t_en) { |
206 | ctask->unsol_count = min((session->first_burst), | 283 | ctask->unsol_count = min(session->first_burst, out_len) |
207 | (scsi_bufflen(sc))) - ctask->imm_count; | 284 | - ctask->imm_count; |
208 | ctask->unsol_offset = ctask->imm_count; | 285 | ctask->unsol_offset = ctask->imm_count; |
209 | } | 286 | } |
210 | 287 | ||
@@ -214,6 +291,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
214 | } else { | 291 | } else { |
215 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 292 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
216 | zero_data(hdr->dlength); | 293 | zero_data(hdr->dlength); |
294 | hdr->data_length = cpu_to_be32(scsi_in(sc)->length); | ||
217 | 295 | ||
218 | if (sc->sc_data_direction == DMA_FROM_DEVICE) | 296 | if (sc->sc_data_direction == DMA_FROM_DEVICE) |
219 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 297 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
@@ -232,10 +310,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
232 | return EIO; | 310 | return EIO; |
233 | 311 | ||
234 | conn->scsicmd_pdus_cnt++; | 312 | conn->scsicmd_pdus_cnt++; |
235 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | 313 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " |
236 | "cmdsn %d win %d]\n", | 314 | "len %d bidi_len %d cmdsn %d win %d]\n", |
237 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 315 | scsi_bidi_cmnd(sc) ? "bidirectional" : |
238 | conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), | 316 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", |
317 | conn->id, sc, sc->cmnd[0], ctask->itt, | ||
318 | scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, | ||
239 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 319 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
240 | return 0; | 320 | return 0; |
241 | } | 321 | } |
@@ -298,7 +378,12 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
298 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 378 | conn->session->tt->cleanup_cmd_task(conn, ctask); |
299 | 379 | ||
300 | sc->result = err; | 380 | sc->result = err; |
301 | scsi_set_resid(sc, scsi_bufflen(sc)); | 381 | if (!scsi_bidi_cmnd(sc)) |
382 | scsi_set_resid(sc, scsi_bufflen(sc)); | ||
383 | else { | ||
384 | scsi_out(sc)->resid = scsi_out(sc)->length; | ||
385 | scsi_in(sc)->resid = scsi_in(sc)->length; | ||
386 | } | ||
302 | if (conn->ctask == ctask) | 387 | if (conn->ctask == ctask) |
303 | conn->ctask = NULL; | 388 | conn->ctask = NULL; |
304 | /* release ref from queuecommand */ | 389 | /* release ref from queuecommand */ |
@@ -433,6 +518,18 @@ invalid_datalen: | |||
433 | min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); | 518 | min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); |
434 | } | 519 | } |
435 | 520 | ||
521 | if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | | ||
522 | ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { | ||
523 | int res_count = be32_to_cpu(rhdr->bi_residual_count); | ||
524 | |||
525 | if (scsi_bidi_cmnd(sc) && res_count > 0 && | ||
526 | (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || | ||
527 | res_count <= scsi_in(sc)->length)) | ||
528 | scsi_in(sc)->resid = res_count; | ||
529 | else | ||
530 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | ||
531 | } | ||
532 | |||
436 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | | 533 | if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | |
437 | ISCSI_FLAG_CMD_OVERFLOW)) { | 534 | ISCSI_FLAG_CMD_OVERFLOW)) { |
438 | int res_count = be32_to_cpu(rhdr->residual_count); | 535 | int res_count = be32_to_cpu(rhdr->residual_count); |
@@ -440,13 +537,11 @@ invalid_datalen: | |||
440 | if (res_count > 0 && | 537 | if (res_count > 0 && |
441 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || | 538 | (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || |
442 | res_count <= scsi_bufflen(sc))) | 539 | res_count <= scsi_bufflen(sc))) |
540 | /* write side for bidi or uni-io set_resid */ | ||
443 | scsi_set_resid(sc, res_count); | 541 | scsi_set_resid(sc, res_count); |
444 | else | 542 | else |
445 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | 543 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
446 | } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | | 544 | } |
447 | ISCSI_FLAG_CMD_BIDI_OVERFLOW)) | ||
448 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | ||
449 | |||
450 | out: | 545 | out: |
451 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", | 546 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
452 | (long)sc, sc->result, ctask->itt); | 547 | (long)sc, sc->result, ctask->itt); |
@@ -1102,7 +1197,12 @@ reject: | |||
1102 | fault: | 1197 | fault: |
1103 | spin_unlock(&session->lock); | 1198 | spin_unlock(&session->lock); |
1104 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); | 1199 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); |
1105 | scsi_set_resid(sc, scsi_bufflen(sc)); | 1200 | if (!scsi_bidi_cmnd(sc)) |
1201 | scsi_set_resid(sc, scsi_bufflen(sc)); | ||
1202 | else { | ||
1203 | scsi_out(sc)->resid = scsi_out(sc)->length; | ||
1204 | scsi_in(sc)->resid = scsi_in(sc)->length; | ||
1205 | } | ||
1106 | sc->scsi_done(sc); | 1206 | sc->scsi_done(sc); |
1107 | spin_lock(host->host_lock); | 1207 | spin_lock(host->host_lock); |
1108 | return 0; | 1208 | return 0; |