changeset 12950:d560524b6bb6

6866610 Add SATA TRIM support 6971542 Add support for TPRZ and TPE bits in READ CAPACITY (16)
author Phi Tran <Phi.Tran@Sun.COM>
date Wed, 28 Jul 2010 12:45:59 -0700
parents dd7214c03e0d
children 21b9be7f3041
files usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c usr/src/uts/common/io/sata/impl/sata.c usr/src/uts/common/sys/sata/sata_defs.h usr/src/uts/common/sys/scsi/impl/spc3_types.h
diffstat 4 files changed, 325 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Wed Jul 28 12:51:51 2010 -0600
+++ b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Wed Jul 28 12:45:59 2010 -0700
@@ -1981,6 +1981,7 @@
 	case SATAC_WRITE_DMA_QUEUED_EXT:
 	case SATAC_READ_FPDMA_QUEUED:
 	case SATAC_WRITE_FPDMA_QUEUED:
+	case SATAC_DSM:
 		dma_cmd = B_TRUE;
 		break;
 	default:
--- a/usr/src/uts/common/io/sata/impl/sata.c	Wed Jul 28 12:51:51 2010 -0600
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Wed Jul 28 12:45:59 2010 -0700
@@ -209,6 +209,7 @@
 static	int sata_txlt_start_stop_unit(sata_pkt_txlate_t *);
 static	int sata_txlt_read_capacity(sata_pkt_txlate_t *);
 static	int sata_txlt_read_capacity16(sata_pkt_txlate_t *);
+static  int sata_txlt_unmap(sata_pkt_txlate_t *);
 static	int sata_txlt_request_sense(sata_pkt_txlate_t *);
 static	int sata_txlt_read(sata_pkt_txlate_t *);
 static	int sata_txlt_write(sata_pkt_txlate_t *);
@@ -226,9 +227,11 @@
 static	int sata_txlt_check_condition(sata_pkt_txlate_t *, uchar_t, uchar_t);
 static	int sata_txlt_lba_out_of_range(sata_pkt_txlate_t *);
 static	int sata_txlt_ata_pass_thru_illegal_cmd(sata_pkt_txlate_t *);
+static  int sata_txlt_unmap_nodata_cmd(sata_pkt_txlate_t *);
 static	void sata_txlt_rw_completion(sata_pkt_t *);
 static	void sata_txlt_nodata_cmd_completion(sata_pkt_t *);
 static	void sata_txlt_apt_completion(sata_pkt_t *sata_pkt);
+static	void sata_txlt_unmap_completion(sata_pkt_t *sata_pkt);
 static	void sata_txlt_download_mcode_cmd_completion(sata_pkt_t *);
 static	int sata_emul_rw_completion(sata_pkt_txlate_t *);
 static	void sata_fill_ata_return_desc(sata_pkt_t *, uint8_t, uint8_t,
@@ -2628,6 +2631,11 @@
 
 		/* Other cases will be filed later */
 		/* postponed until phase 2 of the development */
+	case SPC3_CMD_UNMAP:
+		if (bp != NULL && (bp->b_flags & (B_PHYS | B_PAGEIO)))
+			bp_mapin(bp);
+		rval = sata_txlt_unmap(spx);
+		break;
 	default:
 		rval = sata_txlt_invalid_command(spx);
 		break;
@@ -4500,6 +4508,8 @@
 	uint16_t l2p_exp;
 	uchar_t *rbuf;
 	int rval, reason;
+#define	TPE	0x80
+#define	TPRZ	0x40
 
 	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
 	    "sata_txlt_read_capacity: ", NULL);
@@ -4606,9 +4616,17 @@
 		/* logical blocks per physical block exponent */
 		rbuf[13] = l2p_exp;
 
-		/* tpe, tprz, undefined by SAT-2 */
 		/* lowest aligned logical block address = 0 (for now) */
