diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 144 |
1 files changed, 118 insertions, 26 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5884cd26d53a..c542d0e95e68 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
68 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); | 68 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); |
69 | 69 | ||
70 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 70 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, |
71 | struct iscsi_data *hdr, | 71 | struct iscsi_data *hdr) |
72 | int transport_data_cnt) | ||
73 | { | 72 | { |
74 | struct iscsi_conn *conn = ctask->conn; | 73 | struct iscsi_conn *conn = ctask->conn; |
75 | 74 | ||
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | |||
82 | 81 | ||
83 | hdr->itt = ctask->hdr->itt; | 82 | hdr->itt = ctask->hdr->itt; |
84 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 83 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
85 | 84 | hdr->offset = cpu_to_be32(ctask->unsol_offset); | |
86 | hdr->offset = cpu_to_be32(ctask->total_length - | ||
87 | transport_data_cnt - | ||
88 | ctask->unsol_count); | ||
89 | 85 | ||
90 | if (ctask->unsol_count > conn->max_xmit_dlength) { | 86 | if (ctask->unsol_count > conn->max_xmit_dlength) { |
91 | hton24(hdr->dlength, conn->max_xmit_dlength); | 87 | hton24(hdr->dlength, conn->max_xmit_dlength); |
92 | ctask->data_count = conn->max_xmit_dlength; | 88 | ctask->data_count = conn->max_xmit_dlength; |
89 | ctask->unsol_offset += ctask->data_count; | ||
93 | hdr->flags = 0; | 90 | hdr->flags = 0; |
94 | } else { | 91 | } else { |
95 | hton24(hdr->dlength, ctask->unsol_count); | 92 | hton24(hdr->dlength, ctask->unsol_count); |
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
125 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); | 122 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); |
126 | memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); | 123 | memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); |
127 | 124 | ||
125 | ctask->data_count = 0; | ||
128 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 126 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
129 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 127 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
130 | /* | 128 | /* |
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
143 | */ | 141 | */ |
144 | ctask->imm_count = 0; | 142 | ctask->imm_count = 0; |
145 | ctask->unsol_count = 0; | 143 | ctask->unsol_count = 0; |
144 | ctask->unsol_offset = 0; | ||
146 | ctask->unsol_datasn = 0; | 145 | ctask->unsol_datasn = 0; |
147 | 146 | ||
148 | if (session->imm_data_en) { | 147 | if (session->imm_data_en) { |
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
156 | } else | 155 | } else |
157 | zero_data(ctask->hdr->dlength); | 156 | zero_data(ctask->hdr->dlength); |
158 | 157 | ||
159 | if (!session->initial_r2t_en) | 158 | if (!session->initial_r2t_en) { |
160 | ctask->unsol_count = min(session->first_burst, | 159 | ctask->unsol_count = min(session->first_burst, |
161 | ctask->total_length) - ctask->imm_count; | 160 | ctask->total_length) - ctask->imm_count; |
161 | ctask->unsol_offset = ctask->imm_count; | ||
162 | } | ||
163 | |||
162 | if (!ctask->unsol_count) | 164 | if (!ctask->unsol_count) |
163 | /* No unsolicit Data-Out's */ | 165 | /* No unsolicit Data-Out's */ |
164 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 166 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
@@ -177,25 +179,51 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); | |||
177 | 179 | ||
178 | /** | 180 | /** |
179 | * iscsi_complete_command - return command back to scsi-ml | 181 | * iscsi_complete_command - return command back to scsi-ml |
180 | * @session: iscsi session | ||
181 | * @ctask: iscsi cmd task | 182 | * @ctask: iscsi cmd task |
182 | * | 183 | * |
183 | * Must be called with session lock. | 184 | * Must be called with session lock. |
184 | * This function returns the scsi command to scsi-ml and returns | 185 | * This function returns the scsi command to scsi-ml and returns |
185 | * the cmd task to the pool of available cmd tasks. | 186 | * the cmd task to the pool of available cmd tasks. |
186 | */ | 187 | */ |
187 | static void iscsi_complete_command(struct iscsi_session *session, | 188 | static void iscsi_complete_command(struct iscsi_cmd_task *ctask) |
188 | struct iscsi_cmd_task *ctask) | ||
189 | { | 189 | { |
190 | struct iscsi_session *session = ctask->conn->session; | ||
190 | struct scsi_cmnd *sc = ctask->sc; | 191 | struct scsi_cmnd *sc = ctask->sc; |
191 | 192 | ||
192 | ctask->state = ISCSI_TASK_COMPLETED; | 193 | ctask->state = ISCSI_TASK_COMPLETED; |
193 | ctask->sc = NULL; | 194 | ctask->sc = NULL; |
195 | /* SCSI eh reuses commands to verify us */ | ||
196 | sc->SCp.ptr = NULL; | ||
194 | list_del_init(&ctask->running); | 197 | list_del_init(&ctask->running); |
195 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 198 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); |
196 | sc->scsi_done(sc); | 199 | sc->scsi_done(sc); |
197 | } | 200 | } |
198 | 201 | ||
202 | static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
203 | { | ||
204 | atomic_inc(&ctask->refcount); | ||
205 | } | ||
206 | |||
207 | static void iscsi_get_ctask(struct iscsi_cmd_task *ctask) | ||
208 | { | ||
209 | spin_lock_bh(&ctask->conn->session->lock); | ||
210 | __iscsi_get_ctask(ctask); | ||
211 | spin_unlock_bh(&ctask->conn->session->lock); | ||
212 | } | ||
213 | |||
214 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
215 | { | ||
216 | if (atomic_dec_and_test(&ctask->refcount)) | ||
217 | iscsi_complete_command(ctask); | ||
218 | } | ||
219 | |||
220 | static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | ||
221 | { | ||
222 | spin_lock_bh(&ctask->conn->session->lock); | ||
223 | __iscsi_put_ctask(ctask); | ||
224 | spin_unlock_bh(&ctask->conn->session->lock); | ||
225 | } | ||
226 | |||
199 | /** | 227 | /** |
200 | * iscsi_cmd_rsp - SCSI Command Response processing | 228 | * iscsi_cmd_rsp - SCSI Command Response processing |
201 | * @conn: iscsi connection | 229 | * @conn: iscsi connection |
@@ -272,7 +300,7 @@ out: | |||
272 | (long)sc, sc->result, ctask->itt); | 300 | (long)sc, sc->result, ctask->itt); |
273 | conn->scsirsp_pdus_cnt++; | 301 | conn->scsirsp_pdus_cnt++; |
274 | 302 | ||
275 | iscsi_complete_command(conn->session, ctask); | 303 | __iscsi_put_ctask(ctask); |
276 | return rc; | 304 | return rc; |
277 | } | 305 | } |
278 | 306 | ||
@@ -295,6 +323,30 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
295 | wake_up(&conn->ehwait); | 323 | wake_up(&conn->ehwait); |
296 | } | 324 | } |
297 | 325 | ||
326 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
327 | char *data, int datalen) | ||
328 | { | ||
329 | struct iscsi_reject *reject = (struct iscsi_reject *)hdr; | ||
330 | struct iscsi_hdr rejected_pdu; | ||
331 | uint32_t itt; | ||
332 | |||
333 | conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; | ||
334 | |||
335 | if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { | ||
336 | if (ntoh24(reject->dlength) > datalen) | ||
337 | return ISCSI_ERR_PROTO; | ||
338 | |||
339 | if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { | ||
340 | memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); | ||
341 | itt = rejected_pdu.itt & ISCSI_ITT_MASK; | ||
342 | printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " | ||
343 | "due to DataDigest error.\n", itt, | ||
344 | rejected_pdu.opcode); | ||
345 | } | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
298 | /** | 350 | /** |
299 | * __iscsi_complete_pdu - complete pdu | 351 | * __iscsi_complete_pdu - complete pdu |
300 | * @conn: iscsi conn | 352 | * @conn: iscsi conn |
@@ -336,7 +388,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
336 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 388 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
337 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | 389 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { |
338 | conn->scsirsp_pdus_cnt++; | 390 | conn->scsirsp_pdus_cnt++; |
339 | iscsi_complete_command(session, ctask); | 391 | __iscsi_put_ctask(ctask); |
340 | } | 392 | } |
341 | break; | 393 | break; |
342 | case ISCSI_OP_R2T: | 394 | case ISCSI_OP_R2T: |
@@ -406,6 +458,11 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
406 | break; | 458 | break; |
407 | } | 459 | } |
408 | } else if (itt == ISCSI_RESERVED_TAG) { | 460 | } else if (itt == ISCSI_RESERVED_TAG) { |
461 | rc = iscsi_check_assign_cmdsn(session, | ||
462 | (struct iscsi_nopin*)hdr); | ||
463 | if (rc) | ||
464 | goto done; | ||
465 | |||
409 | switch(opcode) { | 466 | switch(opcode) { |
410 | case ISCSI_OP_NOOP_IN: | 467 | case ISCSI_OP_NOOP_IN: |
411 | if (datalen) { | 468 | if (datalen) { |
@@ -413,11 +470,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
413 | break; | 470 | break; |
414 | } | 471 | } |
415 | 472 | ||
416 | rc = iscsi_check_assign_cmdsn(session, | ||
417 | (struct iscsi_nopin*)hdr); | ||
418 | if (rc) | ||
419 | break; | ||
420 | |||
421 | if (hdr->ttt == ISCSI_RESERVED_TAG) | 473 | if (hdr->ttt == ISCSI_RESERVED_TAG) |
422 | break; | 474 | break; |
423 | 475 | ||
@@ -425,7 +477,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
425 | rc = ISCSI_ERR_CONN_FAILED; | 477 | rc = ISCSI_ERR_CONN_FAILED; |
426 | break; | 478 | break; |
427 | case ISCSI_OP_REJECT: | 479 | case ISCSI_OP_REJECT: |
428 | /* we need sth like iscsi_reject_rsp()*/ | 480 | rc = iscsi_handle_reject(conn, hdr, data, datalen); |
481 | break; | ||
429 | case ISCSI_OP_ASYNC_EVENT: | 482 | case ISCSI_OP_ASYNC_EVENT: |
430 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 483 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
431 | /* we need sth like iscsi_async_event_rsp() */ | 484 | /* we need sth like iscsi_async_event_rsp() */ |
@@ -561,7 +614,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
561 | BUG_ON(conn->ctask && conn->mtask); | 614 | BUG_ON(conn->ctask && conn->mtask); |
562 | 615 | ||
563 | if (conn->ctask) { | 616 | if (conn->ctask) { |
617 | iscsi_get_ctask(conn->ctask); | ||
564 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 618 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
619 | iscsi_put_ctask(conn->ctask); | ||
565 | if (rc) | 620 | if (rc) |
566 | goto again; | 621 | goto again; |
567 | /* done with this in-progress ctask */ | 622 | /* done with this in-progress ctask */ |
@@ -602,12 +657,19 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
602 | struct iscsi_cmd_task, running); | 657 | struct iscsi_cmd_task, running); |
603 | conn->ctask->state = ISCSI_TASK_RUNNING; | 658 | conn->ctask->state = ISCSI_TASK_RUNNING; |
604 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 659 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
660 | __iscsi_get_ctask(conn->ctask); | ||
605 | spin_unlock_bh(&conn->session->lock); | 661 | spin_unlock_bh(&conn->session->lock); |
606 | 662 | ||
607 | rc = tt->xmit_cmd_task(conn, conn->ctask); | 663 | rc = tt->xmit_cmd_task(conn, conn->ctask); |
608 | if (rc) | 664 | if (rc) |
609 | goto again; | 665 | goto again; |
666 | |||
610 | spin_lock_bh(&conn->session->lock); | 667 | spin_lock_bh(&conn->session->lock); |
668 | __iscsi_put_ctask(conn->ctask); | ||
669 | if (rc) { | ||
670 | spin_unlock_bh(&conn->session->lock); | ||
671 | goto again; | ||
672 | } | ||
611 | } | 673 | } |
612 | spin_unlock_bh(&conn->session->lock); | 674 | spin_unlock_bh(&conn->session->lock); |
613 | /* done with this ctask */ | 675 | /* done with this ctask */ |
@@ -657,6 +719,7 @@ enum { | |||
657 | FAILURE_SESSION_FAILED, | 719 | FAILURE_SESSION_FAILED, |
658 | FAILURE_SESSION_FREED, | 720 | FAILURE_SESSION_FREED, |
659 | FAILURE_WINDOW_CLOSED, | 721 | FAILURE_WINDOW_CLOSED, |
722 | FAILURE_OOM, | ||
660 | FAILURE_SESSION_TERMINATE, | 723 | FAILURE_SESSION_TERMINATE, |
661 | FAILURE_SESSION_IN_RECOVERY, | 724 | FAILURE_SESSION_IN_RECOVERY, |
662 | FAILURE_SESSION_RECOVERY_TIMEOUT, | 725 | FAILURE_SESSION_RECOVERY_TIMEOUT, |
@@ -672,6 +735,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
672 | 735 | ||
673 | sc->scsi_done = done; | 736 | sc->scsi_done = done; |
674 | sc->result = 0; | 737 | sc->result = 0; |
738 | sc->SCp.ptr = NULL; | ||
675 | 739 | ||
676 | host = sc->device->host; | 740 | host = sc->device->host; |
677 | session = iscsi_hostdata(host->hostdata); | 741 | session = iscsi_hostdata(host->hostdata); |
@@ -715,10 +779,15 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
715 | 779 | ||
716 | conn = session->leadconn; | 780 | conn = session->leadconn; |
717 | 781 | ||
718 | __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 782 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
783 | sizeof(void*))) { | ||
784 | reason = FAILURE_OOM; | ||
785 | goto reject; | ||
786 | } | ||
719 | sc->SCp.phase = session->age; | 787 | sc->SCp.phase = session->age; |
720 | sc->SCp.ptr = (char *)ctask; | 788 | sc->SCp.ptr = (char *)ctask; |
721 | 789 | ||
790 | atomic_set(&ctask->refcount, 1); | ||
722 | ctask->state = ISCSI_TASK_PENDING; | 791 | ctask->state = ISCSI_TASK_PENDING; |
723 | ctask->mtask = NULL; | 792 | ctask->mtask = NULL; |
724 | ctask->conn = conn; | 793 | ctask->conn = conn; |
@@ -731,9 +800,10 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
731 | 800 | ||
732 | list_add_tail(&ctask->running, &conn->xmitqueue); | 801 | list_add_tail(&ctask->running, &conn->xmitqueue); |
733 | debug_scsi( | 802 | debug_scsi( |
734 | "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n", | 803 | "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " |
804 | "win %d]\n", | ||
735 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 805 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", |
736 | conn->id, (long)sc, ctask->itt, sc->request_bufflen, | 806 | conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, |
737 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 807 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
738 | spin_unlock(&session->lock); | 808 | spin_unlock(&session->lock); |
739 | 809 | ||
@@ -1061,16 +1131,30 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1061 | 1131 | ||
1062 | sc->result = err; | 1132 | sc->result = err; |
1063 | sc->resid = sc->request_bufflen; | 1133 | sc->resid = sc->request_bufflen; |
1064 | iscsi_complete_command(conn->session, ctask); | 1134 | /* release ref from queuecommand */ |
1135 | __iscsi_put_ctask(ctask); | ||
1065 | } | 1136 | } |
1066 | 1137 | ||
1067 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1138 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1068 | { | 1139 | { |
1069 | struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 1140 | struct iscsi_cmd_task *ctask; |
1070 | struct iscsi_conn *conn = ctask->conn; | 1141 | struct iscsi_conn *conn; |
1071 | struct iscsi_session *session = conn->session; | 1142 | struct iscsi_session *session; |
1072 | int rc; | 1143 | int rc; |
1073 | 1144 | ||
1145 | /* | ||
1146 | * if session was ISCSI_STATE_IN_RECOVERY then we may not have | ||
1147 | * got the command. | ||
1148 | */ | ||
1149 | if (!sc->SCp.ptr) { | ||
1150 | debug_scsi("sc never reached iscsi layer or it completed.\n"); | ||
1151 | return SUCCESS; | ||
1152 | } | ||
1153 | |||
1154 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | ||
1155 | conn = ctask->conn; | ||
1156 | session = conn->session; | ||
1157 | |||
1074 | conn->eh_abort_cnt++; | 1158 | conn->eh_abort_cnt++; |
1075 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1159 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
1076 | 1160 | ||
@@ -1520,11 +1604,19 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
1520 | struct iscsi_conn *conn = cls_conn->dd_data; | 1604 | struct iscsi_conn *conn = cls_conn->dd_data; |
1521 | struct iscsi_session *session = conn->session; | 1605 | struct iscsi_session *session = conn->session; |
1522 | 1606 | ||
1523 | if (session == NULL) { | 1607 | if (!session) { |
1524 | printk(KERN_ERR "iscsi: can't start unbound connection\n"); | 1608 | printk(KERN_ERR "iscsi: can't start unbound connection\n"); |
1525 | return -EPERM; | 1609 | return -EPERM; |
1526 | } | 1610 | } |
1527 | 1611 | ||
1612 | if ((session->imm_data_en || !session->initial_r2t_en) && | ||
1613 | session->first_burst > session->max_burst) { | ||
1614 | printk("iscsi: invalid burst lengths: " | ||
1615 | "first_burst %d max_burst %d\n", | ||
1616 | session->first_burst, session->max_burst); | ||
1617 | return -EINVAL; | ||
1618 | } | ||
1619 | |||
1528 | spin_lock_bh(&session->lock); | 1620 | spin_lock_bh(&session->lock); |
1529 | conn->c_stage = ISCSI_CONN_STARTED; | 1621 | conn->c_stage = ISCSI_CONN_STARTED; |
1530 | session->state = ISCSI_STATE_LOGGED_IN; | 1622 | session->state = ISCSI_STATE_LOGGED_IN; |