changeset 10320:35786983c32a

6808004 fdisk fake cylinder size should be a multiple of 4k
author yu, larry liu - Sun Microsystems - Beijing China <Larry.Liu@Sun.COM>
date Mon, 17 Aug 2009 10:56:59 +0800
parents 0355b7a83c0d
children 44087508eb73
files usr/src/uts/common/io/cmlb.c usr/src/uts/common/io/scsi/targets/sd.c usr/src/uts/common/sys/cmlb.h usr/src/uts/common/sys/scsi/targets/sddef.h
diffstat 4 files changed, 139 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/cmlb.c	Sun Aug 16 19:52:03 2009 +0800
+++ b/usr/src/uts/common/io/cmlb.c	Mon Aug 17 10:56:59 2009 +0800
@@ -313,7 +313,8 @@
 #endif
 
 #if defined(_SUNOS_VTOC_16)
-static void cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g);
+static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
+    struct dk_geom *cl_g, void *tg_cookie);
 #endif
 
 static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
@@ -349,7 +350,8 @@
 static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
     void *tg_cookie);
 static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
-static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag);
+static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
+    void *tg_cookie);
 static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
     int flag);
 static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
@@ -1286,7 +1288,7 @@
 	case DKIOCG_PHYGEOM:
 		cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n");
 #if defined(__i386) || defined(__amd64)
-		err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag);
+		err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag, tg_cookie);
 #else
 		err = ENOTTY;
 #endif
@@ -1803,9 +1805,13 @@
  *     Context: Kernel thread only
  */
 static void
-cmlb_convert_geometry(diskaddr_t capacity, struct dk_geom *cl_g)
+cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
+    struct dk_geom *cl_g, void *tg_cookie)
 {
 
+	ASSERT(cl != NULL);
+	ASSERT(mutex_owned(CMLB_MUTEX(cl)));
+
 	/* Unlabeled SCSI floppy device */
 	if (capacity <= 0x1000) {
 		cl_g->dkg_nhead = 2;
@@ -1839,6 +1845,15 @@
 	 * 4211279100 (1.96TB)			255  	252
 	 * 5264098875 (2.45TB)			255  	315
 	 * ...
+	 *
+	 * For Solid State Drive(SSD), it uses 4K page size inside and may be
+	 * double with every new generation. If the I/O is not aligned with
+	 * page size on SSDs, SSDs perform a lot slower.
+	 * By default, Solaris partition starts from cylinder 1. It will be
+	 * misaligned even with 4K if using heads(255) and SPT(63). To
+	 * workaround the problem, if the device is SSD, we use heads(224) and
+	 * SPT multiple of 56. Thus the default Solaris partition starts from
+	 * a position that aligns with 128K on a 512 bytes sector size SSD.
 	 */
 
 	if (capacity <= 0x200000) {
@@ -1848,15 +1863,36 @@
 		cl_g->dkg_nhead = 128;
 		cl_g->dkg_nsect = 32;
 	} else {
-		cl_g->dkg_nhead = 255;
-
-		/* make nsect be smallest multiple of 63 */
+		tg_attribute_t tgattribute;
+		int is_solid_state;
+		unsigned short nhead;
+		unsigned short nsect;
+
+		bzero(&tgattribute, sizeof (tg_attribute_t));
+
+		mutex_exit(CMLB_MUTEX(cl));
+		is_solid_state =
+		    (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
+		    tgattribute.media_is_solid_state : FALSE;
+		mutex_enter(CMLB_MUTEX(cl));
+
+		if (is_solid_state) {
+			nhead = 224;
+			nsect = 56;
+		} else {
+			nhead = 255;
+			nsect = 63;
+		}
+
+		cl_g->dkg_nhead = nhead;
+
+		/* make nsect be smallest multiple of nhead */
 		cl_g->dkg_nsect = ((capacity +
-		    (UINT16_MAX * 255 * 63) - 1) /
-		    (UINT16_MAX * 255 * 63)) * 63;
+		    (UINT16_MAX * nhead * nsect) - 1) /
+		    (UINT16_MAX * nhead * nsect)) * nsect;
 
 		if (cl_g->dkg_nsect == 0)
-			cl_g->dkg_nsect = (UINT16_MAX / 63) * 63;
+			cl_g->dkg_nsect = (UINT16_MAX / nsect) * nsect;
 	}
 
 }
