summaryrefslogtreecommitdiffstats
path: root/sys/cam
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2013-07-13 13:35:09 +0000
committermav <mav@FreeBSD.org>2013-07-13 13:35:09 +0000
commitd75119065b9ad4b13f6870b29b9ebebec97bcaf8 (patch)
tree1bbe85818b0eefda92ddef5eb2034beb5d75adec /sys/cam
parent4b658e6ec59bdcaf0b935ad4ad6403c6211eff74 (diff)
downloadFreeBSD-src-d75119065b9ad4b13f6870b29b9ebebec97bcaf8.zip
FreeBSD-src-d75119065b9ad4b13f6870b29b9ebebec97bcaf8.tar.gz
Improve handling of 0x3F/0x0E "Reported LUNs data has changed" and 0x25/0x00
"Logical unit not supported" errors. First initiates specific target rescan, second -- destroys specific LUN. That allows to automatically detect changes in list of device LUNs. This mechanism doesn't work when target is completely idle, but probably that is all what can be done without active polling. Reviewed by: ken Sponsored by: iXsystems, Inc.
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/cam_periph.c73
-rw-r--r--sys/cam/scsi/scsi_all.c5
-rw-r--r--sys/cam/scsi/scsi_all.h3
3 files changed, 48 insertions, 33 deletions
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index f3300db..8d0d470 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -75,7 +75,7 @@ static int camperiphscsistatuserror(union ccb *ccb,
int *openings,
u_int32_t *relsim_flags,
u_int32_t *timeout,
- int *print,
+ u_int32_t *action,
const char **action_string);
static int camperiphscsisenseerror(union ccb *ccb,
union ccb **orig_ccb,
@@ -84,7 +84,7 @@ static int camperiphscsisenseerror(union ccb *ccb,
int *openings,
u_int32_t *relsim_flags,
u_int32_t *timeout,
- int *print,
+ u_int32_t *action,
const char **action_string);
static int nperiph_drivers;
@@ -1274,7 +1274,7 @@ 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)
+ u_int32_t *timeout, u_int32_t *action, const char **action_string)
{
int error;
@@ -1293,7 +1293,7 @@ camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb,
openings,
relsim_flags,
timeout,
- print,
+ action,
action_string);
break;
case SCSI_STATUS_QUEUE_FULL:
@@ -1348,7 +1348,7 @@ camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb,
}
*timeout = 0;
error = ERESTART;
- *print = 0;
+ *action &= ~SSQ_PRINT_SENSE;
break;
}
/* FALLTHROUGH */
@@ -1380,7 +1380,7 @@ static int
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)
+ u_int32_t *timeout, u_int32_t *action, const char **action_string)
{
struct cam_periph *periph;
union ccb *orig_ccb = ccb;
@@ -1403,7 +1403,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
* imperitive that we don't violate this assumption.
*/
error = ERESTART;
- *print = 0;
+ *action &= ~SSQ_PRINT_SENSE;
} else {
scsi_sense_action err_action;
struct ccb_getdev cgd;
@@ -1575,7 +1575,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
}
sense_error_done:
- *print = ((err_action & SSQ_PRINT_SENSE) != 0);
+ *action = err_action;
}
return (error);
}
@@ -1589,32 +1589,32 @@ 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_path *newpath;
+ union ccb *orig_ccb, *scan_ccb;
struct cam_periph *periph;
const char *action_string;
cam_status status;
- int frozen, error, openings, print, lost_device;
- int error_code, sense_key, asc, ascq;
- u_int32_t relsim_flags, timeout;
+ int frozen, error, openings;
+ u_int32_t action, relsim_flags, timeout;
- print = 1;
+ action = SSQ_PRINT_SENSE;
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 = timeout = lost_device = 0;
+ openings = relsim_flags = timeout = 0;
orig_ccb = ccb;
switch (status) {
case CAM_REQ_CMP:
error = 0;
- print = 0;
+ action &= ~SSQ_PRINT_SENSE;
break;
case CAM_SCSI_STATUS_ERROR:
error = camperiphscsistatuserror(ccb, &orig_ccb,
camflags, sense_flags, &openings, &relsim_flags,
- &timeout, &print, &action_string);
+ &timeout, &action, &action_string);
break;
case CAM_AUTOSENSE_FAIL:
error = EIO; /* we have to kill the command */
@@ -1645,8 +1645,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
/* FALLTHROUGH */
case CAM_DEV_NOT_THERE:
error = ENXIO;
- print = 0;
- lost_device = 1;
+ action = SSQ_LOST;
break;
case CAM_REQ_INVALID:
case CAM_PATH_INVALID:
@@ -1677,7 +1676,7 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
action_string = "Retry was blocked";
} else {
error = ERESTART;
- print = 0;
+ action &= ~SSQ_PRINT_SENSE;
}
break;
case CAM_RESRC_UNAVAIL:
@@ -1716,12 +1715,12 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
if ((sense_flags & SF_PRINT_ALWAYS) ||
CAM_DEBUGGED(ccb->ccb_h.path, CAM_DEBUG_INFO))
- print = 1;
+ action |= SSQ_PRINT_SENSE;
else if (sense_flags & SF_NO_PRINT)
- print = 0;
- if (print)
+ action &= ~SSQ_PRINT_SENSE;
+ if ((action & SSQ_PRINT_SENSE) != 0)
cam_error_print(orig_ccb, CAM_ESF_ALL, CAM_EPF_ALL);
- if (error != 0 && print) {
+ if (error != 0 && (action & SSQ_PRINT_SENSE) != 0) {
if (error != ERESTART) {
if (action_string == NULL)
action_string = "Unretryable error";
@@ -1733,8 +1732,7 @@ 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;
+ if ((action & SSQ_LOST) != 0) {
lun_id_t lun_id;
/*
@@ -1743,10 +1741,10 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
* 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
+ if (status == CAM_SEL_TIMEOUT)
lun_id = CAM_LUN_WILDCARD;
+ else
+ lun_id = xpt_path_lun_id(ccb->ccb_h.path);
/* Should we do more if we can't create the path?? */
if (xpt_create_path(&newpath, periph,
@@ -1761,12 +1759,25 @@ cam_periph_error(union ccb *ccb, cam_flags camflags,
xpt_async(AC_LOST_DEVICE, newpath, NULL);
xpt_free_path(newpath);
}
+ }
/* Broadcast UNIT ATTENTIONs to all periphs. */
- } else if (scsi_extract_sense_ccb(ccb,
- &error_code, &sense_key, &asc, &ascq) &&
- sense_key == SSD_KEY_UNIT_ATTENTION) {
+ if ((action & SSQ_UA) != 0)
xpt_async(AC_UNIT_ATTENTION, orig_ccb->ccb_h.path, orig_ccb);
+
+ /* Rescan target on "Reported LUNs data has changed" */
+ if ((action & SSQ_RESCAN) != 0) {
+ if (xpt_create_path(&newpath, NULL,
+ xpt_path_path_id(ccb->ccb_h.path),
+ xpt_path_target_id(ccb->ccb_h.path),
+ -1) == CAM_REQ_CMP) {
+
+ scan_ccb = xpt_alloc_ccb_nowait();
+ scan_ccb->ccb_h.path = newpath;
+ scan_ccb->ccb_h.func_code = XPT_SCAN_BUS;
+ scan_ccb->crcn.flags = 0;
+ xpt_rescan(scan_ccb);
+ }
}
/* Attempt a retry */
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c
index 40c3ef0..5248338 100644
--- a/sys/cam/scsi/scsi_all.c
+++ b/sys/cam/scsi/scsi_all.c
@@ -1645,7 +1645,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x24, 0x08, SS_RDEF, /* XXX TBD */
"Invalid XCDB") },
/* DTLPWROMAEBKVF */
- { SST(0x25, 0x00, SS_FATAL | ENXIO,
+ { SST(0x25, 0x00, SS_FATAL | ENXIO | SSQ_LOST,
"Logical unit not supported") },
/* DTLPWROMAEBKVF */
{ SST(0x26, 0x00, SS_FATAL | EINVAL,
@@ -2163,7 +2163,7 @@ static struct asc_table_entry asc_table[] = {
{ SST(0x3F, 0x0D, SS_RDEF,
"Volume set reassigned") },
/* DTLPWROMAE */
- { SST(0x3F, 0x0E, SS_RDEF, /* XXX TBD */
+ { SST(0x3F, 0x0E, SS_RDEF | SSQ_RESCAN ,
"Reported LUNs data has changed") },
/* DTLPWROMAEBKVF */
{ SST(0x3F, 0x0F, SS_RDEF, /* XXX TBD */
@@ -3263,6 +3263,7 @@ scsi_error_action(struct ccb_scsiio *csio, struct scsi_inquiry_data *inq_data,
action |= SS_RETRY|SSQ_DECREMENT_COUNT|
SSQ_PRINT_SENSE;
}
+ action |= SSQ_UA;
}
}
if ((action & SS_MASK) >= SS_START &&
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 4c024a9..72d9d15 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -88,6 +88,9 @@ typedef enum {
* and text.
*/
SSQ_PRINT_SENSE = 0x0800,
+ SSQ_UA = 0x1000, /* Broadcast UA. */
+ SSQ_RESCAN = 0x2000, /* Rescan target for LUNs. */
+ SSQ_LOST = 0x4000, /* Destroy the LUNs. */
SSQ_MASK = 0xff00
} scsi_sense_action_qualifier;
OpenPOWER on IntegriCloud