diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/io/scsi/targets/sd.c | 101 |
1 files changed, 76 insertions, 25 deletions
diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c index 66e276bf48..e462bf104e 100644 --- a/usr/src/uts/common/io/scsi/targets/sd.c +++ b/usr/src/uts/common/io/scsi/targets/sd.c @@ -11418,30 +11418,46 @@ sd_ssc_send(sd_ssc_t *ssc, struct uscsi_cmd *incmd, int flag, enum uio_seg dataspace, int path_flag) { struct sd_uscsi_info *uip; - struct uscsi_cmd *uscmd = ssc->ssc_uscsi_cmd; + struct uscsi_cmd *uscmd; struct sd_lun *un; dev_t dev; int format = 0; int rval; - ASSERT(ssc != NULL); un = ssc->ssc_un; ASSERT(un != NULL); + uscmd = ssc->ssc_uscsi_cmd; + ASSERT(uscmd != NULL); ASSERT(!mutex_owned(SD_MUTEX(un))); - ASSERT(!(ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT)); + if (ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT) { + /* + * If enter here, it indicates that the previous uscsi + * command has not been processed by sd_ssc_assessment. + * This is violating our rules of FMA telemetry processing. + * We should print out this message and the last undisposed + * uscsi command. + */ + if (uscmd->uscsi_cdb != NULL) { + SD_INFO(SD_LOG_SDTEST, un, + "sd_ssc_send is missing the alternative " + "sd_ssc_assessment when running command 0x%x.\n", + uscmd->uscsi_cdb[0]); + } + /* + * Set the ssc_flags to SSC_FLAGS_UNKNOWN, which should be + * the initial status. + */ + ssc->ssc_flags = SSC_FLAGS_UNKNOWN; + } + /* * We need to make sure sd_ssc_send will have sd_ssc_assessment - * followed to avoid missing any point of telemetry. + * followed to avoid missing FMA telemetries. */ ssc->ssc_flags |= SSC_FLAGS_NEED_ASSESSMENT; - if (uscmd == NULL) { - return (ENXIO); - } - - #ifdef SDDEBUG switch (dataspace) { case UIO_USERSPACE: @@ -11614,45 +11630,76 @@ sd_ssc_assessment(sd_ssc_t *ssc, enum sd_type_assessment tp_assess) struct sd_lun *un; ASSERT(ssc != NULL); - ASSERT(ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT); - - ssc->ssc_flags &= ~SSC_FLAGS_NEED_ASSESSMENT; un = ssc->ssc_un; ASSERT(un != NULL); + ucmdp = ssc->ssc_uscsi_cmd; + ASSERT(ucmdp != NULL); + + if (ssc->ssc_flags & SSC_FLAGS_NEED_ASSESSMENT) { + ssc->ssc_flags &= ~SSC_FLAGS_NEED_ASSESSMENT; + } else { + /* + * If enter here, it indicates that we have a wrong + * calling sequence of sd_ssc_send and sd_ssc_assessment, + * both of which should be called in a pair in case of + * loss of FMA telemetries. + */ + if (ucmdp->uscsi_cdb != NULL) { + SD_INFO(SD_LOG_SDTEST, un, + "sd_ssc_assessment is missing the " + "alternative sd_ssc_send when running 0x%x, " + "or there are superfluous sd_ssc_assessment for " + "the same sd_ssc_send.\n", + ucmdp->uscsi_cdb[0]); + } + /* + * Set the ssc_flags to the initial value to avoid passing + * down dirty flags to the following sd_ssc_send function. + */ + ssc->ssc_flags = SSC_FLAGS_UNKNOWN; + return; + } /* - * We don't handle CD-ROM, and removable media + * We don't handle a non-disk drive(CD-ROM, removable media). + * Clear the ssc_flags before return in case we've set + * SSC_FLAGS_INVALID_DATA which should be skipped for a non-disk + * driver. */ if (ISCD(un) || un->un_f_has_removable_media) { - ssc->ssc_flags &= ~SSC_FLAGS_CMD_ISSUED; - ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA; + ssc->ssc_flags = SSC_FLAGS_UNKNOWN; return; } /* * Only handle an issued command which is waiting for assessment. + * A command which is not issued will not have + * SSC_FLAGS_INVALID_DATA set, so it'ok we just return here. */ if (!(ssc->ssc_flags & SSC_FLAGS_CMD_ISSUED)) { sd_ssc_print(ssc, SCSI_ERR_INFO); return; - } else + } else { + /* + * For an issued command, we should clear this flag in + * order to make the sd_ssc_t structure be used off + * multiple uscsi commands. + */ ssc->ssc_flags &= ~SSC_FLAGS_CMD_ISSUED; - - ucmdp = ssc->ssc_uscsi_cmd; - ASSERT(ucmdp != NULL); + } /* - * We will not deal with non-retryable commands here. + * We will not deal with non-retryable(flag USCSI_DIAGNOSE set) + * commands here. And we should clear the ssc_flags before return. */ if (ucmdp->uscsi_flags & USCSI_DIAGNOSE) { - ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA; + ssc->ssc_flags = SSC_FLAGS_UNKNOWN; return; } switch (tp_assess) { case SD_FMT_IGNORE: case SD_FMT_IGNORE_COMPROMISE: - ssc->ssc_flags &= ~SSC_FLAGS_INVALID_DATA; break; case SD_FMT_STATUS_CHECK: /* @@ -11680,13 +11727,17 @@ sd_ssc_assessment(sd_ssc_t *ssc, enum sd_type_assessment tp_assess) break; default: /* - * Should be an software error. + * Should not have other type of assessment. */ scsi_log(SD_DEVINFO(un), sd_label, CE_CONT, - "sd_ssc_assessment got wrong \ - sd_type_assessment %d\n", tp_assess); + "sd_ssc_assessment got wrong " + "sd_type_assessment %d.\n", tp_assess); break; } + /* + * Clear up the ssc_flags before return. + */ + ssc->ssc_flags = SSC_FLAGS_UNKNOWN; } /* |