From 174b32ced4be75344530fcbd5d56bb49c5250401 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 2 Feb 2015 20:23:05 +0000 Subject: [PATCH] Retry indefinitely on SCSI BUSY status from VMware disks and CDs. VMware returns BUSY status when storage has transient connectivity issues. It is often better to wait and let VM admin fix the problem then crash. Discussed with: ken MFC after: 1 week --- sys/cam/cam.h | 3 ++- sys/cam/cam_periph.c | 4 ++-- sys/cam/scsi/scsi_cd.c | 17 +++++++++++++++-- sys/cam/scsi/scsi_da.c | 18 ++++++++++++++++-- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/sys/cam/cam.h b/sys/cam/cam.h index 302504fb4fc..e08524b908a 100644 --- a/sys/cam/cam.h +++ b/sys/cam/cam.h @@ -121,7 +121,8 @@ enum { 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. */ + SF_NO_RETRY = 0x20, /* Don't do any retries. */ + SF_RETRY_BUSY = 0x40 /* Retry BUSY status. */ }; /* CAM Status field values */ diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index 2e23996966a..87c1bdd9881 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -1359,8 +1359,8 @@ camperiphscsistatuserror(union ccb *ccb, union ccb **orig_ccb, * Restart the queue after either another * command completes or a 1 second timeout. */ - if (ccb->ccb_h.retry_count > 0) { - ccb->ccb_h.retry_count--; + if ((sense_flags & SF_RETRY_BUSY) != 0 || + (ccb->ccb_h.retry_count--) > 0) { error = ERESTART; *relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT | RELSIM_RELEASE_AFTER_CMDCMPLT; diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index 47a5a438d29..f252b862b10 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -87,14 +87,16 @@ typedef enum { CD_Q_NONE = 0x00, CD_Q_NO_TOUCH = 0x01, CD_Q_BCD_TRACKS = 0x02, - CD_Q_10_BYTE_ONLY = 0x10 + CD_Q_10_BYTE_ONLY = 0x10, + CD_Q_RETRY_BUSY = 0x40 } cd_quirks; #define CD_Q_BIT_STRING \ "\020" \ "\001NO_TOUCH" \ "\002BCD_TRACKS" \ - "\00510_BYTE_ONLY" + "\00510_BYTE_ONLY" \ + "\007RETRY_BUSY" typedef enum { CD_FLAG_INVALID = 0x0001, @@ -189,6 +191,14 @@ static struct cd_quirk_entry cd_quirk_table[] = { { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"}, /* quirks */ CD_Q_BCD_TRACKS + }, + { + /* + * VMware returns BUSY status when storage has transient + * connectivity problems, so better wait. + */ + {T_CDROM, SIP_MEDIA_REMOVABLE, "NECVMWar", "VMware IDE CDR10", "*"}, + /*quirks*/ CD_Q_RETRY_BUSY } }; @@ -2581,6 +2591,9 @@ cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) * don't treat UAs as errors. */ sense_flags |= SF_RETRY_UA; + + if (softc->quirks & CD_Q_RETRY_BUSY) + sense_flags |= SF_RETRY_BUSY; return (cam_periph_error(ccb, cam_flags, sense_flags, &softc->saved_ccb)); } diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index a65d2dc85f3..9b50d7a64e6 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -101,7 +101,8 @@ typedef enum { DA_Q_NO_PREVENT = 0x04, DA_Q_4K = 0x08, DA_Q_NO_RC16 = 0x10, - DA_Q_NO_UNMAP = 0x20 + DA_Q_NO_UNMAP = 0x20, + DA_Q_RETRY_BUSY = 0x40 } da_quirks; #define DA_Q_BIT_STRING \ @@ -110,7 +111,9 @@ typedef enum { "\002NO_6_BYTE" \ "\003NO_PREVENT" \ "\0044K" \ - "\005NO_RC16" + "\005NO_RC16" \ + "\006NO_UNMAP" \ + "\007RETRY_BUSY" typedef enum { DA_CCB_PROBE_RC = 0x01, @@ -359,6 +362,14 @@ static struct da_quirk_entry da_quirk_table[] = {T_DIRECT, SIP_MEDIA_FIXED, "STEC", "*", "*"}, /*quirks*/ DA_Q_NO_UNMAP }, + { + /* + * VMware returns BUSY status when storage has transient + * connectivity problems, so better wait. + */ + {T_DIRECT, SIP_MEDIA_FIXED, "VMware", "Virtual disk", "*"}, + /*quirks*/ DA_Q_RETRY_BUSY + }, /* USB mass storage devices supported by umass(4) */ { /* @@ -3630,6 +3641,9 @@ daerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) * don't treat UAs as errors. */ sense_flags |= SF_RETRY_UA; + + if (softc->quirks & DA_Q_RETRY_BUSY) + sense_flags |= SF_RETRY_BUSY; return(cam_periph_error(ccb, cam_flags, sense_flags, &softc->saved_ccb)); }