diff options
author | john fastabend <john.r.fastabend@intel.com> | 2010-11-30 19:18:39 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-12-21 13:24:21 -0500 |
commit | ac17ea8d7d45d0495316edff13faa0dfd6bb2225 (patch) | |
tree | 6c8d0935d8b59ed3205fdfe9d074ab0b0a978fa2 | |
parent | e90ff5ef0aab1d40f0e92a44d66f8d45a20d8c95 (diff) |
[SCSI] libfc: incorrect scsi host byte codes returned to scsi-ml
The fcp packet recovery handler fc_fcp_recover() is called
when errors occurr in a fcp session. Currently it is
generically setting the status code to FC_CMD_RECOVERY for
all error types. This results in DID_BUS_BUSY errors
being returned to the scsi-ml.
DID_BUS_BUSY errors indicate "BUS stayed busy through time
out period" according to scsi.h. Many of the error reported
by fc_rcp_recovery() are pkt errors. Here we update
fc_fcp_recovery to use better host byte codes.
With certain FAST FAIL flags set DID_BUS_BUSY and DID_ERROR
will have different behaviors this was causing dm multipath
to fail quickly in some cases where a retry would be a
better action.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 61 |
1 files changed, 41 insertions, 20 deletions
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 0e985dbaedc4..8eb67676d0dd 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c | |||
@@ -96,7 +96,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *); | |||
96 | static void fc_fcp_complete_locked(struct fc_fcp_pkt *); | 96 | static void fc_fcp_complete_locked(struct fc_fcp_pkt *); |
97 | static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); | 97 | static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); |
98 | static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *); | 98 | static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *); |
99 | static void fc_fcp_recovery(struct fc_fcp_pkt *); | 99 | static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code); |
100 | static void fc_fcp_timeout(unsigned long); | 100 | static void fc_fcp_timeout(unsigned long); |
101 | static void fc_fcp_rec(struct fc_fcp_pkt *); | 101 | static void fc_fcp_rec(struct fc_fcp_pkt *); |
102 | static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); | 102 | static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); |
@@ -120,7 +120,8 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); | |||
120 | #define FC_DATA_UNDRUN 7 | 120 | #define FC_DATA_UNDRUN 7 |
121 | #define FC_ERROR 8 | 121 | #define FC_ERROR 8 |
122 | #define FC_HRD_ERROR 9 | 122 | #define FC_HRD_ERROR 9 |
123 | #define FC_CMD_RECOVERY 10 | 123 | #define FC_CRC_ERROR 10 |
124 | #define FC_TIMED_OUT 11 | ||
124 | 125 | ||
125 | /* | 126 | /* |
126 | * Error recovery timeout values. | 127 | * Error recovery timeout values. |
@@ -438,6 +439,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
438 | void *buf; | 439 | void *buf; |
439 | struct scatterlist *sg; | 440 | struct scatterlist *sg; |
440 | u32 nents; | 441 | u32 nents; |
442 | u8 host_bcode = FC_COMPLETE; | ||
441 | 443 | ||
442 | fh = fc_frame_header_get(fp); | 444 | fh = fc_frame_header_get(fp); |
443 | offset = ntohl(fh->fh_parm_offset); | 445 | offset = ntohl(fh->fh_parm_offset); |
@@ -446,13 +448,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
446 | buf = fc_frame_payload_get(fp, 0); | 448 | buf = fc_frame_payload_get(fp, 0); |
447 | 449 | ||
448 | /* | 450 | /* |
449 | * if this I/O is ddped then clear it | 451 | * if this I/O is ddped then clear it and initiate recovery since data |
450 | * and initiate recovery since data | 452 | * frames are expected to be placed directly in that case. |
451 | * frames are expected to be placed | 453 | * |
452 | * directly in that case. | 454 | * Indicate error to scsi-ml because something went wrong with the |
455 | * ddp handling to get us here. | ||
453 | */ | 456 | */ |
454 | if (fsp->xfer_ddp != FC_XID_UNKNOWN) { | 457 | if (fsp->xfer_ddp != FC_XID_UNKNOWN) { |
455 | fc_fcp_ddp_done(fsp); | 458 | fc_fcp_ddp_done(fsp); |
459 | FC_FCP_DBG(fsp, "DDP I/O in fc_fcp_recv_data set ERROR\n"); | ||
460 | host_bcode = FC_ERROR; | ||
456 | goto err; | 461 | goto err; |
457 | } | 462 | } |
458 | if (offset + len > fsp->data_len) { | 463 | if (offset + len > fsp->data_len) { |
@@ -462,6 +467,9 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
462 | goto crc_err; | 467 | goto crc_err; |
463 | FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx " | 468 | FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx " |
464 | "data_len %x\n", len, offset, fsp->data_len); | 469 | "data_len %x\n", len, offset, fsp->data_len); |
470 | |||
471 | /* Data is corrupted indicate scsi-ml should retry */ | ||
472 | host_bcode = FC_DATA_OVRRUN; | ||
465 | goto err; | 473 | goto err; |
466 | } | 474 | } |
467 | if (offset != fsp->xfer_len) | 475 | if (offset != fsp->xfer_len) |
@@ -498,8 +506,10 @@ crc_err: | |||
498 | * If so, we need to retry the entire operation. | 506 | * If so, we need to retry the entire operation. |
499 | * Otherwise, ignore it. | 507 | * Otherwise, ignore it. |
500 | */ | 508 | */ |
501 | if (fsp->state & FC_SRB_DISCONTIG) | 509 | if (fsp->state & FC_SRB_DISCONTIG) { |
510 | host_bcode = FC_CRC_ERROR; | ||
502 | goto err; | 511 | goto err; |
512 | } | ||
503 | return; | 513 | return; |
504 | } | 514 | } |
505 | } | 515 | } |
@@ -517,7 +527,7 @@ crc_err: | |||
517 | fc_fcp_complete_locked(fsp); | 527 | fc_fcp_complete_locked(fsp); |
518 | return; | 528 | return; |
519 | err: | 529 | err: |
520 | fc_fcp_recovery(fsp); | 530 | fc_fcp_recovery(fsp, host_bcode); |
521 | } | 531 | } |
522 | 532 | ||
523 | /** | 533 | /** |
@@ -1347,7 +1357,7 @@ static void fc_fcp_timeout(unsigned long data) | |||
1347 | else if (fsp->state & FC_SRB_RCV_STATUS) | 1357 | else if (fsp->state & FC_SRB_RCV_STATUS) |
1348 | fc_fcp_complete_locked(fsp); | 1358 | fc_fcp_complete_locked(fsp); |
1349 | else | 1359 | else |
1350 | fc_fcp_recovery(fsp); | 1360 | fc_fcp_recovery(fsp, FC_TIMED_OUT); |
1351 | fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; | 1361 | fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; |
1352 | unlock: | 1362 | unlock: |
1353 | fc_fcp_unlock_pkt(fsp); | 1363 | fc_fcp_unlock_pkt(fsp); |
@@ -1391,7 +1401,7 @@ retry: | |||
1391 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) | 1401 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) |
1392 | fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); | 1402 | fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV); |
1393 | else | 1403 | else |
1394 | fc_fcp_recovery(fsp); | 1404 | fc_fcp_recovery(fsp, FC_TIMED_OUT); |
1395 | } | 1405 | } |
1396 | 1406 | ||
1397 | /** | 1407 | /** |
@@ -1460,7 +1470,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) | |||
1460 | fc_fcp_retry_cmd(fsp); | 1470 | fc_fcp_retry_cmd(fsp); |
1461 | break; | 1471 | break; |
1462 | } | 1472 | } |
1463 | fc_fcp_recovery(fsp); | 1473 | fc_fcp_recovery(fsp, FC_ERROR); |
1464 | break; | 1474 | break; |
1465 | } | 1475 | } |
1466 | } else if (opcode == ELS_LS_ACC) { | 1476 | } else if (opcode == ELS_LS_ACC) { |
@@ -1575,7 +1585,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
1575 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) | 1585 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) |
1576 | fc_fcp_rec(fsp); | 1586 | fc_fcp_rec(fsp); |
1577 | else | 1587 | else |
1578 | fc_fcp_recovery(fsp); | 1588 | fc_fcp_recovery(fsp, FC_ERROR); |
1579 | break; | 1589 | break; |
1580 | } | 1590 | } |
1581 | fc_fcp_unlock_pkt(fsp); | 1591 | fc_fcp_unlock_pkt(fsp); |
@@ -1587,9 +1597,9 @@ out: | |||
1587 | * fc_fcp_recovery() - Handler for fcp_pkt recovery | 1597 | * fc_fcp_recovery() - Handler for fcp_pkt recovery |
1588 | * @fsp: The FCP pkt that needs to be aborted | 1598 | * @fsp: The FCP pkt that needs to be aborted |
1589 | */ | 1599 | */ |
1590 | static void fc_fcp_recovery(struct fc_fcp_pkt *fsp) | 1600 | static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code) |
1591 | { | 1601 | { |
1592 | fsp->status_code = FC_CMD_RECOVERY; | 1602 | fsp->status_code = code; |
1593 | fsp->cdb_status = 0; | 1603 | fsp->cdb_status = 0; |
1594 | fsp->io_status = 0; | 1604 | fsp->io_status = 0; |
1595 | /* | 1605 | /* |
@@ -1695,7 +1705,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) | |||
1695 | break; | 1705 | break; |
1696 | case ELS_LS_RJT: | 1706 | case ELS_LS_RJT: |
1697 | default: | 1707 | default: |
1698 | fc_fcp_recovery(fsp); | 1708 | fc_fcp_recovery(fsp, FC_ERROR); |
1699 | break; | 1709 | break; |
1700 | } | 1710 | } |
1701 | fc_fcp_unlock_pkt(fsp); | 1711 | fc_fcp_unlock_pkt(fsp); |
@@ -1721,7 +1731,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) | |||
1721 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) | 1731 | if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) |
1722 | fc_fcp_rec(fsp); | 1732 | fc_fcp_rec(fsp); |
1723 | else | 1733 | else |
1724 | fc_fcp_recovery(fsp); | 1734 | fc_fcp_recovery(fsp, FC_TIMED_OUT); |
1725 | break; | 1735 | break; |
1726 | case -FC_EX_CLOSED: /* e.g., link failure */ | 1736 | case -FC_EX_CLOSED: /* e.g., link failure */ |
1727 | /* fall through */ | 1737 | /* fall through */ |
@@ -1946,18 +1956,29 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) | |||
1946 | break; | 1956 | break; |
1947 | case FC_CMD_ABORTED: | 1957 | case FC_CMD_ABORTED: |
1948 | FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " | 1958 | FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " |
1949 | "due to FC_CMD_ABORTED\n"); | 1959 | "due to FC_CMD_ABORTED\n"); |
1950 | sc_cmd->result = (DID_ERROR << 16) | fsp->io_status; | 1960 | sc_cmd->result = (DID_ERROR << 16) | fsp->io_status; |
1951 | break; | 1961 | break; |
1952 | case FC_CMD_RECOVERY: | ||
1953 | sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; | ||
1954 | break; | ||
1955 | case FC_CMD_RESET: | 1962 | case FC_CMD_RESET: |
1963 | FC_FCP_DBG(fsp, "Returning DID_RESET to scsi-ml " | ||
1964 | "due to FC_CMD_RESET\n"); | ||
1956 | sc_cmd->result = (DID_RESET << 16); | 1965 | sc_cmd->result = (DID_RESET << 16); |
1957 | break; | 1966 | break; |
1958 | case FC_HRD_ERROR: | 1967 | case FC_HRD_ERROR: |
1968 | FC_FCP_DBG(fsp, "Returning DID_NO_CONNECT to scsi-ml " | ||
1969 | "due to FC_HRD_ERROR\n"); | ||
1959 | sc_cmd->result = (DID_NO_CONNECT << 16); | 1970 | sc_cmd->result = (DID_NO_CONNECT << 16); |
1960 | break; | 1971 | break; |
1972 | case FC_CRC_ERROR: | ||
1973 | FC_FCP_DBG(fsp, "Returning DID_PARITY to scsi-ml " | ||
1974 | "due to FC_CRC_ERROR\n"); | ||
1975 | sc_cmd->result = (DID_PARITY << 16); | ||
1976 | break; | ||
1977 | case FC_TIMED_OUT: | ||
1978 | FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml " | ||
1979 | "due to FC_TIMED_OUT\n"); | ||
1980 | sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; | ||
1981 | break; | ||
1961 | default: | 1982 | default: |
1962 | FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " | 1983 | FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " |
1963 | "due to unknown error\n"); | 1984 | "due to unknown error\n"); |