diff options
-rw-r--r-- | drivers/infiniband/ulp/iser/iscsi_iser.c | 4 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 4 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 331 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_iscsi.c | 4 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 11 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 8 |
6 files changed, 294 insertions, 68 deletions
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index a2622f4bd858..265606422278 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c | |||
@@ -577,7 +577,9 @@ static struct iscsi_transport iscsi_iser_transport = { | |||
577 | ISCSI_PERSISTENT_ADDRESS | | 577 | ISCSI_PERSISTENT_ADDRESS | |
578 | ISCSI_TARGET_NAME | ISCSI_TPGT | | 578 | ISCSI_TARGET_NAME | ISCSI_TPGT | |
579 | ISCSI_USERNAME | ISCSI_PASSWORD | | 579 | ISCSI_USERNAME | ISCSI_PASSWORD | |
580 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, | 580 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | |
581 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | | ||
582 | ISCSI_PING_TMO | ISCSI_RECV_TMO, | ||
581 | .host_param_mask = ISCSI_HOST_HWADDRESS | | 583 | .host_param_mask = ISCSI_HOST_HWADDRESS | |
582 | ISCSI_HOST_NETDEV_NAME | | 584 | ISCSI_HOST_NETDEV_NAME | |
583 | ISCSI_HOST_INITIATOR_NAME, | 585 | ISCSI_HOST_INITIATOR_NAME, |
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 90eae8e0d978..9b418522c9bf 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -2246,7 +2246,9 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
2246 | ISCSI_TARGET_NAME | ISCSI_TPGT | | 2246 | ISCSI_TARGET_NAME | ISCSI_TPGT | |
2247 | ISCSI_USERNAME | ISCSI_PASSWORD | | 2247 | ISCSI_USERNAME | ISCSI_PASSWORD | |
2248 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | | 2248 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | |
2249 | ISCSI_FAST_ABORT, | 2249 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | |
2250 | ISCSI_LU_RESET_TMO | | ||
2251 | ISCSI_PING_TMO | ISCSI_RECV_TMO, | ||
2250 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | | 2252 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | |
2251 | ISCSI_HOST_INITIATOR_NAME | | 2253 | ISCSI_HOST_INITIATOR_NAME | |
2252 | ISCSI_HOST_NETDEV_NAME, | 2254 | ISCSI_HOST_NETDEV_NAME, |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5205ef2c29b2..96883614ba08 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -313,11 +313,70 @@ void iscsi_free_mgmt_task(struct iscsi_conn *conn, | |||
313 | list_del_init(&mtask->running); | 313 | list_del_init(&mtask->running); |
314 | if (conn->login_mtask == mtask) | 314 | if (conn->login_mtask == mtask) |
315 | return; | 315 | return; |
316 | |||
317 | if (conn->ping_mtask == mtask) | ||
318 | conn->ping_mtask = NULL; | ||
316 | __kfifo_put(conn->session->mgmtpool.queue, | 319 | __kfifo_put(conn->session->mgmtpool.queue, |
317 | (void*)&mtask, sizeof(void*)); | 320 | (void*)&mtask, sizeof(void*)); |
318 | } | 321 | } |
319 | EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); | 322 | EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); |
320 | 323 | ||
324 | static struct iscsi_mgmt_task * | ||
325 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
326 | char *data, uint32_t data_size) | ||
327 | { | ||
328 | struct iscsi_session *session = conn->session; | ||
329 | struct iscsi_mgmt_task *mtask; | ||
330 | |||
331 | if (session->state == ISCSI_STATE_TERMINATE) | ||
332 | return NULL; | ||
333 | |||
334 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || | ||
335 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
336 | /* | ||
337 | * Login and Text are sent serially, in | ||
338 | * request-followed-by-response sequence. | ||
339 | * Same mtask can be used. Same ITT must be used. | ||
340 | * Note that login_mtask is preallocated at conn_create(). | ||
341 | */ | ||
342 | mtask = conn->login_mtask; | ||
343 | else { | ||
344 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | ||
345 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | ||
346 | |||
347 | if (!__kfifo_get(session->mgmtpool.queue, | ||
348 | (void*)&mtask, sizeof(void*))) | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | if (data_size) { | ||
353 | memcpy(mtask->data, data, data_size); | ||
354 | mtask->data_count = data_size; | ||
355 | } else | ||
356 | mtask->data_count = 0; | ||
357 | |||
358 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | ||
359 | INIT_LIST_HEAD(&mtask->running); | ||
360 | list_add_tail(&mtask->running, &conn->mgmtqueue); | ||
361 | return mtask; | ||
362 | } | ||
363 | |||
364 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | ||
365 | char *data, uint32_t data_size) | ||
366 | { | ||
367 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
368 | struct iscsi_session *session = conn->session; | ||
369 | int err = 0; | ||
370 | |||
371 | spin_lock_bh(&session->lock); | ||
372 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | ||
373 | err = -EPERM; | ||
374 | spin_unlock_bh(&session->lock); | ||
375 | scsi_queue_work(session->host, &conn->xmitwork); | ||
376 | return err; | ||
377 | } | ||
378 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | ||
379 | |||
321 | /** | 380 | /** |
322 | * iscsi_cmd_rsp - SCSI Command Response processing | 381 | * iscsi_cmd_rsp - SCSI Command Response processing |
323 | * @conn: iscsi connection | 382 | * @conn: iscsi connection |
@@ -409,6 +468,39 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
409 | wake_up(&conn->ehwait); | 468 | wake_up(&conn->ehwait); |
410 | } | 469 | } |
411 | 470 | ||
471 | static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) | ||
472 | { | ||
473 | struct iscsi_nopout hdr; | ||
474 | struct iscsi_mgmt_task *mtask; | ||
475 | |||
476 | if (!rhdr && conn->ping_mtask) | ||
477 | return; | ||
478 | |||
479 | memset(&hdr, 0, sizeof(struct iscsi_nopout)); | ||
480 | hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; | ||
481 | hdr.flags = ISCSI_FLAG_CMD_FINAL; | ||
482 | |||
483 | if (rhdr) { | ||
484 | memcpy(hdr.lun, rhdr->lun, 8); | ||
485 | hdr.ttt = rhdr->ttt; | ||
486 | hdr.itt = RESERVED_ITT; | ||
487 | } else | ||
488 | hdr.ttt = RESERVED_ITT; | ||
489 | |||
490 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); | ||
491 | if (!mtask) { | ||
492 | printk(KERN_ERR "Could not send nopout\n"); | ||
493 | return; | ||
494 | } | ||
495 | |||
496 | /* only track our nops */ | ||
497 | if (!rhdr) { | ||
498 | conn->ping_mtask = mtask; | ||
499 | conn->last_ping = jiffies; | ||
500 | } | ||
501 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
502 | } | ||
503 | |||
412 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 504 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
413 | char *data, int datalen) | 505 | char *data, int datalen) |
414 | { | 506 | { |
@@ -453,6 +545,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
453 | struct iscsi_mgmt_task *mtask; | 545 | struct iscsi_mgmt_task *mtask; |
454 | uint32_t itt; | 546 | uint32_t itt; |
455 | 547 | ||
548 | conn->last_recv = jiffies; | ||
456 | if (hdr->itt != RESERVED_ITT) | 549 | if (hdr->itt != RESERVED_ITT) |
457 | itt = get_itt(hdr->itt); | 550 | itt = get_itt(hdr->itt); |
458 | else | 551 | else |
@@ -520,14 +613,22 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
520 | iscsi_free_mgmt_task(conn, mtask); | 613 | iscsi_free_mgmt_task(conn, mtask); |
521 | break; | 614 | break; |
522 | case ISCSI_OP_NOOP_IN: | 615 | case ISCSI_OP_NOOP_IN: |
523 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { | 616 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || |
617 | datalen) { | ||
524 | rc = ISCSI_ERR_PROTO; | 618 | rc = ISCSI_ERR_PROTO; |
525 | break; | 619 | break; |
526 | } | 620 | } |
527 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | 621 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; |
528 | 622 | ||
529 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | 623 | if (conn->ping_mtask != mtask) { |
530 | rc = ISCSI_ERR_CONN_FAILED; | 624 | /* |
625 | * If this is not in response to one of our | ||
626 | * nops then it must be from userspace. | ||
627 | */ | ||
628 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, | ||
629 | datalen)) | ||
630 | rc = ISCSI_ERR_CONN_FAILED; | ||
631 | } | ||
531 | iscsi_free_mgmt_task(conn, mtask); | 632 | iscsi_free_mgmt_task(conn, mtask); |
532 | break; | 633 | break; |
533 | default: | 634 | default: |
@@ -547,8 +648,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
547 | if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) | 648 | if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) |
548 | break; | 649 | break; |
549 | 650 | ||
550 | if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) | 651 | iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr); |
551 | rc = ISCSI_ERR_CONN_FAILED; | ||
552 | break; | 652 | break; |
553 | case ISCSI_OP_REJECT: | 653 | case ISCSI_OP_REJECT: |
554 | rc = iscsi_handle_reject(conn, hdr, data, datalen); | 654 | rc = iscsi_handle_reject(conn, hdr, data, datalen); |
@@ -1003,62 +1103,6 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) | |||
1003 | } | 1103 | } |
1004 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | 1104 | EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); |
1005 | 1105 | ||
1006 | static struct iscsi_mgmt_task * | ||
1007 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
1008 | char *data, uint32_t data_size) | ||
1009 | { | ||
1010 | struct iscsi_session *session = conn->session; | ||
1011 | struct iscsi_mgmt_task *mtask; | ||
1012 | |||
1013 | if (session->state == ISCSI_STATE_TERMINATE) | ||
1014 | return NULL; | ||
1015 | |||
1016 | if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || | ||
1017 | hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
1018 | /* | ||
1019 | * Login and Text are sent serially, in | ||
1020 | * request-followed-by-response sequence. | ||
1021 | * Same mtask can be used. Same ITT must be used. | ||
1022 | * Note that login_mtask is preallocated at conn_create(). | ||
1023 | */ | ||
1024 | mtask = conn->login_mtask; | ||
1025 | else { | ||
1026 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | ||
1027 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | ||
1028 | |||
1029 | if (!__kfifo_get(session->mgmtpool.queue, | ||
1030 | (void*)&mtask, sizeof(void*))) | ||
1031 | return NULL; | ||
1032 | } | ||
1033 | |||
1034 | if (data_size) { | ||
1035 | memcpy(mtask->data, data, data_size); | ||
1036 | mtask->data_count = data_size; | ||
1037 | } else | ||
1038 | mtask->data_count = 0; | ||
1039 | |||
1040 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | ||
1041 | INIT_LIST_HEAD(&mtask->running); | ||
1042 | list_add_tail(&mtask->running, &conn->mgmtqueue); | ||
1043 | return mtask; | ||
1044 | } | ||
1045 | |||
1046 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | ||
1047 | char *data, uint32_t data_size) | ||
1048 | { | ||
1049 | struct iscsi_conn *conn = cls_conn->dd_data; | ||
1050 | struct iscsi_session *session = conn->session; | ||
1051 | int err = 0; | ||
1052 | |||
1053 | spin_lock_bh(&session->lock); | ||
1054 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | ||
1055 | err = -EPERM; | ||
1056 | spin_unlock_bh(&session->lock); | ||
1057 | scsi_queue_work(session->host, &conn->xmitwork); | ||
1058 | return err; | ||
1059 | } | ||
1060 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | ||
1061 | |||
1062 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | 1106 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) |
1063 | { | 1107 | { |
1064 | struct iscsi_session *session = class_to_transport_session(cls_session); | 1108 | struct iscsi_session *session = class_to_transport_session(cls_session); |
@@ -1134,7 +1178,8 @@ static void iscsi_tmf_timedout(unsigned long data) | |||
1134 | } | 1178 | } |
1135 | 1179 | ||
1136 | static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | 1180 | static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, |
1137 | struct iscsi_tm *hdr, int age) | 1181 | struct iscsi_tm *hdr, int age, |
1182 | int timeout) | ||
1138 | { | 1183 | { |
1139 | struct iscsi_session *session = conn->session; | 1184 | struct iscsi_session *session = conn->session; |
1140 | struct iscsi_mgmt_task *mtask; | 1185 | struct iscsi_mgmt_task *mtask; |
@@ -1149,7 +1194,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1149 | return -EPERM; | 1194 | return -EPERM; |
1150 | } | 1195 | } |
1151 | conn->tmfcmd_pdus_cnt++; | 1196 | conn->tmfcmd_pdus_cnt++; |
1152 | conn->tmf_timer.expires = 30 * HZ + jiffies; | 1197 | conn->tmf_timer.expires = timeout * HZ + jiffies; |
1153 | conn->tmf_timer.function = iscsi_tmf_timedout; | 1198 | conn->tmf_timer.function = iscsi_tmf_timedout; |
1154 | conn->tmf_timer.data = (unsigned long)conn; | 1199 | conn->tmf_timer.data = (unsigned long)conn; |
1155 | add_timer(&conn->tmf_timer); | 1200 | add_timer(&conn->tmf_timer); |
@@ -1233,6 +1278,106 @@ static void iscsi_start_tx(struct iscsi_conn *conn) | |||
1233 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1278 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
1234 | } | 1279 | } |
1235 | 1280 | ||
1281 | static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | ||
1282 | { | ||
1283 | struct iscsi_cls_session *cls_session; | ||
1284 | struct iscsi_session *session; | ||
1285 | struct iscsi_conn *conn; | ||
1286 | enum scsi_eh_timer_return rc = EH_NOT_HANDLED; | ||
1287 | |||
1288 | cls_session = starget_to_session(scsi_target(scmd->device)); | ||
1289 | session = class_to_transport_session(cls_session); | ||
1290 | |||
1291 | debug_scsi("scsi cmd %p timedout\n", scmd); | ||
1292 | |||
1293 | spin_lock(&session->lock); | ||
1294 | if (session->state != ISCSI_STATE_LOGGED_IN) { | ||
1295 | /* | ||
1296 | * We are probably in the middle of iscsi recovery so let | ||
1297 | * that complete and handle the error. | ||
1298 | */ | ||
1299 | rc = EH_RESET_TIMER; | ||
1300 | goto done; | ||
1301 | } | ||
1302 | |||
1303 | conn = session->leadconn; | ||
1304 | if (!conn) { | ||
1305 | /* In the middle of shuting down */ | ||
1306 | rc = EH_RESET_TIMER; | ||
1307 | goto done; | ||
1308 | } | ||
1309 | |||
1310 | if (!conn->recv_timeout && !conn->ping_timeout) | ||
1311 | goto done; | ||
1312 | /* | ||
1313 | * if the ping timedout then we are in the middle of cleaning up | ||
1314 | * and can let the iscsi eh handle it | ||
1315 | */ | ||
1316 | if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + | ||
1317 | (conn->ping_timeout * HZ), jiffies)) | ||
1318 | rc = EH_RESET_TIMER; | ||
1319 | /* | ||
1320 | * if we are about to check the transport then give the command | ||
1321 | * more time | ||
1322 | */ | ||
1323 | if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), | ||
1324 | jiffies)) | ||
1325 | rc = EH_RESET_TIMER; | ||
1326 | /* if in the middle of checking the transport then give us more time */ | ||
1327 | if (conn->ping_mtask) | ||
1328 | rc = EH_RESET_TIMER; | ||
1329 | done: | ||
1330 | spin_unlock(&session->lock); | ||
1331 | debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh"); | ||
1332 | return rc; | ||
1333 | } | ||
1334 | |||
1335 | static void iscsi_check_transport_timeouts(unsigned long data) | ||
1336 | { | ||
1337 | struct iscsi_conn *conn = (struct iscsi_conn *)data; | ||
1338 | struct iscsi_session *session = conn->session; | ||
1339 | unsigned long timeout, next_timeout = 0, last_recv; | ||
1340 | |||
1341 | spin_lock(&session->lock); | ||
1342 | if (session->state != ISCSI_STATE_LOGGED_IN) | ||
1343 | goto done; | ||
1344 | |||
1345 | timeout = conn->recv_timeout; | ||
1346 | if (!timeout) | ||
1347 | goto done; | ||
1348 | |||
1349 | timeout *= HZ; | ||
1350 | last_recv = conn->last_recv; | ||
1351 | if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), | ||
1352 | jiffies)) { | ||
1353 | printk(KERN_ERR "ping timeout of %d secs expired, " | ||
1354 | "last rx %lu, last ping %lu, now %lu\n", | ||
1355 | conn->ping_timeout, last_recv, | ||
1356 | conn->last_ping, jiffies); | ||
1357 | spin_unlock(&session->lock); | ||
1358 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | ||
1359 | return; | ||
1360 | } | ||
1361 | |||
1362 | if (time_before_eq(last_recv + timeout, jiffies)) { | ||
1363 | if (time_before_eq(conn->last_ping, last_recv)) { | ||
1364 | /* send a ping to try to provoke some traffic */ | ||
1365 | debug_scsi("Sending nopout as ping on conn %p\n", conn); | ||
1366 | iscsi_send_nopout(conn, NULL); | ||
1367 | } | ||
1368 | next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); | ||
1369 | } else { | ||
1370 | next_timeout = last_recv + timeout; | ||
1371 | } | ||
1372 | |||
1373 | if (next_timeout) { | ||
1374 | debug_scsi("Setting next tmo %lu\n", next_timeout); | ||
1375 | mod_timer(&conn->transport_timer, next_timeout); | ||
1376 | } | ||
1377 | done: | ||
1378 | spin_unlock(&session->lock); | ||
1379 | } | ||
1380 | |||
1236 | static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, | 1381 | static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, |
1237 | struct iscsi_tm *hdr) | 1382 | struct iscsi_tm *hdr) |
1238 | { | 1383 | { |
@@ -1304,7 +1449,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1304 | hdr = &conn->tmhdr; | 1449 | hdr = &conn->tmhdr; |
1305 | iscsi_prep_abort_task_pdu(ctask, hdr); | 1450 | iscsi_prep_abort_task_pdu(ctask, hdr); |
1306 | 1451 | ||
1307 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age)) { | 1452 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { |
1308 | rc = FAILED; | 1453 | rc = FAILED; |
1309 | goto failed; | 1454 | goto failed; |
1310 | } | 1455 | } |
@@ -1365,7 +1510,7 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) | |||
1365 | hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; | 1510 | hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; |
1366 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 1511 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
1367 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 1512 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
1368 | hdr->rtt = ISCSI_RESERVED_TAG; | 1513 | hdr->rtt = RESERVED_ITT; |
1369 | } | 1514 | } |
1370 | 1515 | ||
1371 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) | 1516 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) |
@@ -1396,7 +1541,8 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) | |||
1396 | hdr = &conn->tmhdr; | 1541 | hdr = &conn->tmhdr; |
1397 | iscsi_prep_lun_reset_pdu(sc, hdr); | 1542 | iscsi_prep_lun_reset_pdu(sc, hdr); |
1398 | 1543 | ||
1399 | if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age)) { | 1544 | if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, |
1545 | session->lu_reset_timeout)) { | ||
1400 | rc = FAILED; | 1546 | rc = FAILED; |
1401 | goto unlock; | 1547 | goto unlock; |
1402 | } | 1548 | } |
@@ -1572,12 +1718,14 @@ iscsi_session_setup(struct iscsi_transport *iscsit, | |||
1572 | shost->max_cmd_len = iscsit->max_cmd_len; | 1718 | shost->max_cmd_len = iscsit->max_cmd_len; |
1573 | shost->transportt = scsit; | 1719 | shost->transportt = scsit; |
1574 | shost->transportt->create_work_queue = 1; | 1720 | shost->transportt->create_work_queue = 1; |
1721 | shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; | ||
1575 | *hostno = shost->host_no; | 1722 | *hostno = shost->host_no; |
1576 | 1723 | ||
1577 | session = iscsi_hostdata(shost->hostdata); | 1724 | session = iscsi_hostdata(shost->hostdata); |
1578 | memset(session, 0, sizeof(struct iscsi_session)); | 1725 | memset(session, 0, sizeof(struct iscsi_session)); |
1579 | session->host = shost; | 1726 | session->host = shost; |
1580 | session->state = ISCSI_STATE_FREE; | 1727 | session->state = ISCSI_STATE_FREE; |
1728 | session->fast_abort = 1; | ||
1581 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; | 1729 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; |
1582 | session->cmds_max = cmds_max; | 1730 | session->cmds_max = cmds_max; |
1583 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; | 1731 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; |
@@ -1708,6 +1856,11 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1708 | conn->id = conn_idx; | 1856 | conn->id = conn_idx; |
1709 | conn->exp_statsn = 0; | 1857 | conn->exp_statsn = 0; |
1710 | conn->tmf_state = TMF_INITIAL; | 1858 | conn->tmf_state = TMF_INITIAL; |
1859 | |||
1860 | init_timer(&conn->transport_timer); | ||
1861 | conn->transport_timer.data = (unsigned long)conn; | ||
1862 | conn->transport_timer.function = iscsi_check_transport_timeouts; | ||
1863 | |||
1711 | INIT_LIST_HEAD(&conn->run_list); | 1864 | INIT_LIST_HEAD(&conn->run_list); |
1712 | INIT_LIST_HEAD(&conn->mgmt_run_list); | 1865 | INIT_LIST_HEAD(&conn->mgmt_run_list); |
1713 | INIT_LIST_HEAD(&conn->mgmtqueue); | 1866 | INIT_LIST_HEAD(&conn->mgmtqueue); |
@@ -1757,6 +1910,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
1757 | struct iscsi_session *session = conn->session; | 1910 | struct iscsi_session *session = conn->session; |
1758 | unsigned long flags; | 1911 | unsigned long flags; |
1759 | 1912 | ||
1913 | del_timer_sync(&conn->transport_timer); | ||
1914 | |||
1760 | spin_lock_bh(&session->lock); | 1915 | spin_lock_bh(&session->lock); |
1761 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; | 1916 | conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; |
1762 | if (session->leadconn == conn) { | 1917 | if (session->leadconn == conn) { |
@@ -1823,11 +1978,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
1823 | return -EINVAL; | 1978 | return -EINVAL; |
1824 | } | 1979 | } |
1825 | 1980 | ||
1981 | if (conn->ping_timeout && !conn->recv_timeout) { | ||
1982 | printk(KERN_ERR "iscsi: invalid recv timeout of zero " | ||
1983 | "Using 5 seconds\n."); | ||
1984 | conn->recv_timeout = 5; | ||
1985 | } | ||
1986 | |||
1987 | if (conn->recv_timeout && !conn->ping_timeout) { | ||
1988 | printk(KERN_ERR "iscsi: invalid ping timeout of zero " | ||
1989 | "Using 5 seconds.\n"); | ||
1990 | conn->ping_timeout = 5; | ||
1991 | } | ||
1992 | |||
1826 | spin_lock_bh(&session->lock); | 1993 | spin_lock_bh(&session->lock); |
1827 | conn->c_stage = ISCSI_CONN_STARTED; | 1994 | conn->c_stage = ISCSI_CONN_STARTED; |
1828 | session->state = ISCSI_STATE_LOGGED_IN; | 1995 | session->state = ISCSI_STATE_LOGGED_IN; |
1829 | session->queued_cmdsn = session->cmdsn; | 1996 | session->queued_cmdsn = session->cmdsn; |
1830 | 1997 | ||
1998 | conn->last_recv = jiffies; | ||
1999 | conn->last_ping = jiffies; | ||
2000 | if (conn->recv_timeout && conn->ping_timeout) | ||
2001 | mod_timer(&conn->transport_timer, | ||
2002 | jiffies + (conn->recv_timeout * HZ)); | ||
2003 | |||
1831 | switch(conn->stop_stage) { | 2004 | switch(conn->stop_stage) { |
1832 | case STOP_CONN_RECOVER: | 2005 | case STOP_CONN_RECOVER: |
1833 | /* | 2006 | /* |
@@ -1879,6 +2052,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
1879 | { | 2052 | { |
1880 | int old_stop_stage; | 2053 | int old_stop_stage; |
1881 | 2054 | ||
2055 | del_timer_sync(&conn->transport_timer); | ||
2056 | |||
1882 | mutex_lock(&session->eh_mutex); | 2057 | mutex_lock(&session->eh_mutex); |
1883 | spin_lock_bh(&session->lock); | 2058 | spin_lock_bh(&session->lock); |
1884 | if (conn->stop_stage == STOP_CONN_TERM) { | 2059 | if (conn->stop_stage == STOP_CONN_TERM) { |
@@ -1993,6 +2168,18 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
1993 | case ISCSI_PARAM_FAST_ABORT: | 2168 | case ISCSI_PARAM_FAST_ABORT: |
1994 | sscanf(buf, "%d", &session->fast_abort); | 2169 | sscanf(buf, "%d", &session->fast_abort); |
1995 | break; | 2170 | break; |
2171 | case ISCSI_PARAM_ABORT_TMO: | ||
2172 | sscanf(buf, "%d", &session->abort_timeout); | ||
2173 | break; | ||
2174 | case ISCSI_PARAM_LU_RESET_TMO: | ||
2175 | sscanf(buf, "%d", &session->lu_reset_timeout); | ||
2176 | break; | ||
2177 | case ISCSI_PARAM_PING_TMO: | ||
2178 | sscanf(buf, "%d", &conn->ping_timeout); | ||
2179 | break; | ||
2180 | case ISCSI_PARAM_RECV_TMO: | ||
2181 | sscanf(buf, "%d", &conn->recv_timeout); | ||
2182 | break; | ||
1996 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | 2183 | case ISCSI_PARAM_MAX_RECV_DLENGTH: |
1997 | sscanf(buf, "%d", &conn->max_recv_dlength); | 2184 | sscanf(buf, "%d", &conn->max_recv_dlength); |
1998 | break; | 2185 | break; |
@@ -2110,6 +2297,12 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
2110 | case ISCSI_PARAM_FAST_ABORT: | 2297 | case ISCSI_PARAM_FAST_ABORT: |
2111 | len = sprintf(buf, "%d\n", session->fast_abort); | 2298 | len = sprintf(buf, "%d\n", session->fast_abort); |
2112 | break; | 2299 | break; |
2300 | case ISCSI_PARAM_ABORT_TMO: | ||
2301 | len = sprintf(buf, "%d\n", session->abort_timeout); | ||
2302 | break; | ||
2303 | case ISCSI_PARAM_LU_RESET_TMO: | ||
2304 | len = sprintf(buf, "%d\n", session->lu_reset_timeout); | ||
2305 | break; | ||
2113 | case ISCSI_PARAM_INITIAL_R2T_EN: | 2306 | case ISCSI_PARAM_INITIAL_R2T_EN: |
2114 | len = sprintf(buf, "%d\n", session->initial_r2t_en); | 2307 | len = sprintf(buf, "%d\n", session->initial_r2t_en); |
2115 | break; | 2308 | break; |
@@ -2167,6 +2360,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
2167 | int len; | 2360 | int len; |
2168 | 2361 | ||
2169 | switch(param) { | 2362 | switch(param) { |
2363 | case ISCSI_PARAM_PING_TMO: | ||
2364 | len = sprintf(buf, "%u\n", conn->ping_timeout); | ||
2365 | break; | ||
2366 | case ISCSI_PARAM_RECV_TMO: | ||
2367 | len = sprintf(buf, "%u\n", conn->recv_timeout); | ||
2368 | break; | ||
2170 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | 2369 | case ISCSI_PARAM_MAX_RECV_DLENGTH: |
2171 | len = sprintf(buf, "%u\n", conn->max_recv_dlength); | 2370 | len = sprintf(buf, "%u\n", conn->max_recv_dlength); |
2172 | break; | 2371 | break; |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b82139dc4830..36aa50e45ec7 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -1202,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); | |||
1202 | iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); | 1202 | iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); |
1203 | iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); | 1203 | iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); |
1204 | iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); | 1204 | iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); |
1205 | iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO); | ||
1206 | iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO); | ||
1205 | 1207 | ||
1206 | #define iscsi_cdev_to_session(_cdev) \ | 1208 | #define iscsi_cdev_to_session(_cdev) \ |
1207 | iscsi_dev_to_session(_cdev->dev) | 1209 | iscsi_dev_to_session(_cdev->dev) |
@@ -1437,6 +1439,8 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1437 | SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); | 1439 | SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); |
1438 | SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); | 1440 | SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); |
1439 | SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); | 1441 | SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); |
1442 | SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO); | ||
1443 | SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO); | ||
1440 | 1444 | ||
1441 | BUG_ON(count > ISCSI_CONN_ATTRS); | 1445 | BUG_ON(count > ISCSI_CONN_ATTRS); |
1442 | priv->conn_attrs[count] = NULL; | 1446 | priv->conn_attrs[count] = NULL; |
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 8a4426df6c3a..e19e58423166 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -244,6 +244,12 @@ enum iscsi_param { | |||
244 | ISCSI_PARAM_PASSWORD_IN, | 244 | ISCSI_PARAM_PASSWORD_IN, |
245 | 245 | ||
246 | ISCSI_PARAM_FAST_ABORT, | 246 | ISCSI_PARAM_FAST_ABORT, |
247 | ISCSI_PARAM_ABORT_TMO, | ||
248 | ISCSI_PARAM_LU_RESET_TMO, | ||
249 | ISCSI_PARAM_HOST_RESET_TMO, | ||
250 | |||
251 | ISCSI_PARAM_PING_TMO, | ||
252 | ISCSI_PARAM_RECV_TMO, | ||
247 | /* must always be last */ | 253 | /* must always be last */ |
248 | ISCSI_PARAM_MAX, | 254 | ISCSI_PARAM_MAX, |
249 | }; | 255 | }; |
@@ -275,6 +281,11 @@ enum iscsi_param { | |||
275 | #define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) | 281 | #define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) |
276 | #define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) | 282 | #define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) |
277 | #define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT) | 283 | #define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT) |
284 | #define ISCSI_ABORT_TMO (1 << ISCSI_PARAM_ABORT_TMO) | ||
285 | #define ISCSI_LU_RESET_TMO (1 << ISCSI_PARAM_LU_RESET_TMO) | ||
286 | #define ISCSI_HOST_RESET_TMO (1 << ISCSI_PARAM_HOST_RESET_TMO) | ||
287 | #define ISCSI_PING_TMO (1 << ISCSI_PARAM_PING_TMO) | ||
288 | #define ISCSI_RECV_TMO (1 << ISCSI_PARAM_RECV_TMO) | ||
278 | 289 | ||
279 | /* iSCSI HBA params */ | 290 | /* iSCSI HBA params */ |
280 | enum iscsi_host_param { | 291 | enum iscsi_host_param { |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index d68f74523f2e..889f51fabab9 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -148,6 +148,12 @@ struct iscsi_conn { | |||
148 | * conn_stop() flag: stop to recover, stop to terminate | 148 | * conn_stop() flag: stop to recover, stop to terminate |
149 | */ | 149 | */ |
150 | int stop_stage; | 150 | int stop_stage; |
151 | struct timer_list transport_timer; | ||
152 | unsigned long last_recv; | ||
153 | unsigned long last_ping; | ||
154 | int ping_timeout; | ||
155 | int recv_timeout; | ||
156 | struct iscsi_mgmt_task *ping_mtask; | ||
151 | 157 | ||
152 | /* iSCSI connection-wide sequencing */ | 158 | /* iSCSI connection-wide sequencing */ |
153 | uint32_t exp_statsn; | 159 | uint32_t exp_statsn; |
@@ -238,6 +244,8 @@ struct iscsi_session { | |||
238 | uint32_t queued_cmdsn; | 244 | uint32_t queued_cmdsn; |
239 | 245 | ||
240 | /* configuration */ | 246 | /* configuration */ |
247 | int abort_timeout; | ||
248 | int lu_reset_timeout; | ||
241 | int initial_r2t_en; | 249 | int initial_r2t_en; |
242 | unsigned max_r2t; | 250 | unsigned max_r2t; |
243 | int imm_data_en; | 251 | int imm_data_en; |