@@ -3327,7 +3363,7 @@
 			capacity = cl->cl_blockcount;
 
 
-		cmlb_convert_geometry(capacity, &cl_g);
+		cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie);
 		bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g));
 		phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
 	}
@@ -5381,7 +5417,8 @@
 
 #if defined(__i386) || defined(__amd64)
 static int
-cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag)
+cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
+    void *tg_cookie)
 {
 	int err = 0;
 	diskaddr_t capacity;
@@ -5443,7 +5480,7 @@
 			else
 				capacity = cl->cl_blockcount;
 
-			cmlb_convert_geometry(capacity, dkgp);
+			cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie);
 			dkgp->dkg_acyl = 0;
 			dkgp->dkg_ncyl = capacity /
 			    (dkgp->dkg_nhead * dkgp->dkg_nsect);
--- a/usr/src/uts/common/io/scsi/targets/sd.c	Sun Aug 16 19:52:03 2009 +0800
+++ b/usr/src/uts/common/io/scsi/targets/sd.c	Mon Aug 17 10:56:59 2009 +0800
@@ -879,6 +879,7 @@
 #define	sd_blank_cmp			ssd_blank_cmp
 #define	sd_chk_vers1_data		ssd_chk_vers1_data
 #define	sd_set_vers1_properties		ssd_set_vers1_properties
+#define	sd_check_solid_state		ssd_check_solid_state
 
 #define	sd_get_physical_geometry	ssd_get_physical_geometry
 #define	sd_get_virtual_geometry		ssd_get_virtual_geometry
@@ -1271,6 +1272,7 @@
 static int   sd_get_write_cache_enabled(sd_ssc_t *ssc, int *is_enabled);
 static void  sd_get_nv_sup(sd_ssc_t *ssc);
 static dev_t sd_make_device(dev_info_t *devi);
+static void  sd_check_solid_state(sd_ssc_t *ssc);
 
 static void  sd_update_block_info(struct sd_lun *un, uint32_t lbasize,
 	uint64_t capacity);
@@ -5667,8 +5669,8 @@
  * Description: This routine sends an inquiry command with the EVPD bit set and
  *		a page code of 0x00 to the device. It is used to determine which
  *		vital product pages are available to find the devid. We are
- *		looking for pages 0x83 or 0x80.  If we return a negative 1, the
- *		device does not support that command.
+ *		looking for pages 0x83 0x80 or 0xB1.  If we return a negative 1,
+ *		the device does not support that command.
  *
  *   Arguments: un  - driver soft state (unit) structure
  *
@@ -5724,7 +5726,7 @@
 		 * Pages are returned in ascending order, and 0x83 is what we
 		 * are hoping for.
 		 */
