diff options
-rw-r--r-- | drivers/scsi/libiscsi.c | 183 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 34 | ||||
-rw-r--r-- | include/scsi/scsi_transport_iscsi.h | 9 |
3 files changed, 156 insertions, 70 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 3fdee7370ccc..80cbcdce7fa3 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -88,34 +88,47 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
88 | } | 88 | } |
89 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); | 89 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); |
90 | 90 | ||
91 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task, | 91 | /** |
92 | struct iscsi_data *hdr) | 92 | * iscsi_prep_data_out_pdu - initialize Data-Out |
93 | * @task: scsi command task | ||
94 | * @r2t: R2T info | ||
95 | * @hdr: iscsi data in pdu | ||
96 | * | ||
97 | * Notes: | ||
98 | * Initialize Data-Out within this R2T sequence and finds | ||
99 | * proper data_offset within this SCSI command. | ||
100 | * | ||
101 | * This function is called with connection lock taken. | ||
102 | **/ | ||
103 | void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t, | ||
104 | struct iscsi_data *hdr) | ||
93 | { | 105 | { |
94 | struct iscsi_conn *conn = task->conn; | 106 | struct iscsi_conn *conn = task->conn; |
107 | unsigned int left = r2t->data_length - r2t->sent; | ||
108 | |||
109 | task->hdr_len = sizeof(struct iscsi_data); | ||
95 | 110 | ||
96 | memset(hdr, 0, sizeof(struct iscsi_data)); | 111 | memset(hdr, 0, sizeof(struct iscsi_data)); |
97 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | 112 | hdr->ttt = r2t->ttt; |
98 | hdr->datasn = cpu_to_be32(task->unsol_datasn); | 113 | hdr->datasn = cpu_to_be32(r2t->datasn); |
99 | task->unsol_datasn++; | 114 | r2t->datasn++; |
100 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 115 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
101 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); | 116 | memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); |
102 | 117 | hdr->itt = task->hdr_itt; | |
103 | hdr->itt = task->hdr->itt; | 118 | hdr->exp_statsn = r2t->exp_statsn; |
104 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 119 | hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent); |
105 | hdr->offset = cpu_to_be32(task->unsol_offset); | 120 | if (left > conn->max_xmit_dlength) { |
106 | |||
107 | if (task->unsol_count > conn->max_xmit_dlength) { | ||
108 | hton24(hdr->dlength, conn->max_xmit_dlength); | 121 | hton24(hdr->dlength, conn->max_xmit_dlength); |
109 | task->data_count = conn->max_xmit_dlength; | 122 | r2t->data_count = conn->max_xmit_dlength; |
110 | task->unsol_offset += task->data_count; | ||
111 | hdr->flags = 0; | 123 | hdr->flags = 0; |
112 | } else { | 124 | } else { |
113 | hton24(hdr->dlength, task->unsol_count); | 125 | hton24(hdr->dlength, left); |
114 | task->data_count = task->unsol_count; | 126 | r2t->data_count = left; |
115 | hdr->flags = ISCSI_FLAG_CMD_FINAL; | 127 | hdr->flags = ISCSI_FLAG_CMD_FINAL; |
116 | } | 128 | } |
129 | conn->dataout_pdus_cnt++; | ||
117 | } | 130 | } |
118 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); | 131 | EXPORT_SYMBOL_GPL(iscsi_prep_data_out_pdu); |
119 | 132 | ||
120 | static int iscsi_add_hdr(struct iscsi_task *task, unsigned len) | 133 | static int iscsi_add_hdr(struct iscsi_task *task, unsigned len) |
121 | { | 134 | { |
@@ -206,11 +219,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
206 | { | 219 | { |
207 | struct iscsi_conn *conn = task->conn; | 220 | struct iscsi_conn *conn = task->conn; |
208 | struct iscsi_session *session = conn->session; | 221 | struct iscsi_session *session = conn->session; |
209 | struct iscsi_cmd *hdr = task->hdr; | ||
210 | struct scsi_cmnd *sc = task->sc; | 222 | struct scsi_cmnd *sc = task->sc; |
223 | struct iscsi_cmd *hdr; | ||
211 | unsigned hdrlength, cmd_len; | 224 | unsigned hdrlength, cmd_len; |
212 | int rc; | 225 | int rc; |
213 | 226 | ||
227 | rc = conn->session->tt->alloc_pdu(task); | ||
228 | if (rc) | ||
229 | return rc; | ||
230 | hdr = (struct iscsi_cmd *) task->hdr; | ||
231 | memset(hdr, 0, sizeof(*hdr)); | ||
232 | |||
214 | task->hdr_len = 0; | 233 | task->hdr_len = 0; |
215 | rc = iscsi_add_hdr(task, sizeof(*hdr)); | 234 | rc = iscsi_add_hdr(task, sizeof(*hdr)); |
216 | if (rc) | 235 | if (rc) |
@@ -218,8 +237,9 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
218 | hdr->opcode = ISCSI_OP_SCSI_CMD; | 237 | hdr->opcode = ISCSI_OP_SCSI_CMD; |
219 | hdr->flags = ISCSI_ATTR_SIMPLE; | 238 | hdr->flags = ISCSI_ATTR_SIMPLE; |
220 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 239 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
221 | hdr->itt = build_itt(task->itt, session->age); | 240 | memcpy(task->lun, hdr->lun, sizeof(task->lun)); |
222 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 241 | hdr->itt = task->hdr_itt = build_itt(task->itt, session->age); |
242 | hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn); | ||
223 | session->cmdsn++; | 243 | session->cmdsn++; |
224 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 244 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
225 | cmd_len = sc->cmd_len; | 245 | cmd_len = sc->cmd_len; |
@@ -242,6 +262,8 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
242 | } | 262 | } |
243 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 263 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
244 | unsigned out_len = scsi_out(sc)->length; | 264 | unsigned out_len = scsi_out(sc)->length; |
265 | struct iscsi_r2t_info *r2t = &task->unsol_r2t; | ||
266 | |||
245 | hdr->data_length = cpu_to_be32(out_len); | 267 | hdr->data_length = cpu_to_be32(out_len); |
246 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 268 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
247 | /* | 269 | /* |
@@ -254,13 +276,11 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
254 | * without R2T ack right after | 276 | * without R2T ack right after |
255 | * immediate data | 277 | * immediate data |
256 | * | 278 | * |
257 | * r2t_data_count bytes to be sent via R2T ack's | 279 | * r2t data_length bytes to be sent via R2T ack's |
258 | * | 280 | * |
259 | * pad_count bytes to be sent as zero-padding | 281 | * pad_count bytes to be sent as zero-padding |
260 | */ | 282 | */ |
261 | task->unsol_count = 0; | 283 | memset(r2t, 0, sizeof(*r2t)); |
262 | task->unsol_offset = 0; | ||
263 | task->unsol_datasn = 0; | ||
264 | 284 | ||
265 | if (session->imm_data_en) { | 285 | if (session->imm_data_en) { |
266 | if (out_len >= session->first_burst) | 286 | if (out_len >= session->first_burst) |
@@ -274,12 +294,14 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
274 | zero_data(hdr->dlength); | 294 | zero_data(hdr->dlength); |
275 | 295 | ||
276 | if (!session->initial_r2t_en) { | 296 | if (!session->initial_r2t_en) { |
277 | task->unsol_count = min(session->first_burst, out_len) | 297 | r2t->data_length = min(session->first_burst, out_len) - |
278 | - task->imm_count; | 298 | task->imm_count; |
279 | task->unsol_offset = task->imm_count; | 299 | r2t->data_offset = task->imm_count; |
300 | r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | ||
301 | r2t->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
280 | } | 302 | } |
281 | 303 | ||
282 | if (!task->unsol_count) | 304 | if (!task->unsol_r2t.data_length) |
283 | /* No unsolicit Data-Out's */ | 305 | /* No unsolicit Data-Out's */ |
284 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 306 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
285 | } else { | 307 | } else { |
@@ -300,8 +322,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) | |||
300 | WARN_ON(hdrlength >= 256); | 322 | WARN_ON(hdrlength >= 256); |
301 | hdr->hlength = hdrlength & 0xFF; | 323 | hdr->hlength = hdrlength & 0xFF; |
302 | 324 | ||
303 | if (conn->session->tt->init_task && | 325 | if (session->tt->init_task && session->tt->init_task(task)) |
304 | conn->session->tt->init_task(task)) | ||
305 | return -EIO; | 326 | return -EIO; |
306 | 327 | ||
307 | task->state = ISCSI_TASK_RUNNING; | 328 | task->state = ISCSI_TASK_RUNNING; |
@@ -332,6 +353,7 @@ static void iscsi_complete_command(struct iscsi_task *task) | |||
332 | struct iscsi_session *session = conn->session; | 353 | struct iscsi_session *session = conn->session; |
333 | struct scsi_cmnd *sc = task->sc; | 354 | struct scsi_cmnd *sc = task->sc; |
334 | 355 | ||
356 | session->tt->cleanup_task(task); | ||
335 | list_del_init(&task->running); | 357 | list_del_init(&task->running); |
336 | task->state = ISCSI_TASK_COMPLETED; | 358 | task->state = ISCSI_TASK_COMPLETED; |
337 | task->sc = NULL; | 359 | task->sc = NULL; |
@@ -402,8 +424,6 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, | |||
402 | * the cmd in the sequencing | 424 | * the cmd in the sequencing |
403 | */ | 425 | */ |
404 | conn->session->queued_cmdsn--; | 426 | conn->session->queued_cmdsn--; |
405 | else | ||
406 | conn->session->tt->cleanup_task(conn, task); | ||
407 | 427 | ||
408 | sc->result = err; | 428 | sc->result = err; |
409 | if (!scsi_bidi_cmnd(sc)) | 429 | if (!scsi_bidi_cmnd(sc)) |
@@ -423,7 +443,7 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, | |||
423 | struct iscsi_task *task) | 443 | struct iscsi_task *task) |
424 | { | 444 | { |
425 | struct iscsi_session *session = conn->session; | 445 | struct iscsi_session *session = conn->session; |
426 | struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr; | 446 | struct iscsi_hdr *hdr = task->hdr; |
427 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | 447 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; |
428 | 448 | ||
429 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | 449 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) |
@@ -456,6 +476,7 @@ static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, | |||
456 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) | 476 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) |
457 | session->state = ISCSI_STATE_LOGGING_OUT; | 477 | session->state = ISCSI_STATE_LOGGING_OUT; |
458 | 478 | ||
479 | task->state = ISCSI_TASK_RUNNING; | ||
459 | list_move_tail(&task->running, &conn->mgmt_run_list); | 480 | list_move_tail(&task->running, &conn->mgmt_run_list); |
460 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | 481 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", |
461 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, | 482 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, |
@@ -505,23 +526,38 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
505 | } else | 526 | } else |
506 | task->data_count = 0; | 527 | task->data_count = 0; |
507 | 528 | ||
529 | if (conn->session->tt->alloc_pdu(task)) { | ||
530 | iscsi_conn_printk(KERN_ERR, conn, "Could not allocate " | ||
531 | "pdu for mgmt task.\n"); | ||
532 | goto requeue_task; | ||
533 | } | ||
534 | task->hdr_len = sizeof(struct iscsi_hdr); | ||
535 | |||
508 | memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); | 536 | memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); |
509 | INIT_LIST_HEAD(&task->running); | 537 | INIT_LIST_HEAD(&task->running); |
510 | list_add_tail(&task->running, &conn->mgmtqueue); | 538 | list_add_tail(&task->running, &conn->mgmtqueue); |
511 | 539 | ||
512 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | 540 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { |
513 | if (iscsi_prep_mgmt_task(conn, task)) { | 541 | if (iscsi_prep_mgmt_task(conn, task)) |
514 | __iscsi_put_task(task); | 542 | goto free_task; |
515 | return NULL; | ||
516 | } | ||
517 | 543 | ||
518 | if (session->tt->xmit_task(task)) | 544 | if (session->tt->xmit_task(task)) |
519 | task = NULL; | 545 | goto free_task; |
520 | 546 | ||
521 | } else | 547 | } else |
522 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 548 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
523 | 549 | ||
524 | return task; | 550 | return task; |
551 | |||
552 | free_task: | ||
553 | __iscsi_put_task(task); | ||
554 | return NULL; | ||
555 | |||
556 | requeue_task: | ||
557 | if (task != conn->login_task) | ||
558 | __kfifo_put(session->cmdpool.queue, (void*)&task, | ||
559 | sizeof(void*)); | ||
560 | return NULL; | ||
525 | } | 561 | } |
526 | 562 | ||
527 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | 563 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, |
@@ -1136,8 +1172,13 @@ check_mgmt: | |||
1136 | fail_command(conn, conn->task, DID_IMM_RETRY << 16); | 1172 | fail_command(conn, conn->task, DID_IMM_RETRY << 16); |
1137 | continue; | 1173 | continue; |
1138 | } | 1174 | } |
1139 | if (iscsi_prep_scsi_cmd_pdu(conn->task)) { | 1175 | rc = iscsi_prep_scsi_cmd_pdu(conn->task); |
1140 | fail_command(conn, conn->task, DID_ABORT << 16); | 1176 | if (rc) { |
1177 | if (rc == -ENOMEM) { | ||
1178 | conn->task = NULL; | ||
1179 | goto again; | ||
1180 | } else | ||
1181 | fail_command(conn, conn->task, DID_ABORT << 16); | ||
1141 | continue; | 1182 | continue; |
1142 | } | 1183 | } |
1143 | rc = iscsi_xmit_task(conn); | 1184 | rc = iscsi_xmit_task(conn); |
@@ -1195,6 +1236,26 @@ static void iscsi_xmitworker(struct work_struct *work) | |||
1195 | } while (rc >= 0 || rc == -EAGAIN); | 1236 | } while (rc >= 0 || rc == -EAGAIN); |
1196 | } | 1237 | } |
1197 | 1238 | ||
1239 | static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, | ||
1240 | struct scsi_cmnd *sc) | ||
1241 | { | ||
1242 | struct iscsi_task *task; | ||
1243 | |||
1244 | if (!__kfifo_get(conn->session->cmdpool.queue, | ||
1245 | (void *) &task, sizeof(void *))) | ||
1246 | return NULL; | ||
1247 | |||
1248 | sc->SCp.phase = conn->session->age; | ||
1249 | sc->SCp.ptr = (char *) task; | ||
1250 | |||
1251 | atomic_set(&task->refcount, 1); | ||
1252 | task->state = ISCSI_TASK_PENDING; | ||
1253 | task->conn = conn; | ||
1254 | task->sc = sc; | ||
1255 | INIT_LIST_HEAD(&task->running); | ||
1256 | return task; | ||
1257 | } | ||
1258 | |||
1198 | enum { | 1259 | enum { |
1199 | FAILURE_BAD_HOST = 1, | 1260 | FAILURE_BAD_HOST = 1, |
1200 | FAILURE_SESSION_FAILED, | 1261 | FAILURE_SESSION_FAILED, |
@@ -1281,33 +1342,27 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1281 | goto reject; | 1342 | goto reject; |
1282 | } | 1343 | } |
1283 | 1344 | ||
1284 | if (!__kfifo_get(session->cmdpool.queue, (void*)&task, | 1345 | task = iscsi_alloc_task(conn, sc); |
1285 | sizeof(void*))) { | 1346 | if (!task) { |
1286 | reason = FAILURE_OOM; | 1347 | reason = FAILURE_OOM; |
1287 | goto reject; | 1348 | goto reject; |
1288 | } | 1349 | } |
1289 | sc->SCp.phase = session->age; | ||
1290 | sc->SCp.ptr = (char *)task; | ||
1291 | |||
1292 | atomic_set(&task->refcount, 1); | ||
1293 | task->state = ISCSI_TASK_PENDING; | ||
1294 | task->conn = conn; | ||
1295 | task->sc = sc; | ||
1296 | INIT_LIST_HEAD(&task->running); | ||
1297 | list_add_tail(&task->running, &conn->xmitqueue); | 1350 | list_add_tail(&task->running, &conn->xmitqueue); |
1298 | 1351 | ||
1299 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | 1352 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { |
1300 | if (iscsi_prep_scsi_cmd_pdu(task)) { | 1353 | reason = iscsi_prep_scsi_cmd_pdu(task); |
1301 | sc->result = DID_ABORT << 16; | 1354 | if (reason) { |
1302 | sc->scsi_done = NULL; | 1355 | if (reason == -ENOMEM) { |
1303 | iscsi_complete_command(task); | 1356 | reason = FAILURE_OOM; |
1304 | goto fault; | 1357 | goto prepd_reject; |
1358 | } else { | ||
1359 | sc->result = DID_ABORT << 16; | ||
1360 | goto prepd_fault; | ||
1361 | } | ||
1305 | } | 1362 | } |
1306 | if (session->tt->xmit_task(task)) { | 1363 | if (session->tt->xmit_task(task)) { |
1307 | sc->scsi_done = NULL; | ||
1308 | iscsi_complete_command(task); | ||
1309 | reason = FAILURE_SESSION_NOT_READY; | 1364 | reason = FAILURE_SESSION_NOT_READY; |
1310 | goto reject; | 1365 | goto prepd_reject; |
1311 | } | 1366 | } |
1312 | } else | 1367 | } else |
1313 | scsi_queue_work(session->host, &conn->xmitwork); | 1368 | scsi_queue_work(session->host, &conn->xmitwork); |
@@ -1317,12 +1372,18 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1317 | spin_lock(host->host_lock); | 1372 | spin_lock(host->host_lock); |
1318 | return 0; | 1373 | return 0; |
1319 | 1374 | ||
1375 | prepd_reject: | ||
1376 | sc->scsi_done = NULL; | ||
1377 | iscsi_complete_command(task); | ||
1320 | reject: | 1378 | reject: |
1321 | spin_unlock(&session->lock); | 1379 | spin_unlock(&session->lock); |
1322 | debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); | 1380 | debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); |
1323 | spin_lock(host->host_lock); | 1381 | spin_lock(host->host_lock); |
1324 | return SCSI_MLQUEUE_TARGET_BUSY; | 1382 | return SCSI_MLQUEUE_TARGET_BUSY; |
1325 | 1383 | ||
1384 | prepd_fault: | ||
1385 | sc->scsi_done = NULL; | ||
1386 | iscsi_complete_command(task); | ||
1326 | fault: | 1387 | fault: |
1327 | spin_unlock(&session->lock); | 1388 | spin_unlock(&session->lock); |
1328 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); | 1389 | debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); |
@@ -1634,9 +1695,9 @@ static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, | |||
1634 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | 1695 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; |
1635 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; | 1696 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; |
1636 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 1697 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
1637 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); | 1698 | memcpy(hdr->lun, task->lun, sizeof(hdr->lun)); |
1638 | hdr->rtt = task->hdr->itt; | 1699 | hdr->rtt = task->hdr_itt; |
1639 | hdr->refcmdsn = task->hdr->cmdsn; | 1700 | hdr->refcmdsn = task->cmdsn; |
1640 | } | 1701 | } |
1641 | 1702 | ||
1642 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1703 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 61e53f14f7e1..51500573c0b8 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -93,24 +93,38 @@ enum { | |||
93 | ISCSI_TASK_RUNNING, | 93 | ISCSI_TASK_RUNNING, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | struct iscsi_r2t_info { | ||
97 | __be32 ttt; /* copied from R2T */ | ||
98 | __be32 exp_statsn; /* copied from R2T */ | ||
99 | uint32_t data_length; /* copied from R2T */ | ||
100 | uint32_t data_offset; /* copied from R2T */ | ||
101 | int data_count; /* DATA-Out payload progress */ | ||
102 | int datasn; | ||
103 | /* LLDs should set/update these values */ | ||
104 | int sent; /* R2T sequence progress */ | ||
105 | }; | ||
106 | |||
96 | struct iscsi_task { | 107 | struct iscsi_task { |
97 | /* | 108 | /* |
98 | * Because LLDs allocate their hdr differently, this is a pointer | 109 | * Because LLDs allocate their hdr differently, this is a pointer |
99 | * and length to that storage. It must be setup at session | 110 | * and length to that storage. It must be setup at session |
100 | * creation time. | 111 | * creation time. |
101 | */ | 112 | */ |
102 | struct iscsi_cmd *hdr; | 113 | struct iscsi_hdr *hdr; |
103 | unsigned short hdr_max; | 114 | unsigned short hdr_max; |
104 | unsigned short hdr_len; /* accumulated size of hdr used */ | 115 | unsigned short hdr_len; /* accumulated size of hdr used */ |
116 | /* copied values in case we need to send tmfs */ | ||
117 | itt_t hdr_itt; | ||
118 | __be32 cmdsn; | ||
119 | uint8_t lun[8]; | ||
120 | |||
105 | int itt; /* this ITT */ | 121 | int itt; /* this ITT */ |
106 | 122 | ||
107 | uint32_t unsol_datasn; | ||
108 | unsigned imm_count; /* imm-data (bytes) */ | 123 | unsigned imm_count; /* imm-data (bytes) */ |
109 | unsigned unsol_count; /* unsolicited (bytes)*/ | ||
110 | /* offset in unsolicited stream (bytes); */ | 124 | /* offset in unsolicited stream (bytes); */ |
111 | unsigned unsol_offset; | 125 | struct iscsi_r2t_info unsol_r2t; |
112 | unsigned data_count; /* remaining Data-Out */ | ||
113 | char *data; /* mgmt payload */ | 126 | char *data; /* mgmt payload */ |
127 | unsigned data_count; | ||
114 | struct scsi_cmnd *sc; /* associated SCSI cmd*/ | 128 | struct scsi_cmnd *sc; /* associated SCSI cmd*/ |
115 | struct iscsi_conn *conn; /* used connection */ | 129 | struct iscsi_conn *conn; /* used connection */ |
116 | 130 | ||
@@ -121,6 +135,11 @@ struct iscsi_task { | |||
121 | void *dd_data; /* driver/transport data */ | 135 | void *dd_data; /* driver/transport data */ |
122 | }; | 136 | }; |
123 | 137 | ||
138 | static inline int iscsi_task_has_unsol_data(struct iscsi_task *task) | ||
139 | { | ||
140 | return task->unsol_r2t.data_length > task->unsol_r2t.sent; | ||
141 | } | ||
142 | |||
124 | static inline void* iscsi_next_hdr(struct iscsi_task *task) | 143 | static inline void* iscsi_next_hdr(struct iscsi_task *task) |
125 | { | 144 | { |
126 | return (void*)task->hdr + task->hdr_len; | 145 | return (void*)task->hdr + task->hdr_len; |
@@ -376,8 +395,9 @@ extern void iscsi_suspend_tx(struct iscsi_conn *conn); | |||
376 | * pdu and task processing | 395 | * pdu and task processing |
377 | */ | 396 | */ |
378 | extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *); | 397 | extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *); |
379 | extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *, | 398 | extern void iscsi_prep_data_out_pdu(struct iscsi_task *task, |
380 | struct iscsi_data *hdr); | 399 | struct iscsi_r2t_info *r2t, |
400 | struct iscsi_data *hdr); | ||
381 | extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, | 401 | extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, |
382 | char *, uint32_t); | 402 | char *, uint32_t); |
383 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, | 403 | extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, |
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index c667cc396545..c928234c018f 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h | |||
@@ -113,10 +113,15 @@ struct iscsi_transport { | |||
113 | char *data, uint32_t data_size); | 113 | char *data, uint32_t data_size); |
114 | void (*get_stats) (struct iscsi_cls_conn *conn, | 114 | void (*get_stats) (struct iscsi_cls_conn *conn, |
115 | struct iscsi_stats *stats); | 115 | struct iscsi_stats *stats); |
116 | |||
116 | int (*init_task) (struct iscsi_task *task); | 117 | int (*init_task) (struct iscsi_task *task); |
117 | int (*xmit_task) (struct iscsi_task *task); | 118 | int (*xmit_task) (struct iscsi_task *task); |
118 | void (*cleanup_task) (struct iscsi_conn *conn, | 119 | void (*cleanup_task) (struct iscsi_task *task); |
119 | struct iscsi_task *task); | 120 | |
121 | int (*alloc_pdu) (struct iscsi_task *task); | ||
122 | int (*xmit_pdu) (struct iscsi_task *task); | ||
123 | int (*init_pdu) (struct iscsi_task *task, unsigned int offset, | ||
124 | unsigned int count); | ||
120 | void (*session_recovery_timedout) (struct iscsi_cls_session *session); | 125 | void (*session_recovery_timedout) (struct iscsi_cls_session *session); |
121 | struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr, | 126 | struct iscsi_endpoint *(*ep_connect) (struct sockaddr *dst_addr, |
122 | int non_blocking); | 127 | int non_blocking); |