1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-08 13:28:05 +00:00

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.
This commit is contained in:
Alexander Motin 2013-07-13 13:35:09 +00:00
parent b8f19c9247
commit 0181d54b6b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=253322
3 changed files with 48 additions and 33 deletions

View File

@ -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 */

View File

@ -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 &&

View File

@ -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;