aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libiscsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r--drivers/scsi/libiscsi.c140
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 */
143static 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
179static 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
450out: 545out:
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:
1102fault: 1197fault:
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;