diff options
Diffstat (limited to 'drivers/scsi/libiscsi.c')
-rw-r--r-- | drivers/scsi/libiscsi.c | 650 |
1 files changed, 377 insertions, 273 deletions
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 3f5b9b445b29..4d85ce100192 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 | */ | 23 | */ |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/mutex.h> | ||
26 | #include <linux/kfifo.h> | 25 | #include <linux/kfifo.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <asm/unaligned.h> | 27 | #include <asm/unaligned.h> |
@@ -46,27 +45,53 @@ class_to_transport_session(struct iscsi_cls_session *cls_session) | |||
46 | } | 45 | } |
47 | EXPORT_SYMBOL_GPL(class_to_transport_session); | 46 | EXPORT_SYMBOL_GPL(class_to_transport_session); |
48 | 47 | ||
49 | #define INVALID_SN_DELTA 0xffff | 48 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ |
49 | #define SNA32_CHECK 2147483648UL | ||
50 | 50 | ||
51 | int | 51 | static int iscsi_sna_lt(u32 n1, u32 n2) |
52 | iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | 52 | { |
53 | return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || | ||
54 | (n1 > n2 && (n2 - n1 < SNA32_CHECK))); | ||
55 | } | ||
56 | |||
57 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ | ||
58 | static int iscsi_sna_lte(u32 n1, u32 n2) | ||
59 | { | ||
60 | return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || | ||
61 | (n1 > n2 && (n2 - n1 < SNA32_CHECK))); | ||
62 | } | ||
63 | |||
64 | void | ||
65 | iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | ||
53 | { | 66 | { |
54 | uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); | 67 | uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); |
55 | uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); | 68 | uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); |
56 | 69 | ||
57 | if (max_cmdsn < exp_cmdsn -1 && | 70 | /* |
58 | max_cmdsn > exp_cmdsn - INVALID_SN_DELTA) | 71 | * standard specifies this check for when to update expected and |
59 | return ISCSI_ERR_MAX_CMDSN; | 72 | * max sequence numbers |
60 | if (max_cmdsn > session->max_cmdsn || | 73 | */ |
61 | max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA) | 74 | if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1)) |
62 | session->max_cmdsn = max_cmdsn; | 75 | return; |
63 | if (exp_cmdsn > session->exp_cmdsn || | 76 | |
64 | exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA) | 77 | if (exp_cmdsn != session->exp_cmdsn && |
78 | !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) | ||
65 | session->exp_cmdsn = exp_cmdsn; | 79 | session->exp_cmdsn = exp_cmdsn; |
66 | 80 | ||
67 | return 0; | 81 | if (max_cmdsn != session->max_cmdsn && |
82 | !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { | ||
83 | session->max_cmdsn = max_cmdsn; | ||
84 | /* | ||
85 | * if the window closed with IO queued, then kick the | ||
86 | * xmit thread | ||
87 | */ | ||
88 | if (!list_empty(&session->leadconn->xmitqueue) || | ||
89 | __kfifo_len(session->leadconn->mgmtqueue)) | ||
90 | scsi_queue_work(session->host, | ||
91 | &session->leadconn->xmitwork); | ||
92 | } | ||
68 | } | 93 | } |
69 | EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); | 94 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); |
70 | 95 | ||
71 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 96 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, |
72 | struct iscsi_data *hdr) | 97 | struct iscsi_data *hdr) |
@@ -115,14 +140,17 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
115 | hdr->flags = ISCSI_ATTR_SIMPLE; | 140 | hdr->flags = ISCSI_ATTR_SIMPLE; |
116 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 141 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
117 | hdr->itt = build_itt(ctask->itt, conn->id, session->age); | 142 | hdr->itt = build_itt(ctask->itt, conn->id, session->age); |
118 | hdr->data_length = cpu_to_be32(sc->request_bufflen); | 143 | hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); |
119 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 144 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
120 | session->cmdsn++; | 145 | session->cmdsn++; |
121 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 146 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
122 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); | 147 | memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); |
123 | memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); | 148 | if (sc->cmd_len < MAX_COMMAND_SIZE) |
149 | memset(&hdr->cdb[sc->cmd_len], 0, | ||
150 | MAX_COMMAND_SIZE - sc->cmd_len); | ||
124 | 151 | ||
125 | ctask->data_count = 0; | 152 | ctask->data_count = 0; |
153 | ctask->imm_count = 0; | ||
126 | if (sc->sc_data_direction == DMA_TO_DEVICE) { | 154 | if (sc->sc_data_direction == DMA_TO_DEVICE) { |
127 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; | 155 | hdr->flags |= ISCSI_FLAG_CMD_WRITE; |
128 | /* | 156 | /* |
@@ -139,25 +167,24 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
139 | * | 167 | * |
140 | * pad_count bytes to be sent as zero-padding | 168 | * pad_count bytes to be sent as zero-padding |
141 | */ | 169 | */ |
142 | ctask->imm_count = 0; | ||
143 | ctask->unsol_count = 0; | 170 | ctask->unsol_count = 0; |
144 | ctask->unsol_offset = 0; | 171 | ctask->unsol_offset = 0; |
145 | ctask->unsol_datasn = 0; | 172 | ctask->unsol_datasn = 0; |
146 | 173 | ||
147 | if (session->imm_data_en) { | 174 | if (session->imm_data_en) { |
148 | if (ctask->total_length >= session->first_burst) | 175 | if (scsi_bufflen(sc) >= session->first_burst) |
149 | ctask->imm_count = min(session->first_burst, | 176 | ctask->imm_count = min(session->first_burst, |
150 | conn->max_xmit_dlength); | 177 | conn->max_xmit_dlength); |
151 | else | 178 | else |
152 | ctask->imm_count = min(ctask->total_length, | 179 | ctask->imm_count = min(scsi_bufflen(sc), |
153 | conn->max_xmit_dlength); | 180 | conn->max_xmit_dlength); |
154 | hton24(ctask->hdr->dlength, ctask->imm_count); | 181 | hton24(ctask->hdr->dlength, ctask->imm_count); |
155 | } else | 182 | } else |
156 | zero_data(ctask->hdr->dlength); | 183 | zero_data(ctask->hdr->dlength); |
157 | 184 | ||
158 | if (!session->initial_r2t_en) { | 185 | if (!session->initial_r2t_en) { |
159 | ctask->unsol_count = min(session->first_burst, | 186 | ctask->unsol_count = min((session->first_burst), |
160 | ctask->total_length) - ctask->imm_count; | 187 | (scsi_bufflen(sc))) - ctask->imm_count; |
161 | ctask->unsol_offset = ctask->imm_count; | 188 | ctask->unsol_offset = ctask->imm_count; |
162 | } | 189 | } |
163 | 190 | ||
@@ -165,7 +192,6 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
165 | /* No unsolicit Data-Out's */ | 192 | /* No unsolicit Data-Out's */ |
166 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 193 | ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
167 | } else { | 194 | } else { |
168 | ctask->datasn = 0; | ||
169 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 195 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
170 | zero_data(hdr->dlength); | 196 | zero_data(hdr->dlength); |
171 | 197 | ||
@@ -174,8 +200,13 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
174 | } | 200 | } |
175 | 201 | ||
176 | conn->scsicmd_pdus_cnt++; | 202 | conn->scsicmd_pdus_cnt++; |
203 | |||
204 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " | ||
205 | "cmdsn %d win %d]\n", | ||
206 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | ||
207 | conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), | ||
208 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | ||
177 | } | 209 | } |
178 | EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); | ||
179 | 210 | ||
180 | /** | 211 | /** |
181 | * iscsi_complete_command - return command back to scsi-ml | 212 | * iscsi_complete_command - return command back to scsi-ml |
@@ -204,26 +235,12 @@ static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | |||
204 | atomic_inc(&ctask->refcount); | 235 | atomic_inc(&ctask->refcount); |
205 | } | 236 | } |
206 | 237 | ||
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) | 238 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) |
215 | { | 239 | { |
216 | if (atomic_dec_and_test(&ctask->refcount)) | 240 | if (atomic_dec_and_test(&ctask->refcount)) |
217 | iscsi_complete_command(ctask); | 241 | iscsi_complete_command(ctask); |
218 | } | 242 | } |
219 | 243 | ||
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 | |||
227 | /** | 244 | /** |
228 | * iscsi_cmd_rsp - SCSI Command Response processing | 245 | * iscsi_cmd_rsp - SCSI Command Response processing |
229 | * @conn: iscsi connection | 246 | * @conn: iscsi connection |
@@ -235,21 +252,15 @@ static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) | |||
235 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and | 252 | * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and |
236 | * then completes the command and task. | 253 | * then completes the command and task. |
237 | **/ | 254 | **/ |
238 | static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 255 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
239 | struct iscsi_cmd_task *ctask, char *data, | 256 | struct iscsi_cmd_task *ctask, char *data, |
240 | int datalen) | 257 | int datalen) |
241 | { | 258 | { |
242 | int rc; | ||
243 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; | 259 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; |
244 | struct iscsi_session *session = conn->session; | 260 | struct iscsi_session *session = conn->session; |
245 | struct scsi_cmnd *sc = ctask->sc; | 261 | struct scsi_cmnd *sc = ctask->sc; |
246 | 262 | ||
247 | rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); | 263 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
248 | if (rc) { | ||
249 | sc->result = DID_ERROR << 16; | ||
250 | goto out; | ||
251 | } | ||
252 | |||
253 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; | 264 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; |
254 | 265 | ||
255 | sc->result = (DID_OK << 16) | rhdr->cmd_status; | 266 | sc->result = (DID_OK << 16) | rhdr->cmd_status; |
@@ -286,14 +297,14 @@ invalid_datalen: | |||
286 | if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { | 297 | if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { |
287 | int res_count = be32_to_cpu(rhdr->residual_count); | 298 | int res_count = be32_to_cpu(rhdr->residual_count); |
288 | 299 | ||
289 | if (res_count > 0 && res_count <= sc->request_bufflen) | 300 | if (res_count > 0 && res_count <= scsi_bufflen(sc)) |
290 | sc->resid = res_count; | 301 | scsi_set_resid(sc, res_count); |
291 | else | 302 | else |
292 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | 303 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
293 | } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) | 304 | } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) |
294 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; | 305 | sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; |
295 | else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) | 306 | else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) |
296 | sc->resid = be32_to_cpu(rhdr->residual_count); | 307 | scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); |
297 | 308 | ||
298 | out: | 309 | out: |
299 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", | 310 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
@@ -301,7 +312,6 @@ out: | |||
301 | conn->scsirsp_pdus_cnt++; | 312 | conn->scsirsp_pdus_cnt++; |
302 | 313 | ||
303 | __iscsi_put_ctask(ctask); | 314 | __iscsi_put_ctask(ctask); |
304 | return rc; | ||
305 | } | 315 | } |
306 | 316 | ||
307 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 317 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
@@ -381,8 +391,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
381 | switch(opcode) { | 391 | switch(opcode) { |
382 | case ISCSI_OP_SCSI_CMD_RSP: | 392 | case ISCSI_OP_SCSI_CMD_RSP: |
383 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 393 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
384 | rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, | 394 | iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, |
385 | datalen); | 395 | datalen); |
386 | break; | 396 | break; |
387 | case ISCSI_OP_SCSI_DATA_IN: | 397 | case ISCSI_OP_SCSI_DATA_IN: |
388 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | 398 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); |
@@ -405,11 +415,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
405 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", | 415 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", |
406 | opcode, conn->id, mtask->itt, datalen); | 416 | opcode, conn->id, mtask->itt, datalen); |
407 | 417 | ||
408 | rc = iscsi_check_assign_cmdsn(session, | 418 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
409 | (struct iscsi_nopin*)hdr); | ||
410 | if (rc) | ||
411 | goto done; | ||
412 | |||
413 | switch(opcode) { | 419 | switch(opcode) { |
414 | case ISCSI_OP_LOGOUT_RSP: | 420 | case ISCSI_OP_LOGOUT_RSP: |
415 | if (datalen) { | 421 | if (datalen) { |
@@ -458,10 +464,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
458 | break; | 464 | break; |
459 | } | 465 | } |
460 | } else if (itt == ~0U) { | 466 | } else if (itt == ~0U) { |
461 | rc = iscsi_check_assign_cmdsn(session, | 467 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
462 | (struct iscsi_nopin*)hdr); | ||
463 | if (rc) | ||
464 | goto done; | ||
465 | 468 | ||
466 | switch(opcode) { | 469 | switch(opcode) { |
467 | case ISCSI_OP_NOOP_IN: | 470 | case ISCSI_OP_NOOP_IN: |
@@ -491,7 +494,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
491 | } else | 494 | } else |
492 | rc = ISCSI_ERR_BAD_ITT; | 495 | rc = ISCSI_ERR_BAD_ITT; |
493 | 496 | ||
494 | done: | ||
495 | return rc; | 497 | return rc; |
496 | } | 498 | } |
497 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | 499 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); |
@@ -578,17 +580,47 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | |||
578 | } | 580 | } |
579 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); | 581 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
580 | 582 | ||
583 | static void iscsi_prep_mtask(struct iscsi_conn *conn, | ||
584 | struct iscsi_mgmt_task *mtask) | ||
585 | { | ||
586 | struct iscsi_session *session = conn->session; | ||
587 | struct iscsi_hdr *hdr = mtask->hdr; | ||
588 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
589 | |||
590 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
591 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
592 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
593 | /* | ||
594 | * pre-format CmdSN for outgoing PDU. | ||
595 | */ | ||
596 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
597 | if (hdr->itt != RESERVED_ITT) { | ||
598 | hdr->itt = build_itt(mtask->itt, conn->id, session->age); | ||
599 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
600 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) | ||
601 | session->cmdsn++; | ||
602 | } | ||
603 | |||
604 | if (session->tt->init_mgmt_task) | ||
605 | session->tt->init_mgmt_task(conn, mtask); | ||
606 | |||
607 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
608 | hdr->opcode, hdr->itt, mtask->data_count); | ||
609 | } | ||
610 | |||
581 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | 611 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) |
582 | { | 612 | { |
583 | struct iscsi_hdr *hdr = conn->mtask->hdr; | 613 | struct iscsi_hdr *hdr = conn->mtask->hdr; |
584 | int rc, was_logout = 0; | 614 | int rc, was_logout = 0; |
585 | 615 | ||
616 | spin_unlock_bh(&conn->session->lock); | ||
586 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { | 617 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { |
587 | conn->session->state = ISCSI_STATE_IN_RECOVERY; | 618 | conn->session->state = ISCSI_STATE_IN_RECOVERY; |
588 | iscsi_block_session(session_to_cls(conn->session)); | 619 | iscsi_block_session(session_to_cls(conn->session)); |
589 | was_logout = 1; | 620 | was_logout = 1; |
590 | } | 621 | } |
591 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | 622 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); |
623 | spin_lock_bh(&conn->session->lock); | ||
592 | if (rc) | 624 | if (rc) |
593 | return rc; | 625 | return rc; |
594 | 626 | ||
@@ -602,6 +634,45 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) | |||
602 | return 0; | 634 | return 0; |
603 | } | 635 | } |
604 | 636 | ||
637 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | ||
638 | { | ||
639 | struct iscsi_session *session = conn->session; | ||
640 | |||
641 | /* | ||
642 | * Check for iSCSI window and take care of CmdSN wrap-around | ||
643 | */ | ||
644 | if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) { | ||
645 | debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n", | ||
646 | session->max_cmdsn, session->cmdsn); | ||
647 | return -ENOSPC; | ||
648 | } | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) | ||
653 | { | ||
654 | struct iscsi_cmd_task *ctask = conn->ctask; | ||
655 | int rc = 0; | ||
656 | |||
657 | /* | ||
658 | * serialize with TMF AbortTask | ||
659 | */ | ||
660 | if (ctask->state == ISCSI_TASK_ABORTING) | ||
661 | goto done; | ||
662 | |||
663 | __iscsi_get_ctask(ctask); | ||
664 | spin_unlock_bh(&conn->session->lock); | ||
665 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); | ||
666 | spin_lock_bh(&conn->session->lock); | ||
667 | __iscsi_put_ctask(ctask); | ||
668 | |||
669 | done: | ||
670 | if (!rc) | ||
671 | /* done with this ctask */ | ||
672 | conn->ctask = NULL; | ||
673 | return rc; | ||
674 | } | ||
675 | |||
605 | /** | 676 | /** |
606 | * iscsi_data_xmit - xmit any command into the scheduled connection | 677 | * iscsi_data_xmit - xmit any command into the scheduled connection |
607 | * @conn: iscsi connection | 678 | * @conn: iscsi connection |
@@ -613,106 +684,79 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) | |||
613 | **/ | 684 | **/ |
614 | static int iscsi_data_xmit(struct iscsi_conn *conn) | 685 | static int iscsi_data_xmit(struct iscsi_conn *conn) |
615 | { | 686 | { |
616 | struct iscsi_transport *tt; | ||
617 | int rc = 0; | 687 | int rc = 0; |
618 | 688 | ||
689 | spin_lock_bh(&conn->session->lock); | ||
619 | if (unlikely(conn->suspend_tx)) { | 690 | if (unlikely(conn->suspend_tx)) { |
620 | debug_scsi("conn %d Tx suspended!\n", conn->id); | 691 | debug_scsi("conn %d Tx suspended!\n", conn->id); |
692 | spin_unlock_bh(&conn->session->lock); | ||
621 | return -ENODATA; | 693 | return -ENODATA; |
622 | } | 694 | } |
623 | tt = conn->session->tt; | ||
624 | |||
625 | /* | ||
626 | * Transmit in the following order: | ||
627 | * | ||
628 | * 1) un-finished xmit (ctask or mtask) | ||
629 | * 2) immediate control PDUs | ||
630 | * 3) write data | ||
631 | * 4) SCSI commands | ||
632 | * 5) non-immediate control PDUs | ||
633 | * | ||
634 | * No need to lock around __kfifo_get as long as | ||
635 | * there's one producer and one consumer. | ||
636 | */ | ||
637 | |||
638 | BUG_ON(conn->ctask && conn->mtask); | ||
639 | 695 | ||
640 | if (conn->ctask) { | 696 | if (conn->ctask) { |
641 | iscsi_get_ctask(conn->ctask); | 697 | rc = iscsi_xmit_ctask(conn); |
642 | rc = tt->xmit_cmd_task(conn, conn->ctask); | ||
643 | iscsi_put_ctask(conn->ctask); | ||
644 | if (rc) | 698 | if (rc) |
645 | goto again; | 699 | goto again; |
646 | /* done with this in-progress ctask */ | ||
647 | conn->ctask = NULL; | ||
648 | } | 700 | } |
701 | |||
649 | if (conn->mtask) { | 702 | if (conn->mtask) { |
650 | rc = iscsi_xmit_mtask(conn); | 703 | rc = iscsi_xmit_mtask(conn); |
651 | if (rc) | 704 | if (rc) |
652 | goto again; | 705 | goto again; |
653 | } | 706 | } |
654 | 707 | ||
655 | /* process immediate first */ | 708 | /* |
656 | if (unlikely(__kfifo_len(conn->immqueue))) { | 709 | * process mgmt pdus like nops before commands since we should |
657 | while (__kfifo_get(conn->immqueue, (void*)&conn->mtask, | 710 | * only have one nop-out as a ping from us and targets should not |
658 | sizeof(void*))) { | 711 | * overflow us with nop-ins |
659 | spin_lock_bh(&conn->session->lock); | 712 | */ |
660 | list_add_tail(&conn->mtask->running, | 713 | check_mgmt: |
661 | &conn->mgmt_run_list); | 714 | while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, |
662 | spin_unlock_bh(&conn->session->lock); | 715 | sizeof(void*))) { |
663 | rc = iscsi_xmit_mtask(conn); | 716 | iscsi_prep_mtask(conn, conn->mtask); |
664 | if (rc) | 717 | list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); |
665 | goto again; | 718 | rc = iscsi_xmit_mtask(conn); |
666 | } | 719 | if (rc) |
720 | goto again; | ||
667 | } | 721 | } |
668 | 722 | ||
669 | /* process command queue */ | 723 | /* process command queue */ |
670 | spin_lock_bh(&conn->session->lock); | ||
671 | while (!list_empty(&conn->xmitqueue)) { | 724 | while (!list_empty(&conn->xmitqueue)) { |
725 | rc = iscsi_check_cmdsn_window_closed(conn); | ||
726 | if (rc) { | ||
727 | spin_unlock_bh(&conn->session->lock); | ||
728 | return rc; | ||
729 | } | ||
672 | /* | 730 | /* |
673 | * iscsi tcp may readd the task to the xmitqueue to send | 731 | * iscsi tcp may readd the task to the xmitqueue to send |
674 | * write data | 732 | * write data |
675 | */ | 733 | */ |
676 | conn->ctask = list_entry(conn->xmitqueue.next, | 734 | conn->ctask = list_entry(conn->xmitqueue.next, |
677 | struct iscsi_cmd_task, running); | 735 | struct iscsi_cmd_task, running); |
736 | if (conn->ctask->state == ISCSI_TASK_PENDING) { | ||
737 | iscsi_prep_scsi_cmd_pdu(conn->ctask); | ||
738 | conn->session->tt->init_cmd_task(conn->ctask); | ||
739 | } | ||
678 | conn->ctask->state = ISCSI_TASK_RUNNING; | 740 | conn->ctask->state = ISCSI_TASK_RUNNING; |
679 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | 741 | list_move_tail(conn->xmitqueue.next, &conn->run_list); |
680 | __iscsi_get_ctask(conn->ctask); | 742 | rc = iscsi_xmit_ctask(conn); |
681 | spin_unlock_bh(&conn->session->lock); | 743 | if (rc) |
682 | |||
683 | rc = tt->xmit_cmd_task(conn, conn->ctask); | ||
684 | |||
685 | spin_lock_bh(&conn->session->lock); | ||
686 | __iscsi_put_ctask(conn->ctask); | ||
687 | if (rc) { | ||
688 | spin_unlock_bh(&conn->session->lock); | ||
689 | goto again; | 744 | goto again; |
690 | } | 745 | /* |
746 | * we could continuously get new ctask requests so | ||
747 | * we need to check the mgmt queue for nops that need to | ||
748 | * be sent to aviod starvation | ||
749 | */ | ||
750 | if (__kfifo_len(conn->mgmtqueue)) | ||
751 | goto check_mgmt; | ||
691 | } | 752 | } |
692 | spin_unlock_bh(&conn->session->lock); | 753 | spin_unlock_bh(&conn->session->lock); |
693 | /* done with this ctask */ | ||
694 | conn->ctask = NULL; | ||
695 | |||
696 | /* process the rest control plane PDUs, if any */ | ||
697 | if (unlikely(__kfifo_len(conn->mgmtqueue))) { | ||
698 | while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, | ||
699 | sizeof(void*))) { | ||
700 | spin_lock_bh(&conn->session->lock); | ||
701 | list_add_tail(&conn->mtask->running, | ||
702 | &conn->mgmt_run_list); | ||
703 | spin_unlock_bh(&conn->session->lock); | ||
704 | rc = iscsi_xmit_mtask(conn); | ||
705 | if (rc) | ||
706 | goto again; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | return -ENODATA; | 754 | return -ENODATA; |
711 | 755 | ||
712 | again: | 756 | again: |
713 | if (unlikely(conn->suspend_tx)) | 757 | if (unlikely(conn->suspend_tx)) |
714 | return -ENODATA; | 758 | rc = -ENODATA; |
715 | 759 | spin_unlock_bh(&conn->session->lock); | |
716 | return rc; | 760 | return rc; |
717 | } | 761 | } |
718 | 762 | ||
@@ -724,11 +768,9 @@ static void iscsi_xmitworker(struct work_struct *work) | |||
724 | /* | 768 | /* |
725 | * serialize Xmit worker on a per-connection basis. | 769 | * serialize Xmit worker on a per-connection basis. |
726 | */ | 770 | */ |
727 | mutex_lock(&conn->xmitmutex); | ||
728 | do { | 771 | do { |
729 | rc = iscsi_data_xmit(conn); | 772 | rc = iscsi_data_xmit(conn); |
730 | } while (rc >= 0 || rc == -EAGAIN); | 773 | } while (rc >= 0 || rc == -EAGAIN); |
731 | mutex_unlock(&conn->xmitmutex); | ||
732 | } | 774 | } |
733 | 775 | ||
734 | enum { | 776 | enum { |
@@ -786,20 +828,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
786 | goto fault; | 828 | goto fault; |
787 | } | 829 | } |
788 | 830 | ||
789 | /* | ||
790 | * Check for iSCSI window and take care of CmdSN wrap-around | ||
791 | */ | ||
792 | if ((int)(session->max_cmdsn - session->cmdsn) < 0) { | ||
793 | reason = FAILURE_WINDOW_CLOSED; | ||
794 | goto reject; | ||
795 | } | ||
796 | |||
797 | conn = session->leadconn; | 831 | conn = session->leadconn; |
798 | if (!conn) { | 832 | if (!conn) { |
799 | reason = FAILURE_SESSION_FREED; | 833 | reason = FAILURE_SESSION_FREED; |
800 | goto fault; | 834 | goto fault; |
801 | } | 835 | } |
802 | 836 | ||
837 | /* | ||
838 | * We check this here and in data xmit, because if we get to the point | ||
839 | * that this check is hitting the window then we have enough IO in | ||
840 | * flight and enough IO waiting to be transmitted it is better | ||
841 | * to let the scsi/block layer queue up. | ||
842 | */ | ||
843 | if (iscsi_check_cmdsn_window_closed(conn)) { | ||
844 | reason = FAILURE_WINDOW_CLOSED; | ||
845 | goto reject; | ||
846 | } | ||
847 | |||
803 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, | 848 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, |
804 | sizeof(void*))) { | 849 | sizeof(void*))) { |
805 | reason = FAILURE_OOM; | 850 | reason = FAILURE_OOM; |
@@ -814,18 +859,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
814 | ctask->conn = conn; | 859 | ctask->conn = conn; |
815 | ctask->sc = sc; | 860 | ctask->sc = sc; |
816 | INIT_LIST_HEAD(&ctask->running); | 861 | INIT_LIST_HEAD(&ctask->running); |
817 | ctask->total_length = sc->request_bufflen; | ||
818 | iscsi_prep_scsi_cmd_pdu(ctask); | ||
819 | |||
820 | session->tt->init_cmd_task(ctask); | ||
821 | 862 | ||
822 | list_add_tail(&ctask->running, &conn->xmitqueue); | 863 | list_add_tail(&ctask->running, &conn->xmitqueue); |
823 | debug_scsi( | ||
824 | "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " | ||
825 | "win %d]\n", | ||
826 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | ||
827 | conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, | ||
828 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | ||
829 | spin_unlock(&session->lock); | 864 | spin_unlock(&session->lock); |
830 | 865 | ||
831 | scsi_queue_work(host, &conn->xmitwork); | 866 | scsi_queue_work(host, &conn->xmitwork); |
@@ -841,7 +876,7 @@ fault: | |||
841 | printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", | 876 | printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", |
842 | sc->cmnd[0], reason); | 877 | sc->cmnd[0], reason); |
843 | sc->result = (DID_NO_CONNECT << 16); | 878 | sc->result = (DID_NO_CONNECT << 16); |
844 | sc->resid = sc->request_bufflen; | 879 | scsi_set_resid(sc, scsi_bufflen(sc)); |
845 | sc->scsi_done(sc); | 880 | sc->scsi_done(sc); |
846 | return 0; | 881 | return 0; |
847 | } | 882 | } |
@@ -856,19 +891,16 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) | |||
856 | } | 891 | } |
857 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | 892 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); |
858 | 893 | ||
859 | static int | 894 | static struct iscsi_mgmt_task * |
860 | iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 895 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
861 | char *data, uint32_t data_size) | 896 | char *data, uint32_t data_size) |
862 | { | 897 | { |
863 | struct iscsi_session *session = conn->session; | 898 | struct iscsi_session *session = conn->session; |
864 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
865 | struct iscsi_mgmt_task *mtask; | 899 | struct iscsi_mgmt_task *mtask; |
866 | 900 | ||
867 | spin_lock_bh(&session->lock); | 901 | if (session->state == ISCSI_STATE_TERMINATE) |
868 | if (session->state == ISCSI_STATE_TERMINATE) { | 902 | return NULL; |
869 | spin_unlock_bh(&session->lock); | 903 | |
870 | return -EPERM; | ||
871 | } | ||
872 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || | 904 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || |
873 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | 905 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) |
874 | /* | 906 | /* |
@@ -882,27 +914,11 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
882 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | 914 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); |
883 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | 915 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); |
884 | 916 | ||
885 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
886 | if (!__kfifo_get(session->mgmtpool.queue, | 917 | if (!__kfifo_get(session->mgmtpool.queue, |
887 | (void*)&mtask, sizeof(void*))) { | 918 | (void*)&mtask, sizeof(void*))) |
888 | spin_unlock_bh(&session->lock); | 919 | return NULL; |
889 | return -ENOSPC; | ||
890 | } | ||
891 | } | 920 | } |
892 | 921 | ||
893 | /* | ||
894 | * pre-format CmdSN for outgoing PDU. | ||
895 | */ | ||
896 | if (hdr->itt != RESERVED_ITT) { | ||
897 | hdr->itt = build_itt(mtask->itt, conn->id, session->age); | ||
898 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
899 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
900 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) | ||
901 | session->cmdsn++; | ||
902 | } else | ||
903 | /* do not advance CmdSN */ | ||
904 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
905 | |||
906 | if (data_size) { | 922 | if (data_size) { |
907 | memcpy(mtask->data, data, data_size); | 923 | memcpy(mtask->data, data, data_size); |
908 | mtask->data_count = data_size; | 924 | mtask->data_count = data_size; |
@@ -911,38 +927,23 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
911 | 927 | ||
912 | INIT_LIST_HEAD(&mtask->running); | 928 | INIT_LIST_HEAD(&mtask->running); |
913 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | 929 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); |
914 | if (session->tt->init_mgmt_task) | 930 | __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); |
915 | session->tt->init_mgmt_task(conn, mtask, data, data_size); | 931 | return mtask; |
916 | spin_unlock_bh(&session->lock); | ||
917 | |||
918 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
919 | hdr->opcode, hdr->itt, data_size); | ||
920 | |||
921 | /* | ||
922 | * since send_pdu() could be called at least from two contexts, | ||
923 | * we need to serialize __kfifo_put, so we don't have to take | ||
924 | * additional lock on fast data-path | ||
925 | */ | ||
926 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) | ||
927 | __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); | ||
928 | else | ||
929 | __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); | ||
930 | |||
931 | scsi_queue_work(session->host, &conn->xmitwork); | ||
932 | return 0; | ||
933 | } | 932 | } |
934 | 933 | ||
935 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | 934 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, |
936 | char *data, uint32_t data_size) | 935 | char *data, uint32_t data_size) |
937 | { | 936 | { |
938 | struct iscsi_conn *conn = cls_conn->dd_data; | 937 | struct iscsi_conn *conn = cls_conn->dd_data; |
939 | int rc; | 938 | struct iscsi_session *session = conn->session; |
940 | 939 | int err = 0; | |
941 | mutex_lock(&conn->xmitmutex); | ||
942 | rc = iscsi_conn_send_generic(conn, hdr, data, data_size); | ||
943 | mutex_unlock(&conn->xmitmutex); | ||
944 | 940 | ||
945 | return rc; | 941 | spin_lock_bh(&session->lock); |
942 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | ||
943 | err = -EPERM; | ||
944 | spin_unlock_bh(&session->lock); | ||
945 | scsi_queue_work(session->host, &conn->xmitwork); | ||
946 | return err; | ||
946 | } | 947 | } |
947 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | 948 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); |
948 | 949 | ||
@@ -1027,14 +1028,12 @@ static void iscsi_tmabort_timedout(unsigned long data) | |||
1027 | spin_unlock(&session->lock); | 1028 | spin_unlock(&session->lock); |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | /* must be called with the mutex lock */ | ||
1031 | static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | 1031 | static int iscsi_exec_abort_task(struct scsi_cmnd *sc, |
1032 | struct iscsi_cmd_task *ctask) | 1032 | struct iscsi_cmd_task *ctask) |
1033 | { | 1033 | { |
1034 | struct iscsi_conn *conn = ctask->conn; | 1034 | struct iscsi_conn *conn = ctask->conn; |
1035 | struct iscsi_session *session = conn->session; | 1035 | struct iscsi_session *session = conn->session; |
1036 | struct iscsi_tm *hdr = &conn->tmhdr; | 1036 | struct iscsi_tm *hdr = &conn->tmhdr; |
1037 | int rc; | ||
1038 | 1037 | ||
1039 | /* | 1038 | /* |
1040 | * ctask timed out but session is OK requests must be serialized. | 1039 | * ctask timed out but session is OK requests must be serialized. |
@@ -1047,32 +1046,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1047 | hdr->rtt = ctask->hdr->itt; | 1046 | hdr->rtt = ctask->hdr->itt; |
1048 | hdr->refcmdsn = ctask->hdr->cmdsn; | 1047 | hdr->refcmdsn = ctask->hdr->cmdsn; |
1049 | 1048 | ||
1050 | rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, | 1049 | ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1051 | NULL, 0); | 1050 | NULL, 0); |
1052 | if (rc) { | 1051 | if (!ctask->mtask) { |
1053 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1052 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1054 | debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt, | 1053 | debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); |
1055 | rc); | 1054 | return -EPERM; |
1056 | return rc; | ||
1057 | } | 1055 | } |
1056 | ctask->state = ISCSI_TASK_ABORTING; | ||
1058 | 1057 | ||
1059 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); | 1058 | debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); |
1060 | 1059 | ||
1061 | spin_lock_bh(&session->lock); | ||
1062 | ctask->mtask = (struct iscsi_mgmt_task *) | ||
1063 | session->mgmt_cmds[get_itt(hdr->itt) - | ||
1064 | ISCSI_MGMT_ITT_OFFSET]; | ||
1065 | |||
1066 | if (conn->tmabort_state == TMABORT_INITIAL) { | 1060 | if (conn->tmabort_state == TMABORT_INITIAL) { |
1067 | conn->tmfcmd_pdus_cnt++; | 1061 | conn->tmfcmd_pdus_cnt++; |
1068 | conn->tmabort_timer.expires = 10*HZ + jiffies; | 1062 | conn->tmabort_timer.expires = 20*HZ + jiffies; |
1069 | conn->tmabort_timer.function = iscsi_tmabort_timedout; | 1063 | conn->tmabort_timer.function = iscsi_tmabort_timedout; |
1070 | conn->tmabort_timer.data = (unsigned long)ctask; | 1064 | conn->tmabort_timer.data = (unsigned long)ctask; |
1071 | add_timer(&conn->tmabort_timer); | 1065 | add_timer(&conn->tmabort_timer); |
1072 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); | 1066 | debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); |
1073 | } | 1067 | } |
1074 | spin_unlock_bh(&session->lock); | 1068 | spin_unlock_bh(&session->lock); |
1075 | mutex_unlock(&conn->xmitmutex); | 1069 | scsi_queue_work(session->host, &conn->xmitwork); |
1076 | 1070 | ||
1077 | /* | 1071 | /* |
1078 | * block eh thread until: | 1072 | * block eh thread until: |
@@ -1089,13 +1083,12 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, | |||
1089 | if (signal_pending(current)) | 1083 | if (signal_pending(current)) |
1090 | flush_signals(current); | 1084 | flush_signals(current); |
1091 | del_timer_sync(&conn->tmabort_timer); | 1085 | del_timer_sync(&conn->tmabort_timer); |
1092 | 1086 | spin_lock_bh(&session->lock); | |
1093 | mutex_lock(&conn->xmitmutex); | ||
1094 | return 0; | 1087 | return 0; |
1095 | } | 1088 | } |
1096 | 1089 | ||
1097 | /* | 1090 | /* |
1098 | * xmit mutex and session lock must be held | 1091 | * session lock must be held |
1099 | */ | 1092 | */ |
1100 | static struct iscsi_mgmt_task * | 1093 | static struct iscsi_mgmt_task * |
1101 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) | 1094 | iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) |
@@ -1127,7 +1120,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | |||
1127 | if (!ctask->mtask) | 1120 | if (!ctask->mtask) |
1128 | return -EINVAL; | 1121 | return -EINVAL; |
1129 | 1122 | ||
1130 | if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt)) | 1123 | if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt)) |
1131 | list_del(&ctask->mtask->running); | 1124 | list_del(&ctask->mtask->running); |
1132 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, | 1125 | __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, |
1133 | sizeof(void*)); | 1126 | sizeof(void*)); |
@@ -1136,7 +1129,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) | |||
1136 | } | 1129 | } |
1137 | 1130 | ||
1138 | /* | 1131 | /* |
1139 | * session lock and xmitmutex must be held | 1132 | * session lock must be held |
1140 | */ | 1133 | */ |
1141 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 1134 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, |
1142 | int err) | 1135 | int err) |
@@ -1147,11 +1140,14 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1147 | if (!sc) | 1140 | if (!sc) |
1148 | return; | 1141 | return; |
1149 | 1142 | ||
1150 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 1143 | if (ctask->state != ISCSI_TASK_PENDING) |
1144 | conn->session->tt->cleanup_cmd_task(conn, ctask); | ||
1151 | iscsi_ctask_mtask_cleanup(ctask); | 1145 | iscsi_ctask_mtask_cleanup(ctask); |
1152 | 1146 | ||
1153 | sc->result = err; | 1147 | sc->result = err; |
1154 | sc->resid = sc->request_bufflen; | 1148 | scsi_set_resid(sc, scsi_bufflen(sc)); |
1149 | if (conn->ctask == ctask) | ||
1150 | conn->ctask = NULL; | ||
1155 | /* release ref from queuecommand */ | 1151 | /* release ref from queuecommand */ |
1156 | __iscsi_put_ctask(ctask); | 1152 | __iscsi_put_ctask(ctask); |
1157 | } | 1153 | } |
@@ -1179,7 +1175,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1179 | conn->eh_abort_cnt++; | 1175 | conn->eh_abort_cnt++; |
1180 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1176 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); |
1181 | 1177 | ||
1182 | mutex_lock(&conn->xmitmutex); | ||
1183 | spin_lock_bh(&session->lock); | 1178 | spin_lock_bh(&session->lock); |
1184 | 1179 | ||
1185 | /* | 1180 | /* |
@@ -1192,9 +1187,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1192 | 1187 | ||
1193 | /* ctask completed before time out */ | 1188 | /* ctask completed before time out */ |
1194 | if (!ctask->sc) { | 1189 | if (!ctask->sc) { |
1195 | spin_unlock_bh(&session->lock); | ||
1196 | debug_scsi("sc completed while abort in progress\n"); | 1190 | debug_scsi("sc completed while abort in progress\n"); |
1197 | goto success_rel_mutex; | 1191 | goto success; |
1198 | } | 1192 | } |
1199 | 1193 | ||
1200 | /* what should we do here ? */ | 1194 | /* what should we do here ? */ |
@@ -1204,15 +1198,13 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1204 | goto failed; | 1198 | goto failed; |
1205 | } | 1199 | } |
1206 | 1200 | ||
1207 | if (ctask->state == ISCSI_TASK_PENDING) | 1201 | if (ctask->state == ISCSI_TASK_PENDING) { |
1208 | goto success_cleanup; | 1202 | fail_command(conn, ctask, DID_ABORT << 16); |
1203 | goto success; | ||
1204 | } | ||
1209 | 1205 | ||
1210 | conn->tmabort_state = TMABORT_INITIAL; | 1206 | conn->tmabort_state = TMABORT_INITIAL; |
1211 | |||
1212 | spin_unlock_bh(&session->lock); | ||
1213 | rc = iscsi_exec_abort_task(sc, ctask); | 1207 | rc = iscsi_exec_abort_task(sc, ctask); |
1214 | spin_lock_bh(&session->lock); | ||
1215 | |||
1216 | if (rc || sc->SCp.phase != session->age || | 1208 | if (rc || sc->SCp.phase != session->age || |
1217 | session->state != ISCSI_STATE_LOGGED_IN) | 1209 | session->state != ISCSI_STATE_LOGGED_IN) |
1218 | goto failed; | 1210 | goto failed; |
@@ -1220,45 +1212,44 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1220 | 1212 | ||
1221 | switch (conn->tmabort_state) { | 1213 | switch (conn->tmabort_state) { |
1222 | case TMABORT_SUCCESS: | 1214 | case TMABORT_SUCCESS: |
1223 | goto success_cleanup; | 1215 | spin_unlock_bh(&session->lock); |
1216 | /* | ||
1217 | * clean up task if aborted. grab the recv lock as a writer | ||
1218 | */ | ||
1219 | write_lock_bh(conn->recv_lock); | ||
1220 | spin_lock(&session->lock); | ||
1221 | fail_command(conn, ctask, DID_ABORT << 16); | ||
1222 | spin_unlock(&session->lock); | ||
1223 | write_unlock_bh(conn->recv_lock); | ||
1224 | /* | ||
1225 | * make sure xmit thread is not still touching the | ||
1226 | * ctask/scsi_cmnd | ||
1227 | */ | ||
1228 | scsi_flush_work(session->host); | ||
1229 | goto success_unlocked; | ||
1224 | case TMABORT_NOT_FOUND: | 1230 | case TMABORT_NOT_FOUND: |
1225 | if (!ctask->sc) { | 1231 | if (!ctask->sc) { |
1226 | /* ctask completed before tmf abort response */ | 1232 | /* ctask completed before tmf abort response */ |
1227 | spin_unlock_bh(&session->lock); | ||
1228 | debug_scsi("sc completed while abort in progress\n"); | 1233 | debug_scsi("sc completed while abort in progress\n"); |
1229 | goto success_rel_mutex; | 1234 | goto success; |
1230 | } | 1235 | } |
1231 | /* fall through */ | 1236 | /* fall through */ |
1232 | default: | 1237 | default: |
1233 | /* timedout or failed */ | 1238 | /* timedout or failed */ |
1234 | spin_unlock_bh(&session->lock); | 1239 | spin_unlock_bh(&session->lock); |
1235 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1240 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1236 | spin_lock_bh(&session->lock); | 1241 | goto failed_unlocked; |
1237 | goto failed; | ||
1238 | } | 1242 | } |
1239 | 1243 | ||
1240 | success_cleanup: | 1244 | success: |
1241 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | ||
1242 | spin_unlock_bh(&session->lock); | 1245 | spin_unlock_bh(&session->lock); |
1243 | 1246 | success_unlocked: | |
1244 | /* | 1247 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1245 | * clean up task if aborted. we have the xmitmutex so grab | ||
1246 | * the recv lock as a writer | ||
1247 | */ | ||
1248 | write_lock_bh(conn->recv_lock); | ||
1249 | spin_lock(&session->lock); | ||
1250 | fail_command(conn, ctask, DID_ABORT << 16); | ||
1251 | spin_unlock(&session->lock); | ||
1252 | write_unlock_bh(conn->recv_lock); | ||
1253 | |||
1254 | success_rel_mutex: | ||
1255 | mutex_unlock(&conn->xmitmutex); | ||
1256 | return SUCCESS; | 1248 | return SUCCESS; |
1257 | 1249 | ||
1258 | failed: | 1250 | failed: |
1259 | spin_unlock_bh(&session->lock); | 1251 | spin_unlock_bh(&session->lock); |
1260 | mutex_unlock(&conn->xmitmutex); | 1252 | failed_unlocked: |
1261 | |||
1262 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1253 | debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); |
1263 | return FAILED; | 1254 | return FAILED; |
1264 | } | 1255 | } |
@@ -1339,6 +1330,10 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free); | |||
1339 | * iscsi_session_setup - create iscsi cls session and host and session | 1330 | * iscsi_session_setup - create iscsi cls session and host and session |
1340 | * @scsit: scsi transport template | 1331 | * @scsit: scsi transport template |
1341 | * @iscsit: iscsi transport template | 1332 | * @iscsit: iscsi transport template |
1333 | * @cmds_max: scsi host can queue | ||
1334 | * @qdepth: scsi host cmds per lun | ||
1335 | * @cmd_task_size: LLD ctask private data size | ||
1336 | * @mgmt_task_size: LLD mtask private data size | ||
1342 | * @initial_cmdsn: initial CmdSN | 1337 | * @initial_cmdsn: initial CmdSN |
1343 | * @hostno: host no allocated | 1338 | * @hostno: host no allocated |
1344 | * | 1339 | * |
@@ -1348,6 +1343,7 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free); | |||
1348 | struct iscsi_cls_session * | 1343 | struct iscsi_cls_session * |
1349 | iscsi_session_setup(struct iscsi_transport *iscsit, | 1344 | iscsi_session_setup(struct iscsi_transport *iscsit, |
1350 | struct scsi_transport_template *scsit, | 1345 | struct scsi_transport_template *scsit, |
1346 | uint16_t cmds_max, uint16_t qdepth, | ||
1351 | int cmd_task_size, int mgmt_task_size, | 1347 | int cmd_task_size, int mgmt_task_size, |
1352 | uint32_t initial_cmdsn, uint32_t *hostno) | 1348 | uint32_t initial_cmdsn, uint32_t *hostno) |
1353 | { | 1349 | { |
@@ -1356,11 +1352,32 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1356 | struct iscsi_cls_session *cls_session; | 1352 | struct iscsi_cls_session *cls_session; |
1357 | int cmd_i; | 1353 | int cmd_i; |
1358 | 1354 | ||
1355 | if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { | ||
1356 | if (qdepth != 0) | ||
1357 | printk(KERN_ERR "iscsi: invalid queue depth of %d. " | ||
1358 | "Queue depth must be between 1 and %d.\n", | ||
1359 | qdepth, ISCSI_MAX_CMD_PER_LUN); | ||
1360 | qdepth = ISCSI_DEF_CMD_PER_LUN; | ||
1361 | } | ||
1362 | |||
1363 | if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || | ||
1364 | cmds_max >= ISCSI_MGMT_ITT_OFFSET) { | ||
1365 | if (cmds_max != 0) | ||
1366 | printk(KERN_ERR "iscsi: invalid can_queue of %d. " | ||
1367 | "can_queue must be a power of 2 and between " | ||
1368 | "2 and %d - setting to %d.\n", cmds_max, | ||
1369 | ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX); | ||
1370 | cmds_max = ISCSI_DEF_XMIT_CMDS_MAX; | ||
1371 | } | ||
1372 | |||
1359 | shost = scsi_host_alloc(iscsit->host_template, | 1373 | shost = scsi_host_alloc(iscsit->host_template, |
1360 | hostdata_privsize(sizeof(*session))); | 1374 | hostdata_privsize(sizeof(*session))); |
1361 | if (!shost) | 1375 | if (!shost) |
1362 | return NULL; | 1376 | return NULL; |
1363 | 1377 | ||
1378 | /* the iscsi layer takes one task for reserve */ | ||
1379 | shost->can_queue = cmds_max - 1; | ||
1380 | shost->cmd_per_lun = qdepth; | ||
1364 | shost->max_id = 1; | 1381 | shost->max_id = 1; |
1365 | shost->max_channel = 0; | 1382 | shost->max_channel = 0; |
1366 | shost->max_lun = iscsit->max_lun; | 1383 | shost->max_lun = iscsit->max_lun; |
@@ -1374,7 +1391,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1374 | session->host = shost; | 1391 | session->host = shost; |
1375 | session->state = ISCSI_STATE_FREE; | 1392 | session->state = ISCSI_STATE_FREE; |
1376 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; | 1393 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; |
1377 | session->cmds_max = ISCSI_XMIT_CMDS_MAX; | 1394 | session->cmds_max = cmds_max; |
1378 | session->cmdsn = initial_cmdsn; | 1395 | session->cmdsn = initial_cmdsn; |
1379 | session->exp_cmdsn = initial_cmdsn + 1; | 1396 | session->exp_cmdsn = initial_cmdsn + 1; |
1380 | session->max_cmdsn = initial_cmdsn + 1; | 1397 | session->max_cmdsn = initial_cmdsn + 1; |
@@ -1461,7 +1478,14 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | |||
1461 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); | 1478 | iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); |
1462 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); | 1479 | iscsi_pool_free(&session->cmdpool, (void**)session->cmds); |
1463 | 1480 | ||
1481 | kfree(session->password); | ||
1482 | kfree(session->password_in); | ||
1483 | kfree(session->username); | ||
1484 | kfree(session->username_in); | ||
1464 | kfree(session->targetname); | 1485 | kfree(session->targetname); |
1486 | kfree(session->netdev); | ||
1487 | kfree(session->hwaddress); | ||
1488 | kfree(session->initiatorname); | ||
1465 | 1489 | ||
1466 | iscsi_destroy_session(cls_session); | 1490 | iscsi_destroy_session(cls_session); |
1467 | scsi_host_put(shost); | 1491 | scsi_host_put(shost); |
@@ -1499,11 +1523,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1499 | INIT_LIST_HEAD(&conn->xmitqueue); | 1523 | INIT_LIST_HEAD(&conn->xmitqueue); |
1500 | 1524 | ||
1501 | /* initialize general immediate & non-immediate PDU commands queue */ | 1525 | /* initialize general immediate & non-immediate PDU commands queue */ |
1502 | conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | ||
1503 | GFP_KERNEL, NULL); | ||
1504 | if (conn->immqueue == ERR_PTR(-ENOMEM)) | ||
1505 | goto immqueue_alloc_fail; | ||
1506 | |||
1507 | conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), | 1526 | conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), |
1508 | GFP_KERNEL, NULL); | 1527 | GFP_KERNEL, NULL); |
1509 | if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) | 1528 | if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) |
@@ -1527,7 +1546,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1527 | conn->login_mtask->data = conn->data = data; | 1546 | conn->login_mtask->data = conn->data = data; |
1528 | 1547 | ||
1529 | init_timer(&conn->tmabort_timer); | 1548 | init_timer(&conn->tmabort_timer); |
1530 | mutex_init(&conn->xmitmutex); | ||
1531 | init_waitqueue_head(&conn->ehwait); | 1549 | init_waitqueue_head(&conn->ehwait); |
1532 | 1550 | ||
1533 | return cls_conn; | 1551 | return cls_conn; |
@@ -1538,8 +1556,6 @@ login_mtask_data_alloc_fail: | |||
1538 | login_mtask_alloc_fail: | 1556 | login_mtask_alloc_fail: |
1539 | kfifo_free(conn->mgmtqueue); | 1557 | kfifo_free(conn->mgmtqueue); |
1540 | mgmtqueue_alloc_fail: | 1558 | mgmtqueue_alloc_fail: |
1541 | kfifo_free(conn->immqueue); | ||
1542 | immqueue_alloc_fail: | ||
1543 | iscsi_destroy_conn(cls_conn); | 1559 | iscsi_destroy_conn(cls_conn); |
1544 | return NULL; | 1560 | return NULL; |
1545 | } | 1561 | } |
@@ -1558,10 +1574,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1558 | struct iscsi_session *session = conn->session; | 1574 | struct iscsi_session *session = conn->session; |
1559 | unsigned long flags; | 1575 | unsigned long flags; |
1560 | 1576 | ||
1561 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1562 | mutex_lock(&conn->xmitmutex); | ||
1563 | |||
1564 | spin_lock_bh(&session->lock); | 1577 | spin_lock_bh(&session->lock); |
1578 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | ||
1565 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; | 1579 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; |
1566 | if (session->leadconn == conn) { | 1580 | if (session->leadconn == conn) { |
1567 | /* | 1581 | /* |
@@ -1572,8 +1586,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1572 | } | 1586 | } |
1573 | spin_unlock_bh(&session->lock); | 1587 | spin_unlock_bh(&session->lock); |
1574 | 1588 | ||
1575 | mutex_unlock(&conn->xmitmutex); | ||
1576 | |||
1577 | /* | 1589 | /* |
1578 | * Block until all in-progress commands for this connection | 1590 | * Block until all in-progress commands for this connection |
1579 | * time out or fail. | 1591 | * time out or fail. |
@@ -1610,7 +1622,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1610 | } | 1622 | } |
1611 | spin_unlock_bh(&session->lock); | 1623 | spin_unlock_bh(&session->lock); |
1612 | 1624 | ||
1613 | kfifo_free(conn->immqueue); | ||
1614 | kfifo_free(conn->mgmtqueue); | 1625 | kfifo_free(conn->mgmtqueue); |
1615 | 1626 | ||
1616 | iscsi_destroy_conn(cls_conn); | 1627 | iscsi_destroy_conn(cls_conn); |
@@ -1671,8 +1682,7 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | |||
1671 | struct iscsi_mgmt_task *mtask, *tmp; | 1682 | struct iscsi_mgmt_task *mtask, *tmp; |
1672 | 1683 | ||
1673 | /* handle pending */ | 1684 | /* handle pending */ |
1674 | while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || | 1685 | while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { |
1675 | __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { | ||
1676 | if (mtask == conn->login_mtask) | 1686 | if (mtask == conn->login_mtask) |
1677 | continue; | 1687 | continue; |
1678 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | 1688 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); |
@@ -1742,12 +1752,12 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1742 | conn->c_stage = ISCSI_CONN_STOPPED; | 1752 | conn->c_stage = ISCSI_CONN_STOPPED; |
1743 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1753 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1744 | spin_unlock_bh(&session->lock); | 1754 | spin_unlock_bh(&session->lock); |
1755 | scsi_flush_work(session->host); | ||
1745 | 1756 | ||
1746 | write_lock_bh(conn->recv_lock); | 1757 | write_lock_bh(conn->recv_lock); |
1747 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | 1758 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); |
1748 | write_unlock_bh(conn->recv_lock); | 1759 | write_unlock_bh(conn->recv_lock); |
1749 | 1760 | ||
1750 | mutex_lock(&conn->xmitmutex); | ||
1751 | /* | 1761 | /* |
1752 | * for connection level recovery we should not calculate | 1762 | * for connection level recovery we should not calculate |
1753 | * header digest. conn->hdr_size used for optimization | 1763 | * header digest. conn->hdr_size used for optimization |
@@ -1771,8 +1781,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1771 | fail_all_commands(conn); | 1781 | fail_all_commands(conn); |
1772 | flush_control_queues(session, conn); | 1782 | flush_control_queues(session, conn); |
1773 | spin_unlock_bh(&session->lock); | 1783 | spin_unlock_bh(&session->lock); |
1774 | |||
1775 | mutex_unlock(&conn->xmitmutex); | ||
1776 | } | 1784 | } |
1777 | 1785 | ||
1778 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1786 | void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
@@ -1867,6 +1875,30 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
1867 | case ISCSI_PARAM_EXP_STATSN: | 1875 | case ISCSI_PARAM_EXP_STATSN: |
1868 | sscanf(buf, "%u", &conn->exp_statsn); | 1876 | sscanf(buf, "%u", &conn->exp_statsn); |
1869 | break; | 1877 | break; |
1878 | case ISCSI_PARAM_USERNAME: | ||
1879 | kfree(session->username); | ||
1880 | session->username = kstrdup(buf, GFP_KERNEL); | ||
1881 | if (!session->username) | ||
1882 | return -ENOMEM; | ||
1883 | break; | ||
1884 | case ISCSI_PARAM_USERNAME_IN: | ||
1885 | kfree(session->username_in); | ||
1886 | session->username_in = kstrdup(buf, GFP_KERNEL); | ||
1887 | if (!session->username_in) | ||
1888 | return -ENOMEM; | ||
1889 | break; | ||
1890 | case ISCSI_PARAM_PASSWORD: | ||
1891 | kfree(session->password); | ||
1892 | session->password = kstrdup(buf, GFP_KERNEL); | ||
1893 | if (!session->password) | ||
1894 | return -ENOMEM; | ||
1895 | break; | ||
1896 | case ISCSI_PARAM_PASSWORD_IN: | ||
1897 | kfree(session->password_in); | ||
1898 | session->password_in = kstrdup(buf, GFP_KERNEL); | ||
1899 | if (!session->password_in) | ||
1900 | return -ENOMEM; | ||
1901 | break; | ||
1870 | case ISCSI_PARAM_TARGET_NAME: | 1902 | case ISCSI_PARAM_TARGET_NAME: |
1871 | /* this should not change between logins */ | 1903 | /* this should not change between logins */ |
1872 | if (session->targetname) | 1904 | if (session->targetname) |
@@ -1940,6 +1972,18 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
1940 | case ISCSI_PARAM_TPGT: | 1972 | case ISCSI_PARAM_TPGT: |
1941 | len = sprintf(buf, "%d\n", session->tpgt); | 1973 | len = sprintf(buf, "%d\n", session->tpgt); |
1942 | break; | 1974 | break; |
1975 | case ISCSI_PARAM_USERNAME: | ||
1976 | len = sprintf(buf, "%s\n", session->username); | ||
1977 | break; | ||
1978 | case ISCSI_PARAM_USERNAME_IN: | ||
1979 | len = sprintf(buf, "%s\n", session->username_in); | ||
1980 | break; | ||
1981 | case ISCSI_PARAM_PASSWORD: | ||
1982 | len = sprintf(buf, "%s\n", session->password); | ||
1983 | break; | ||
1984 | case ISCSI_PARAM_PASSWORD_IN: | ||
1985 | len = sprintf(buf, "%s\n", session->password_in); | ||
1986 | break; | ||
1943 | default: | 1987 | default: |
1944 | return -ENOSYS; | 1988 | return -ENOSYS; |
1945 | } | 1989 | } |
@@ -1990,6 +2034,66 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
1990 | } | 2034 | } |
1991 | EXPORT_SYMBOL_GPL(iscsi_conn_get_param); | 2035 | EXPORT_SYMBOL_GPL(iscsi_conn_get_param); |
1992 | 2036 | ||
2037 | int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | ||
2038 | char *buf) | ||
2039 | { | ||
2040 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2041 | int len; | ||
2042 | |||
2043 | switch (param) { | ||
2044 | case ISCSI_HOST_PARAM_NETDEV_NAME: | ||
2045 | if (!session->netdev) | ||
2046 | len = sprintf(buf, "%s\n", "default"); | ||
2047 | else | ||
2048 | len = sprintf(buf, "%s\n", session->netdev); | ||
2049 | break; | ||
2050 | case ISCSI_HOST_PARAM_HWADDRESS: | ||
2051 | if (!session->hwaddress) | ||
2052 | len = sprintf(buf, "%s\n", "default"); | ||
2053 | else | ||
2054 | len = sprintf(buf, "%s\n", session->hwaddress); | ||
2055 | break; | ||
2056 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | ||
2057 | if (!session->initiatorname) | ||
2058 | len = sprintf(buf, "%s\n", "unknown"); | ||
2059 | else | ||
2060 | len = sprintf(buf, "%s\n", session->initiatorname); | ||
2061 | break; | ||
2062 | |||
2063 | default: | ||
2064 | return -ENOSYS; | ||
2065 | } | ||
2066 | |||
2067 | return len; | ||
2068 | } | ||
2069 | EXPORT_SYMBOL_GPL(iscsi_host_get_param); | ||
2070 | |||
2071 | int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, | ||
2072 | char *buf, int buflen) | ||
2073 | { | ||
2074 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2075 | |||
2076 | switch (param) { | ||
2077 | case ISCSI_HOST_PARAM_NETDEV_NAME: | ||
2078 | if (!session->netdev) | ||
2079 | session->netdev = kstrdup(buf, GFP_KERNEL); | ||
2080 | break; | ||
2081 | case ISCSI_HOST_PARAM_HWADDRESS: | ||
2082 | if (!session->hwaddress) | ||
2083 | session->hwaddress = kstrdup(buf, GFP_KERNEL); | ||
2084 | break; | ||
2085 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | ||
2086 | if (!session->initiatorname) | ||
2087 | session->initiatorname = kstrdup(buf, GFP_KERNEL); | ||
2088 | break; | ||
2089 | default: | ||
2090 | return -ENOSYS; | ||
2091 | } | ||
2092 | |||
2093 | return 0; | ||
2094 | } | ||
2095 | EXPORT_SYMBOL_GPL(iscsi_host_set_param); | ||
2096 | |||
1993 | MODULE_AUTHOR("Mike Christie"); | 2097 | MODULE_AUTHOR("Mike Christie"); |
1994 | MODULE_DESCRIPTION("iSCSI library functions"); | 2098 | MODULE_DESCRIPTION("iSCSI library functions"); |
1995 | MODULE_LICENSE("GPL"); | 2099 | MODULE_LICENSE("GPL"); |