-		while ((page_list[counter] <= 0x86) &&
+		while ((page_list[counter] <= 0xB1) &&
 		    (counter <= (page_list[VPD_PAGE_LENGTH] +
 		    VPD_HEAD_OFFSET))) {
 			/*
@@ -5751,6 +5753,9 @@
 			case 0x86:
 				un->un_vpd_page_mask |= SD_VPD_EXTENDED_DATA_PG;
 				break;
+			case 0xB1:
+				un->un_vpd_page_mask |= SD_VPD_DEV_CHARACTER_PG;
+				break;
 			}
 			counter++;
 		}
@@ -8092,6 +8097,11 @@
 
 	un->un_mediastate = DKIO_NONE;
 
+	/*
+	 * Check if this is a SSD(Solid State Drive).
+	 */
+	sd_check_solid_state(ssc);
+
 	cmlb_alloc_handle(&un->un_cmlbhandle);
 
 #if defined(__i386) || defined(__amd64)
@@ -30828,6 +30838,8 @@
 		mutex_enter(SD_MUTEX(un));
 		((tg_attribute_t *)arg)->media_is_writable =
 		    un->un_f_mmc_writable_media;
+		((tg_attribute_t *)arg)->media_is_solid_state =
+		    un->un_f_is_solid_state;
 		mutex_exit(SD_MUTEX(un));
 		return (0);
 	default:
@@ -31289,3 +31301,73 @@
 		xp->xb_ena = fm_ena_generate(0, FM_ENA_FMT1);
 	ssc->ssc_uscsi_info->ui_ena = xp->xb_ena;
 }
+
+
+/*
+ *     Function: sd_check_solid_state
+ *
+ * Description: Query the optional INQUIRY VPD page 0xb1. If the device
+ *              supports VPD page 0xb1, sd examines the MEDIUM ROTATION
+ *              RATE. If the MEDIUM ROTATION RATE is 1, sd assumes the
+ *              device is a solid state drive.
+ *
+ *     Context: Kernel thread or interrupt context.
+ */
+
+static void
+sd_check_solid_state(sd_ssc_t *ssc)
+{
+	int		rval		= 0;
+	uchar_t		*inqb1		= NULL;
+	size_t		inqb1_len	= MAX_INQUIRY_SIZE;
+	size_t		inqb1_resid	= 0;
+	struct sd_lun	*un;
+
+	ASSERT(ssc != NULL);
+	un = ssc->ssc_un;
+	ASSERT(un != NULL);
+	ASSERT(!mutex_owned(SD_MUTEX(un)));
+
+	mutex_enter(SD_MUTEX(un));
+	un->un_f_is_solid_state = FALSE;
+
+	if (ISCD(un)) {
+		mutex_exit(SD_MUTEX(un));
+		return;
+	}
+
+	if (sd_check_vpd_page_support(ssc) == 0 &&
+	    un->un_vpd_page_mask & SD_VPD_DEV_CHARACTER_PG) {
+		mutex_exit(SD_MUTEX(un));
+		/* collect page b1 data */
+		inqb1 = kmem_zalloc(inqb1_len, KM_SLEEP);
+
+		rval = sd_send_scsi_INQUIRY(ssc, inqb1, inqb1_len,
+		    0x01, 0xB1, &inqb1_resid);
+
+		if (rval == 0 && (inqb1_len - inqb1_resid > 5)) {
+			SD_TRACE(SD_LOG_COMMON, un,
+			    "sd_check_solid_state: \
+			    successfully get VPD page: %x \
+			    PAGE LENGTH: %x BYTE 4: %x \
+			    BYTE 5: %x", inqb1[1], inqb1[3], inqb1[4],
+			    inqb1[5]);
+
+			mutex_enter(SD_MUTEX(un));
+			/*
+			 * Check the MEDIUM ROTATION RATE. If it is set
+			 * to 1, the device is a solid state drive.
+			 */
+			if (inqb1[4] == 0 && inqb1[5] == 1) {
+				un->un_f_is_solid_state = TRUE;
+			}
+			mutex_exit(SD_MUTEX(un));
+		} else if (rval != 0) {
+			sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+		}
+
+		kmem_free(inqb1, inqb1_len);
+	} else {
+		mutex_exit(SD_MUTEX(un));
+	}
+}
--- a/usr/src/uts/common/sys/cmlb.h	Sun Aug 16 19:52:03 2009 +0800
+++ b/usr/src/uts/common/sys/cmlb.h	Mon Aug 17 10:56:59 2009 +0800
@@ -49,6 +49,7 @@
 
 typedef struct tg_attribute {
 	int media_is_writable;
+	int media_is_solid_state;
 } tg_attribute_t;
 
 
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h	Sun Aug 16 19:52:03 2009 +0800
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h	Mon Aug 17 10:56:59 2009 +0800
@@ -453,7 +453,8 @@
 						/* field by hardware */
 	    un_f_pm_log_sense_smart	:1,	/* log sense support SMART */
 						/* feature attribute */
-	    un_f_reserved		:7;
+	    un_f_is_solid_state		:1,	/* has solid state media */
+	    un_f_reserved		:6;
 
 	/* Ptr to table of strings for ASC/ASCQ error message printing */
 	struct scsi_asq_key_strings	*un_additional_codes;
@@ -2357,6 +2358,7 @@
 #define	SD_VPD_ASCII_OP_PG	0x08	/* 0x82 - ASCII Op Defs */
 #define	SD_VPD_DEVID_WWN_PG	0x10	/* 0x83 - Device Identification */
 #define	SD_VPD_EXTENDED_DATA_PG	0x80	/* 0x86 - Extended data about the lun */
+#define	SD_VPD_DEV_CHARACTER_PG	0x400	/* 0xB1 - Device Characteristics */
 
 /*
  * Non-volatile cache support