-		/* rbuf[14] = 0; */
+		/* tpe and tprz as defined in T10/10-079 r0 */
+		if (sdinfo->satadrv_id.ai_addsupported &
+		    SATA_DETERMINISTIC_READ) {
+			if (sdinfo->satadrv_id.ai_addsupported &
+			    SATA_READ_ZERO) {
+				rbuf[14] |= TPRZ;
+			} else {
+				rbuf[14] |= TPE;
+			}
+		}
 		/* rbuf[15] = 0; */
 
 		scsipkt->pkt_state |= STATE_XFERRED_DATA;
@@ -4647,6 +4665,167 @@
 }
 
 /*
+ * Translate command: UNMAP
+ *
+ * The function cannot be called in interrupt context since it may sleep.
+ */
+static int
+sata_txlt_unmap(sata_pkt_txlate_t *spx)
+{
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+	sata_cmd_t *scmd = &spx->txlt_sata_pkt->satapkt_cmd;
+	struct buf *bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
+	uint16_t count = 0;
+	int synch;
+	int rval, reason;
+	int i, x;
+	int bdlen = 0;
+	int ranges = 0;
+	int paramlen = 8;
+	uint8_t *data, *tmpbd;
+	sata_drive_info_t *sdinfo;
+#define	TRIM	0x1
+
+	SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+	    "sata_txlt_unmap: ", NULL);
+
+	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+	sdinfo = sata_get_device_info(spx->txlt_sata_hba_inst,
+	    &spx->txlt_sata_pkt->satapkt_device);
+	if (sdinfo != NULL) {
+		SATADBG2(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+		    "DSM support 0x%x, max number of 512 byte blocks of LBA "
+		    "range entries 0x%x\n", sdinfo->satadrv_id.ai_dsm,
+		    sdinfo->satadrv_id.ai_maxcount);
+	}
+
+	rval = sata_txlt_generic_pkt_info(spx, &reason, 1);
+	if ((rval != TRAN_ACCEPT) || (reason == CMD_DEV_GONE)) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (rval);
+	}
+
+	/*
+	 * Need to modify bp to have TRIM data instead of UNMAP data.
+	 * Start by getting the block descriptor data length by subtracting
+	 * the 8 byte parameter list header from the parameter list length.
+	 * The block descriptor size has to be a multiple of 16 bytes.
+	 */
+	bdlen = scsipkt->pkt_cdbp[7];
+	bdlen = (bdlen << 8) + scsipkt->pkt_cdbp[8] - paramlen;
+	if ((bdlen < 0) || ((bdlen % 16) != 0) ||
+	    (bdlen > (bp->b_bcount - paramlen))) {
+		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+		    "sata_txlt_unmap: invalid block descriptor length", NULL);
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return ((sata_txlt_check_condition(spx, KEY_ILLEGAL_REQUEST,
+		    SD_SCSI_ASC_INVALID_FIELD_IN_CDB)));
+	}
+	/*
+	 * If there are no parameter data or block descriptors, it is not
+	 * considered an error so just complete the command without sending
+	 * TRIM.
+	 */
+	if ((bdlen == 0) || (bp == NULL) || (bp->b_un.b_addr == NULL) ||
+	    (bp->b_bcount == 0)) {
+		SATADBG1(SATA_DBG_SCSI_IF, spx->txlt_sata_hba_inst,
+		    "sata_txlt_unmap: no parameter data or block descriptors",
+		    NULL);
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (sata_txlt_unmap_nodata_cmd(spx));
+	}
+	tmpbd = (uint8_t *)bp->b_un.b_addr + paramlen;
+	data = kmem_zalloc(bdlen, KM_SLEEP);
+
+	/*
+	 * Loop through all the UNMAP block descriptors and convert the data
+	 * into TRIM format.
+	 */
+	for (i = 0, x = 0; i < bdlen; i += 16, x += 8) {
+		/* get range length */
+		data[x] = tmpbd[i+7];
+		data[x+1] = tmpbd[i+6];
+		/* get LBA */
+		data[x+2] = tmpbd[i+5];
+		data[x+3] = tmpbd[i+4];
+		data[x+4] = tmpbd[i+3];
+		data[x+5] = tmpbd[i+2];
+		data[x+6] = tmpbd[i+11];
+		data[x+7] = tmpbd[i+10];
+
+		ranges++;
+	}
+
+	/*
+	 * The TRIM command expects the data buffer to be a multiple of
+	 * 512-byte blocks of range entries.  This means that the UNMAP buffer
+	 * may be too small.  Free the original DMA resources and create a
+	 * local buffer.
+	 */
+	sata_common_free_dma_rsrcs(spx);
+
+	/*
+	 * Get count of 512-byte blocks of range entries.  The length
+	 * of a range entry is 8 bytes which means one count has 64 range
+	 * entries.
+	 */
+	count = (ranges + 63)/64;
+
+	/* Allocate a buffer that is a multiple of 512 bytes. */
+	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+	bp = sata_alloc_local_buffer(spx, count * 512);
+	if (bp == NULL) {
+		SATADBG1(SATA_DBG_ATAPI, spx->txlt_sata_hba_inst,
+		    "sata_txlt_unmap: "
+		    "cannot allocate buffer for TRIM command", NULL);
+		kmem_free(data, bdlen);
+		return (TRAN_BUSY);
+	}
+	bp_mapin(bp); /* make data buffer accessible */
+	mutex_enter(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+	bzero(bp->b_un.b_addr, bp->b_bcount);
+	bcopy(data, bp->b_un.b_addr, x);
+	kmem_free(data, bdlen);
+	rval = ddi_dma_sync(spx->txlt_buf_dma_handle, 0, 0,
+	    DDI_DMA_SYNC_FORDEV);
+	ASSERT(rval == DDI_SUCCESS);
+
+	scmd->satacmd_flags.sata_data_direction = SATA_DIR_WRITE;
+	scmd->satacmd_addr_type = ATA_ADDR_LBA48;
+	scmd->satacmd_cmd_reg = SATAC_DSM;
+	scmd->satacmd_sec_count_msb = (count >> 8) & 0xff;
+	scmd->satacmd_sec_count_lsb = count & 0xff;
+	scmd->satacmd_features_reg = TRIM;
+	scmd->satacmd_device_reg = SATA_ADH_LBA;
+	scmd->satacmd_status_reg = 0;
+	scmd->satacmd_error_reg = 0;
+
+	/* Start processing command */
+	if (!(spx->txlt_sata_pkt->satapkt_op_mode & SATA_OPMODE_SYNCH)) {
+		spx->txlt_sata_pkt->satapkt_comp =
+		    sata_txlt_unmap_completion;
+		synch = FALSE;
+	} else {
+		synch = TRUE;
+	}
+
+	if (sata_hba_start(spx, &rval) != 0) {
+		mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+		return (rval);
+	}
+
+	mutex_exit(&(SATA_TXLT_CPORT_MUTEX(spx)));
+
+	if (synch) {
+		sata_txlt_unmap_completion(spx->txlt_sata_pkt);
+	}
+
+	return (TRAN_ACCEPT);
+}
+
+/*
  * SATA translate command: Mode Sense.
  * Translated into appropriate SATA command or emulated.
  * Saved Values Page Control (03) are not supported.
@@ -6720,7 +6899,6 @@
 
 	stat = (*SATA_START_FUNC(sata_hba_inst))(SATA_DIP(sata_hba_inst),
 	    spx->txlt_sata_pkt);
-
 	mutex_enter(&(SATA_CPORT_MUTEX(sata_hba_inst, cport)));
 	/*
 	 * If sata pkt was accepted and executed in asynchronous mode, i.e.
@@ -7067,6 +7245,35 @@
 }
 
 /*
+ * The UNMAP command considers it not to be an error if the parameter length
+ * or block descriptor length is 0.  For this case, there is nothing for TRIM
+ * to do so just complete the command.
+ */
+static int
+sata_txlt_unmap_nodata_cmd(sata_pkt_txlate_t *spx)
+{
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+
+	scsipkt->pkt_reason = CMD_CMPLT;
+	*scsipkt->pkt_scbp = STATUS_GOOD;
+	scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+	    STATE_SENT_CMD | STATE_GOT_STATUS;
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0 &&
+	    scsipkt->pkt_comp != NULL) {
+		/* scsi callback required */
+		if (taskq_dispatch(SATA_TXLT_TASKQ(spx),
+		    (task_func_t *)spx->txlt_scsi_pkt->pkt_comp,
+		    (void *)spx->txlt_scsi_pkt, TQ_SLEEP) == NULL) {
+			/* Scheduling the callback failed */
+			return (TRAN_BUSY);
+		}
+	}
+
+	return (TRAN_ACCEPT);
+}
+
+/*
  * Emulated SATA Read/Write command completion for zero-length requests.
  * This request always succedes, so in synchronous mode it always returns
  * TRAN_ACCEPT, and in non-synchronous mode it may return TRAN_BUSY if the
@@ -7392,7 +7599,99 @@
 }
 
 /*
- * j
+ * Completion handler for unmap translation command
+ */
+static void
+sata_txlt_unmap_completion(sata_pkt_t *sata_pkt)
+{
+	sata_pkt_txlate_t *spx =
+	    (sata_pkt_txlate_t *)sata_pkt->satapkt_framework_private;
+	sata_cmd_t *scmd = &sata_pkt->satapkt_cmd;
+	struct scsi_pkt *scsipkt = spx->txlt_scsi_pkt;
+	struct buf *bp;
+	uint8_t sense_key = 0, addl_sense_code = 0, addl_sense_qual = 0;
+
+	if (sata_pkt->satapkt_reason == SATA_PKT_COMPLETED) {
+		/* Normal completion */
+		scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+		    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS;
+		scsipkt->pkt_reason = CMD_CMPLT;
+		*scsipkt->pkt_scbp = STATUS_GOOD;
+
+		if (spx->txlt_tmp_buf != NULL) {
+			/* Temporary buffer was used */
+			bp = spx->txlt_sata_pkt->satapkt_cmd.satacmd_bp;
+			if (bp->b_flags & B_READ) {
+				bcopy(spx->txlt_tmp_buf, bp->b_un.b_addr,
+				    bp->b_bcount);
+			}
+		}
+	} else {
+		scsipkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
+		    STATE_SENT_CMD | STATE_GOT_STATUS;
+		scsipkt->pkt_reason = CMD_INCOMPLETE;
+		*scsipkt->pkt_scbp = STATUS_CHECK;
+
+		/*
+		 * If DF or ERR was set, the HBA should have copied out the
+		 * status and error registers to the satacmd structure.
+		 */
+		if (scmd->satacmd_status_reg & SATA_STATUS_DF) {
+			sense_key = KEY_HARDWARE_ERROR;
+			addl_sense_code = SD_SCSI_ASC_INTERNAL_TARGET_FAILURE;
+			addl_sense_qual = 0;
+		} else if (scmd->satacmd_status_reg & SATA_STATUS_ERR) {
+			if (scmd->satacmd_error_reg & SATA_ERROR_NM) {
+				sense_key = KEY_NOT_READY;
+				addl_sense_code =
+				    SD_SCSI_ASC_MEDIUM_NOT_PRESENT;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_UNC) {
+				sense_key = KEY_MEDIUM_ERROR;
+				addl_sense_code = SD_SCSI_ASC_WRITE_ERR;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_ILI) {
+				sense_key = KEY_DATA_PROTECT;
+				addl_sense_code = SD_SCSI_ASC_WRITE_PROTECTED;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_IDNF) {
+				sense_key = KEY_ILLEGAL_REQUEST;
+				addl_sense_code = SD_SCSI_ASC_LBA_OUT_OF_RANGE;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_ABORT) {
+				sense_key = KEY_ABORTED_COMMAND;
+				addl_sense_code = SD_SCSI_ASC_NO_ADD_SENSE;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_MC) {
+				sense_key = KEY_UNIT_ATTENTION;
+				addl_sense_code =
+				    SD_SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_MCR) {
+				sense_key = KEY_UNIT_ATTENTION;
+				addl_sense_code = SD_SCSI_ASC_OP_MEDIUM_REM_REQ;
+				addl_sense_qual = 0;
+			} else if (scmd->satacmd_error_reg & SATA_ERROR_ICRC) {
+				sense_key = KEY_ABORTED_COMMAND;
+				addl_sense_code =
+				    SD_SCSI_ASC_INFO_UNIT_IUCRC_ERR;
+				addl_sense_qual = 0;
+			}
+		}
+
+		sata_fill_ata_return_desc(sata_pkt, sense_key, addl_sense_code,
+		    addl_sense_qual);
+	}
+
+	sata_free_local_buffer(spx);
+
+	if ((scsipkt->pkt_flags & FLAG_NOINTR) == 0)
+		/* scsi callback required */
+		scsi_hba_pkt_comp(scsipkt);
+}
+
+/*
+ *
  */
 static void
 sata_fill_ata_return_desc(sata_pkt_t *sata_pkt, uint8_t sense_key,
@@ -7749,7 +8048,7 @@
  * if these features are supported by the device. If these features are not
  * supported, the command will be terminated with STATUS_CHECK.
  * This function fails only if the SET FEATURE command sent to
- * the device fails. The page format is not varified, assuming that the
+ * the device fails. The page format is not verified, assuming that the
  * target driver operates correctly - if parameters length is too short,
  * we just drop the page.
  * Two command may be sent if both Read Cache/Read Ahead and Write Cache
--- a/usr/src/uts/common/sys/sata/sata_defs.h	Wed Jul 28 12:51:51 2010 -0600
+++ b/usr/src/uts/common/sys/sata/sata_defs.h	Wed Jul 28 12:45:59 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SATA_DEFS_H
@@ -50,6 +49,7 @@
 /*
  * ATA/ATAPI disk commands (subset)
  */
+#define	SATAC_DSM		0x06	/* Data Set Management */
 #define	SATAC_DEVICE_RESET	0x08    /* ATAPI device reset */
 #define	SATAC_DOWNLOAD_MICROCODE 0x92   /* Download microcode */
 #define	SATAC_EJECT		0xed	/* media eject */
@@ -197,7 +197,8 @@
 	ushort_t ai_recmwdma;	   /*  66  rec multi-word dma cycle info  */
 	ushort_t ai_minpio;	   /*  67  min PIO cycle info		  */
 	ushort_t ai_minpioflow;	   /*  68  min PIO cycle info w/flow ctl  */
-	ushort_t ai_resv3[2];	   /* 69,70 reserved			  */
+	ushort_t ai_addsupported;  /*  69  additional supported		  */
+	ushort_t ai_resv3;	   /*  70 reserved			  */
 	ushort_t ai_typtime[2];	   /* 71-72 timing			  */
 	ushort_t ai_resv4[2];	   /* 73-74 reserved			  */
 	ushort_t ai_qdepth;	   /*  75  queue depth			  */
@@ -226,7 +227,8 @@
 	ushort_t ai_streamperf[2]; /* 98-99 streaming performance gran.   */
 	ushort_t ai_addrsecxt[4];  /* 100 extended max LBA sector	  */
 	ushort_t ai_stream_xfer_p; /* 104 streaming transfer time (PIO)   */
-	ushort_t ai_padding1;	   /* 105 pad				  */
+	ushort_t ai_maxcount;	   /* 105 max count of 512-byte blocks of */
+				    /* LBA range entries		  */
 	ushort_t ai_phys_sect_sz;  /* 106 physical sector size		  */
 	ushort_t ai_seek_delay;	   /* 107 inter-seek delay time (usecs)	  */
 	ushort_t ai_naa_ieee_oui;  /* 108 NAA/IEEE OUI			  */
@@ -238,18 +240,19 @@
 	ushort_t ai_words_lsec[2]; /* 117-118 words per logical sector	  */
 	ushort_t ai_cmdset119;	   /* 119 more command sets supported	  */
 	ushort_t ai_features120;   /* 120 enabled features		  */
-	ushort_t ai_padding2[6];   /* pad to 126			  */
+	ushort_t ai_padding1[6];   /* pad to 126			  */
 	ushort_t ai_rmsn;	   /* 127 removable media notification	  */
 	ushort_t ai_securestatus;  /* 128 security status		  */
 	ushort_t ai_vendor[31];	   /* 129-159 vendor specific		  */
-	ushort_t ai_padding3[8];   /* 160 pad to 168			  */
+	ushort_t ai_padding2[8];   /* 160 pad to 168			  */
 	ushort_t ai_nomformfactor; /* 168 nominal form factor		  */
-	ushort_t ai_padding4[7];   /* 169 pad to 176			  */
+	ushort_t ai_dsm;	   /* 169 data set management		  */
+	ushort_t ai_padding3[6];   /* 170 pad to 176			  */
 	ushort_t ai_curmedser[30]; /* 176-205 current media serial #	  */
 	ushort_t ai_sctsupport;	   /* 206 SCT command transport		  */
-	ushort_t ai_padding5[10];  /* 207 pad to 217			  */
+	ushort_t ai_padding4[10];  /* 207 pad to 217			  */
 	ushort_t ai_medrotrate;	   /* 217 nominal media rotation rate	  */
-	ushort_t ai_padding6[37];  /* 218 pad to 255			  */
+	ushort_t ai_padding5[37];  /* 218 pad to 255			  */
 	ushort_t ai_integrity;	   /* 255 integrity word		  */
 } sata_id_t;
 
