Module Name: src Committed By: kardel Date: Fri Aug 9 19:51:29 UTC 2013
Modified Files: src/sys/dev/pci: mpii.c Log Message: fix issues when reading variable block sized tapes. symptoms: generic HBA error on console when reading with a larger blocksize. blocks read are padded to requested block size with a 5a... a5... pattern. problems fixed: - controller scsi_status values did not match the ones used by the spsipi layer. a mapping function was introduced. - when experiencing an underrun (read 64k and get a 63k block) the controller posted not a SUCCESS status but CHECK status. handle that like SUCCESS adjusting xs->resid and set XS_SENSE. now the correct data amount is returned and nothing is 'added' and no 'generic HBA error' occurs. - make decisions using variables and constants from the controller domain. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/dev/pci/mpii.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/mpii.c diff -u src/sys/dev/pci/mpii.c:1.2 src/sys/dev/pci/mpii.c:1.3 --- src/sys/dev/pci/mpii.c:1.2 Thu Aug 8 07:06:13 2013 +++ src/sys/dev/pci/mpii.c Fri Aug 9 19:51:29 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: mpii.c,v 1.2 2013/08/08 07:06:13 kardel Exp $ */ +/* $NetBSD: mpii.c,v 1.3 2013/08/09 19:51:29 kardel Exp $ */ /* OpenBSD: mpii.c,v 1.51 2012/04/11 13:29:14 naddy Exp */ /* * Copyright (c) 2010 Mike Belopuhov <m...@crypt.org.ru> @@ -20,7 +20,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: mpii.c,v 1.2 2013/08/08 07:06:13 kardel Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mpii.c,v 1.3 2013/08/09 19:51:29 kardel Exp $"); #include "bio.h" @@ -790,18 +790,18 @@ struct mpii_msg_scsi_io_error { u_int16_t reserved3; u_int8_t scsi_status; - /* XXX JPG validate this */ -#if notyet -#define MPII_SCSIIO_ERR_STATUS_SUCCESS -#define MPII_SCSIIO_ERR_STATUS_CHECK_COND -#define MPII_SCSIIO_ERR_STATUS_BUSY -#define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE -#define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET -#define MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT -#define MPII_SCSIIO_ERR_STATUS_CMD_TERM -#define MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL -#define MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE -#endif + +#define MPII_SCSIIO_ERR_STATUS_SUCCESS (0x00) +#define MPII_SCSIIO_ERR_STATUS_CHECK_COND (0x02) +#define MPII_SCSIIO_ERR_STATUS_BUSY (0x04) +#define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE (0x08) +#define MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET (0x10) +#define MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT (0x14) +#define MPII_SCSIIO_ERR_STATUS_CMD_TERM (0x22) +#define MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL (0x28) +#define MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE (0x30) +#define MPII_SCSIIO_ERR_STATUS_TASK_ABORTED (0x40) + u_int8_t scsi_state; #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_VALID (1<<0) #define MPII_SCSIIO_ERR_STATE_AUTOSENSE_FAILED (1<<1) @@ -4682,6 +4682,58 @@ mpii_scsi_cmd_tmo_done(struct mpii_ccb * mpii_put_ccb(tccb->ccb_sc, tccb); } +static u_int8_t +map_scsi_status(u_int8_t mpii_scsi_status) +{ + u_int8_t scsi_status; + + switch (mpii_scsi_status) + { + case MPII_SCSIIO_ERR_STATUS_SUCCESS: + scsi_status = SCSI_OK; + break; + + case MPII_SCSIIO_ERR_STATUS_CHECK_COND: + scsi_status = SCSI_CHECK; + break; + + case MPII_SCSIIO_ERR_STATUS_BUSY: + scsi_status = SCSI_BUSY; + break; + + case MPII_SCSIIO_ERR_STATUS_INTERMEDIATE: + scsi_status = SCSI_INTERM; + break; + + case MPII_SCSIIO_ERR_STATUS_INTERMEDIATE_CONDMET: + scsi_status = SCSI_INTERM; + break; + + case MPII_SCSIIO_ERR_STATUS_RESERVATION_CONFLICT: + scsi_status = SCSI_RESV_CONFLICT; + break; + + case MPII_SCSIIO_ERR_STATUS_CMD_TERM: + case MPII_SCSIIO_ERR_STATUS_TASK_ABORTED: + scsi_status = SCSI_TERMINATED; + break; + + case MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL: + scsi_status = SCSI_QUEUE_FULL; + break; + + case MPII_SCSIIO_ERR_STATUS_ACA_ACTIVE: + scsi_status = SCSI_ACA_ACTIVE; + break; + + default: + /* XXX: for the lack of anything better and other than OK */ + scsi_status = 0xFF; + break; + } + + return scsi_status; +} static void mpii_scsi_cmd_done(struct mpii_ccb *ccb) @@ -4745,31 +4797,43 @@ mpii_scsi_cmd_done(struct mpii_ccb *ccb) DNPRINTF(MPII_D_CMD, "%s: bidirectional_transfer_count: 0x%08x\n", DEVNAME(sc), le32toh(sie->bidirectional_transfer_count)); - xs->status = sie->scsi_status; + xs->status = map_scsi_status(sie->scsi_status); + switch (le16toh(sie->ioc_status) & MPII_IOCSTATUS_MASK) { case MPII_IOCSTATUS_SCSI_DATA_UNDERRUN: - switch (xs->status) { - case SCSI_OK: + switch (sie->scsi_status) { + case MPII_SCSIIO_ERR_STATUS_CHECK_COND: + xs->error = XS_SENSE; + /*FALLTHROUGH*/ + case MPII_SCSIIO_ERR_STATUS_SUCCESS: xs->resid = xs->datalen - le32toh(sie->transfer_count); break; + default: xs->error = XS_DRIVER_STUFFUP; break; } break; + case MPII_IOCSTATUS_SUCCESS: case MPII_IOCSTATUS_SCSI_RECOVERED_ERROR: - switch (xs->status) { - case SCSI_OK: - xs->resid = 0; + switch (sie->scsi_status) { + case MPII_SCSIIO_ERR_STATUS_SUCCESS: + /* + * xs->resid = 0; - already set above + * + * XXX: check whether UNDERUN strategy + * would be appropriate here too. + * that would allow joining these cases. + */ break; - case SCSI_CHECK: + case MPII_SCSIIO_ERR_STATUS_CHECK_COND: xs->error = XS_SENSE; break; - - case SCSI_BUSY: - case SCSI_QUEUE_FULL: + + case MPII_SCSIIO_ERR_STATUS_BUSY: + case MPII_SCSIIO_ERR_STATUS_TASK_SET_FULL: xs->error = XS_BUSY; break;