From owner-svn-src-all@freebsd.org Thu Jul 25 18:48:33 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 4D527AB8AA; Thu, 25 Jul 2019 18:48:33 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 3AF598FFD6; Thu, 25 Jul 2019 18:48:33 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id E78DD2F2A; Thu, 25 Jul 2019 18:48:32 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x6PImW05034513; Thu, 25 Jul 2019 18:48:32 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x6PImVsN034508; Thu, 25 Jul 2019 18:48:31 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201907251848.x6PImVsN034508@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Thu, 25 Jul 2019 18:48:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r350331 - in head: sbin/camcontrol sys/cam/ata sys/cam/scsi sys/sys X-SVN-Group: head X-SVN-Commit-Author: mav X-SVN-Commit-Paths: in head: sbin/camcontrol sys/cam/ata sys/cam/scsi sys/sys X-SVN-Commit-Revision: 350331 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 3AF598FFD6 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.97 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.97)[-0.971,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Jul 2019 18:48:33 -0000 Author: mav Date: Thu Jul 25 18:48:31 2019 New Revision: 350331 URL: https://svnweb.freebsd.org/changeset/base/350331 Log: Make `camcontrol sanitize` support also ATA devices. ATA sanitize is functionally identical to SCSI, just uses different initiation commands and status reporting mechanism. While there, make kernel better handle sanitize commands and statuses. MFC after: 2 weeks Sponsored by: iXsystems, Inc. Modified: head/sbin/camcontrol/camcontrol.8 head/sbin/camcontrol/camcontrol.c head/sys/cam/ata/ata_all.c head/sys/cam/scsi/scsi_all.c head/sys/sys/ata.h Modified: head/sbin/camcontrol/camcontrol.8 ============================================================================== --- head/sbin/camcontrol/camcontrol.8 Thu Jul 25 18:15:43 2019 (r350330) +++ head/sbin/camcontrol/camcontrol.8 Thu Jul 25 18:48:31 2019 (r350331) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 22, 2019 +.Dd July 25, 2019 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -1276,13 +1276,11 @@ will not be asked about the timeout if a timeout is sp command line. .El .It Ic sanitize -Issue the -.Tn SCSI -SANITIZE command to the named device. +Issue the SANITIZE command to the named device. .Pp .Em WARNING! WARNING! WARNING! .Pp -ALL data in the cache and on the disk will be destroyed or made inaccessible. +ALL data on the disk will be destroyed or made inaccessible. Recovery of the data is not possible. Use extreme caution when issuing this command. .Pp Modified: head/sbin/camcontrol/camcontrol.c ============================================================================== --- head/sbin/camcontrol/camcontrol.c Thu Jul 25 18:15:43 2019 (r350330) +++ head/sbin/camcontrol/camcontrol.c Thu Jul 25 18:48:31 2019 (r350331) @@ -347,7 +347,7 @@ static int ratecontrol(struct cam_device *device, int static int scsiformat(struct cam_device *device, int argc, char **argv, char *combinedopt, int task_attr, int retry_count, int timeout); -static int scsisanitize(struct cam_device *device, int argc, char **argv, +static int sanitize(struct cam_device *device, int argc, char **argv, char *combinedopt, int task_attr, int retry_count, int timeout); static int scsireportluns(struct cam_device *device, int argc, char **argv, @@ -1743,6 +1743,19 @@ atacapprint(struct ata_params *parm) } else { printf("no\n"); } + printf("Sanitize "); + if (parm->multi & ATA_SUPPORT_SANITIZE) { + printf("yes\t\t%s%s%s\n", + parm->multi & ATA_SUPPORT_BLOCK_ERASE_EXT ? "block, " : "", + parm->multi & ATA_SUPPORT_OVERWRITE_EXT ? "overwrite, " : "", + parm->multi & ATA_SUPPORT_CRYPTO_SCRAMBLE_EXT ? "crypto" : ""); + printf("Sanitize - commands allowed %s\n", + parm->multi & ATA_SUPPORT_SANITIZE_ALLOWED ? "yes" : "no"); + printf("Sanitize - antifreeze lock %s\n", + parm->multi & ATA_SUPPORT_ANTIFREEZE_LOCK_EXT ? "yes" : "no"); + } else { + printf("no\n"); + } } static int @@ -1989,6 +2002,11 @@ ata_do_cmd(struct cam_device *device, union ccb *ccb, res->lba_high_exp = res_pass16->lba_high_exp; res->sector_count = res_pass16->sector_count; res->sector_count_exp = res_pass16->sector_count_exp; + ccb->ccb_h.status &= ~CAM_STATUS_MASK; + if (res->status & ATA_STATUS_ERROR) + ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR; + else + ccb->ccb_h.status |= CAM_REQ_CMP; } return (error); @@ -2479,12 +2497,6 @@ ata_do_identify(struct cam_device *device, int retry_c 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)); - } - /* check for invalid (all zero) response */ if (error != 0) { warnx("Invalid identify response detected"); @@ -2515,6 +2527,12 @@ ataidentify(struct cam_device *device, int retry_count return (1); } + if (arglist & CAM_ARG_VERBOSE) { + printf("%s%d: Raw identify data:\n", + device->device_name, device->dev_unit_num); + dump_data((void*)ident_buf, sizeof(struct ata_params)); + } + if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) { if (ata_read_native_max(device, retry_count, timeout, ccb, ident_buf, &hpasize) != 0) { @@ -6744,15 +6762,184 @@ scsiformat_bailout: } static int -scsisanitize(struct cam_device *device, int argc, char **argv, +sanitize_wait_ata(struct cam_device *device, union ccb *ccb, int quiet) +{ + struct ata_res *res; + int retval; + cam_status status; + u_int val, perc; + + do { + retval = ata_do_cmd(device, + ccb, + /*retries*/1, + /*flags*/CAM_DIR_NONE, + /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, + /*ata_flags*/AP_FLAG_CHK_COND, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*command*/ATA_SANITIZE, + /*features*/0x00, /* SANITIZE STATUS EXT */ + /*lba*/0, + /*sector_count*/0, + /*data_ptr*/NULL, + /*dxfer_len*/0, + /*timeout*/10000, + /*is48bit*/1); + if (retval < 0) { + warn("error sending CAMIOCOMMAND ioctl"); + if (arglist & CAM_ARG_VERBOSE) { + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + } + return (1); + } + + status = ccb->ccb_h.status & CAM_STATUS_MASK; + if (status == CAM_REQ_CMP) { + res = &ccb->ataio.res; + if (res->sector_count_exp & 0x40) { + if (quiet == 0) { + val = (res->lba_mid << 8) + res->lba_low; + perc = 10000 * val; + fprintf(stdout, + "Sanitizing: %u.%02u%% (%d/%d)\r", + (perc / (0x10000 * 100)), + ((perc / 0x10000) % 100), + val, 0x10000); + fflush(stdout); + } + sleep(1); + } else if ((res->sector_count_exp & 0x80) == 0) { + warnx("Sanitize complete with an error. "); + return (1); + } else + break; + + } else if (status != CAM_REQ_CMP && status != CAM_REQUEUE_REQ) { + warnx("Unexpected CAM status %#x", status); + if (arglist & CAM_ARG_VERBOSE) + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + return (1); + } + } while (1); + return (0); +} + +static int +sanitize_wait_scsi(struct cam_device *device, union ccb *ccb, int task_attr, int quiet) +{ + int warnings = 0, retval; + cam_status status; + u_int val, perc; + + do { + CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); + + /* + * There's really no need to do error recovery or + * retries here, since we're just going to sit in a + * loop and wait for the device to finish sanitizing. + */ + scsi_test_unit_ready(&ccb->csio, + /* retries */ 0, + /* cbfcnp */ NULL, + /* tag_action */ task_attr, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ 5000); + + /* Disable freezing the device queue */ + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + + retval = cam_send_ccb(device, ccb); + + /* + * If we get an error from the ioctl, bail out. SCSI + * errors are expected. + */ + if (retval < 0) { + warn("error sending CAMIOCOMMAND ioctl"); + if (arglist & CAM_ARG_VERBOSE) { + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + } + return (1); + } + + status = ccb->ccb_h.status & CAM_STATUS_MASK; + if ((status == CAM_SCSI_STATUS_ERROR) && + ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { + struct scsi_sense_data *sense; + int error_code, sense_key, asc, ascq; + + sense = &ccb->csio.sense_data; + scsi_extract_sense_len(sense, ccb->csio.sense_len - + ccb->csio.sense_resid, &error_code, &sense_key, + &asc, &ascq, /*show_errors*/ 1); + + /* + * According to the SCSI-3 spec, a drive that is in the + * middle of a sanitize should return NOT READY with an + * ASC of "logical unit not ready, sanitize in + * progress". The sense key specific bytes will then + * be a progress indicator. + */ + if ((sense_key == SSD_KEY_NOT_READY) + && (asc == 0x04) && (ascq == 0x1b)) { + uint8_t sks[3]; + + if ((scsi_get_sks(sense, ccb->csio.sense_len - + ccb->csio.sense_resid, sks) == 0) + && (quiet == 0)) { + val = scsi_2btoul(&sks[1]); + perc = 10000 * val; + fprintf(stdout, + "Sanitizing: %u.%02u%% (%d/%d)\r", + (perc / (0x10000 * 100)), + ((perc / 0x10000) % 100), + val, 0x10000); + fflush(stdout); + } else if ((quiet == 0) && (++warnings <= 1)) { + warnx("Unexpected SCSI Sense Key " + "Specific value returned " + "during sanitize:"); + scsi_sense_print(device, &ccb->csio, + stderr); + warnx("Unable to print status " + "information, but sanitze will " + "proceed."); + warnx("will exit when sanitize is " + "complete"); + } + sleep(1); + } else { + warnx("Unexpected SCSI error during sanitize"); + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + return (1); + } + + } else if (status != CAM_REQ_CMP && status != CAM_REQUEUE_REQ) { + warnx("Unexpected CAM status %#x", status); + if (arglist & CAM_ARG_VERBOSE) + cam_error_print(device, ccb, CAM_ESF_ALL, + CAM_EPF_ALL, stderr); + return (1); + } + } while ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); + return (0); +} + +static int +sanitize(struct cam_device *device, int argc, char **argv, char *combinedopt, int task_attr, int retry_count, int timeout) { union ccb *ccb; u_int8_t action = 0; int c; int ycount = 0, quiet = 0; - int error = 0, retval = 0; - int use_timeout = 10800 * 1000; + int error = 0; + int use_timeout; int immediate = 1; int invert = 0; int passes = 0; @@ -6761,14 +6948,25 @@ scsisanitize(struct cam_device *device, int argc, char const char *pattern = NULL; u_int8_t *data_ptr = NULL; u_int32_t dxfer_len = 0; - u_int8_t byte2 = 0; - int num_warnings = 0; + uint8_t byte2; + uint16_t feature, count; + uint64_t lba; int reportonly = 0; + camcontrol_devtype dt; + /* + * Get the device type, request no I/O be done to do this. + */ + error = get_device_type(device, -1, 0, 0, &dt); + if (error != 0 || (unsigned)dt > CC_DT_UNKNOWN) { + warnx("sanitize: can't get device type"); + return (1); + } + ccb = cam_getccb(device); if (ccb == NULL) { - warnx("scsisanitize: error allocating ccb"); + warnx("sanitize: error allocating ccb"); return (1); } @@ -6789,7 +6987,7 @@ scsisanitize(struct cam_device *device, int argc, char warnx("invalid service operation \"%s\"", optarg); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } break; case 'c': @@ -6797,7 +6995,7 @@ scsisanitize(struct cam_device *device, int argc, char if (passes < 1 || passes > 31) { warnx("invalid passes value %d", passes); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } break; case 'I': @@ -6816,7 +7014,9 @@ scsisanitize(struct cam_device *device, int argc, char reportonly = 1; break; case 'w': - immediate = 0; + /* ATA supports only immediate commands. */ + if (dt == CC_DT_SCSI) + immediate = 0; break; case 'y': ycount++; @@ -6830,7 +7030,7 @@ scsisanitize(struct cam_device *device, int argc, char if (action == 0) { warnx("an action is required"); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } else if (action == SSZ_SERVICE_ACTION_OVERWRITE) { struct scsi_sanitize_parameter_list *pl; struct stat sb; @@ -6839,43 +7039,43 @@ scsisanitize(struct cam_device *device, int argc, char if (pattern == NULL) { warnx("overwrite action requires -P argument"); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } fd = open(pattern, O_RDONLY); if (fd < 0) { warn("cannot open pattern file %s", pattern); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } if (fstat(fd, &sb) < 0) { warn("cannot stat pattern file %s", pattern); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } sz = sb.st_size; if (sz > SSZPL_MAX_PATTERN_LENGTH) { warnx("pattern file size exceeds maximum value %d", SSZPL_MAX_PATTERN_LENGTH); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } dxfer_len = sizeof(*pl) + sz; data_ptr = calloc(1, dxfer_len); if (data_ptr == NULL) { warnx("cannot allocate parameter list buffer"); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } amt = read(fd, data_ptr + sizeof(*pl), sz); if (amt < 0) { warn("cannot read pattern file"); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } else if (amt != sz) { warnx("short pattern file read"); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } pl = (struct scsi_sanitize_parameter_list *)data_ptr; @@ -6901,7 +7101,7 @@ scsisanitize(struct cam_device *device, int argc, char warnx("%s argument only valid with overwrite " "operation", arg); error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } } @@ -6909,26 +7109,41 @@ scsisanitize(struct cam_device *device, int argc, char fprintf(stdout, "You are about to REMOVE ALL DATA from the " "following device:\n"); - error = scsidoinquiry(device, argc, argv, combinedopt, - task_attr, retry_count, timeout); + if (dt == CC_DT_SCSI) { + error = scsidoinquiry(device, argc, argv, combinedopt, + task_attr, retry_count, timeout); + } else if (dt == CC_DT_ATA || dt == CC_DT_SATL) { + struct ata_params *ident_buf; + error = ata_do_identify(device, retry_count, timeout, + ccb, &ident_buf); + if (error == 0) { + printf("%s%d: ", device->device_name, + device->dev_unit_num); + ata_print_ident(ident_buf); + free(ident_buf); + } + } else + error = 1; if (error != 0) { - warnx("scsisanitize: error sending inquiry"); - goto scsisanitize_bailout; + warnx("sanitize: error sending inquiry"); + goto sanitize_bailout; } } if (ycount == 0) { if (!get_confirmation()) { error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } } if (timeout != 0) use_timeout = timeout; + else + use_timeout = (immediate ? 10 : 10800) * 1000; - if (quiet == 0) { + if (immediate == 0 && quiet == 0) { fprintf(stdout, "Current sanitize timeout is %d seconds\n", use_timeout / 1000); } @@ -6938,8 +7153,7 @@ scsisanitize(struct cam_device *device, int argc, char * timeout on the command line, ask them if they want the current * timeout. */ - if ((ycount == 0) - && (timeout == 0)) { + if (immediate == 0 && ycount == 0 && timeout == 0) { char str[1024]; int new_timeout = 0; @@ -6959,33 +7173,76 @@ scsisanitize(struct cam_device *device, int argc, char } } - byte2 = action; - if (ause != 0) - byte2 |= SSZ_UNRESTRICTED_EXIT; - if (immediate != 0) - byte2 |= SSZ_IMMED; + if (dt == CC_DT_SCSI) { + byte2 = action; + if (ause != 0) + byte2 |= SSZ_UNRESTRICTED_EXIT; + if (immediate != 0) + byte2 |= SSZ_IMMED; + scsi_sanitize(&ccb->csio, + /* retries */ retry_count, + /* cbfcnp */ NULL, + /* tag_action */ task_attr, + /* byte2 */ byte2, + /* control */ 0, + /* data_ptr */ data_ptr, + /* dxfer_len */ dxfer_len, + /* sense_len */ SSD_FULL_SIZE, + /* timeout */ use_timeout); - scsi_sanitize(&ccb->csio, - /* retries */ retry_count, - /* cbfcnp */ NULL, - /* tag_action */ task_attr, - /* byte2 */ byte2, - /* control */ 0, - /* data_ptr */ data_ptr, - /* dxfer_len */ dxfer_len, - /* sense_len */ SSD_FULL_SIZE, - /* timeout */ use_timeout); + ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; + if (arglist & CAM_ARG_ERR_RECOVER) + ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; + if (cam_send_ccb(device, ccb) < 0) { + warn("error sending sanitize command"); + error = 1; + goto sanitize_bailout; + } + } else if (dt == CC_DT_ATA || dt == CC_DT_SATL) { + if (action == SSZ_SERVICE_ACTION_OVERWRITE) { + feature = 0x14; /* OVERWRITE EXT */ + lba = 0x4F5700000000 | scsi_4btoul(data_ptr + 4); + count = (passes == 0) ? 1 : (passes >= 16) ? 0 : passes; + if (invert) + count |= 0x80; /* INVERT PATTERN */ + if (ause) + count |= 0x10; /* FAILURE MODE */ + } else if (action == SSZ_SERVICE_ACTION_BLOCK_ERASE) { + feature = 0x12; /* BLOCK ERASE EXT */ + lba = 0x0000426B4572; + count = 0; + if (ause) + count |= 0x10; /* FAILURE MODE */ + } else if (action == SSZ_SERVICE_ACTION_CRYPTO_ERASE) { + feature = 0x11; /* CRYPTO SCRAMBLE EXT */ + lba = 0x000043727970; + count = 0; + if (ause) + count |= 0x10; /* FAILURE MODE */ + } else if (action == SSZ_SERVICE_ACTION_EXIT_MODE_FAILURE) { + feature = 0x00; /* SANITIZE STATUS EXT */ + lba = 0; + count = 1; /* CLEAR SANITIZE OPERATION FAILED */ + } else { + error = 1; + goto sanitize_bailout; + } - /* Disable freezing the device queue */ - ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; - - if (arglist & CAM_ARG_ERR_RECOVER) - ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER; - - if (cam_send_ccb(device, ccb) < 0) { - warn("error sending sanitize command"); - error = 1; - goto scsisanitize_bailout; + error = ata_do_cmd(device, + ccb, + retry_count, + /*flags*/CAM_DIR_NONE, + /*protocol*/AP_PROTO_NON_DATA | AP_EXTEND, + /*ata_flags*/AP_FLAG_CHK_COND, + /*tag_action*/MSG_SIMPLE_Q_TAG, + /*command*/ATA_SANITIZE, + /*features*/feature, + /*lba*/lba, + /*sector_count*/count, + /*data_ptr*/NULL, + /*dxfer_len*/0, + /*timeout*/ use_timeout, + /*is48bit*/1); } if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { @@ -7013,7 +7270,7 @@ scsisanitize(struct cam_device *device, int argc, char CAM_EPF_ALL, stderr); } error = 1; - goto scsisanitize_bailout; + goto sanitize_bailout; } /* @@ -7026,124 +7283,20 @@ scsisanitize(struct cam_device *device, int argc, char if (quiet == 0) { fprintf(stdout, "Sanitize Complete\n"); } - goto scsisanitize_bailout; + goto sanitize_bailout; } doreport: - do { - cam_status status; + if (dt == CC_DT_SCSI) { + error = sanitize_wait_scsi(device, ccb, task_attr, quiet); + } else if (dt == CC_DT_ATA || dt == CC_DT_SATL) { + error = sanitize_wait_ata(device, ccb, quiet); + } else + error = 1; + if (error == 0 && quiet == 0) + fprintf(stdout, "Sanitize Complete \n"); - CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); - - /* - * There's really no need to do error recovery or - * retries here, since we're just going to sit in a - * loop and wait for the device to finish sanitizing. - */ - scsi_test_unit_ready(&ccb->csio, - /* retries */ 0, - /* cbfcnp */ NULL, - /* tag_action */ task_attr, - /* sense_len */ SSD_FULL_SIZE, - /* timeout */ 5000); - - /* Disable freezing the device queue */ - ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; - - retval = cam_send_ccb(device, ccb); - - /* - * If we get an error from the ioctl, bail out. SCSI - * errors are expected. - */ - if (retval < 0) { - warn("error sending CAMIOCOMMAND ioctl"); - if (arglist & CAM_ARG_VERBOSE) { - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); - } - error = 1; - goto scsisanitize_bailout; - } - - status = ccb->ccb_h.status & CAM_STATUS_MASK; - - if ((status != CAM_REQ_CMP) - && (status == CAM_SCSI_STATUS_ERROR) - && ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0)) { - struct scsi_sense_data *sense; - int error_code, sense_key, asc, ascq; - - sense = &ccb->csio.sense_data; - scsi_extract_sense_len(sense, ccb->csio.sense_len - - ccb->csio.sense_resid, &error_code, &sense_key, - &asc, &ascq, /*show_errors*/ 1); - - /* - * According to the SCSI-3 spec, a drive that is in the - * middle of a sanitize should return NOT READY with an - * ASC of "logical unit not ready, sanitize in - * progress". The sense key specific bytes will then - * be a progress indicator. - */ - if ((sense_key == SSD_KEY_NOT_READY) - && (asc == 0x04) && (ascq == 0x1b)) { - uint8_t sks[3]; - - if ((scsi_get_sks(sense, ccb->csio.sense_len - - ccb->csio.sense_resid, sks) == 0) - && (quiet == 0)) { - int val; - u_int64_t percentage; - - val = scsi_2btoul(&sks[1]); - percentage = 10000 * val; - - fprintf(stdout, - "\rSanitizing: %ju.%02u %% " - "(%d/%d) done", - (uintmax_t)(percentage / - (0x10000 * 100)), - (unsigned)((percentage / - 0x10000) % 100), - val, 0x10000); - fflush(stdout); - } else if ((quiet == 0) - && (++num_warnings <= 1)) { - warnx("Unexpected SCSI Sense Key " - "Specific value returned " - "during sanitize:"); - scsi_sense_print(device, &ccb->csio, - stderr); - warnx("Unable to print status " - "information, but sanitze will " - "proceed."); - warnx("will exit when sanitize is " - "complete"); - } - sleep(1); - } else { - warnx("Unexpected SCSI error during sanitize"); - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); - error = 1; - goto scsisanitize_bailout; - } - - } else if (status != CAM_REQ_CMP) { - warnx("Unexpected CAM status %#x", status); - if (arglist & CAM_ARG_VERBOSE) - cam_error_print(device, ccb, CAM_ESF_ALL, - CAM_EPF_ALL, stderr); - error = 1; - goto scsisanitize_bailout; - } - } while((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP); - - if (quiet == 0) - fprintf(stdout, "\nSanitize Complete\n"); - -scsisanitize_bailout: +sanitize_bailout: if (fd >= 0) close(fd); if (data_ptr != NULL) @@ -10520,9 +10673,8 @@ main(int argc, char **argv) timeout); break; case CAM_CMD_SANITIZE: - error = scsisanitize(cam_dev, argc, argv, - combinedopt, task_attr, - retry_count, timeout); + error = sanitize(cam_dev, argc, argv, combinedopt, task_attr, + retry_count, timeout); break; case CAM_CMD_PERSIST: error = scsipersist(cam_dev, argc, argv, combinedopt, Modified: head/sys/cam/ata/ata_all.c ============================================================================== --- head/sys/cam/ata/ata_all.c Thu Jul 25 18:15:43 2019 (r350330) +++ head/sys/cam/ata/ata_all.c Thu Jul 25 18:48:31 2019 (r350331) @@ -215,7 +215,16 @@ ata_op_string(struct ata_cmd *cmd) return ("SMART"); case 0xb1: return ("DEVICE CONFIGURATION"); case 0xb2: return ("SET_SECTOR_CONFIGURATION_EXT"); - case 0xb4: return ("SANITIZE_DEVICE"); + case 0xb4: + switch(cmd->features) { + case 0x00: return ("SANITIZE_STATUS_EXT"); + case 0x11: return ("CRYPTO_SCRAMBLE_EXT"); + case 0x12: return ("BLOCK_ERASE_EXT"); + case 0x14: return ("OVERWRITE_EXT"); + case 0x20: return ("SANITIZE_FREEZE_LOCK_EXT"); + case 0x40: return ("SANITIZE_ANTIFREEZE_LOCK_EXT"); + } + return ("SANITIZE_DEVICE"); case 0xc0: return ("CFA_ERASE"); case 0xc4: return ("READ_MUL"); case 0xc5: return ("WRITE_MUL"); Modified: head/sys/cam/scsi/scsi_all.c ============================================================================== --- head/sys/cam/scsi/scsi_all.c Thu Jul 25 18:15:43 2019 (r350330) +++ head/sys/cam/scsi/scsi_all.c Thu Jul 25 18:48:31 2019 (r350331) @@ -379,7 +379,7 @@ static struct op_table_entry scsi_op_codes[] = { { 0x40, D | T | L | P | W | R | O | M | S | C, "CHANGE DEFINITION" }, /* 41 O WRITE SAME(10) */ { 0x41, D, "WRITE SAME(10)" }, - /* 42 O UNMAP */ + /* 42 O UNMAP */ { 0x42, D, "UNMAP" }, /* 42 O READ SUB-CHANNEL */ { 0x42, R, "READ SUB-CHANNEL" }, @@ -394,7 +394,8 @@ static struct op_table_entry scsi_op_codes[] = { { 0x46, R, "GET CONFIGURATION" }, /* 47 O PLAY AUDIO MSF */ { 0x47, R, "PLAY AUDIO MSF" }, - /* 48 */ + /* 48 O SANITIZE */ + { 0x48, D, "SANITIZE" }, /* 49 */ /* 4A M GET EVENT STATUS NOTIFICATION */ { 0x4A, R, "GET EVENT STATUS NOTIFICATION" }, @@ -1162,7 +1163,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x04, 0x1A, SS_RDEF, /* XXX TBD */ "Logical unit not ready, START/STOP UNIT command in progress") }, /* D B */ - { SST(0x04, 0x1B, SS_RDEF, /* XXX TBD */ + { SST(0x04, 0x1B, SS_WAIT | EBUSY, "Logical unit not ready, sanitize in progress") }, /* DT MAEB */ { SST(0x04, 0x1C, SS_START | SSQ_DECREMENT_COUNT | ENXIO, @@ -1453,7 +1454,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x11, 0x14, SS_RDEF, /* XXX TBD */ "Read error - LBA marked bad by application client") }, /* D */ - { SST(0x11, 0x15, SS_RDEF, /* XXX TBD */ + { SST(0x11, 0x15, SS_FATAL | EIO, "Write after sanitize required") }, /* D W O BK */ { SST(0x12, 0x00, SS_RDEF, @@ -2064,7 +2065,7 @@ static struct asc_table_entry asc_table[] = { { SST(0x31, 0x02, SS_RDEF, /* XXX TBD */ "Zoned formatting failed due to spare linking") }, /* D B */ - { SST(0x31, 0x03, SS_RDEF, /* XXX TBD */ + { SST(0x31, 0x03, SS_FATAL | EIO, "SANITIZE command failed") }, /* D W O BK */ { SST(0x32, 0x00, SS_RDEF, Modified: head/sys/sys/ata.h ============================================================================== --- head/sys/sys/ata.h Thu Jul 25 18:15:43 2019 (r350330) +++ head/sys/sys/ata.h Thu Jul 25 18:48:31 2019 (r350331) @@ -97,6 +97,8 @@ struct ata_params { #define ATA_SUPPORT_OVERWRITE_EXT 0x4000 #define ATA_SUPPORT_CRYPTO_SCRAMBLE_EXT 0x2000 #define ATA_SUPPORT_SANITIZE 0x1000 +#define ATA_SUPPORT_SANITIZE_ALLOWED 0x0800 +#define ATA_SUPPORT_ANTIFREEZE_LOCK_EXT 0x0400 #define ATA_MULTI_VALID 0x0100 /*060*/ u_int16_t lba_size_1; @@ -454,6 +456,7 @@ struct ata_params { #define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/ #define ATA_SERVICE 0xa2 /* service command */ #define ATA_SMART_CMD 0xb0 /* SMART command */ +#define ATA_SANITIZE 0xb4 /* sanitize device */ #define ATA_CFA_ERASE 0xc0 /* CFA erase */ #define ATA_READ_MUL 0xc4 /* read multi */ #define ATA_WRITE_MUL 0xc5 /* write multi */