@@ -282,6 +285,11 @@
 #define	SATA_VALIDINFO_88	0x0004	/* word 88 supported fields valid */
 #define	SATA_VALIDINFO_70_64	0x0004	/* words 70-64 fields valid */
 
+/* Identify Device: ai_addsupported (word 69) */
+
+#define	SATA_DETERMINISTIC_READ	0x4000	/* word 69 deterministic read supp. */
+#define	SATA_READ_ZERO		0x0020	/* word 69 read zero after TRIM supp. */
+
 /* Identify Device: ai_majorversion (word 80) */
 
 #define	SATA_MAJVER_7		0x0080	/* ATA/ATAPI-7 version supported */
--- a/usr/src/uts/common/sys/scsi/impl/spc3_types.h	Wed Jul 28 12:51:51 2010 -0600
+++ b/usr/src/uts/common/sys/scsi/impl/spc3_types.h	Wed Jul 28 12:45:59 2010 -0700
@@ -20,15 +20,12 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_SPC3_TYPES_H
 #define	_SPC3_TYPES_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -161,6 +158,8 @@
 	SPC3_CMD_CHANGE_DEFINITION = 0x40,
 	SPC3_CMD_WRITE_SAME = 0x41,
 	SPC3_CMD_WRITE_SAME10 = 0x41,
+	SPC3_CMD_UNMAP = 0x42,
+	SPC3_CMD_UNMAP10 = 0x42,
 	SPC3_CMD_READ_SUBCHANNEL = SCMD_READ_SUBCHANNEL,
 	SPC3_CMD_READ_TOC = SCMD_READ_TOC,
 	SPC3_CMD_REPORT_DENSITY_SUPPORT = SCMD_REPORT_DENSITIES,