Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 25 Jul 2019 18:48:31 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
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
Message-ID:  <201907251848.x6PImVsN034508@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907251848.x6PImVsN034508>