mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-23 04:51:08 +01:00
One more major cam_periph_error() rewrite to improve error handling and
reporting. It includes: - removing of error messages controlled by bootverbose, replacing them with more universal and informative debugging on CAM_DEBUG_INFO level, that is now built into the kernel by default; - more close following to the arguments submitted by caller, such as SF_PRINT_ALWAYS, SF_QUIET_IR and SF_NO_PRINT; consumer knows better which errors are usual/expected at this point and which are really informative; - adding two new flags SF_NO_RECOVERY and SF_NO_RETRY to allow caller specify how much assistance it needs at this point; previously consumers controlled that by not calling cam_periph_error() at all, but that made behavior inconsistent and debugging complicated; - tuning debug messages and taken actions order to make debugging output more readable and cause-effect relationships visible; - making camperiphdone() (common device recovery completion handler) to also use cam_periph_error() in most cases, instead of own dumb code; - removing manual sense fetching code from cam_periph_error(); I was told by number of people that it is SIM obligation to fetch sense data, so this code is useless and only significantly complicates recovery logic; - making ada, da and pass driver to use cam_periph_error() with new limited recovery options to handle error recovery and debugging in common way; as one of results, CAM_REQUEUE_REQ and other retrying statuses are now working fine with pass driver, that caused many problems before. - reverting r186891 by raj@ to avoid burning few seconds in tight DELAY() loops on device probe, while device simply loads media; I think that problem may already be fixed in other way, and even if it is not, solution must be different. Sponsored by: iXsystems, Inc. MFC after: 2 weeks
This commit is contained in:
parent
5d02ed91e9
commit
0191d9b367
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=236814
@ -584,6 +584,7 @@ adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t len
|
||||
struct disk *dp;
|
||||
uint64_t lba;
|
||||
uint16_t count;
|
||||
int error = 0;
|
||||
|
||||
dp = arg;
|
||||
periph = dp->d_drv1;
|
||||
@ -622,13 +623,16 @@ adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t len
|
||||
}
|
||||
xpt_polled_action(&ccb);
|
||||
|
||||
if ((ccb.ataio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
error = cam_periph_error(&ccb,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
printf("Aborting dump due to I/O error.\n");
|
||||
cam_periph_unlock(periph);
|
||||
return(EIO);
|
||||
}
|
||||
|
||||
cam_periph_unlock(periph);
|
||||
return(0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (softc->flags & ADA_FLAG_CAN_FLUSHCACHE) {
|
||||
@ -636,7 +640,7 @@ adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t len
|
||||
|
||||
ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
|
||||
cam_fill_ataio(&ccb.ataio,
|
||||
1,
|
||||
0,
|
||||
adadone,
|
||||
CAM_DIR_NONE,
|
||||
0,
|
||||
@ -650,18 +654,16 @@ adadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t len
|
||||
ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
|
||||
xpt_polled_action(&ccb);
|
||||
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
|
||||
error = cam_periph_error(&ccb,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb.ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
}
|
||||
cam_periph_unlock(periph);
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1716,6 +1718,7 @@ adaflush(void)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct ada_softc *softc;
|
||||
int error;
|
||||
|
||||
TAILQ_FOREACH(periph, &adadriver.units, unit_links) {
|
||||
union ccb ccb;
|
||||
@ -1739,7 +1742,7 @@ adaflush(void)
|
||||
|
||||
ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
|
||||
cam_fill_ataio(&ccb.ataio,
|
||||
1,
|
||||
0,
|
||||
adadone,
|
||||
CAM_DIR_NONE,
|
||||
0,
|
||||
@ -1753,15 +1756,13 @@ adaflush(void)
|
||||
ata_28bit_cmd(&ccb.ataio, ATA_FLUSHCACHE, 0, 0, 0);
|
||||
xpt_polled_action(&ccb);
|
||||
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
|
||||
error = cam_periph_error(&ccb,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb.ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
cam_periph_unlock(periph);
|
||||
}
|
||||
}
|
||||
@ -1771,6 +1772,7 @@ adaspindown(uint8_t cmd, int flags)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct ada_softc *softc;
|
||||
int error;
|
||||
|
||||
TAILQ_FOREACH(periph, &adadriver.units, unit_links) {
|
||||
union ccb ccb;
|
||||
@ -1795,7 +1797,7 @@ adaspindown(uint8_t cmd, int flags)
|
||||
|
||||
ccb.ccb_h.ccb_state = ADA_CCB_DUMP;
|
||||
cam_fill_ataio(&ccb.ataio,
|
||||
1,
|
||||
0,
|
||||
adadone,
|
||||
CAM_DIR_NONE | flags,
|
||||
0,
|
||||
@ -1806,15 +1808,13 @@ adaspindown(uint8_t cmd, int flags)
|
||||
ata_28bit_cmd(&ccb.ataio, cmd, 0, 0, 0);
|
||||
xpt_polled_action(&ccb);
|
||||
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
|
||||
xpt_print(periph->path, "Spin-down disk failed\n");
|
||||
|
||||
error = cam_periph_error(&ccb,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb.ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
xpt_print(periph->path, "Spin-down disk failed\n");
|
||||
cam_periph_unlock(periph);
|
||||
}
|
||||
}
|
||||
|
@ -705,12 +705,9 @@ probedone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
inq_buf = &path->device->inq_data;
|
||||
|
||||
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
if (softc->restart) {
|
||||
if (bootverbose) {
|
||||
cam_error_print(done_ccb,
|
||||
CAM_ESF_ALL, CAM_EPF_ALL);
|
||||
}
|
||||
} else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART)
|
||||
if (cam_periph_error(done_ccb,
|
||||
0, softc->restart ? (SF_NO_RECOVERY | SF_NO_RETRY) : 0,
|
||||
NULL) == ERESTART)
|
||||
return;
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
|
@ -108,6 +108,15 @@ typedef enum {
|
||||
CAM_RETRY_SELTO = 0x02 /* Retry Selection Timeouts */
|
||||
} cam_flags;
|
||||
|
||||
enum {
|
||||
SF_RETRY_UA = 0x01, /* Retry UNIT ATTENTION conditions. */
|
||||
SF_NO_PRINT = 0x02, /* Never print error status. */
|
||||
SF_QUIET_IR = 0x04, /* Be quiet about Illegal Request reponses */
|
||||
SF_PRINT_ALWAYS = 0x08, /* Always print error status. */
|
||||
SF_NO_RECOVERY = 0x10, /* Don't do active error recovery. */
|
||||
SF_NO_RETRY = 0x20 /* Don't do any retries. */
|
||||
};
|
||||
|
||||
/* CAM Status field values */
|
||||
typedef enum {
|
||||
CAM_REQ_INPROG, /* CCB request is in progress */
|
||||
|
@ -69,18 +69,22 @@ static void camperiphdone(struct cam_periph *periph,
|
||||
union ccb *done_ccb);
|
||||
static void camperiphfree(struct cam_periph *periph);
|
||||
static int camperiphscsistatuserror(union ccb *ccb,
|
||||
union ccb **orig_ccb,
|
||||
cam_flags camflags,
|
||||
u_int32_t sense_flags,
|
||||
int *openings,
|
||||
u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout,
|
||||
int *print,
|
||||
const char **action_string);
|
||||
static int camperiphscsisenseerror(union ccb *ccb,
|
||||
union ccb **orig_ccb,
|
||||
cam_flags camflags,
|
||||
u_int32_t sense_flags,
|
||||
int *openings,
|
||||
u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout,
|
||||
int *print,
|
||||
const char **action_string);
|
||||
|
||||
static int nperiph_drivers;
|
||||
@ -1108,107 +1112,59 @@ cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
|
||||
}
|
||||
|
||||
#define saved_ccb_ptr ppriv_ptr0
|
||||
#define recovery_depth ppriv_field1
|
||||
static void
|
||||
camperiphsensedone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
{
|
||||
union ccb *saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
|
||||
cam_status status;
|
||||
int frozen = 0;
|
||||
int depth = done_ccb->ccb_h.recovery_depth;
|
||||
|
||||
status = done_ccb->ccb_h.status;
|
||||
if (status & CAM_DEV_QFRZN) {
|
||||
frozen = 1;
|
||||
/*
|
||||
* Clear freeze flag now for case of retry,
|
||||
* freeze will be dropped later.
|
||||
*/
|
||||
done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
|
||||
}
|
||||
status &= CAM_STATUS_MASK;
|
||||
switch (status) {
|
||||
case CAM_REQ_CMP:
|
||||
{
|
||||
int error_code, sense_key, asc, ascq;
|
||||
|
||||
scsi_extract_sense_len(&saved_ccb->csio.sense_data,
|
||||
saved_ccb->csio.sense_len -
|
||||
saved_ccb->csio.sense_resid,
|
||||
&error_code, &sense_key, &asc, &ascq,
|
||||
/*show_errors*/ 1);
|
||||
/*
|
||||
* If we manually retrieved sense into a CCB and got
|
||||
* something other than "NO SENSE" send the updated CCB
|
||||
* back to the client via xpt_done() to be processed via
|
||||
* the error recovery code again.
|
||||
*/
|
||||
if ((sense_key != -1)
|
||||
&& (sense_key != SSD_KEY_NO_SENSE)) {
|
||||
saved_ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
|
||||
} else {
|
||||
saved_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
|
||||
saved_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
|
||||
}
|
||||
saved_ccb->csio.sense_resid = done_ccb->csio.resid;
|
||||
bcopy(saved_ccb, done_ccb, sizeof(union ccb));
|
||||
xpt_free_ccb(saved_ccb);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
bcopy(saved_ccb, done_ccb, sizeof(union ccb));
|
||||
xpt_free_ccb(saved_ccb);
|
||||
done_ccb->ccb_h.status &= ~CAM_STATUS_MASK;
|
||||
done_ccb->ccb_h.status |= CAM_AUTOSENSE_FAIL;
|
||||
break;
|
||||
}
|
||||
periph->flags &= ~CAM_PERIPH_SENSE_INPROG;
|
||||
/*
|
||||
* If it is the end of recovery, drop freeze, taken due to
|
||||
* CAM_DEV_QFREEZE flag, set on recovery request.
|
||||
*/
|
||||
if (depth == 0) {
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*openings*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
}
|
||||
/*
|
||||
* Copy frozen flag from recovery request if it is set there
|
||||
* for some reason.
|
||||
*/
|
||||
if (frozen != 0)
|
||||
done_ccb->ccb_h.status |= CAM_DEV_QFRZN;
|
||||
(*done_ccb->ccb_h.cbfcnp)(periph, done_ccb);
|
||||
}
|
||||
|
||||
static void
|
||||
camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
{
|
||||
union ccb *saved_ccb, *save_ccb;
|
||||
union ccb *saved_ccb;
|
||||
cam_status status;
|
||||
int frozen = 0;
|
||||
struct scsi_start_stop_unit *scsi_cmd;
|
||||
u_int32_t relsim_flags, timeout;
|
||||
|
||||
scsi_cmd = (struct scsi_start_stop_unit *)
|
||||
&done_ccb->csio.cdb_io.cdb_bytes;
|
||||
status = done_ccb->ccb_h.status;
|
||||
if (status & CAM_DEV_QFRZN) {
|
||||
frozen = 1;
|
||||
/*
|
||||
* Clear freeze flag now for case of retry,
|
||||
* freeze will be dropped later.
|
||||
*/
|
||||
done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
|
||||
}
|
||||
|
||||
timeout = 0;
|
||||
relsim_flags = 0;
|
||||
saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
|
||||
if ((status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
if ((status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
|
||||
(status & CAM_AUTOSNS_VALID)) {
|
||||
struct scsi_sense_data *sense;
|
||||
int error_code, sense_key, asc, ascq, sense_len;
|
||||
|
||||
switch (status & CAM_STATUS_MASK) {
|
||||
case CAM_REQ_CMP:
|
||||
{
|
||||
sense = &done_ccb->csio.sense_data;
|
||||
sense_len = done_ccb->csio.sense_len -
|
||||
done_ccb->csio.sense_resid;
|
||||
scsi_extract_sense_len(sense, sense_len, &error_code,
|
||||
&sense_key, &asc, &ascq, /*show_errors*/ 1);
|
||||
/*
|
||||
* If the error is "invalid field in CDB",
|
||||
* and the load/eject flag is set, turn the
|
||||
* flag off and try again. This is just in
|
||||
* case the drive in question barfs on the
|
||||
* load eject flag. The CAM code should set
|
||||
* the load/eject flag by default for
|
||||
* removable media.
|
||||
*/
|
||||
if ((scsi_cmd->opcode == START_STOP_UNIT) &&
|
||||
((scsi_cmd->how & SSS_LOEJ) != 0) &&
|
||||
(asc == 0x24) && (ascq == 0x00)) {
|
||||
scsi_cmd->how &= ~SSS_LOEJ;
|
||||
if (status & CAM_DEV_QFRZN) {
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
0, 0, 0, 0);
|
||||
done_ccb->ccb_h.status &=
|
||||
~CAM_DEV_QFRZN;
|
||||
}
|
||||
xpt_action(done_ccb);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (cam_periph_error(done_ccb,
|
||||
0, SF_RETRY_UA | SF_NO_PRINT, NULL) == ERESTART)
|
||||
goto out;
|
||||
if (done_ccb->ccb_h.status & CAM_DEV_QFRZN) {
|
||||
cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
|
||||
done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If we have successfully taken a device from the not
|
||||
* ready to ready state, re-scan the device and re-get
|
||||
@ -1216,147 +1172,24 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
|
||||
* don't properly report their inquiry information unless
|
||||
* they are spun up.
|
||||
*/
|
||||
scsi_cmd = (struct scsi_start_stop_unit *)
|
||||
&done_ccb->csio.cdb_io.cdb_bytes;
|
||||
|
||||
if (scsi_cmd->opcode == START_STOP_UNIT)
|
||||
xpt_async(AC_INQ_CHANGED,
|
||||
done_ccb->ccb_h.path, NULL);
|
||||
goto final;
|
||||
if (scsi_cmd->opcode == START_STOP_UNIT)
|
||||
xpt_async(AC_INQ_CHANGED, done_ccb->ccb_h.path, NULL);
|
||||
}
|
||||
case CAM_SCSI_STATUS_ERROR:
|
||||
scsi_cmd = (struct scsi_start_stop_unit *)
|
||||
&done_ccb->csio.cdb_io.cdb_bytes;
|
||||
if (status & CAM_AUTOSNS_VALID) {
|
||||
struct ccb_getdev cgd;
|
||||
struct scsi_sense_data *sense;
|
||||
int error_code, sense_key, asc, ascq, sense_len;
|
||||
scsi_sense_action err_action;
|
||||
|
||||
sense = &done_ccb->csio.sense_data;
|
||||
sense_len = done_ccb->csio.sense_len -
|
||||
done_ccb->csio.sense_resid;
|
||||
scsi_extract_sense_len(sense, sense_len, &error_code,
|
||||
&sense_key, &asc, &ascq,
|
||||
/*show_errors*/ 1);
|
||||
/*
|
||||
* Grab the inquiry data for this device.
|
||||
*/
|
||||
xpt_setup_ccb(&cgd.ccb_h, done_ccb->ccb_h.path,
|
||||
CAM_PRIORITY_NORMAL);
|
||||
cgd.ccb_h.func_code = XPT_GDEV_TYPE;
|
||||
xpt_action((union ccb *)&cgd);
|
||||
err_action = scsi_error_action(&done_ccb->csio,
|
||||
&cgd.inq_data, 0);
|
||||
/*
|
||||
* If the error is "invalid field in CDB",
|
||||
* and the load/eject flag is set, turn the
|
||||
* flag off and try again. This is just in
|
||||
* case the drive in question barfs on the
|
||||
* load eject flag. The CAM code should set
|
||||
* the load/eject flag by default for
|
||||
* removable media.
|
||||
*/
|
||||
/* XXX KDM
|
||||
* Should we check to see what the specific
|
||||
* scsi status is?? Or does it not matter
|
||||
* since we already know that there was an
|
||||
* error, and we know what the specific
|
||||
* error code was, and we know what the
|
||||
* opcode is..
|
||||
*/
|
||||
if ((scsi_cmd->opcode == START_STOP_UNIT) &&
|
||||
((scsi_cmd->how & SSS_LOEJ) != 0) &&
|
||||
(asc == 0x24) && (ascq == 0x00) &&
|
||||
(done_ccb->ccb_h.retry_count > 0)) {
|
||||
|
||||
scsi_cmd->how &= ~SSS_LOEJ;
|
||||
xpt_action(done_ccb);
|
||||
} else if ((done_ccb->ccb_h.retry_count > 1)
|
||||
&& ((err_action & SS_MASK) != SS_FAIL)) {
|
||||
|
||||
/*
|
||||
* In this case, the error recovery
|
||||
* command failed, but we've got
|
||||
* some retries left on it. Give
|
||||
* it another try unless this is an
|
||||
* unretryable error.
|
||||
*/
|
||||
/* set the timeout to .5 sec */
|
||||
relsim_flags =
|
||||
RELSIM_RELEASE_AFTER_TIMEOUT;
|
||||
timeout = 500;
|
||||
xpt_action(done_ccb);
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Perform the final retry with the original
|
||||
* CCB so that final error processing is
|
||||
* performed by the owner of the CCB.
|
||||
*/
|
||||
goto final;
|
||||
}
|
||||
} else {
|
||||
save_ccb = xpt_alloc_ccb_nowait();
|
||||
if (save_ccb == NULL)
|
||||
goto final;
|
||||
bcopy(done_ccb, save_ccb, sizeof(*save_ccb));
|
||||
periph->flags |= CAM_PERIPH_SENSE_INPROG;
|
||||
/*
|
||||
* Send a Request Sense to the device. We
|
||||
* assume that we are in a contingent allegiance
|
||||
* condition so we do not tag this request.
|
||||
*/
|
||||
scsi_request_sense(&done_ccb->csio, /*retries*/1,
|
||||
camperiphsensedone,
|
||||
&save_ccb->csio.sense_data,
|
||||
save_ccb->csio.sense_len,
|
||||
CAM_TAG_ACTION_NONE,
|
||||
/*sense_len*/SSD_FULL_SIZE,
|
||||
/*timeout*/5000);
|
||||
done_ccb->ccb_h.pinfo.priority--;
|
||||
done_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
|
||||
done_ccb->ccb_h.saved_ccb_ptr = save_ccb;
|
||||
done_ccb->ccb_h.recovery_depth++;
|
||||
xpt_action(done_ccb);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
final:
|
||||
bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
|
||||
xpt_free_ccb(saved_ccb);
|
||||
/*
|
||||
* Perform the final retry with the original CCB so that final
|
||||
* error processing is performed by the owner of the CCB.
|
||||
*/
|
||||
saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
|
||||
bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
|
||||
xpt_free_ccb(saved_ccb);
|
||||
if (done_ccb->ccb_h.cbfcnp != camperiphdone)
|
||||
periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
|
||||
xpt_action(done_ccb);
|
||||
break;
|
||||
}
|
||||
xpt_action(done_ccb);
|
||||
|
||||
/* decrement the retry count */
|
||||
/*
|
||||
* XXX This isn't appropriate in all cases. Restructure,
|
||||
* so that the retry count is only decremented on an
|
||||
* actual retry. Remeber that the orignal ccb had its
|
||||
* retry count dropped before entering recovery, so
|
||||
* doing it again is a bug.
|
||||
*/
|
||||
if (done_ccb->ccb_h.retry_count > 0)
|
||||
done_ccb->ccb_h.retry_count--;
|
||||
/*
|
||||
* Drop freeze taken due to CAM_DEV_QFREEZE flag set on recovery
|
||||
* request.
|
||||
*/
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
/*relsim_flags*/relsim_flags,
|
||||
/*openings*/0,
|
||||
/*timeout*/timeout,
|
||||
/*getcount_only*/0);
|
||||
/* Drop freeze taken, if this recovery request got error. */
|
||||
if (frozen != 0) {
|
||||
cam_release_devq(done_ccb->ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*openings*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
}
|
||||
out:
|
||||
/* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
|
||||
cam_release_devq(done_ccb->ccb_h.path, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1415,10 +1248,10 @@ cam_periph_freeze_after_event(struct cam_periph *periph,
|
||||
}
|
||||
|
||||
static int
|
||||
camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
u_int32_t sense_flags,
|
||||
int *openings, u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout, const char **action_string)
|
||||
camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb,
|
||||
cam_flags camflags, u_int32_t sense_flags,
|
||||
int *openings, u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout, int *print, const char **action_string)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -1431,14 +1264,13 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
break;
|
||||
case SCSI_STATUS_CMD_TERMINATED:
|
||||
case SCSI_STATUS_CHECK_COND:
|
||||
if (bootverbose)
|
||||
xpt_print(ccb->ccb_h.path, "SCSI status error\n");
|
||||
error = camperiphscsisenseerror(ccb,
|
||||
error = camperiphscsisenseerror(ccb, orig_ccb,
|
||||
camflags,
|
||||
sense_flags,
|
||||
openings,
|
||||
relsim_flags,
|
||||
timeout,
|
||||
print,
|
||||
action_string);
|
||||
break;
|
||||
case SCSI_STATUS_QUEUE_FULL:
|
||||
@ -1493,9 +1325,6 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
}
|
||||
*timeout = 0;
|
||||
error = ERESTART;
|
||||
if (bootverbose) {
|
||||
xpt_print(ccb->ccb_h.path, "Queue full\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
@ -1505,9 +1334,6 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
* Restart the queue after either another
|
||||
* command completes or a 1 second timeout.
|
||||
*/
|
||||
if (bootverbose) {
|
||||
xpt_print(ccb->ccb_h.path, "Device busy\n");
|
||||
}
|
||||
if (ccb->ccb_h.retry_count > 0) {
|
||||
ccb->ccb_h.retry_count--;
|
||||
error = ERESTART;
|
||||
@ -1519,12 +1345,7 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
}
|
||||
break;
|
||||
case SCSI_STATUS_RESERV_CONFLICT:
|
||||
xpt_print(ccb->ccb_h.path, "Reservation conflict\n");
|
||||
error = EIO;
|
||||
break;
|
||||
default:
|
||||
xpt_print(ccb->ccb_h.path, "SCSI status 0x%x\n",
|
||||
ccb->csio.scsi_status);
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
@ -1532,18 +1353,18 @@ camperiphscsistatuserror(union ccb *ccb, cam_flags camflags,
|
||||
}
|
||||
|
||||
static int
|
||||
camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
u_int32_t sense_flags,
|
||||
int *openings, u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout, const char **action_string)
|
||||
camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
|
||||
cam_flags camflags, u_int32_t sense_flags,
|
||||
int *openings, u_int32_t *relsim_flags,
|
||||
u_int32_t *timeout, int *print, const char **action_string)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
union ccb *orig_ccb = ccb;
|
||||
int error;
|
||||
int error, recoveryccb;
|
||||
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
if (periph->flags &
|
||||
(CAM_PERIPH_RECOVERY_INPROG | CAM_PERIPH_SENSE_INPROG)) {
|
||||
recoveryccb = (ccb->ccb_h.cbfcnp == camperiphdone);
|
||||
if ((periph->flags & CAM_PERIPH_RECOVERY_INPROG) && !recoveryccb) {
|
||||
/*
|
||||
* If error recovery is already in progress, don't attempt
|
||||
* to process this error, but requeue it unconditionally
|
||||
@ -1558,6 +1379,7 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
* imperitive that we don't violate this assumption.
|
||||
*/
|
||||
error = ERESTART;
|
||||
*print = 0;
|
||||
} else {
|
||||
scsi_sense_action err_action;
|
||||
struct ccb_getdev cgd;
|
||||
@ -1573,13 +1395,35 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
err_action = scsi_error_action(&ccb->csio,
|
||||
&cgd.inq_data,
|
||||
sense_flags);
|
||||
else if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
|
||||
err_action = SS_REQSENSE;
|
||||
else
|
||||
err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO;
|
||||
|
||||
error = err_action & SS_ERRMASK;
|
||||
|
||||
/*
|
||||
* Do not autostart sequential access devices
|
||||
* to avoid unexpected tape loading.
|
||||
*/
|
||||
if ((err_action & SS_MASK) == SS_START &&
|
||||
SID_TYPE(&cgd.inq_data) == T_SEQUENTIAL) {
|
||||
*action_string = "Will not autostart a "
|
||||
"sequential access device";
|
||||
goto sense_error_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid recovery recursion if recovery action is the same.
|
||||
*/
|
||||
if ((err_action & SS_MASK) >= SS_START && recoveryccb) {
|
||||
if (((err_action & SS_MASK) == SS_START &&
|
||||
ccb->csio.cdb_io.cdb_bytes[0] == START_STOP_UNIT) ||
|
||||
((err_action & SS_MASK) == SS_TUR &&
|
||||
(ccb->csio.cdb_io.cdb_bytes[0] == TEST_UNIT_READY))) {
|
||||
err_action = SS_RETRY|SSQ_DECREMENT_COUNT|EIO;
|
||||
*relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
|
||||
*timeout = 500;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the recovery action will consume a retry,
|
||||
* make sure we actually have retries available.
|
||||
@ -1627,15 +1471,6 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
case SS_START:
|
||||
{
|
||||
int le;
|
||||
if (SID_TYPE(&cgd.inq_data) == T_SEQUENTIAL) {
|
||||
xpt_free_ccb(orig_ccb);
|
||||
ccb->ccb_h.status |= CAM_DEV_QFRZN;
|
||||
*action_string = "Will not autostart a "
|
||||
"sequential access device";
|
||||
err_action = SS_FAIL;
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a start unit command to the device, and
|
||||
@ -1699,24 +1534,6 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
*timeout = 500;
|
||||
break;
|
||||
}
|
||||
case SS_REQSENSE:
|
||||
{
|
||||
*action_string = "Requesting SCSI sense data";
|
||||
periph->flags |= CAM_PERIPH_SENSE_INPROG;
|
||||
/*
|
||||
* Send a Request Sense to the device. We
|
||||
* assume that we are in a contingent allegiance
|
||||
* condition so we do not tag this request.
|
||||
*/
|
||||
scsi_request_sense(&ccb->csio, /*retries*/1,
|
||||
camperiphsensedone,
|
||||
&orig_ccb->csio.sense_data,
|
||||
orig_ccb->csio.sense_len,
|
||||
CAM_TAG_ACTION_NONE,
|
||||
/*sense_len*/SSD_FULL_SIZE,
|
||||
/*timeout*/5000);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Unhandled error action %x", err_action);
|
||||
}
|
||||
@ -1733,14 +1550,12 @@ camperiphscsisenseerror(union ccb *ccb, cam_flags camflags,
|
||||
ccb->ccb_h.pinfo.priority--;
|
||||
ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
|
||||
ccb->ccb_h.saved_ccb_ptr = orig_ccb;
|
||||
ccb->ccb_h.recovery_depth = 0;
|
||||
error = ERESTART;
|
||||
*orig = orig_ccb;
|
||||
}
|
||||
|
||||
sense_error_done:
|
||||
if ((err_action & SSQ_PRINT_SENSE) != 0
|
||||
&& (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)
|
||||
cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
|
||||
*print = ((err_action & SSQ_PRINT_SENSE) != 0);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
@ -1754,87 +1569,35 @@ int
|
||||
cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
u_int32_t sense_flags, union ccb *save_ccb)
|
||||
{
|
||||
union ccb *orig_ccb;
|
||||
struct cam_periph *periph;
|
||||
const char *action_string;
|
||||
cam_status status;
|
||||
int frozen;
|
||||
int error, printed = 0;
|
||||
int openings;
|
||||
u_int32_t relsim_flags;
|
||||
u_int32_t timeout = 0;
|
||||
int frozen, error, openings, print, lost_device;
|
||||
u_int32_t relsim_flags, timeout;
|
||||
|
||||
print = 1;
|
||||
periph = xpt_path_periph(ccb->ccb_h.path);
|
||||
action_string = NULL;
|
||||
status = ccb->ccb_h.status;
|
||||
frozen = (status & CAM_DEV_QFRZN) != 0;
|
||||
status &= CAM_STATUS_MASK;
|
||||
openings = relsim_flags = 0;
|
||||
openings = relsim_flags = timeout = lost_device = 0;
|
||||
orig_ccb = ccb;
|
||||
|
||||
switch (status) {
|
||||
case CAM_REQ_CMP:
|
||||
error = 0;
|
||||
print = 0;
|
||||
break;
|
||||
case CAM_SCSI_STATUS_ERROR:
|
||||
error = camperiphscsistatuserror(ccb,
|
||||
camflags,
|
||||
sense_flags,
|
||||
&openings,
|
||||
&relsim_flags,
|
||||
&timeout,
|
||||
&action_string);
|
||||
error = camperiphscsistatuserror(ccb, &orig_ccb,
|
||||
camflags, sense_flags, &openings, &relsim_flags,
|
||||
&timeout, &print, &action_string);
|
||||
break;
|
||||
case CAM_AUTOSENSE_FAIL:
|
||||
xpt_print(ccb->ccb_h.path, "AutoSense failed\n");
|
||||
error = EIO; /* we have to kill the command */
|
||||
break;
|
||||
case CAM_ATA_STATUS_ERROR:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "ATA status error\n");
|
||||
cam_error_print(ccb, CAM_ESF_ALL, CAM_EPF_ALL);
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_REQ_CMP_ERR:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path,
|
||||
"Request completed with CAM_REQ_CMP_ERR\n");
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_CMD_TIMEOUT:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "Command timed out\n");
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_UNEXP_BUSFREE:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "Unexpected Bus Free\n");
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_UNCOR_PARITY:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path,
|
||||
"Uncorrected parity error\n");
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_DATA_RUN_ERR:
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "Data overrun\n");
|
||||
printed++;
|
||||
}
|
||||
/* decrement the number of retries */
|
||||
if (ccb->ccb_h.retry_count > 0 &&
|
||||
(periph->flags & CAM_PERIPH_INVALID) == 0) {
|
||||
ccb->ccb_h.retry_count--;
|
||||
error = ERESTART;
|
||||
} else {
|
||||
action_string = "Retries exhausted";
|
||||
error = EIO;
|
||||
}
|
||||
break;
|
||||
case CAM_UA_ABORT:
|
||||
case CAM_UA_TERMIO:
|
||||
case CAM_MSG_REJECT_REC:
|
||||
@ -1845,14 +1608,8 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
if ((camflags & CAM_RETRY_SELTO) != 0) {
|
||||
if (ccb->ccb_h.retry_count > 0 &&
|
||||
(periph->flags & CAM_PERIPH_INVALID) == 0) {
|
||||
|
||||
ccb->ccb_h.retry_count--;
|
||||
error = ERESTART;
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path,
|
||||
"Selection timeout\n");
|
||||
printed++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait a bit to give the device
|
||||
@ -1866,38 +1623,10 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_DEV_NOT_THERE:
|
||||
{
|
||||
struct cam_path *newpath;
|
||||
lun_id_t lun_id;
|
||||
|
||||
error = ENXIO;
|
||||
|
||||
/*
|
||||
* For a selection timeout, we consider all of the LUNs on
|
||||
* the target to be gone. If the status is CAM_DEV_NOT_THERE,
|
||||
* then we only get rid of the device(s) specified by the
|
||||
* path in the original CCB.
|
||||
*/
|
||||
if (status == CAM_DEV_NOT_THERE)
|
||||
lun_id = xpt_path_lun_id(ccb->ccb_h.path);
|
||||
else
|
||||
lun_id = CAM_LUN_WILDCARD;
|
||||
|
||||
/* Should we do more if we can't create the path?? */
|
||||
if (xpt_create_path(&newpath, periph,
|
||||
xpt_path_path_id(ccb->ccb_h.path),
|
||||
xpt_path_target_id(ccb->ccb_h.path),
|
||||
lun_id) != CAM_REQ_CMP)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Let peripheral drivers know that this device has gone
|
||||
* away.
|
||||
*/
|
||||
xpt_async(AC_LOST_DEVICE, newpath, NULL);
|
||||
xpt_free_path(newpath);
|
||||
print = 0;
|
||||
lost_device = 1;
|
||||
break;
|
||||
}
|
||||
case CAM_REQ_INVALID:
|
||||
case CAM_PATH_INVALID:
|
||||
case CAM_NO_HBA:
|
||||
@ -1917,27 +1646,16 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
* these events and should be unconditionally
|
||||
* retried.
|
||||
*/
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print_path(ccb->ccb_h.path);
|
||||
if (status == CAM_BDR_SENT)
|
||||
printf("Bus Device Reset sent\n");
|
||||
else
|
||||
printf("Bus Reset issued\n");
|
||||
printed++;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case CAM_REQUEUE_REQ:
|
||||
/* Unconditional requeue */
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "Request requeued\n");
|
||||
printed++;
|
||||
}
|
||||
if ((periph->flags & CAM_PERIPH_INVALID) == 0)
|
||||
error = ERESTART;
|
||||
else {
|
||||
action_string = "Retries exhausted";
|
||||
/* Unconditional requeue if device is still there */
|
||||
if (periph->flags & CAM_PERIPH_INVALID) {
|
||||
action_string = "Periph was invalidated";
|
||||
error = EIO;
|
||||
}
|
||||
} else if (sense_flags & SF_NO_RETRY) {
|
||||
error = EIO;
|
||||
action_string = "Retry was blocked";
|
||||
} else
|
||||
error = ERESTART;
|
||||
break;
|
||||
case CAM_RESRC_UNAVAIL:
|
||||
/* Wait a bit for the resource shortage to abate. */
|
||||
@ -1950,30 +1668,37 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
}
|
||||
relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT;
|
||||
/* FALLTHROUGH */
|
||||
case CAM_ATA_STATUS_ERROR:
|
||||
case CAM_REQ_CMP_ERR:
|
||||
case CAM_CMD_TIMEOUT:
|
||||
case CAM_UNEXP_BUSFREE:
|
||||
case CAM_UNCOR_PARITY:
|
||||
case CAM_DATA_RUN_ERR:
|
||||
default:
|
||||
/* decrement the number of retries */
|
||||
if (ccb->ccb_h.retry_count > 0 &&
|
||||
(periph->flags & CAM_PERIPH_INVALID) == 0) {
|
||||
ccb->ccb_h.retry_count--;
|
||||
error = ERESTART;
|
||||
if (bootverbose && printed == 0) {
|
||||
xpt_print(ccb->ccb_h.path, "CAM status 0x%x\n",
|
||||
status);
|
||||
printed++;
|
||||
}
|
||||
} else {
|
||||
if (periph->flags & CAM_PERIPH_INVALID) {
|
||||
error = EIO;
|
||||
action_string = "Periph was invalidated";
|
||||
} else if (ccb->ccb_h.retry_count == 0) {
|
||||
error = EIO;
|
||||
action_string = "Retries exhausted";
|
||||
} else if (sense_flags & SF_NO_RETRY) {
|
||||
error = EIO;
|
||||
action_string = "Retry was blocked";
|
||||
} else {
|
||||
ccb->ccb_h.retry_count--;
|
||||
error = ERESTART;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have and error and are booting verbosely, whine
|
||||
* *unless* this was a non-retryable selection timeout.
|
||||
*/
|
||||
if (error != 0 && bootverbose &&
|
||||
!(status == CAM_SEL_TIMEOUT && (camflags & CAM_RETRY_SELTO) == 0)) {
|
||||
if ((sense_flags & SF_PRINT_ALWAYS) ||
|
||||
CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO))
|
||||
print = 1;
|
||||
else if (sense_flags & SF_NO_PRINT)
|
||||
print = 0;
|
||||
if (print)
|
||||
cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
|
||||
if (error != 0 && print) {
|
||||
if (error != ERESTART) {
|
||||
if (action_string == NULL)
|
||||
action_string = "Unretryable error";
|
||||
@ -1985,6 +1710,36 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
|
||||
xpt_print(ccb->ccb_h.path, "Retrying command\n");
|
||||
}
|
||||
|
||||
if (lost_device) {
|
||||
struct cam_path *newpath;
|
||||
lun_id_t lun_id;
|
||||
|
||||
/*
|
||||
* For a selection timeout, we consider all of the LUNs on
|
||||
* the target to be gone. If the status is CAM_DEV_NOT_THERE,
|
||||
* then we only get rid of the device(s) specified by the
|
||||
* path in the original CCB.
|
||||
*/
|
||||
if (status == CAM_DEV_NOT_THERE)
|
||||
lun_id = xpt_path_lun_id(ccb->ccb_h.path);
|
||||
else
|
||||
lun_id = CAM_LUN_WILDCARD;
|
||||
|
||||
/* Should we do more if we can't create the path?? */
|
||||
if (xpt_create_path(&newpath, periph,
|
||||
xpt_path_path_id(ccb->ccb_h.path),
|
||||
xpt_path_target_id(ccb->ccb_h.path),
|
||||
lun_id) == CAM_REQ_CMP) {
|
||||
|
||||
/*
|
||||
* Let peripheral drivers know that this
|
||||
* device has gone away.
|
||||
*/
|
||||
xpt_async(AC_LOST_DEVICE, newpath, NULL);
|
||||
xpt_free_path(newpath);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt a retry */
|
||||
if (error == ERESTART || error == 0) {
|
||||
if (frozen != 0)
|
||||
|
@ -118,7 +118,6 @@ struct cam_periph {
|
||||
#define CAM_PERIPH_INVALID 0x08
|
||||
#define CAM_PERIPH_NEW_DEV_FOUND 0x10
|
||||
#define CAM_PERIPH_RECOVERY_INPROG 0x20
|
||||
#define CAM_PERIPH_SENSE_INPROG 0x40
|
||||
#define CAM_PERIPH_FREE 0x80
|
||||
u_int32_t immediate_priority;
|
||||
u_int32_t refcount;
|
||||
|
@ -2901,11 +2901,17 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
|
||||
SSQ_PRINT_SENSE;
|
||||
}
|
||||
}
|
||||
if ((action & SS_MASK) >= SS_START &&
|
||||
(sense_flags & SF_NO_RECOVERY)) {
|
||||
action &= ~SS_MASK;
|
||||
action |= SS_FAIL;
|
||||
} else if ((action & SS_MASK) == SS_RETRY &&
|
||||
(sense_flags & SF_NO_RETRY)) {
|
||||
action &= ~SS_MASK;
|
||||
action |= SS_FAIL;
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef _KERNEL
|
||||
if (bootverbose)
|
||||
sense_flags |= SF_PRINT_ALWAYS;
|
||||
#endif
|
||||
if ((sense_flags & SF_PRINT_ALWAYS) != 0)
|
||||
action |= SSQ_PRINT_SENSE;
|
||||
else if ((sense_flags & SF_NO_PRINT) != 0)
|
||||
|
@ -74,9 +74,6 @@ typedef enum {
|
||||
SS_TUR = 0x040000, /* Send a Test Unit Ready command to the
|
||||
* device, then retry the original command.
|
||||
*/
|
||||
SS_REQSENSE = 0x050000, /* Send a RequestSense command to the
|
||||
* device, then retry the original command.
|
||||
*/
|
||||
SS_MASK = 0xff0000
|
||||
} scsi_sense_action;
|
||||
|
||||
@ -2196,12 +2193,6 @@ void scsi_sense_print(struct cam_device *device,
|
||||
struct ccb_scsiio *csio, FILE *ofile);
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#define SF_RETRY_UA 0x01
|
||||
#define SF_NO_PRINT 0x02
|
||||
#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */
|
||||
#define SF_PRINT_ALWAYS 0x08
|
||||
|
||||
|
||||
const char * scsi_op_desc(u_int16_t opcode,
|
||||
struct scsi_inquiry_data *inq_data);
|
||||
char * scsi_cdb_string(u_int8_t *cdb_ptr, char *cdb_string,
|
||||
|
@ -1120,6 +1120,7 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
||||
u_int secsize;
|
||||
struct ccb_scsiio csio;
|
||||
struct disk *dp;
|
||||
int error = 0;
|
||||
|
||||
dp = arg;
|
||||
periph = dp->d_drv1;
|
||||
@ -1138,7 +1139,7 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
||||
xpt_setup_ccb(&csio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
|
||||
csio.ccb_h.ccb_state = DA_CCB_DUMP;
|
||||
scsi_read_write(&csio,
|
||||
/*retries*/1,
|
||||
/*retries*/0,
|
||||
dadone,
|
||||
MSG_ORDERED_Q_TAG,
|
||||
/*read*/FALSE,
|
||||
@ -1151,19 +1152,16 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
||||
/*sense_len*/SSD_FULL_SIZE,
|
||||
da_default_timeout * 1000);
|
||||
xpt_polled_action((union ccb *)&csio);
|
||||
cam_periph_unlock(periph);
|
||||
|
||||
if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
error = cam_periph_error((union ccb *)&csio,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
if ((csio.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(csio.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
printf("Aborting dump due to I/O error.\n");
|
||||
if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR)
|
||||
scsi_sense_print(&csio);
|
||||
else
|
||||
printf("status == 0x%x, scsi status == 0x%x\n",
|
||||
csio.ccb_h.status, csio.scsi_status);
|
||||
return(EIO);
|
||||
}
|
||||
return(0);
|
||||
cam_periph_unlock(periph);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1174,7 +1172,7 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
||||
xpt_setup_ccb(&csio.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
|
||||
csio.ccb_h.ccb_state = DA_CCB_DUMP;
|
||||
scsi_synchronize_cache(&csio,
|
||||
/*retries*/1,
|
||||
/*retries*/0,
|
||||
/*cbfcnp*/dadone,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
/*begin_lba*/0,/* Cover the whole disk */
|
||||
@ -1183,28 +1181,16 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
||||
5 * 60 * 1000);
|
||||
xpt_polled_action((union ccb *)&csio);
|
||||
|
||||
if ((csio.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
if ((csio.ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR) {
|
||||
int asc, ascq;
|
||||
int sense_key, error_code;
|
||||
|
||||
scsi_extract_sense_len(&csio.sense_data,
|
||||
csio.sense_len - csio.sense_resid,
|
||||
&error_code, &sense_key, &asc, &ascq,
|
||||
/*show_errors*/ 1);
|
||||
if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
|
||||
scsi_sense_print(&csio);
|
||||
} else {
|
||||
xpt_print(periph->path, "Synchronize cache "
|
||||
"failed, status == 0x%x, scsi status == "
|
||||
"0x%x\n", csio.ccb_h.status,
|
||||
csio.scsi_status);
|
||||
}
|
||||
}
|
||||
error = cam_periph_error((union ccb *)&csio,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY | SF_QUIET_IR, NULL);
|
||||
if ((csio.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(csio.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
}
|
||||
cam_periph_unlock(periph);
|
||||
return (0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2678,6 +2664,7 @@ dashutdown(void * arg, int howto)
|
||||
{
|
||||
struct cam_periph *periph;
|
||||
struct da_softc *softc;
|
||||
int error;
|
||||
|
||||
TAILQ_FOREACH(periph, &dadriver.units, unit_links) {
|
||||
union ccb ccb;
|
||||
@ -2699,7 +2686,7 @@ dashutdown(void * arg, int howto)
|
||||
|
||||
ccb.ccb_h.ccb_state = DA_CCB_DUMP;
|
||||
scsi_synchronize_cache(&ccb.csio,
|
||||
/*retries*/1,
|
||||
/*retries*/0,
|
||||
/*cbfcnp*/dadone,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
/*begin_lba*/0, /* whole disk */
|
||||
@ -2709,32 +2696,13 @@ dashutdown(void * arg, int howto)
|
||||
|
||||
xpt_polled_action(&ccb);
|
||||
|
||||
if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
if (((ccb.ccb_h.status & CAM_STATUS_MASK) ==
|
||||
CAM_SCSI_STATUS_ERROR)
|
||||
&& (ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND)){
|
||||
int error_code, sense_key, asc, ascq;
|
||||
|
||||
scsi_extract_sense(&ccb.csio.sense_data,
|
||||
&error_code, &sense_key,
|
||||
&asc, &ascq);
|
||||
|
||||
if (sense_key != SSD_KEY_ILLEGAL_REQUEST)
|
||||
scsi_sense_print(&ccb.csio);
|
||||
} else {
|
||||
xpt_print(periph->path, "Synchronize "
|
||||
"cache failed, status == 0x%x, scsi status "
|
||||
"== 0x%x\n", ccb.ccb_h.status,
|
||||
ccb.csio.scsi_status);
|
||||
}
|
||||
}
|
||||
|
||||
error = cam_periph_error(&ccb,
|
||||
0, SF_NO_RECOVERY | SF_NO_RETRY | SF_QUIET_IR, NULL);
|
||||
if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0)
|
||||
cam_release_devq(ccb.ccb_h.path,
|
||||
/*relsim_flags*/0,
|
||||
/*reduction*/0,
|
||||
/*timeout*/0,
|
||||
/*getcount_only*/0);
|
||||
cam_release_devq(ccb.ccb_h.path, /*relsim_flags*/0,
|
||||
/*reduction*/0, /*timeout*/0, /*getcount_only*/0);
|
||||
if (error != 0)
|
||||
xpt_print(periph->path, "Synchronize cache failed\n");
|
||||
cam_periph_unlock(periph);
|
||||
}
|
||||
}
|
||||
|
@ -624,9 +624,9 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
|
||||
* that request. Otherwise, it's up to the user to perform any
|
||||
* error recovery.
|
||||
*/
|
||||
cam_periph_runccb(ccb,
|
||||
(ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ? passerror : NULL,
|
||||
/* cam_flags */ CAM_RETRY_SELTO, /* sense_flags */SF_RETRY_UA,
|
||||
cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
|
||||
/* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
|
||||
SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
|
||||
softc->device_stats);
|
||||
|
||||
if (need_unmap != 0)
|
||||
|
@ -747,7 +747,7 @@ again:
|
||||
case PROBE_DV_EXIT:
|
||||
{
|
||||
scsi_test_unit_ready(csio,
|
||||
/*retries*/10,
|
||||
/*retries*/4,
|
||||
probedone,
|
||||
MSG_SIMPLE_Q_TAG,
|
||||
SSD_FULL_SIZE,
|
||||
@ -1596,14 +1596,11 @@ probe_device_check:
|
||||
break;
|
||||
}
|
||||
case PROBE_TUR_FOR_NEGOTIATION:
|
||||
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
DELAY(500000);
|
||||
if (cam_periph_error(done_ccb, 0, SF_RETRY_UA,
|
||||
NULL) == ERESTART)
|
||||
return;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case PROBE_DV_EXIT:
|
||||
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
cam_periph_error(done_ccb, 0,
|
||||
SF_NO_PRINT | SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
}
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
@ -1651,6 +1648,10 @@ probe_device_check:
|
||||
struct scsi_inquiry_data *nbuf;
|
||||
struct ccb_scsiio *csio;
|
||||
|
||||
if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
|
||||
cam_periph_error(done_ccb, 0,
|
||||
SF_NO_PRINT | SF_NO_RECOVERY | SF_NO_RETRY, NULL);
|
||||
}
|
||||
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
|
||||
/* Don't wedge the queue */
|
||||
xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
|
||||
|
Loading…
Reference in New Issue
Block a user