diff options
Diffstat (limited to 'usr/src/uts/common')
| -rw-r--r-- | usr/src/uts/common/io/cmlb.c | 58 | ||||
| -rw-r--r-- | usr/src/uts/common/io/scsi/targets/sd.c | 744 | ||||
| -rw-r--r-- | usr/src/uts/common/os/dumpsubr.c | 12 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dkio.h | 18 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/dklabel.h | 4 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/scsi/targets/sddef.h | 34 | ||||
| -rw-r--r-- | usr/src/uts/common/xen/io/xdb.c | 18 | ||||
| -rw-r--r-- | usr/src/uts/common/xen/io/xdb.h | 2 | ||||
| -rw-r--r-- | usr/src/uts/common/xen/io/xdf.c | 93 | ||||
| -rw-r--r-- | usr/src/uts/common/xen/io/xdf.h | 3 | ||||
| -rw-r--r-- | usr/src/uts/common/xen/sys/xendev.h | 1 |
11 files changed, 854 insertions, 133 deletions
diff --git a/usr/src/uts/common/io/cmlb.c b/usr/src/uts/common/io/cmlb.c index 75559a9b94..343b1b965c 100644 --- a/usr/src/uts/common/io/cmlb.c +++ b/usr/src/uts/common/io/cmlb.c @@ -1287,6 +1287,9 @@ cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie) if ((capacity != 0) && (lbasize != 0)) { cl->cl_blockcount = capacity; cl->cl_tgt_blocksize = lbasize; + if (!cl->cl_is_removable) { + cl->cl_sys_blocksize = lbasize; + } return (0); } else { return (EIO); @@ -1592,7 +1595,7 @@ cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags, label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC); - buffer_size = sizeof (struct dk_label); + buffer_size = cl->cl_sys_blocksize; cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: " "label_addr: 0x%x allocation size: 0x%x\n", @@ -2199,12 +2202,6 @@ cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags, ASSERT(mutex_owned(CMLB_MUTEX(cl))); - if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) { - rval = EINVAL; - goto done_err1; - } - - lbasize = cl->cl_sys_blocksize; cl->cl_reserved = -1; @@ -3637,7 +3634,7 @@ cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag, } buffer = kmem_alloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP); - rval = DK_TG_READ(cl, buffer, 1, DEV_BSIZE, tg_cookie); + rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie); if (rval != 0) goto done_error; @@ -4048,9 +4045,9 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) cl->cl_reserved = -1; mutex_exit(CMLB_MUTEX(cl)); - gpt = kmem_alloc(sizeof (efi_gpt_t), KM_SLEEP); + gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP); - if (DK_TG_READ(cl, gpt, 1, DEV_BSIZE, tg_cookie) != 0) { + if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) { goto done; } @@ -4059,7 +4056,8 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) if (rval == 0) { /* clear primary */ bzero(gpt, sizeof (efi_gpt_t)); - if (rval = DK_TG_WRITE(cl, gpt, 1, EFI_LABEL_SIZE, tg_cookie)) { + if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize, + tg_cookie)) { cmlb_dbg(CMLB_INFO, cl, "cmlb_clear_efi: clear primary label failed\n"); } @@ -4070,8 +4068,8 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) goto done; } - if ((rval = DK_TG_READ(cl, gpt, cap - 1, EFI_LABEL_SIZE, tg_cookie)) - != 0) { + if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize, + tg_cookie)) != 0) { goto done; } cmlb_swap_efi_gpt(gpt); @@ -4081,7 +4079,7 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) cmlb_dbg(CMLB_TRACE, cl, "cmlb_clear_efi clear backup@%lu\n", cap - 1); bzero(gpt, sizeof (efi_gpt_t)); - if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, EFI_LABEL_SIZE, + if ((rval = DK_TG_WRITE(cl, gpt, cap - 1, cl->cl_sys_blocksize, tg_cookie))) { cmlb_dbg(CMLB_INFO, cl, "cmlb_clear_efi: clear backup label failed\n"); @@ -4092,7 +4090,7 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) * header of this file */ if ((rval = DK_TG_READ(cl, gpt, cap - 2, - EFI_LABEL_SIZE, tg_cookie)) != 0) { + cl->cl_sys_blocksize, tg_cookie)) != 0) { goto done; } cmlb_swap_efi_gpt(gpt); @@ -4104,7 +4102,7 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) cap - 2); bzero(gpt, sizeof (efi_gpt_t)); if ((rval = DK_TG_WRITE(cl, gpt, cap - 2, - EFI_LABEL_SIZE, tg_cookie))) { + cl->cl_sys_blocksize, tg_cookie))) { cmlb_dbg(CMLB_INFO, cl, "cmlb_clear_efi: clear legacy backup label " "failed\n"); @@ -4113,7 +4111,7 @@ cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie) } done: - kmem_free(gpt, sizeof (efi_gpt_t)); + kmem_free(gpt, cl->cl_sys_blocksize); } /* @@ -4210,7 +4208,7 @@ cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) struct dk_label *dkl; mutex_exit(CMLB_MUTEX(cl)); - dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); + dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); mutex_enter(CMLB_MUTEX(cl)); /* * cmlb_set_vtoc uses these fields in order to figure out @@ -4223,7 +4221,7 @@ cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie) dkl->dkl_nsect = cl->cl_g.dkg_nsect; mutex_exit(CMLB_MUTEX(cl)); (void) cmlb_set_vtoc(cl, dkl, tg_cookie); - kmem_free(dkl, sizeof (struct dk_label)); + kmem_free(dkl, cl->cl_sys_blocksize); mutex_enter(CMLB_MUTEX(cl)); } @@ -4258,7 +4256,7 @@ cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) ASSERT(mutex_owned(CMLB_MUTEX(cl))); mutex_exit(CMLB_MUTEX(cl)); - dkl = kmem_zalloc(sizeof (struct dk_label), KM_SLEEP); + dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); mutex_enter(CMLB_MUTEX(cl)); bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc)); @@ -4303,7 +4301,7 @@ cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie) rval = cmlb_set_vtoc(cl, dkl, tg_cookie); exit: - kmem_free(dkl, sizeof (struct dk_label)); + kmem_free(dkl, cl->cl_sys_blocksize); mutex_enter(CMLB_MUTEX(cl)); return (rval); } @@ -4422,7 +4420,7 @@ cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) /* * Read the mboot block, located at absolute block 0 on the target. */ - buffer_size = sizeof (struct mboot); + buffer_size = cl->cl_sys_blocksize; cmlb_dbg(CMLB_TRACE, cl, "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size); @@ -4481,18 +4479,18 @@ cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) return (EINVAL); } - mboot = kmem_zalloc(sizeof (struct mboot), KM_SLEEP); + mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP); if (ddi_copyin((const void *)arg, mboot, - sizeof (struct mboot), flag) != 0) { - kmem_free(mboot, (size_t)(sizeof (struct mboot))); + cl->cl_sys_blocksize, flag) != 0) { + kmem_free(mboot, cl->cl_sys_blocksize); return (EFAULT); } /* Is this really a master boot record? */ magic = LE_16(mboot->signature); if (magic != MBB_MAGIC) { - kmem_free(mboot, (size_t)(sizeof (struct mboot))); + kmem_free(mboot, cl->cl_sys_blocksize); return (EINVAL); } @@ -4508,7 +4506,7 @@ cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie); if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) { mutex_exit(CMLB_MUTEX(cl)); - kmem_free(mboot, (size_t)(sizeof (struct mboot))); + kmem_free(mboot, cl->cl_sys_blocksize); return (rval); } } @@ -4529,7 +4527,7 @@ cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie) #endif cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN; mutex_exit(CMLB_MUTEX(cl)); - kmem_free(mboot, (size_t)(sizeof (struct mboot))); + kmem_free(mboot, cl->cl_sys_blocksize); return (rval); } @@ -5098,10 +5096,10 @@ fallback: return (ddi_prop_op(dev, dip, prop_op, mod_flags, (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie); /* - * Assume partition information is in DEV_BSIZE units, compute + * Assume partition information is in sys_blocksize units, compute * divisor for size(9P) property representation. */ - dblk = lbasize / DEV_BSIZE; + dblk = lbasize / cl->cl_sys_blocksize; /* Now let ddi_prop_op_nblocks_blksize() handle the request. */ return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags, diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c index f2cbc0df37..8cbc1310a3 100644 --- a/usr/src/uts/common/io/scsi/targets/sd.c +++ b/usr/src/uts/common/io/scsi/targets/sd.c @@ -1017,6 +1017,7 @@ static int sd_pm_idletime = 1; #define sd_free_rqs ssd_free_rqs #define sd_dump_memory ssd_dump_memory #define sd_get_media_info ssd_get_media_info +#define sd_get_media_info_ext ssd_get_media_info_ext #define sd_dkio_ctrl_info ssd_dkio_ctrl_info #define sd_nvpair_str_decode ssd_nvpair_str_decode #define sd_strtok_r ssd_strtok_r @@ -1093,6 +1094,7 @@ static int sd_pm_idletime = 1; #define sd_is_lsi ssd_is_lsi #define sd_tg_rdwr ssd_tg_rdwr #define sd_tg_getinfo ssd_tg_getinfo +#define sd_rmw_msg_print_handler ssd_rmw_msg_print_handler #endif /* #if (defined(__fibre)) */ @@ -1463,7 +1465,7 @@ static int sd_send_scsi_DOORLOCK(sd_ssc_t *ssc, int flag, int path_flag); static int sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, int path_flag); static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, - uint32_t *lbap, int path_flag); + uint32_t *lbap, uint32_t *psp, int path_flag); static int sd_send_scsi_START_STOP_UNIT(sd_ssc_t *ssc, int flag, int path_flag); static int sd_send_scsi_INQUIRY(sd_ssc_t *ssc, uchar_t *bufaddr, @@ -1510,6 +1512,7 @@ static void sd_panic_for_res_conflict(struct sd_lun *un); * Disk Ioctl Function Prototypes */ static int sd_get_media_info(dev_t dev, caddr_t arg, int flag); +static int sd_get_media_info_ext(dev_t dev, caddr_t arg, int flag); static int sd_dkio_ctrl_info(dev_t dev, caddr_t arg, int flag); static int sd_dkio_get_temp(dev_t dev, caddr_t arg, int flag); @@ -1610,6 +1613,11 @@ static int sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, static int sd_tg_getinfo(dev_info_t *devi, int cmd, void *arg, void *tg_cookie); /* + * For printing RMW warning message timely + */ +static void sd_rmw_msg_print_handler(void *arg); + +/* * Constants for failfast support: * * SD_FAILFAST_INACTIVE: Instance is currently in a normal state, with NO @@ -1781,13 +1789,19 @@ static sd_chain_t sd_iostart_chain[] = { sd_mapblockaddr_iostart, /* Index: 3 */ sd_core_iostart, /* Index: 4 */ - /* Chain for buf IO for removable-media targets (PM enabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets with RMW needed (PM enabled) + */ sd_mapblockaddr_iostart, /* Index: 5 */ sd_mapblocksize_iostart, /* Index: 6 */ sd_pm_iostart, /* Index: 7 */ sd_core_iostart, /* Index: 8 */ - /* Chain for buf IO for removable-media targets (PM disabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets with RMW needed (PM disabled) + */ sd_mapblockaddr_iostart, /* Index: 9 */ sd_mapblocksize_iostart, /* Index: 10 */ sd_core_iostart, /* Index: 11 */ @@ -1817,6 +1831,26 @@ static sd_chain_t sd_iostart_chain[] = { /* Chain for "direct priority" USCSI commands (all targets) */ sd_core_iostart, /* Index: 25 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with RMW needed with checksumming (PM enabled) + */ + sd_mapblockaddr_iostart, /* Index: 26 */ + sd_mapblocksize_iostart, /* Index: 27 */ + sd_checksum_iostart, /* Index: 28 */ + sd_pm_iostart, /* Index: 29 */ + sd_core_iostart, /* Index: 30 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with RMW needed with checksumming (PM disabled) + */ + sd_mapblockaddr_iostart, /* Index: 31 */ + sd_mapblocksize_iostart, /* Index: 32 */ + sd_checksum_iostart, /* Index: 33 */ + sd_core_iostart, /* Index: 34 */ + }; /* @@ -1825,7 +1859,9 @@ static sd_chain_t sd_iostart_chain[] = { */ #define SD_CHAIN_DISK_IOSTART 0 #define SD_CHAIN_DISK_IOSTART_NO_PM 3 +#define SD_CHAIN_MSS_DISK_IOSTART 5 #define SD_CHAIN_RMMEDIA_IOSTART 5 +#define SD_CHAIN_MSS_DISK_IOSTART_NO_PM 9 #define SD_CHAIN_RMMEDIA_IOSTART_NO_PM 9 #define SD_CHAIN_CHKSUM_IOSTART 12 #define SD_CHAIN_CHKSUM_IOSTART_NO_PM 16 @@ -1833,6 +1869,8 @@ static sd_chain_t sd_iostart_chain[] = { #define SD_CHAIN_USCSI_CHKSUM_IOSTART 21 #define SD_CHAIN_DIRECT_CMD_IOSTART 24 #define SD_CHAIN_PRIORITY_CMD_IOSTART 25 +#define SD_CHAIN_MSS_CHKSUM_IOSTART 26 +#define SD_CHAIN_MSS_CHKSUM_IOSTART_NO_PM 31 /* @@ -1859,13 +1897,19 @@ static sd_chain_t sd_iodone_chain[] = { sd_buf_iodone, /* Index: 3 */ sd_mapblockaddr_iodone, /* Index: 4 */ - /* Chain for buf IO for removable-media targets (PM enabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets with RMW needed (PM enabled) + */ sd_buf_iodone, /* Index: 5 */ sd_mapblockaddr_iodone, /* Index: 6 */ sd_mapblocksize_iodone, /* Index: 7 */ sd_pm_iodone, /* Index: 8 */ - /* Chain for buf IO for removable-media targets (PM disabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets with RMW needed (PM disabled) + */ sd_buf_iodone, /* Index: 9 */ sd_mapblockaddr_iodone, /* Index: 10 */ sd_mapblocksize_iodone, /* Index: 11 */ @@ -1895,6 +1939,25 @@ static sd_chain_t sd_iodone_chain[] = { /* Chain for "direct priority" USCSI commands (all targets) */ sd_uscsi_iodone, /* Index: 25 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM enabled) + */ + sd_buf_iodone, /* Index: 26 */ + sd_mapblockaddr_iodone, /* Index: 27 */ + sd_mapblocksize_iodone, /* Index: 28 */ + sd_checksum_iodone, /* Index: 29 */ + sd_pm_iodone, /* Index: 30 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM disabled) + */ + sd_buf_iodone, /* Index: 31 */ + sd_mapblockaddr_iodone, /* Index: 32 */ + sd_mapblocksize_iodone, /* Index: 33 */ + sd_checksum_iodone, /* Index: 34 */ }; @@ -1910,14 +1973,17 @@ static sd_chain_t sd_iodone_chain[] = { #define SD_CHAIN_DISK_IODONE 2 #define SD_CHAIN_DISK_IODONE_NO_PM 4 #define SD_CHAIN_RMMEDIA_IODONE 8 +#define SD_CHAIN_MSS_DISK_IODONE 8 #define SD_CHAIN_RMMEDIA_IODONE_NO_PM 11 +#define SD_CHAIN_MSS_DISK_IODONE_NO_PM 11 #define SD_CHAIN_CHKSUM_IODONE 15 #define SD_CHAIN_CHKSUM_IODONE_NO_PM 18 #define SD_CHAIN_USCSI_CMD_IODONE 20 #define SD_CHAIN_USCSI_CHKSUM_IODONE 22 #define SD_CHAIN_DIRECT_CMD_IODONE 24 #define SD_CHAIN_PRIORITY_CMD_IODONE 25 - +#define SD_CHAIN_MSS_CHKSUM_IODONE 30 +#define SD_CHAIN_MSS_CHKSUM_IODONE_NO_PM 34 @@ -1940,13 +2006,19 @@ static sd_initpkt_t sd_initpkt_map[] = { sd_initpkt_for_buf, /* Index: 3 */ sd_initpkt_for_buf, /* Index: 4 */ - /* Chain for buf IO for removable-media targets (PM enabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM enabled) + */ sd_initpkt_for_buf, /* Index: 5 */ sd_initpkt_for_buf, /* Index: 6 */ sd_initpkt_for_buf, /* Index: 7 */ sd_initpkt_for_buf, /* Index: 8 */ - /* Chain for buf IO for removable-media targets (PM disabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM disabled) + */ sd_initpkt_for_buf, /* Index: 9 */ sd_initpkt_for_buf, /* Index: 10 */ sd_initpkt_for_buf, /* Index: 11 */ @@ -1977,6 +2049,24 @@ static sd_initpkt_t sd_initpkt_map[] = { /* Chain for "direct priority" USCSI commands (all targets) */ sd_initpkt_for_uscsi, /* Index: 25 */ + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM enabled) + */ + sd_initpkt_for_buf, /* Index: 26 */ + sd_initpkt_for_buf, /* Index: 27 */ + sd_initpkt_for_buf, /* Index: 28 */ + sd_initpkt_for_buf, /* Index: 29 */ + sd_initpkt_for_buf, /* Index: 30 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM disabled) + */ + sd_initpkt_for_buf, /* Index: 31 */ + sd_initpkt_for_buf, /* Index: 32 */ + sd_initpkt_for_buf, /* Index: 33 */ + sd_initpkt_for_buf, /* Index: 34 */ }; @@ -1999,13 +2089,19 @@ static sd_destroypkt_t sd_destroypkt_map[] = { sd_destroypkt_for_buf, /* Index: 3 */ sd_destroypkt_for_buf, /* Index: 4 */ - /* Chain for buf IO for removable-media targets (PM enabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM enabled) + */ sd_destroypkt_for_buf, /* Index: 5 */ sd_destroypkt_for_buf, /* Index: 6 */ sd_destroypkt_for_buf, /* Index: 7 */ sd_destroypkt_for_buf, /* Index: 8 */ - /* Chain for buf IO for removable-media targets (PM disabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM disabled) + */ sd_destroypkt_for_buf, /* Index: 9 */ sd_destroypkt_for_buf, /* Index: 10 */ sd_destroypkt_for_buf, /* Index: 11 */ @@ -2036,6 +2132,24 @@ static sd_destroypkt_t sd_destroypkt_map[] = { /* Chain for "direct priority" USCSI commands (all targets) */ sd_destroypkt_for_uscsi, /* Index: 25 */ + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM disabled) + */ + sd_destroypkt_for_buf, /* Index: 26 */ + sd_destroypkt_for_buf, /* Index: 27 */ + sd_destroypkt_for_buf, /* Index: 28 */ + sd_destroypkt_for_buf, /* Index: 29 */ + sd_destroypkt_for_buf, /* Index: 30 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM enabled) + */ + sd_destroypkt_for_buf, /* Index: 31 */ + sd_destroypkt_for_buf, /* Index: 32 */ + sd_destroypkt_for_buf, /* Index: 33 */ + sd_destroypkt_for_buf, /* Index: 34 */ }; @@ -2066,13 +2180,19 @@ static int sd_chain_type_map[] = { SD_CHAIN_BUFIO, /* Index: 3 */ SD_CHAIN_BUFIO, /* Index: 4 */ - /* Chain for buf IO for removable-media targets (PM enabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM enabled) + */ SD_CHAIN_BUFIO, /* Index: 5 */ SD_CHAIN_BUFIO, /* Index: 6 */ SD_CHAIN_BUFIO, /* Index: 7 */ SD_CHAIN_BUFIO, /* Index: 8 */ - /* Chain for buf IO for removable-media targets (PM disabled) */ + /* + * Chain for buf IO for removable-media or large sector size + * disk drive targets (PM disabled) + */ SD_CHAIN_BUFIO, /* Index: 9 */ SD_CHAIN_BUFIO, /* Index: 10 */ SD_CHAIN_BUFIO, /* Index: 11 */ @@ -2095,13 +2215,32 @@ static int sd_chain_type_map[] = { /* Chain for USCSI commands (checksum targets) */ SD_CHAIN_USCSI, /* Index: 21 */ SD_CHAIN_USCSI, /* Index: 22 */ - SD_CHAIN_USCSI, /* Index: 22 */ + SD_CHAIN_USCSI, /* Index: 23 */ /* Chain for "direct" USCSI commands (all targets) */ SD_CHAIN_DIRECT, /* Index: 24 */ /* Chain for "direct priority" USCSI commands (all targets) */ SD_CHAIN_DIRECT_PRIORITY, /* Index: 25 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM enabled) + */ + SD_CHAIN_BUFIO, /* Index: 26 */ + SD_CHAIN_BUFIO, /* Index: 27 */ + SD_CHAIN_BUFIO, /* Index: 28 */ + SD_CHAIN_BUFIO, /* Index: 29 */ + SD_CHAIN_BUFIO, /* Index: 30 */ + + /* + * Chain for buf IO for large sector size disk drive targets + * with checksumming (PM disabled) + */ + SD_CHAIN_BUFIO, /* Index: 31 */ + SD_CHAIN_BUFIO, /* Index: 32 */ + SD_CHAIN_BUFIO, /* Index: 33 */ + SD_CHAIN_BUFIO, /* Index: 34 */ }; @@ -2147,6 +2286,9 @@ static struct sd_chain_index sd_chain_index_map[] = { { SD_CHAIN_USCSI_CHKSUM_IOSTART, SD_CHAIN_USCSI_CHKSUM_IODONE }, { SD_CHAIN_DIRECT_CMD_IOSTART, SD_CHAIN_DIRECT_CMD_IODONE }, { SD_CHAIN_PRIORITY_CMD_IOSTART, SD_CHAIN_PRIORITY_CMD_IODONE }, + { SD_CHAIN_MSS_CHKSUM_IOSTART, SD_CHAIN_MSS_CHKSUM_IODONE }, + { SD_CHAIN_MSS_CHKSUM_IOSTART_NO_PM, SD_CHAIN_MSS_CHKSUM_IODONE_NO_PM }, + }; @@ -2158,9 +2300,13 @@ static struct sd_chain_index sd_chain_index_map[] = { #define SD_CHAIN_INFO_DISK 0 #define SD_CHAIN_INFO_DISK_NO_PM 1 #define SD_CHAIN_INFO_RMMEDIA 2 +#define SD_CHAIN_INFO_MSS_DISK 2 #define SD_CHAIN_INFO_RMMEDIA_NO_PM 3 +#define SD_CHAIN_INFO_MSS_DSK_NO_PM 3 #define SD_CHAIN_INFO_CHKSUM 4 #define SD_CHAIN_INFO_CHKSUM_NO_PM 5 +#define SD_CHAIN_INFO_MSS_DISK_CHKSUM 10 +#define SD_CHAIN_INFO_MSS_DISK_CHKSUM_NO_PM 11 /* un->un_uscsi_chain_type must be set to one of these */ #define SD_CHAIN_INFO_USCSI_CMD 6 @@ -3967,6 +4113,16 @@ sd_set_properties(struct sd_lun *un, char *name, char *value) "min throttle set to %d\n", un->un_min_throttle); } + if (strcasecmp(name, "rmw-type") == 0) { + if (ddi_strtol(value, &endptr, 0, &val) == 0) { + un->un_f_rmw_type = val; + } else { + goto value_invalid; + } + SD_INFO(SD_LOG_ATTACH_DETACH, un, "sd_set_properties: " + "RMW type set to %d\n", un->un_f_rmw_type); + } + /* * Validate the throttle values. * If any of the numbers are invalid, set everything to defaults. @@ -4996,7 +5152,10 @@ sd_update_block_info(struct sd_lun *un, uint32_t lbasize, uint64_t capacity) { if (lbasize != 0) { un->un_tgt_blocksize = lbasize; - un->un_f_tgt_blocksize_is_valid = TRUE; + un->un_f_tgt_blocksize_is_valid = TRUE; + if (!un->un_f_has_removable_media) { + un->un_sys_blocksize = lbasize; + } } if (capacity != 0) { @@ -5290,7 +5449,7 @@ sd_get_devid(sd_ssc_t *ssc) /* Calculate the checksum */ chksum = 0; ip = (uint_t *)dkdevid; - for (i = 0; i < ((un->un_sys_blocksize - sizeof (int))/sizeof (int)); + for (i = 0; i < ((DEV_BSIZE - sizeof (int)) / sizeof (int)); i++) { chksum ^= ip[i]; } @@ -5386,6 +5545,7 @@ static int sd_write_deviceid(sd_ssc_t *ssc) { struct dk_devid *dkdevid; + uchar_t *buf; diskaddr_t blk; uint_t *ip, chksum; int status; @@ -5406,7 +5566,8 @@ sd_write_deviceid(sd_ssc_t *ssc) /* Allocate the buffer */ - dkdevid = kmem_zalloc(un->un_sys_blocksize, KM_SLEEP); + buf = kmem_zalloc(un->un_sys_blocksize, KM_SLEEP); + dkdevid = (struct dk_devid *)buf; /* Fill in the revision */ dkdevid->dkd_rev_hi = DK_DEVID_REV_MSB; @@ -5421,7 +5582,7 @@ sd_write_deviceid(sd_ssc_t *ssc) /* Calculate the checksum */ chksum = 0; ip = (uint_t *)dkdevid; - for (i = 0; i < ((un->un_sys_blocksize - sizeof (int))/sizeof (int)); + for (i = 0; i < ((DEV_BSIZE - sizeof (int)) / sizeof (int)); i++) { chksum ^= ip[i]; } @@ -5430,12 +5591,12 @@ sd_write_deviceid(sd_ssc_t *ssc) DKD_FORMCHKSUM(chksum, dkdevid); /* Write the reserved sector */ - status = sd_send_scsi_WRITE(ssc, dkdevid, un->un_sys_blocksize, blk, + status = sd_send_scsi_WRITE(ssc, buf, un->un_sys_blocksize, blk, SD_PATH_DIRECT); if (status != 0) sd_ssc_assessment(ssc, SD_FMT_IGNORE); - kmem_free(dkdevid, un->un_sys_blocksize); + kmem_free(buf, un->un_sys_blocksize); mutex_enter(SD_MUTEX(un)); return (status); @@ -5903,6 +6064,14 @@ sd_ddi_suspend(dev_info_t *devi) mutex_exit(&un->un_pm_mutex); } + if (un->un_rmw_msg_timeid != NULL) { + timeout_id_t temp_id = un->un_rmw_msg_timeid; + un->un_rmw_msg_timeid = NULL; + mutex_exit(SD_MUTEX(un)); + (void) untimeout(temp_id); + mutex_enter(SD_MUTEX(un)); + } + if (un->un_retry_timeid != NULL) { timeout_id_t temp_id = un->un_retry_timeid; un->un_retry_timeid = NULL; @@ -6217,7 +6386,7 @@ sd_pm_idletimeout_handler(void *arg) } else { un->un_buf_chain_type = SD_CHAIN_INFO_DISK; } - un->un_uscsi_chain_type = SD_CHAIN_INFO_USCSI_CMD; + un->un_uscsi_chain_type = SD_CHAIN_INFO_USCSI_CMD; SD_TRACE(SD_LOG_IO_PM, un, "sd_pm_idletimeout_handler: idling device\n"); @@ -6839,6 +7008,7 @@ sd_unit_attach(dev_info_t *devi) struct scsi_device *devp; struct sd_lun *un; char *variantp; + char name_str[48]; int reservation_flag = SD_TARGET_IS_UNRESERVED; int instance; int rval; @@ -7267,6 +7437,7 @@ sd_unit_attach(dev_info_t *devi) * meaning a non-zero value must be entered to change the default. */ un->un_f_disksort_disabled = FALSE; + un->un_f_rmw_type = SD_RMW_TYPE_DEFAULT; /* * Retrieve the properties from the static driver table or the driver @@ -7906,6 +8077,24 @@ sd_unit_attach(dev_info_t *devi) un->un_f_write_cache_enabled = (wc_enabled != 0); mutex_exit(SD_MUTEX(un)); + if (un->un_f_rmw_type != SD_RMW_TYPE_RETURN_ERROR && + un->un_tgt_blocksize != DEV_BSIZE) { + if (!(un->un_wm_cache)) { + (void) snprintf(name_str, sizeof (name_str), + "%s%d_cache", + ddi_driver_name(SD_DEVINFO(un)), + ddi_get_instance(SD_DEVINFO(un))); + un->un_wm_cache = kmem_cache_create( + name_str, sizeof (struct sd_w_map), + 8, sd_wm_cache_constructor, + sd_wm_cache_destructor, NULL, + (void *)un, NULL, 0); + if (!(un->un_wm_cache)) { + goto wm_cache_failed; + } + } + } + /* * Check the value of the NV_SUP bit and set * un_f_suppress_cache_flush accordingly. @@ -7994,7 +8183,7 @@ sd_unit_attach(dev_info_t *devi) /* * An error occurred during the attach; clean up & return failure. */ - +wm_cache_failed: devid_failed: setup_pm_failed: @@ -8057,6 +8246,15 @@ spinup_failed: mutex_enter(SD_MUTEX(un)); } + /* Cancel rmw warning message timeouts */ + if (un->un_rmw_msg_timeid != NULL) { + timeout_id_t temp_id = un->un_rmw_msg_timeid; + un->un_rmw_msg_timeid = NULL; + mutex_exit(SD_MUTEX(un)); + (void) untimeout(temp_id); + mutex_enter(SD_MUTEX(un)); + } + /* Cancel any pending retry timeouts */ if (un->un_retry_timeid != NULL) { timeout_id_t temp_id = un->un_retry_timeid; @@ -8270,6 +8468,14 @@ sd_unit_detach(dev_info_t *devi) mutex_enter(SD_MUTEX(un)); } + if (un->un_rmw_msg_timeid != NULL) { + timeout_id_t temp_id = un->un_rmw_msg_timeid; + un->un_rmw_msg_timeid = NULL; + mutex_exit(SD_MUTEX(un)); + (void) untimeout(temp_id); + mutex_enter(SD_MUTEX(un)); + } + if (un->un_dcvb_timeid != NULL) { timeout_id_t temp_id = un->un_dcvb_timeid; un->un_dcvb_timeid = NULL; @@ -10288,7 +10494,9 @@ sd_ready_and_valid(sd_ssc_t *ssc, int part) * a media is changed this routine will be called and the * block size is a function of media rather than device. */ - if (un->un_f_non_devbsize_supported && NOT_DEVBSIZE(un)) { + if ((un->un_f_rmw_type != SD_RMW_TYPE_RETURN_ERROR || + un->un_f_non_devbsize_supported) && + un->un_tgt_blocksize != DEV_BSIZE) { if (!(un->un_wm_cache)) { (void) snprintf(name_str, sizeof (name_str), "%s%d_cache", @@ -10518,17 +10726,20 @@ sdread(dev_t dev, struct uio *uio, cred_t *cred_p) /* * Read requests are restricted to multiples of the system block size. */ - secmask = un->un_sys_blocksize - 1; + if (un->un_f_rmw_type == SD_RMW_TYPE_RETURN_ERROR) + secmask = un->un_tgt_blocksize - 1; + else + secmask = DEV_BSIZE - 1; if (uio->uio_loffset & ((offset_t)(secmask))) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdread: file offset not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else if (uio->uio_iov->iov_len & (secmask)) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdread: transfer length not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else { err = physio(sdstrategy, NULL, dev, B_READ, sdmin, uio); @@ -10604,17 +10815,20 @@ sdwrite(dev_t dev, struct uio *uio, cred_t *cred_p) /* * Write requests are restricted to multiples of the system block size. */ - secmask = un->un_sys_blocksize - 1; + if (un->un_f_rmw_type == SD_RMW_TYPE_RETURN_ERROR) + secmask = un->un_tgt_blocksize - 1; + else + secmask = DEV_BSIZE - 1; if (uio->uio_loffset & ((offset_t)(secmask))) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdwrite: file offset not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else if (uio->uio_iov->iov_len & (secmask)) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdwrite: transfer length not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else { err = physio(sdstrategy, NULL, dev, B_WRITE, sdmin, uio); @@ -10690,17 +10904,20 @@ sdaread(dev_t dev, struct aio_req *aio, cred_t *cred_p) /* * Read requests are restricted to multiples of the system block size. */ - secmask = un->un_sys_blocksize - 1; + if (un->un_f_rmw_type == SD_RMW_TYPE_RETURN_ERROR) + secmask = un->un_tgt_blocksize - 1; + else + secmask = DEV_BSIZE - 1; if (uio->uio_loffset & ((offset_t)(secmask))) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdaread: file offset not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else if (uio->uio_iov->iov_len & (secmask)) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdaread: transfer length not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else { err = aphysio(sdstrategy, anocancel, dev, B_READ, sdmin, aio); @@ -10776,17 +10993,20 @@ sdawrite(dev_t dev, struct aio_req *aio, cred_t *cred_p) /* * Write requests are restricted to multiples of the system block size. */ - secmask = un->un_sys_blocksize - 1; + if (un->un_f_rmw_type == SD_RMW_TYPE_RETURN_ERROR) + secmask = un->un_tgt_blocksize - 1; + else + secmask = DEV_BSIZE - 1; if (uio->uio_loffset & ((offset_t)(secmask))) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdawrite: file offset not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else if (uio->uio_iov->iov_len & (secmask)) { SD_ERROR(SD_LOG_READ_WRITE, un, "sdawrite: transfer length not modulo %d\n", - un->un_sys_blocksize); + secmask + 1); err = EINVAL; } else { err = aphysio(sdstrategy, anocancel, dev, B_WRITE, sdmin, aio); @@ -11012,6 +11232,7 @@ sdstrategy(struct buf *bp) biodone(bp); return (0); } + /* As was done in the past, fail new cmds. if state is dumping. */ if (un->un_state == SD_STATE_DUMPING) { bioerror(bp, ENXIO); @@ -11150,6 +11371,27 @@ sd_xbuf_init(struct sd_lun *un, struct buf *bp, struct sd_xbuf *xp, /* FALLTHRU */ case SD_CHAIN_BUFIO: index = un->un_buf_chain_type; + if ((!un->un_f_has_removable_media) && + (un->un_tgt_blocksize != 0) && + (un->un_tgt_blocksize != DEV_BSIZE)) { + int secmask = 0, blknomask = 0; + blknomask = + (un->un_tgt_blocksize / DEV_BSIZE) - 1; + secmask = un->un_tgt_blocksize - 1; + + if ((bp->b_lblkno & (blknomask)) || + (bp->b_bcount & (secmask))) { + if (un->un_f_rmw_type != + SD_RMW_TYPE_RETURN_ERROR) { + if (un->un_f_pm_is_enabled == FALSE) + index = + SD_CHAIN_INFO_MSS_DSK_NO_PM; + else + index = + SD_CHAIN_INFO_MSS_DISK; + } + } + } break; case SD_CHAIN_USCSI: index = un->un_uscsi_chain_type; @@ -12039,6 +12281,20 @@ sd_uscsi_iodone(int index, struct sd_lun *un, struct buf *bp) * request would exceed partition range. Converts * partition-relative block address to absolute. * + * Upon exit of this function: + * 1.I/O is aligned + * xp->xb_blkno represents the absolute sector address + * 2.I/O is misaligned + * xp->xb_blkno represents the absolute logical block address + * based on DEV_BSIZE. The logical block address will be + * converted to physical sector address in sd_mapblocksize_\ + * iostart. + * 3.I/O is misaligned but is aligned in "overrun" buf + * xp->xb_blkno represents the absolute logical block address + * based on DEV_BSIZE. The logical block address will be + * converted to physical sector address in sd_mapblocksize_\ + * iostart. But no RMW will be issued in this case. + * * Context: Can sleep * * Issues: This follows what the old code did, in terms of accessing @@ -12060,6 +12316,8 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp) int partition; diskaddr_t partition_offset; struct sd_xbuf *xp; + int secmask = 0, blknomask = 0; + ushort_t is_aligned = TRUE; ASSERT(un != NULL); ASSERT(bp != NULL); @@ -12116,6 +12374,57 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp) (void) cmlb_partinfo(un->un_cmlbhandle, partition, &nblocks, &partition_offset, NULL, NULL, (void *)SD_PATH_DIRECT); + blknomask = (un->un_tgt_blocksize / DEV_BSIZE) - 1; + secmask = un->un_tgt_blocksize - 1; + + if ((bp->b_lblkno & (blknomask)) || (bp->b_bcount & (secmask))) { + is_aligned = FALSE; + } + + if (!(NOT_DEVBSIZE(un))) { + /* + * If I/O is aligned, no need to involve RMW(Read Modify Write) + * Convert the logical block number to target's physical sector + * number. + */ + if (is_aligned) { + xp->xb_blkno = SD_SYS2TGTBLOCK(un, xp->xb_blkno); + } else { + switch (un->un_f_rmw_type) { + case SD_RMW_TYPE_RETURN_ERROR: + bp->b_flags |= B_ERROR; + goto error_exit; + + case SD_RMW_TYPE_DEFAULT: + mutex_enter(SD_MUTEX(un)); + if (un->un_rmw_msg_timeid == NULL) { + scsi_log(SD_DEVINFO(un), sd_label, + CE_WARN, "I/O request is not " + "aligned with %d disk sector size. " + "It is handled through Read Modify " + "Write but the performance is " + "very low.\n", + un->un_tgt_blocksize); + un->un_rmw_msg_timeid = + timeout(sd_rmw_msg_print_handler, + un, SD_RMW_MSG_PRINT_TIMEOUT); + } else { + un->un_rmw_incre_count ++; + } + mutex_exit(SD_MUTEX(un)); + break; + + case SD_RMW_TYPE_NO_WARNING: + default: + break; + } + + nblocks = SD_TGT2SYSBLOCK(un, nblocks); + partition_offset = SD_TGT2SYSBLOCK(un, + partition_offset); + } + } + /* * blocknum is the starting block number of the request. At this * point it is still relative to the start of the minor device. @@ -12136,7 +12445,7 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp) * a multiple of the system block size. */ if ((blocknum < 0) || (blocknum >= nblocks) || - ((bp->b_bcount & (un->un_sys_blocksize - 1)) != 0)) { + ((bp->b_bcount & (DEV_BSIZE - 1)) != 0)) { bp->b_flags |= B_ERROR; goto error_exit; } @@ -12145,11 +12454,18 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp) * If the requsted # blocks exceeds the available # blocks, that * is an overrun of the partition. */ - requested_nblocks = SD_BYTES2SYSBLOCKS(un, bp->b_bcount); + if ((!NOT_DEVBSIZE(un)) && is_aligned) { + requested_nblocks = SD_BYTES2TGTBLOCKS(un, bp->b_bcount); + } else { + requested_nblocks = SD_BYTES2SYSBLOCKS(bp->b_bcount); + } + available_nblocks = (size_t)(nblocks - blocknum); ASSERT(nblocks >= blocknum); if (requested_nblocks > available_nblocks) { + size_t resid; + /* * Allocate an "overrun" buf to allow the request to proceed * for the amount of space available in the partition. The @@ -12158,8 +12474,14 @@ sd_mapblockaddr_iostart(int index, struct sd_lun *un, struct buf *bp) * replaces the original buf here, and the original buf * is saved inside the overrun buf, for later use. */ - size_t resid = SD_SYSBLOCKS2BYTES(un, - (offset_t)(requested_nblocks - available_nblocks)); + if ((!NOT_DEVBSIZE(un)) && is_aligned) { + resid = SD_TGTBLOCKS2BYTES(un, + (offset_t)(requested_nblocks - available_nblocks)); + } else { + resid = SD_SYSBLOCKS2BYTES( + (offset_t)(requested_nblocks - available_nblocks)); + } + size_t count = bp->b_bcount - resid; /* * Note: count is an unsigned entity thus it'll NEVER @@ -12318,7 +12640,7 @@ sd_mapblocksize_iostart(int index, struct sd_lun *un, struct buf *bp) * un->un_sys_blocksize as its block size or if bcount == 0. * In this case there is no layer-private data block allocated. */ - if ((un->un_tgt_blocksize == un->un_sys_blocksize) || + if ((un->un_tgt_blocksize == DEV_BSIZE) || (bp->b_bcount == 0)) { goto done; } @@ -12333,7 +12655,7 @@ sd_mapblocksize_iostart(int index, struct sd_lun *un, struct buf *bp) SD_INFO(SD_LOG_IO_RMMEDIA, un, "sd_mapblocksize_iostart: " "tgt_blocksize:0x%x sys_blocksize: 0x%x\n", - un->un_tgt_blocksize, un->un_sys_blocksize); + un->un_tgt_blocksize, DEV_BSIZE); SD_INFO(SD_LOG_IO_RMMEDIA, un, "sd_mapblocksize_iostart: " "request start block:0x%x\n", xp->xb_blkno); SD_INFO(SD_LOG_IO_RMMEDIA, un, "sd_mapblocksize_iostart: " @@ -12376,7 +12698,7 @@ sd_mapblocksize_iostart(int index, struct sd_lun *un, struct buf *bp) * Note that end_block is actually the block that follows the last * block of the request, but that's what is needed for the computation. */ - first_byte = SD_SYSBLOCKS2BYTES(un, (offset_t)xp->xb_blkno); + first_byte = SD_SYSBLOCKS2BYTES((offset_t)xp->xb_blkno); start_block = xp->xb_blkno = first_byte / un->un_tgt_blocksize; end_block = (first_byte + bp->b_bcount + un->un_tgt_blocksize - 1) / un->un_tgt_blocksize; @@ -12519,7 +12841,7 @@ sd_mapblocksize_iodone(int index, struct sd_lun *un, struct buf *bp) * There is no shadow buf or layer-private data if the target is * using un->un_sys_blocksize as its block size or if bcount == 0. */ - if ((un->un_tgt_blocksize == un->un_sys_blocksize) || + if ((un->un_tgt_blocksize == DEV_BSIZE) || (bp->b_bcount == 0)) { goto exit; } @@ -15550,6 +15872,48 @@ sd_start_retry_command(void *arg) "sd_start_retry_command: exit\n"); } +/* + * Function: sd_rmw_msg_print_handler + * + * Description: If RMW mode is enabled and warning message is triggered + * print I/O count during a fixed interval. + * + * Arguments: arg - pointer to associated softstate for the device. + * + * Context: timeout(9F) thread context. May not sleep. + */ +static void +sd_rmw_msg_print_handler(void *arg) +{ + struct sd_lun *un = arg; + + ASSERT(un != NULL); + ASSERT(!mutex_owned(SD_MUTEX(un))); + + SD_TRACE(SD_LOG_IO_CORE | SD_LOG_ERROR, un, + "sd_rmw_msg_print_handler: entry\n"); + + mutex_enter(SD_MUTEX(un)); + + if (un->un_rmw_incre_count > 0) { + scsi_log(SD_DEVINFO(un), sd_label, CE_WARN, + "%"PRIu64" I/O requests are not aligned with %d disk " + "sector size in %ld seconds. They are handled through " + "Read Modify Write but the performance is very low!\n", + un->un_rmw_incre_count, un->un_tgt_blocksize, + drv_hztousec(SD_RMW_MSG_PRINT_TIMEOUT) / 1000000); + un->un_rmw_incre_count = 0; + un->un_rmw_msg_timeid = timeout(sd_rmw_msg_print_handler, + un, SD_RMW_MSG_PRINT_TIMEOUT); + } else { + un->un_rmw_msg_timeid = NULL; + } + + mutex_exit(SD_MUTEX(un)); + + SD_TRACE(SD_LOG_IO_CORE | SD_LOG_ERROR, un, + "sd_rmw_msg_print_handler: exit\n"); +} /* * Function: sd_start_direct_priority_command @@ -19336,6 +19700,7 @@ sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, uint32_t *capacity_buf; uint64_t capacity; uint32_t lbasize; + uint32_t pbsize; int status; struct sd_lun *un; @@ -19418,7 +19783,7 @@ sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, if (capacity == 0xffffffff) { sd_ssc_assessment(ssc, SD_FMT_IGNORE); status = sd_send_scsi_READ_CAPACITY_16(ssc, &capacity, - &lbasize, path_flag); + &lbasize, &pbsize, path_flag); if (status != 0) { return (status); } @@ -19467,10 +19832,11 @@ sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, * on the logical unit. The actual logical block count will be * this value plus one. * - * Currently the capacity is saved in terms of un->un_sys_blocksize, - * so scale the capacity value to reflect this. + * Currently, for removable media, the capacity is saved in terms + * of un->un_sys_blocksize, so scale the capacity value to reflect this. */ - capacity = (capacity + 1) * (lbasize / un->un_sys_blocksize); + if (un->un_f_has_removable_media) + capacity = (capacity + 1) * (lbasize / un->un_sys_blocksize); /* * Copy the values from the READ CAPACITY command into the space @@ -19504,15 +19870,19 @@ sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, * determine the device capacity in number of blocks and the * device native block size. If this function returns a failure, * then the values in *capp and *lbap are undefined. - * This routine should always be called by - * sd_send_scsi_READ_CAPACITY which will appy any device - * specific adjustments to capacity and lbasize. + * This routine should be called by sd_send_scsi_READ_CAPACITY + * which will apply any device specific adjustments to capacity + * and lbasize. One exception is it is also called by + * sd_get_media_info_ext. In that function, there is no need to + * adjust the capacity and lbasize. * * Arguments: ssc - ssc contains ptr to soft state struct for the target * capp - ptr to unsigned 64-bit variable to receive the * capacity value from the command. * lbap - ptr to unsigned 32-bit varaible to receive the * block size value from the command + * psp - ptr to unsigned 32-bit variable to receive the + * physical block size value from the command * path_flag - SD_PATH_DIRECT to use the USCSI "direct" chain and * the normal command waitq, or SD_PATH_DIRECT_PRIORITY * to use the USCSI "direct" chain and bypass the normal @@ -19533,7 +19903,7 @@ sd_send_scsi_READ_CAPACITY(sd_ssc_t *ssc, uint64_t *capp, uint32_t *lbap, static int sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, - uint32_t *lbap, int path_flag) + uint32_t *lbap, uint32_t *psp, int path_flag) { struct scsi_extended_sense sense_buf; struct uscsi_cmd ucmd_buf; @@ -19541,6 +19911,8 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, uint64_t *capacity16_buf; uint64_t capacity; uint32_t lbasize; + uint32_t pbsize; + uint32_t lbpb_exp; int status; struct sd_lun *un; @@ -19617,9 +19989,13 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, * bytes 8-11: Block length in bytes * (MSB in byte:8 & LSB in byte:11) * + * byte 13: LOGICAL BLOCKS PER PHYSICAL BLOCK EXPONENT */ capacity = BE_64(capacity16_buf[0]); lbasize = BE_32(*(uint32_t *)&capacity16_buf[1]); + lbpb_exp = (BE_64(capacity16_buf[1]) >> 40) & 0x0f; + + pbsize = lbasize << lbpb_exp; /* * Done with capacity16_buf @@ -19666,9 +20042,11 @@ sd_send_scsi_READ_CAPACITY_16(sd_ssc_t *ssc, uint64_t *capp, *capp = capacity; *lbap = lbasize; + *psp = pbsize; SD_TRACE(SD_LOG_IO, un, "sd_send_scsi_READ_CAPACITY_16: " - "capacity:0x%llx lbasize:0x%x\n", capacity, lbasize); + "capacity:0x%llx lbasize:0x%x, pbsize: 0x%x\n", + capacity, lbasize, pbsize); return (0); } @@ -21443,6 +21821,7 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p) case DKIOCHOTPLUGGABLE: case DKIOCINFO: case DKIOCGMEDIAINFO: + case DKIOCGMEDIAINFOEXT: case MHIOCENFAILFAST: case MHIOCSTATUS: case MHIOCTKOWN: @@ -21509,6 +21888,11 @@ skip_ready_valid: err = sd_get_media_info(dev, (caddr_t)arg, flag); break; + case DKIOCGMEDIAINFOEXT: + SD_TRACE(SD_LOG_IOCTL, un, "DKIOCGMEDIAINFOEXT\n"); + err = sd_get_media_info_ext(dev, (caddr_t)arg, flag); + break; + case DKIOCGGEOM: case DKIOCGVTOC: case DKIOCGEXTVTOC: @@ -22609,6 +22993,205 @@ no_assessment: return (rval); } +/* + * Function: sd_get_media_info_ext + * + * Description: This routine is the driver entry point for handling ioctl + * requests for the media type or command set profile used by the + * drive to operate on the media (DKIOCGMEDIAINFOEXT). The + * difference this ioctl and DKIOCGMEDIAINFO is the return value + * of this ioctl contains both logical block size and physical + * block size. + * + * + * Arguments: dev - the device number + * arg - pointer to user provided dk_minfo_ext structure + * specifying the media type, logical block size, + * physical block size and disk capacity. + * flag - this argument is a pass through to ddi_copyxxx() + * directly from the mode argument of ioctl(). + * + * Return Code: 0 + * EACCESS + * EFAULT + * ENXIO + * EIO + */ + +static int +sd_get_media_info_ext(dev_t dev, caddr_t arg, int flag) +{ + struct sd_lun *un = NULL; + struct uscsi_cmd com; + struct scsi_inquiry *sinq; + struct dk_minfo_ext media_info_ext; + u_longlong_t media_capacity; + uint64_t capacity; + uint_t lbasize; + uint_t pbsize; + uchar_t *out_data; + uchar_t *rqbuf; + int rval = 0; + int rtn; + sd_ssc_t *ssc; + + if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL || + (un->un_state == SD_STATE_OFFLINE)) { + return (ENXIO); + } + + SD_TRACE(SD_LOG_IOCTL_DKIO, un, "sd_get_media_info_ext: entry\n"); + + out_data = kmem_zalloc(SD_PROFILE_HEADER_LEN, KM_SLEEP); + rqbuf = kmem_zalloc(SENSE_LENGTH, KM_SLEEP); + ssc = sd_ssc_init(un); + + /* Issue a TUR to determine if the drive is ready with media present */ + rval = sd_send_scsi_TEST_UNIT_READY(ssc, SD_CHECK_FOR_MEDIA); + if (rval == ENXIO) { + goto done; + } else if (rval != 0) { + sd_ssc_assessment(ssc, SD_FMT_IGNORE); + } + + /* Now get configuration data */ + if (ISCD(un)) { + media_info_ext.dki_media_type = DK_CDROM; + + /* Allow SCMD_GET_CONFIGURATION to MMC devices only */ + if (un->un_f_mmc_cap == TRUE) { + rtn = sd_send_scsi_GET_CONFIGURATION(ssc, &com, rqbuf, + SENSE_LENGTH, out_data, SD_PROFILE_HEADER_LEN, + SD_PATH_STANDARD); + + if (rtn) { + /* + * We ignore all failures for CD and need to + * put the assessment before processing code + * to avoid missing assessment for FMA. + */ + sd_ssc_assessment(ssc, SD_FMT_IGNORE); + /* + * Failed for other than an illegal request + * or command not supported + */ + if ((com.uscsi_status == STATUS_CHECK) && + (com.uscsi_rqstatus == STATUS_GOOD)) { + if ((rqbuf[2] != KEY_ILLEGAL_REQUEST) || + (rqbuf[12] != 0x20)) { + rval = EIO; + goto no_assessment; + } + } + } else { + /* + * The GET CONFIGURATION command succeeded + * so set the media type according to the + * returned data + */ + media_info_ext.dki_media_type = out_data[6]; + media_info_ext.dki_media_type <<= 8; + media_info_ext.dki_media_type |= out_data[7]; + } + } + } else { + /* + * The profile list is not available, so we attempt to identify + * the media type based on the inquiry data + */ + sinq = un->un_sd->sd_inq; + if ((sinq->inq_dtype == DTYPE_DIRECT) || + (sinq->inq_dtype == DTYPE_OPTICAL)) { + /* This is a direct access device or optical disk */ + media_info_ext.dki_media_type = DK_FIXED_DISK; + + if ((bcmp(sinq->inq_vid, "IOMEGA", 6) == 0) || + (bcmp(sinq->inq_vid, "iomega", 6) == 0)) { + if ((bcmp(sinq->inq_pid, "ZIP", 3) == 0)) { + media_info_ext.dki_media_type = DK_ZIP; + } else if ( + (bcmp(sinq->inq_pid, "jaz", 3) == 0)) { + media_info_ext.dki_media_type = DK_JAZ; + } + } + } else { + /* + * Not a CD, direct access or optical disk so return + * unknown media + */ + media_info_ext.dki_media_type = DK_UNKNOWN; + } + } + + /* + * Now read the capacity so we can provide the lbasize, + * pbsize and capacity. + */ + rval = sd_send_scsi_READ_CAPACITY_16(ssc, &capacity, &lbasize, &pbsize, + SD_PATH_DIRECT); + + if (rval != 0) { + rval = sd_send_scsi_READ_CAPACITY(ssc, &capacity, &lbasize, + SD_PATH_DIRECT); + + switch (rval) { + case 0: + pbsize = lbasize; + media_capacity = capacity; + /* + * sd_send_scsi_READ_CAPACITY() reports capacity in + * un->un_sys_blocksize chunks. So we need to convert + * it into cap.lbsize chunks. + */ + if (un->un_f_has_removable_media) { + media_capacity *= un->un_sys_blocksize; + media_capacity /= lbasize; + } + break; + case EACCES: + rval = EACCES; + goto done; + default: + rval = EIO; + goto done; + } + } else { + media_capacity = capacity; + } + + /* + * If lun is expanded dynamically, update the un structure. + */ + mutex_enter(SD_MUTEX(un)); + if ((un->un_f_blockcount_is_valid == TRUE) && + (un->un_f_tgt_blocksize_is_valid == TRUE) && + (capacity > un->un_blockcount)) { + sd_update_block_info(un, lbasize, capacity); + } + mutex_exit(SD_MUTEX(un)); + + media_info_ext.dki_lbsize = lbasize; + media_info_ext.dki_capacity = media_capacity; + media_info_ext.dki_pbsize = pbsize; + + if (ddi_copyout(&media_info_ext, arg, sizeof (struct dk_minfo_ext), + flag)) { + rval = EFAULT; + goto no_assessment; + } +done: + if (rval != 0) { + if (rval == EIO) + sd_ssc_assessment(ssc, SD_FMT_STATUS_CHECK); + else + sd_ssc_assessment(ssc, SD_FMT_IGNORE); + } +no_assessment: + sd_ssc_fini(ssc); + kmem_free(out_data, SD_PROFILE_HEADER_LEN); + kmem_free(rqbuf, SENSE_LENGTH); + return (rval); +} /* * Function: sd_check_media @@ -24700,17 +25283,51 @@ sddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) partition = SDPART(dev); SD_INFO(SD_LOG_DUMP, un, "sddump: partition = %d\n", partition); + if (!(NOT_DEVBSIZE(un))) { + int secmask = 0; + int blknomask = 0; + + blknomask = (un->un_tgt_blocksize / DEV_BSIZE) - 1; + secmask = un->un_tgt_blocksize - 1; + + if (blkno & blknomask) { + SD_TRACE(SD_LOG_DUMP, un, + "sddump: dump start block not modulo %d\n", + un->un_tgt_blocksize); + return (EINVAL); + } + + if ((nblk * DEV_BSIZE) & secmask) { + SD_TRACE(SD_LOG_DUMP, un, + "sddump: dump length not modulo %d\n", + un->un_tgt_blocksize); + return (EINVAL); + } + + } + /* Validate blocks to dump at against partition size. */ (void) cmlb_partinfo(un->un_cmlbhandle, partition, &nblks, &start_block, NULL, NULL, (void *)SD_PATH_DIRECT); - if ((blkno + nblk) > nblks) { - SD_TRACE(SD_LOG_DUMP, un, - "sddump: dump range larger than partition: " - "blkno = 0x%x, nblk = 0x%x, dkl_nblk = 0x%x\n", - blkno, nblk, nblks); - return (EINVAL); + if (NOT_DEVBSIZE(un)) { + if ((blkno + nblk) > nblks) { + SD_TRACE(SD_LOG_DUMP, un, + "sddump: dump range larger than partition: " + "blkno = 0x%x, nblk = 0x%x, dkl_nblk = 0x%x\n", + blkno, nblk, nblks); + return (EINVAL); + } + } else { + if (((blkno / (un->un_tgt_blocksize / DEV_BSIZE)) + + (nblk / (un->un_tgt_blocksize / DEV_BSIZE))) > nblks) { + SD_TRACE(SD_LOG_DUMP, un, + "sddump: dump range larger than partition: " + "blkno = 0x%x, nblk = 0x%x, dkl_nblk = 0x%x\n", + blkno, nblk, nblks); + return (EINVAL); + } } mutex_enter(&un->un_pm_mutex); @@ -24813,7 +25430,12 @@ sddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) * Convert the partition-relative block number to a * disk physical block number. */ - blkno += start_block; + if (NOT_DEVBSIZE(un)) { + blkno += start_block; + } else { + blkno = blkno / (un->un_tgt_blocksize / DEV_BSIZE); + blkno += start_block; + } SD_INFO(SD_LOG_DUMP, un, "sddump: disk blkno = 0x%x\n", blkno); @@ -24901,6 +25523,10 @@ sddump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) dma_resid = wr_bp->b_bcount; oblkno = blkno; + if (!(NOT_DEVBSIZE(un))) { + nblk = nblk / (un->un_tgt_blocksize / DEV_BSIZE); + } + while (dma_resid != 0) { for (i = 0; i < SD_NDUMP_RETRIES; i++) { @@ -29894,7 +30520,7 @@ sd_tg_rdwr(dev_info_t *devi, uchar_t cmd, void *bufaddr, * sys_blocksize != tgt_blocksize, need to re-adjust * blkno and save the index to beginning of dk_label */ - first_byte = SD_SYSBLOCKS2BYTES(un, start_block); + first_byte = SD_SYSBLOCKS2BYTES(start_block); real_addr = first_byte / un->un_tgt_blocksize; end_block = (first_byte + reqlength + diff --git a/usr/src/uts/common/os/dumpsubr.c b/usr/src/uts/common/os/dumpsubr.c index 201d6d1bfd..0753cc19da 100644 --- a/usr/src/uts/common/os/dumpsubr.c +++ b/usr/src/uts/common/os/dumpsubr.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -255,12 +255,12 @@ dumpinit(vnode_t *vp, char *name, int justchecking) if (VOP_OPEN(&cdev_vp, FREAD | FWRITE, kcred, NULL) == 0) { size_t blk_size; struct dk_cinfo dki; - struct extvtoc vtoc; + struct dk_minfo minf; - if (VOP_IOCTL(cdev_vp, DKIOCGEXTVTOC, (intptr_t)&vtoc, - FKIOCTL, kcred, NULL, NULL) == 0 && - vtoc.v_sectorsz != 0) - blk_size = vtoc.v_sectorsz; + if (VOP_IOCTL(cdev_vp, DKIOCGMEDIAINFO, + (intptr_t)&minf, FKIOCTL, kcred, NULL, NULL) + == 0 && minf.dki_lbsize != 0) + blk_size = minf.dki_lbsize; else blk_size = DEV_BSIZE; diff --git a/usr/src/uts/common/sys/dkio.h b/usr/src/uts/common/sys/dkio.h index 18f49e513a..caf7d7976d 100644 --- a/usr/src/uts/common/sys/dkio.h +++ b/usr/src/uts/common/sys/dkio.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -301,6 +301,11 @@ enum dkio_state { DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED, DKIO_DEV_GONE }; #define DKIOCGTEMPERATURE (DKIOC|45) /* get temperature */ /* + * ioctl to get the media info including physical block size + */ +#define DKIOCGMEDIAINFOEXT (DKIOC|48) + +/* * Used for providing the temperature. */ @@ -324,6 +329,17 @@ struct dk_minfo { }; /* + * Used for Media info or the current profile info + * including physical block size if supported. + */ +struct dk_minfo_ext { + uint_t dki_media_type; /* Media type or profile info */ + uint_t dki_lbsize; /* Logical blocksize of media */ + diskaddr_t dki_capacity; /* Capacity as # of dki_lbsize blks */ + uint_t dki_pbsize; /* Physical blocksize of media */ +}; + +/* * Media types or profiles known */ #define DK_UNKNOWN 0x00 /* Media inserted - type unknown */ diff --git a/usr/src/uts/common/sys/dklabel.h b/usr/src/uts/common/sys/dklabel.h index 01baa7157c..457c1ecadc 100644 --- a/usr/src/uts/common/sys/dklabel.h +++ b/usr/src/uts/common/sys/dklabel.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -207,7 +207,7 @@ struct dk_label { uint16_t dkl_ncyl; /* # of data cylinders */ uint16_t dkl_acyl; /* # of alternate cylinders */ uint16_t dkl_nhead; /* # of heads in this partition */ - uint16_t dkl_nsect; /* # of 512 byte sectors per track */ + uint16_t dkl_nsect; /* # of sectors per track */ uint16_t dkl_obs3; /* obsolete */ uint16_t dkl_obs4; /* obsolete */ struct dk_map32 dkl_map[NDKMAP]; /* logical partition headers */ diff --git a/usr/src/uts/common/sys/scsi/targets/sddef.h b/usr/src/uts/common/sys/scsi/targets/sddef.h index c5bbc59ef1..90129e40c3 100644 --- a/usr/src/uts/common/sys/scsi/targets/sddef.h +++ b/usr/src/uts/common/sys/scsi/targets/sddef.h @@ -438,7 +438,8 @@ struct sd_lun { /* SYNC CACHE needs to be */ /* sent in sdclose */ un_f_devid_transport_defined :1, /* devid defined by transport */ - un_f_reserved :12; + un_f_rmw_type :2, /* RMW type */ + un_f_reserved :10; /* Ptr to table of strings for ASC/ASCQ error message printing */ struct scsi_asq_key_strings *un_additional_codes; @@ -477,6 +478,8 @@ struct sd_lun { struct kmem_cache *un_wm_cache; /* fast alloc in non-512 write case */ uint_t un_rmw_count; /* count of read-modify-writes */ struct sd_w_map *un_wm; /* head of sd_w_map chain */ + uint64_t un_rmw_incre_count; /* count I/O */ + timeout_id_t un_rmw_msg_timeid; /* for RMW message control */ /* For timeout callback to issue a START STOP UNIT command */ timeout_id_t un_startstop_timeid; @@ -560,12 +563,12 @@ struct sd_lun { (blockcount * (un)->un_tgt_blocksize) /* Convert a byte count to a number of system blocks */ -#define SD_BYTES2SYSBLOCKS(un, bytecount) \ - ((bytecount + (un->un_sys_blocksize - 1))/un->un_sys_blocksize) +#define SD_BYTES2SYSBLOCKS(bytecount) \ + ((bytecount + (DEV_BSIZE - 1))/DEV_BSIZE) /* Convert a system block count to a number of bytes */ -#define SD_SYSBLOCKS2BYTES(un, blockcount) \ - (blockcount * (un)->un_sys_blocksize) +#define SD_SYSBLOCKS2BYTES(blockcount) \ + (blockcount * DEV_BSIZE) /* * Calculate the number of bytes needed to hold the requested number of bytes @@ -579,13 +582,19 @@ struct sd_lun { * to the system block location. */ #define SD_TGTBYTEOFFSET(un, sysblk, tgtblk) \ - (SD_SYSBLOCKS2BYTES(un, sysblk) - SD_TGTBLOCKS2BYTES(un, tgtblk)) + (SD_SYSBLOCKS2BYTES(sysblk) - SD_TGTBLOCKS2BYTES(un, tgtblk)) /* * Calculate the target block location from the system block location */ #define SD_SYS2TGTBLOCK(un, blockcnt) \ - ((blockcnt * un->un_sys_blocksize) / un->un_tgt_blocksize) + (blockcnt / ((un)->un_tgt_blocksize / DEV_BSIZE)) + +/* + * Calculate the target block location from the system block location + */ +#define SD_TGT2SYSBLOCK(un, blockcnt) \ + (blockcnt * ((un)->un_tgt_blocksize / DEV_BSIZE)) /* * SD_DEFAULT_MAX_XFER_SIZE is the default value to bound the max xfer @@ -768,6 +777,12 @@ _NOTE(MUTEX_PROTECTS_DATA(sd_lun::un_fi_mutex, #define SD_WTYPE_RMW 0x002 /* Write requires read-modify-write */ #define SD_WM_BUSY 0x100 /* write-map is busy */ +/* + * RMW type + */ +#define SD_RMW_TYPE_DEFAULT 0 /* do rmw with warning message */ +#define SD_RMW_TYPE_NO_WARNING 1 /* do rmw without warning message */ +#define SD_RMW_TYPE_RETURN_ERROR 2 /* rmw disabled */ /* Device error kstats */ struct sd_errstats { @@ -1678,6 +1693,11 @@ struct sd_fm_internal { #define SD_RESTART_TIMEOUT (drv_usectohz((clock_t)100000)) /* + * 10s misaligned I/O warning message interval + */ +#define SD_RMW_MSG_PRINT_TIMEOUT (drv_usectohz((clock_t)10000000)) + +/* * 100 msec. is what we'll wait for certain retries for fibre channel * targets, 0 msec for parallel SCSI. */ diff --git a/usr/src/uts/common/xen/io/xdb.c b/usr/src/uts/common/xen/io/xdb.c index 16fd5aff9d..06551ebe85 100644 --- a/usr/src/uts/common/xen/io/xdb.c +++ b/usr/src/uts/common/xen/io/xdb.c @@ -1202,6 +1202,7 @@ xdb_open_device(xdb_t *vdp) { dev_info_t *dip = vdp->xs_dip; uint64_t devsize; + int blksize; char *nodepath; ASSERT(MUTEX_HELD(&vdp->xs_cbmutex)); @@ -1252,7 +1253,17 @@ xdb_open_device(xdb_t *vdp) kmem_free(nodepath, MAXPATHLEN); return (DDI_FAILURE); } - vdp->xs_sectors = devsize / XB_BSIZE; + + blksize = ldi_prop_get_int64(vdp->xs_ldi_hdl, + DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, + "blksize", DEV_BSIZE); + if (blksize == DEV_BSIZE) + blksize = ldi_prop_get_int(vdp->xs_ldi_hdl, + LDI_DEV_T_ANY | DDI_PROP_DONTPASS | + DDI_PROP_NOTPROM, "device-blksize", DEV_BSIZE); + + vdp->xs_sec_size = blksize; + vdp->xs_sectors = devsize / blksize; /* check if the underlying device is a CD/DVD disc */ if (ldi_prop_get_int(vdp->xs_ldi_hdl, LDI_DEV_T_ANY | DDI_PROP_DONTPASS, @@ -1388,13 +1399,12 @@ trans_retry: /* If feature-barrier isn't present in xenstore, add it. */ fb_exists = xenbus_exists(xsname, XBP_FB); - /* hard-coded 512-byte sector size */ - ssize = DEV_BSIZE; + ssize = (vdp->xs_sec_size == 0) ? DEV_BSIZE : vdp->xs_sec_size; sectors = vdp->xs_sectors; if (((!fb_exists && (err = xenbus_printf(xbt, xsname, XBP_FB, "%d", 1)))) || (err = xenbus_printf(xbt, xsname, XBP_INFO, "%u", dinfo)) || - (err = xenbus_printf(xbt, xsname, "sector-size", "%u", ssize)) || + (err = xenbus_printf(xbt, xsname, XBP_SECTOR_SIZE, "%u", ssize)) || (err = xenbus_printf(xbt, xsname, XBP_SECTORS, "%"PRIu64, sectors)) || (err = xenbus_printf(xbt, xsname, "instance", "%d", instance)) || diff --git a/usr/src/uts/common/xen/io/xdb.h b/usr/src/uts/common/xen/io/xdb.h index f8046e8219..2173ca6ad9 100644 --- a/usr/src/uts/common/xen/io/xdb.h +++ b/usr/src/uts/common/xen/io/xdb.h @@ -113,6 +113,8 @@ struct xdb { uint32_t xs_type; /* # of total sectors */ uint64_t xs_sectors; + /* sector size if existed */ + uint_t xs_sec_size; /* blkif I/O request ring buffer */ xendev_ring_t *xs_ring; /* handle to access the ring buffer */ diff --git a/usr/src/uts/common/xen/io/xdf.c b/usr/src/uts/common/xen/io/xdf.c index 109421797d..ef50b2bec7 100644 --- a/usr/src/uts/common/xen/io/xdf.c +++ b/usr/src/uts/common/xen/io/xdf.c @@ -478,7 +478,6 @@ vreq_setup(xdf_t *vdp, v_req_t *vreq) if (!ALIGNED_XFER(bp)) { if (bp->b_flags & (B_PAGEIO | B_PHYS)) bp_mapin(bp); - rc = ddi_dma_mem_alloc(vreq->v_memdmahdl, roundup(bp->b_bcount, XB_BSIZE), &xc_acc_attr, DDI_DMA_STREAMING, xdf_dmacallback, (caddr_t)vdp, @@ -1638,11 +1637,13 @@ xdf_get_flush_block(xdf_t *vdp) /* * Get a DEV_BSIZE aligned bufer */ - vdp->xdf_flush_mem = kmem_alloc(DEV_BSIZE * 2, KM_SLEEP); + vdp->xdf_flush_mem = kmem_alloc(vdp->xdf_xdev_secsize * 2, KM_SLEEP); vdp->xdf_cache_flush_block = - (char *)P2ROUNDUP((uintptr_t)(vdp->xdf_flush_mem), DEV_BSIZE); + (char *)P2ROUNDUP((uintptr_t)(vdp->xdf_flush_mem), + (int)vdp->xdf_xdev_secsize); + if (xdf_lb_rdwr(vdp->xdf_dip, TG_READ, vdp->xdf_cache_flush_block, - xdf_flush_block, DEV_BSIZE, NULL) != 0) + xdf_flush_block, vdp->xdf_xdev_secsize, NULL) != 0) return (DDI_FAILURE); return (DDI_SUCCESS); } @@ -1746,7 +1747,7 @@ xdf_synthetic_pgeom(dev_info_t *dip, cmlb_geom_t *geomp) geomp->g_acyl = 0; geomp->g_nhead = XDF_NHEADS; geomp->g_nsect = XDF_NSECTS; - geomp->g_secsize = XB_BSIZE; + geomp->g_secsize = vdp->xdf_xdev_secsize; geomp->g_capacity = vdp->xdf_xdev_nblocks; geomp->g_intrlv = 0; geomp->g_rpm = 7200; @@ -1764,6 +1765,7 @@ xdf_setstate_connected(xdf_t *vdp) dev_info_t *dip = vdp->xdf_dip; cmlb_geom_t pgeom; diskaddr_t nblocks = 0; + uint_t secsize = 0; char *oename, *xsname, *str; uint_t dinfo; @@ -1793,6 +1795,7 @@ xdf_setstate_connected(xdf_t *vdp) */ if (xenbus_gather(XBT_NULL, oename, XBP_SECTORS, "%"SCNu64, &nblocks, + XBP_SECTOR_SIZE, "%u", &secsize, XBP_INFO, "%u", &dinfo, NULL) != 0) { cmn_err(CE_WARN, "xdf@%s: xdf_setstate_connected: " @@ -1808,7 +1811,10 @@ xdf_setstate_connected(xdf_t *vdp) dinfo |= VDISK_CDROM; strfree(str); + if (secsize == 0 || !(ISP2(secsize / DEV_BSIZE))) + secsize = DEV_BSIZE; vdp->xdf_xdev_nblocks = nblocks; + vdp->xdf_xdev_secsize = secsize; #ifdef _ILP32 if (vdp->xdf_xdev_nblocks > DK_MAX_BLOCKS) { cmn_err(CE_WARN, "xdf@%s: xdf_setstate_connected: " @@ -2373,6 +2379,14 @@ xdf_lb_getattribute(dev_info_t *dip, tg_attribute_t *tgattributep) int xdf_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) { + int instance; + xdf_t *vdp; + + instance = ddi_get_instance(dip); + + if ((vdp = ddi_get_soft_state(xdf_ssp, instance)) == NULL) + return (ENXIO); + switch (cmd) { case TG_GETPHYGEOM: return (xdf_lb_getpgeom(dip, (cmlb_geom_t *)arg)); @@ -2381,7 +2395,9 @@ xdf_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) case TG_GETCAPACITY: return (xdf_lb_getcap(dip, (diskaddr_t *)arg)); case TG_GETBLOCKSIZE: - *(uint32_t *)arg = XB_BSIZE; + mutex_enter(&vdp->xdf_cb_lk); + *(uint32_t *)arg = vdp->xdf_xdev_secsize; + mutex_exit(&vdp->xdf_cb_lk); return (0); case TG_GETATTR: return (xdf_lb_getattribute(dip, (tg_attribute_t *)arg)); @@ -2404,7 +2420,8 @@ xdf_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufp, /* We don't allow IO from the oe_change callback thread */ ASSERT(curthread != vdp->xdf_oe_change_thread); - if ((start + (reqlen >> DEV_BSHIFT)) > vdp->xdf_pgeom.g_capacity) + if ((start + ((reqlen / (vdp->xdf_xdev_secsize / DEV_BSIZE)) + >> DEV_BSHIFT)) > vdp->xdf_pgeom.g_capacity) return (EINVAL); bp = getrbuf(KM_SLEEP); @@ -2412,9 +2429,10 @@ xdf_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufp, bp->b_flags = B_BUSY | B_READ; else bp->b_flags = B_BUSY | B_WRITE; + bp->b_un.b_addr = bufp; bp->b_bcount = reqlen; - bp->b_blkno = start; + bp->b_blkno = start * (vdp->xdf_xdev_secsize / DEV_BSIZE); bp->b_edev = DDI_DEV_T_NONE; /* don't have dev_t */ mutex_enter(&vdp->xdf_dev_lk); @@ -2582,7 +2600,7 @@ xdf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, case DKIOCGMEDIAINFO: { struct dk_minfo media_info; - media_info.dki_lbsize = DEV_BSIZE; + media_info.dki_lbsize = vdp->xdf_xdev_secsize; media_info.dki_capacity = vdp->xdf_pgeom.g_capacity; if (XD_IS_CD(vdp)) media_info.dki_media_type = DK_CDROM; @@ -2664,7 +2682,7 @@ xdf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, !xdf_barrier_flush_disable) { rv = xdf_lb_rdwr(vdp->xdf_dip, TG_WRITE, vdp->xdf_cache_flush_block, xdf_flush_block, - DEV_BSIZE, (void *)dev); + vdp->xdf_xdev_secsize, (void *)dev); } else { return (ENOTTY); } @@ -2686,6 +2704,7 @@ xdf_strategy(struct buf *bp) xdf_t *vdp; minor_t minor; diskaddr_t p_blkct, p_blkst; + daddr_t blkno; ulong_t nblks; int part; @@ -2726,16 +2745,24 @@ xdf_strategy(struct buf *bp) mutex_enter(&vdp->xdf_dev_lk); } + /* + * Adjust the real blkno and bcount according to the underline + * physical sector size. + */ + blkno = bp->b_blkno / (vdp->xdf_xdev_secsize / XB_BSIZE); + /* check for a starting block beyond the disk or partition limit */ - if (bp->b_blkno > p_blkct) { + if (blkno > p_blkct) { DPRINTF(IO_DBG, ("xdf@%s: block %lld exceeds VBD size %"PRIu64, - vdp->xdf_addr, (longlong_t)bp->b_blkno, (uint64_t)p_blkct)); + vdp->xdf_addr, (longlong_t)blkno, (uint64_t)p_blkct)); + mutex_exit(&vdp->xdf_dev_lk); xdf_io_err(bp, EINVAL, 0); return (0); } /* Legacy: don't set error flag at this case */ - if (bp->b_blkno == p_blkct) { + if (blkno == p_blkct) { + mutex_exit(&vdp->xdf_dev_lk); bp->b_resid = bp->b_bcount; biodone(bp); return (0); @@ -2747,14 +2774,29 @@ xdf_strategy(struct buf *bp) bp->av_back = bp->av_forw = NULL; /* Adjust for partial transfer, this will result in an error later */ - nblks = bp->b_bcount >> XB_BSHIFT; - if ((bp->b_blkno + nblks) > p_blkct) { - bp->b_resid = ((bp->b_blkno + nblks) - p_blkct) << XB_BSHIFT; + if (vdp->xdf_xdev_secsize != 0 && + vdp->xdf_xdev_secsize != XB_BSIZE) { + nblks = bp->b_bcount / vdp->xdf_xdev_secsize; + } else { + nblks = bp->b_bcount >> XB_BSHIFT; + } + + if ((blkno + nblks) > p_blkct) { + if (vdp->xdf_xdev_secsize != 0 && + vdp->xdf_xdev_secsize != XB_BSIZE) { + bp->b_resid = + ((blkno + nblks) - p_blkct) * + vdp->xdf_xdev_secsize; + } else { + bp->b_resid = + ((blkno + nblks) - p_blkct) << + XB_BSHIFT; + } bp->b_bcount -= bp->b_resid; } DPRINTF(IO_DBG, ("xdf@%s: strategy blk %lld len %lu\n", - vdp->xdf_addr, (longlong_t)bp->b_blkno, (ulong_t)bp->b_bcount)); + vdp->xdf_addr, (longlong_t)blkno, (ulong_t)bp->b_bcount)); /* Fix up the buf struct */ bp->b_flags |= B_BUSY; @@ -2792,6 +2834,9 @@ xdf_read(dev_t dev, struct uio *uiop, cred_t *credp) NULL, NULL, NULL, NULL)) return (ENXIO); + if (uiop->uio_loffset >= XB_DTOB(p_blkcnt, vdp)) + return (ENOSPC); + if (U_INVAL(uiop)) return (EINVAL); @@ -2822,7 +2867,7 @@ xdf_write(dev_t dev, struct uio *uiop, cred_t *credp) NULL, NULL, NULL, NULL)) return (ENXIO); - if (uiop->uio_loffset >= XB_DTOB(p_blkcnt)) + if (uiop->uio_loffset >= XB_DTOB(p_blkcnt, vdp)) return (ENOSPC); if (U_INVAL(uiop)) @@ -2853,7 +2898,7 @@ xdf_aread(dev_t dev, struct aio_req *aiop, cred_t *credp) NULL, NULL, NULL, NULL)) return (ENXIO); - if (uiop->uio_loffset >= XB_DTOB(p_blkcnt)) + if (uiop->uio_loffset >= XB_DTOB(p_blkcnt, vdp)) return (ENOSPC); if (U_INVAL(uiop)) @@ -2884,7 +2929,7 @@ xdf_awrite(dev_t dev, struct aio_req *aiop, cred_t *credp) NULL, NULL, NULL, NULL)) return (ENXIO); - if (uiop->uio_loffset >= XB_DTOB(p_blkcnt)) + if (uiop->uio_loffset >= XB_DTOB(p_blkcnt, vdp)) return (ENOSPC); if (U_INVAL(uiop)) @@ -2921,9 +2966,11 @@ xdf_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) NULL, NULL, NULL)) return (ENXIO); - if ((blkno + nblk) > p_blkcnt) { + if ((blkno + nblk) > + (p_blkcnt * (vdp->xdf_xdev_secsize / XB_BSIZE))) { cmn_err(CE_WARN, "xdf@%s: block %ld exceeds VBD size %"PRIu64, - vdp->xdf_addr, blkno + nblk, (uint64_t)p_blkcnt); + vdp->xdf_addr, (daddr_t)((blkno + nblk) / + (vdp->xdf_xdev_secsize / XB_BSIZE)), (uint64_t)p_blkcnt); return (EINVAL); } @@ -3451,7 +3498,7 @@ xdf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) mutex_destroy(&vdp->xdf_cb_lk); mutex_destroy(&vdp->xdf_dev_lk); if (vdp->xdf_cache_flush_block != NULL) - kmem_free(vdp->xdf_flush_mem, 2 * DEV_BSIZE); + kmem_free(vdp->xdf_flush_mem, 2 * vdp->xdf_xdev_secsize); ddi_soft_state_free(xdf_ssp, instance); return (DDI_SUCCESS); } diff --git a/usr/src/uts/common/xen/io/xdf.h b/usr/src/uts/common/xen/io/xdf.h index a3319f70a3..f2a2a82dd5 100644 --- a/usr/src/uts/common/xen/io/xdf.h +++ b/usr/src/uts/common/xen/io/xdf.h @@ -48,7 +48,7 @@ extern "C" { #define XB_BSIZE DEV_BSIZE #define XB_BMASK (XB_BSIZE - 1) #define XB_BSHIFT 9 -#define XB_DTOB(bn) ((bn) << XB_BSHIFT) +#define XB_DTOB(bn, vdp) ((bn) * (vdp)->xdf_xdev_secsize) #define XB_MAX_SEGLEN (8 * XB_BSIZE) #define XB_SEGOFFSET (XB_MAX_SEGLEN - 1) @@ -222,6 +222,7 @@ typedef struct xdf { kcondvar_t xdf_dev_cv; /* cv used in I/O path */ uint_t xdf_dinfo; /* disk info from backend xenstore */ diskaddr_t xdf_xdev_nblocks; /* total size in block */ + uint_t xdf_xdev_secsize; /* disk blksize from backend */ cmlb_geom_t xdf_pgeom; boolean_t xdf_pgeom_set; boolean_t xdf_pgeom_fixed; diff --git a/usr/src/uts/common/xen/sys/xendev.h b/usr/src/uts/common/xen/sys/xendev.h index 8e5921dc3f..dad4ad222f 100644 --- a/usr/src/uts/common/xen/sys/xendev.h +++ b/usr/src/uts/common/xen/sys/xendev.h @@ -52,6 +52,7 @@ extern "C" { /* * Xenbus property interfaces, initialized by backend disk driver */ +#define XBP_SECTOR_SIZE "sector-size" /* backend prop: uint */ #define XBP_SECTORS "sectors" /* backend prop: uint64 */ #define XBP_INFO "info" /* backend prop: uint */ #define XBP_FB "feature-barrier" /* backend prop: boolean int */ |
