Index: sbin/camcontrol/camcontrol.8 =================================================================== --- sbin/camcontrol/camcontrol.8 +++ sbin/camcontrol/camcontrol.8 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 22, 2019 +.Dd June, 15, 2019 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -425,6 +425,15 @@ the code will generally attempt to spin up drives that are not spinning. It may take some other actions, depending upon the sense code returned from the command. +.It Fl j +The kernel caches information like the ATA identify command. +Normally, +.Nm +uses this cached information to avoid I/O to the device. +With +.Pq Fl j +this cached information is ignored and the data is fetched from +the device. .It Fl n Ar dev_name Specify the device type to operate on, e.g.\& "da", "cd". .It Fl Q Ar task_attr Index: sbin/camcontrol/camcontrol.c =================================================================== --- sbin/camcontrol/camcontrol.c +++ sbin/camcontrol/camcontrol.c @@ -131,6 +131,7 @@ CAM_ARG_GET_STDINQ = 0x00002000, CAM_ARG_GET_XFERRATE = 0x00004000, CAM_ARG_INQ_MASK = 0x00007000, + CAM_ARG_NO_CACHE = 0x00010000, CAM_ARG_TIMEOUT = 0x00020000, CAM_ARG_CMD_IN = 0x00040000, CAM_ARG_CMD_OUT = 0x00080000, @@ -2263,13 +2264,13 @@ return (-1); } + if (get_cgd(device, &cgd) != 0) { + warnx("couldn't get CGD"); + return (-1); + } + /* Neither PROTO_ATAPI or PROTO_SATAPM are used in cpi.protocol */ if (cpi.protocol == PROTO_ATA) { - if (get_cgd(device, &cgd) != 0) { - warnx("couldn't get CGD"); - return (-1); - } - command = (cgd.protocol == PROTO_ATA) ? ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY; retry_command = 0; @@ -2285,6 +2286,22 @@ return (1); } + /* + * Any valid ATA ident_ata will have a non-zero config. However, + * when no ident_data has been fetched, it will be all zeros. + */ + if ((arglist & CAM_ARG_NO_CACHE) == 0 && cgd.ident_data.config != 0) { + memcpy(ptr, &cgd.ident_data, sizeof(struct ata_params)); + error = 0; + if (arglist & CAM_ARG_VERBOSE) { + fprintf(stdout, "%s%d: Raw identify data:\n", + device->device_name, device->dev_unit_num); + dump_data(ptr, sizeof(struct ata_params)); + } + *ident_bufp = (struct ata_params *)ptr; + return (0); + } + error = ata_do_28bit_cmd(device, ccb, /*retries*/retry_count, @@ -2326,9 +2343,11 @@ } } + ident_buf = (struct ata_params *)ptr; + ata_param_fixup(ident_buf); + error = 1; for (i = 0; i < sizeof(struct ata_params) / 2; i++) { - ptr[i] = le16toh(ptr[i]); if (ptr[i] != 0) error = 0; } @@ -2346,26 +2365,6 @@ return (error); } - ident_buf = (struct ata_params *)ptr; - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bswap(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); - ata_btrim(ident_buf->media_serial, sizeof(ident_buf->media_serial)); - ata_bpack(ident_buf->media_serial, ident_buf->media_serial, - sizeof(ident_buf->media_serial)); - *ident_bufp = ident_buf; return (0); @@ -5415,21 +5414,37 @@ break; /*NOTREACHED*/ } - /* - * Check for the ATA Information VPD page (0x89). If this is an - * ATA device behind a SCSI to ATA translation layer, this VPD page - * should be present. - * - * If that VPD page isn't present, or we get an error back from the - * INQUIRY command, we'll just treat it as a normal SCSI device. - */ - retval = dev_has_vpd_page(dev, SVPD_ATA_INFORMATION, retry_count, - timeout, verbosemode); - if (retval == 1) - *devtype = CC_DT_ATA_BEHIND_SCSI; - else - *devtype = CC_DT_SCSI; - + if ((arglist & CAM_ARG_NO_CACHE) == 0) { + /* + * Check to see if we have a cached copy of the ata_params + * structure then we know for sure that it's ATA behind the SCSI + * protocol. Otherwise we're unsure, but the kernel doesn't + * think there's ATA behind this SCSI device. Either it's an old + * kernel (and we don't know) or it's a new kernel and we do + * know. We accept that we can guess wrong and don't second + * guess it. + */ + if (cgd.ident_data.config != 0) + *devtype = CC_DT_ATA_BEHIND_SCSI; + else + *devtype = CC_DT_SCSI; + } else { + /* + * Check for the ATA Information VPD page (0x89). If this is an + * ATA device behind a SCSI to ATA translation layer, this VPD + * page should be present. + * + * If that VPD page isn't present, or we get an error back from + * the INQUIRY command, we'll just treat it as a normal SCSI + * device. + */ + retval = dev_has_vpd_page(dev, SVPD_ATA_INFORMATION, retry_count, + timeout, verbosemode); + if (retval == 1) + *devtype = CC_DT_ATA_BEHIND_SCSI; + else + *devtype = CC_DT_SCSI; + } retval = 0; bailout: @@ -9714,6 +9729,7 @@ "Generic arguments:\n" "-v be verbose, print out sense information\n" "-t timeout command timeout in seconds, overrides default timeout\n" +"-j don't use cached data from the kernel\n" "-n dev_name specify device name, e.g. \"da\", \"cd\"\n" "-u unit specify unit number, e.g. \"0\", \"5\"\n" "-E have the kernel attempt to perform SCSI error recovery\n" @@ -9923,7 +9939,7 @@ int timeout = 0, retry_count = 1; camcontrol_optret optreturn; char *tstr; - const char *mainopt = "C:En:Q:t:u:v"; + const char *mainopt = "C:Ejn:Q:t:u:v"; const char *subopt = NULL; char combinedopt[256]; int error = 0, optstart = 2; @@ -10074,6 +10090,9 @@ case 'E': arglist |= CAM_ARG_ERR_RECOVER; break; + case 'j': + arglist |= CAM_ARG_NO_CACHE; + break; case 'n': arglist |= CAM_ARG_DEVICE; tstr = optarg; Index: sys/cam/ata/ata_all.h =================================================================== --- sys/cam/ata/ata_all.h +++ sys/cam/ata/ata_all.h @@ -135,6 +135,7 @@ uint16_t block_count, uint32_t protocol, uint8_t *data_ptr, uint32_t dxfer_len, uint32_t timeout); +void ata_param_fixup(struct ata_params *ident_buf); void ata_bswap(int8_t *buf, int len); void ata_btrim(int8_t *buf, int len); void ata_bpack(int8_t *src, int8_t *dst, int len); Index: sys/cam/ata/ata_all.c =================================================================== --- sys/cam/ata/ata_all.c +++ sys/cam/ata/ata_all.c @@ -1238,3 +1238,28 @@ ataio->aux = auxiliary; } } + +void +ata_param_fixup(struct ata_params *ident_buf) +{ + int16_t *ptr; + + for (ptr = (int16_t *)ident_buf; + ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { + *ptr = le16toh(*ptr); + } + if (strncmp(ident_buf->model, "FX", 2) && + strncmp(ident_buf->model, "NEC", 3) && + strncmp(ident_buf->model, "Pioneer", 7) && + strncmp(ident_buf->model, "SHARP", 5)) { + ata_bswap(ident_buf->model, sizeof(ident_buf->model)); + ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); + } + ata_btrim(ident_buf->model, sizeof(ident_buf->model)); + ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); + ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); + ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); + ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); + ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); +} Index: sys/cam/ata/ata_xpt.c =================================================================== --- sys/cam/ata/ata_xpt.c +++ sys/cam/ata/ata_xpt.c @@ -893,14 +893,13 @@ case PROBE_IDENTIFY: { struct ccb_pathinq cpi; - int16_t *ptr; int veto = 0; + /* + * Convert to host byte order, and fix the strings. + */ ident_buf = &softc->ident_data; - for (ptr = (int16_t *)ident_buf; - ptr < (int16_t *)ident_buf + sizeof(struct ata_params)/2; ptr++) { - *ptr = le16toh(*ptr); - } + ata_param_fixup(ident_buf); /* * Allow others to veto this ATA disk attachment. This @@ -912,20 +911,6 @@ goto device_fail; } - if (strncmp(ident_buf->model, "FX", 2) && - strncmp(ident_buf->model, "NEC", 3) && - strncmp(ident_buf->model, "Pioneer", 7) && - strncmp(ident_buf->model, "SHARP", 5)) { - ata_bswap(ident_buf->model, sizeof(ident_buf->model)); - ata_bswap(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bswap(ident_buf->serial, sizeof(ident_buf->serial)); - } - ata_btrim(ident_buf->model, sizeof(ident_buf->model)); - ata_bpack(ident_buf->model, ident_buf->model, sizeof(ident_buf->model)); - ata_btrim(ident_buf->revision, sizeof(ident_buf->revision)); - ata_bpack(ident_buf->revision, ident_buf->revision, sizeof(ident_buf->revision)); - ata_btrim(ident_buf->serial, sizeof(ident_buf->serial)); - ata_bpack(ident_buf->serial, ident_buf->serial, sizeof(ident_buf->serial)); /* Device may need spin-up before IDENTIFY become valid. */ if ((ident_buf->specconf == 0x37c8 || ident_buf->specconf == 0x738c) && Index: sys/cam/scsi/scsi_da.c =================================================================== --- sys/cam/scsi/scsi_da.c +++ sys/cam/scsi/scsi_da.c @@ -64,6 +64,9 @@ #include #include #include +#ifdef _KERNEL +#include +#endif /* _KERNEL */ #include #include @@ -3613,15 +3616,7 @@ break; } - ata_params = (struct ata_params*) - malloc(sizeof(*ata_params), M_SCSIDA,M_NOWAIT|M_ZERO); - - if (ata_params == NULL) { - xpt_print(periph->path, "Couldn't malloc ata_params " - "data\n"); - /* da_free_periph??? */ - break; - } + ata_params = &periph->path->device->ident_data; scsi_ata_identify(&start_ccb->csio, /*retries*/da_retry_count, @@ -5192,7 +5187,7 @@ struct da_softc *softc; u_int32_t priority; int continue_probe; - int error, i; + int error; int16_t *ptr; CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("dadone_probeata\n")); @@ -5210,8 +5205,7 @@ if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { uint16_t old_rate; - for (i = 0; i < sizeof(*ata_params) / 2; i++) - ptr[i] = le16toh(ptr[i]); + ata_param_fixup(ata_params); if (ata_params->support_dsm & ATA_SUPPORT_DSM_TRIM && (softc->quirks & DA_Q_NO_UNMAP) == 0) { dadeleteflag(softc, DA_DELETE_ATA_TRIM, 1); @@ -5295,7 +5289,6 @@ } } - free(ata_params, M_SCSIDA); if ((softc->zone_mode == DA_ZONE_HOST_AWARE) || (softc->zone_mode == DA_ZONE_HOST_MANAGED)) { /*