diff options
Diffstat (limited to 'usr/src/uts/sun4v/io/vds.c')
-rw-r--r-- | usr/src/uts/sun4v/io/vds.c | 338 |
1 files changed, 209 insertions, 129 deletions
diff --git a/usr/src/uts/sun4v/io/vds.c b/usr/src/uts/sun4v/io/vds.c index 548fc0f048..45f4122465 100644 --- a/usr/src/uts/sun4v/io/vds.c +++ b/usr/src/uts/sun4v/io/vds.c @@ -119,6 +119,10 @@ #define VD_EFI_LBA_GPT 1 /* LBA of the GPT */ #define VD_EFI_LBA_GPE 2 /* LBA of the GPE */ +#define VD_EFI_DEV_SET(dev, vdsk, ioctl) \ + VDSK_EFI_DEV_SET(dev, vdsk, ioctl, \ + (vdsk)->vdisk_bsize, (vdsk)->vdisk_size) + /* * Flags defining the behavior for flushing asynchronous writes used to * performed some write I/O requests. @@ -451,13 +455,14 @@ typedef struct vd { int open_flags; /* open flags */ uint_t nslices; /* number of slices we export */ size_t vdisk_size; /* number of blocks in vdisk */ - size_t vdisk_block_size; /* size of each vdisk block */ + size_t vdisk_bsize; /* blk size of the vdisk */ vd_disk_type_t vdisk_type; /* slice or entire disk */ vd_disk_label_t vdisk_label; /* EFI or VTOC label */ vd_media_t vdisk_media; /* media type of backing dev. */ boolean_t is_atapi_dev; /* Is this an IDE CD-ROM dev? */ ushort_t max_xfer_sz; /* max xfer size in DEV_BSIZE */ - size_t block_size; /* blk size of actual device */ + size_t backend_bsize; /* blk size of backend device */ + int vio_bshift; /* shift for blk convertion */ boolean_t volume; /* is vDisk backed by volume */ boolean_t zvol; /* is vDisk backed by a zvol */ boolean_t file; /* is vDisk backed by a file? */ @@ -506,21 +511,20 @@ typedef struct vd { * followed by a GPT (efi_gpt_t) and a GPE (efi_gpe_t). * */ -#define VD_LABEL_VTOC_SIZE \ - P2ROUNDUP(sizeof (struct dk_label), DEV_BSIZE) +#define VD_LABEL_VTOC_SIZE(lba) \ + P2ROUNDUP(sizeof (struct dk_label), (lba)) -#define VD_LABEL_EFI_SIZE \ - P2ROUNDUP(DEV_BSIZE + sizeof (efi_gpt_t) + \ - sizeof (efi_gpe_t) * VD_MAXPART, DEV_BSIZE) +#define VD_LABEL_EFI_SIZE(lba) \ + P2ROUNDUP(2 * (lba) + sizeof (efi_gpe_t) * VD_MAXPART, \ + (lba)) #define VD_LABEL_VTOC(vd) \ ((struct dk_label *)(void *)((vd)->flabel)) -#define VD_LABEL_EFI_GPT(vd) \ - ((efi_gpt_t *)(void *)((vd)->flabel + DEV_BSIZE)) -#define VD_LABEL_EFI_GPE(vd) \ - ((efi_gpe_t *)(void *)((vd)->flabel + DEV_BSIZE + \ - sizeof (efi_gpt_t))) +#define VD_LABEL_EFI_GPT(vd, lba) \ + ((efi_gpt_t *)(void *)((vd)->flabel + (lba))) +#define VD_LABEL_EFI_GPE(vd, lba) \ + ((efi_gpe_t *)(void *)((vd)->flabel + 2 * (lba))) typedef struct vds_operation { @@ -757,6 +761,7 @@ vd_dskimg_io_params(vd_t *vd, int slice, size_t *blkp, size_t *lenp) ASSERT(vd->file || VD_DSKIMG(vd)); ASSERT(len > 0); + ASSERT(vd->vdisk_bsize == DEV_BSIZE); /* * If a file is exported as a slice then we don't care about the vtoc. @@ -797,7 +802,6 @@ vd_dskimg_io_params(vd_t *vd, int slice, size_t *blkp, size_t *lenp) ASSERT(vd->vtoc.v_sectorsz == DEV_BSIZE); } else { ASSERT(vd->vdisk_label == VD_DISK_LABEL_EFI); - ASSERT(vd->vdisk_block_size == DEV_BSIZE); } if (blk >= vd->slices[slice].nblocks) { @@ -875,6 +879,7 @@ vd_dskimg_rw(vd_t *vd, int slice, int operation, caddr_t data, size_t offset, ASSERT(vd->file || VD_DSKIMG(vd)); ASSERT(len > 0); + ASSERT(vd->vdisk_bsize == DEV_BSIZE); if ((status = vd_dskimg_io_params(vd, slice, &offset, &len)) != 0) return ((status == ENODATA)? 0: -1); @@ -941,13 +946,14 @@ vd_dskimg_rw(vd_t *vd, int slice, int operation, caddr_t data, size_t offset, * * Parameters: * disk_size - the disk size in bytes + * bsize - the disk block size in bytes * label - the returned default label. * * Return Code: * none. */ static void -vd_build_default_label(size_t disk_size, struct dk_label *label) +vd_build_default_label(size_t disk_size, size_t bsize, struct dk_label *label) { size_t size; char unit; @@ -1005,7 +1011,7 @@ vd_build_default_label(size_t disk_size, struct dk_label *label) } label->dkl_pcyl = disk_size / - (label->dkl_nsect * label->dkl_nhead * DEV_BSIZE); + (label->dkl_nsect * label->dkl_nhead * bsize); if (label->dkl_pcyl == 0) label->dkl_pcyl = 1; @@ -1027,7 +1033,7 @@ vd_build_default_label(size_t disk_size, struct dk_label *label) label->dkl_nhead, label->dkl_nsect); PR0("provided disk size: %ld bytes\n", (uint64_t) (label->dkl_pcyl * label->dkl_nhead * - label->dkl_nsect * DEV_BSIZE)); + label->dkl_nsect * bsize)); vd_get_readable_size(disk_size, &size, &unit); @@ -1230,6 +1236,8 @@ vd_dskimg_read_devid(vd_t *vd, ddi_devid_t *devid) uint_t chksum; int status, sz; + ASSERT(vd->vdisk_bsize == DEV_BSIZE); + if ((status = vd_dskimg_get_devid_block(vd, &blk)) != 0) return (status); @@ -1304,6 +1312,8 @@ vd_dskimg_write_devid(vd_t *vd, ddi_devid_t devid) size_t blk; int status; + ASSERT(vd->vdisk_bsize == DEV_BSIZE); + if (devid == NULL) { /* nothing to write */ return (0); @@ -1371,12 +1381,12 @@ vd_do_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t blk, size_t len) ASSERT(!vd->file); ASSERT(!vd->volume); - ASSERT(vd->vdisk_block_size > 0); + ASSERT(vd->vdisk_bsize > 0); max_sectors = vd->max_xfer_sz; - nblk = (len / vd->vdisk_block_size); + nblk = (len / vd->vdisk_bsize); - if (len % vd->vdisk_block_size != 0) + if (len % vd->vdisk_bsize != 0) return (EINVAL); /* @@ -1414,7 +1424,7 @@ vd_do_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t blk, size_t len) } ucmd.uscsi_cdb = (caddr_t)&cdb; ucmd.uscsi_bufaddr = data; - ucmd.uscsi_buflen = nsectors * vd->block_size; + ucmd.uscsi_buflen = nsectors * vd->backend_bsize; ucmd.uscsi_timeout = vd_scsi_rdwr_timeout; /* * Set flags so that the command is isolated from normal @@ -1459,7 +1469,7 @@ vd_do_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t blk, size_t len) blk += nsectors; nblk -= nsectors; - data += nsectors * vd->vdisk_block_size; /* SECSIZE */ + data += nsectors * vd->vdisk_bsize; } return (status); @@ -1498,7 +1508,7 @@ vd_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t vblk, size_t vlen) size_t plen; /* length of data to be read from physical device */ char *buf; /* buffer area to fit physical device's block size */ - if (vd->block_size == 0) { + if (vd->backend_bsize == 0) { /* * The block size was not available during the attach, * try to update it now. @@ -1514,10 +1524,10 @@ vd_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t vblk, size_t vlen) * and adjust the block to be read from and the amount of data to * read to correspond with the device's block size. */ - if (vd->vdisk_block_size == vd->block_size) + if (vd->vdisk_bsize == vd->backend_bsize) return (vd_do_scsi_rdwr(vd, operation, data, vblk, vlen)); - if (vd->vdisk_block_size > vd->block_size) + if (vd->vdisk_bsize > vd->backend_bsize) return (EINVAL); /* @@ -1540,23 +1550,23 @@ vd_scsi_rdwr(vd_t *vd, int operation, caddr_t data, size_t vblk, size_t vlen) * v v * --+--+--+--+--+--+--+--+--+--+--+--+--+--+--+- virtual disk: * | | | |XX|XX|XX|XX|XX|XX| | | | | | } block size is - * --+--+--+--+--+--+--+--+--+--+--+--+--+--+--+- vd->vdisk_block_size + * --+--+--+--+--+--+--+--+--+--+--+--+--+--+--+- vd->vdisk_bsize * : : : : * >:==:< delta : : * : : : : * --+-----+-----+-----+-----+-----+-----+-----+-- physical disk: * | |YY:YY|YYYYY|YYYYY|YY:YY| | | } block size is - * --+-----+-----+-----+-----+-----+-----+-----+-- vd->block_size + * --+-----+-----+-----+-----+-----+-----+-----+-- vd->backend_bsize * ^ ^ * |<--------------------->| * | plen * pblk */ /* END CSTYLED */ - pblk = (vblk * vd->vdisk_block_size) / vd->block_size; - delta = (vblk * vd->vdisk_block_size) - (pblk * vd->block_size); - pnblk = ((delta + vlen - 1) / vd->block_size) + 1; - plen = pnblk * vd->block_size; + pblk = (vblk * vd->vdisk_bsize) / vd->backend_bsize; + delta = (vblk * vd->vdisk_bsize) - (pblk * vd->backend_bsize); + pnblk = ((delta + vlen - 1) / vd->backend_bsize) + 1; + plen = pnblk * vd->backend_bsize; PR2("vblk %lx:pblk %lx: vlen %ld:plen %ld", vblk, pblk, vlen, plen); @@ -1591,7 +1601,7 @@ static ssize_t vd_slice_flabel_read(vd_t *vd, caddr_t data, size_t offset, size_t length) { size_t n = 0; - uint_t limit = vd->flabel_limit * DEV_BSIZE; + uint_t limit = vd->flabel_limit * vd->vdisk_bsize; ASSERT(vd->vdisk_type == VD_DISK_TYPE_SLICE); ASSERT(vd->flabel != NULL); @@ -1646,7 +1656,7 @@ vd_slice_flabel_read(vd_t *vd, caddr_t data, size_t offset, size_t length) static ssize_t vd_slice_flabel_write(vd_t *vd, caddr_t data, size_t offset, size_t length) { - uint_t limit = vd->flabel_limit * DEV_BSIZE; + uint_t limit = vd->flabel_limit * vd->vdisk_bsize; struct dk_label *label; struct dk_geom geom; struct extvtoc vtoc; @@ -1663,7 +1673,7 @@ vd_slice_flabel_write(vd_t *vd, caddr_t data, size_t offset, size_t length) * write was successful, but note that nothing is actually overwritten. */ if (vd->vdisk_label == VD_DISK_LABEL_VTOC && - offset == 0 && length == DEV_BSIZE) { + offset == 0 && length == vd->vdisk_bsize) { label = (void *)data; /* check that this is a valid label */ @@ -1721,7 +1731,7 @@ vd_slice_flabel_write(vd_t *vd, caddr_t data, size_t offset, size_t length) * Return the starting block relative to the vdisk * backend for the remaining operation. * lengthp - pointer to the number of bytes to read or write. - * This should be a multiple of DEV_BSIZE. Return the + * This should be a multiple of vdisk_bsize. Return the * remaining number of bytes to read or write. * * Return Code: @@ -1739,6 +1749,7 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, size_t ablk, asize, aoff, alen; ssize_t n; int sec, status; + size_t bsize = vd->vdisk_bsize; ASSERT(vd->vdisk_type == VD_DISK_TYPE_SLICE); ASSERT(slice != 0); @@ -1759,23 +1770,23 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, return (EIO); } - if (length % DEV_BSIZE != 0) + if (length % bsize != 0) return (EINVAL); /* handle any I/O with the fake label */ if (operation == VD_OP_BWRITE) - n = vd_slice_flabel_write(vd, data, blk * DEV_BSIZE, length); + n = vd_slice_flabel_write(vd, data, blk * bsize, length); else - n = vd_slice_flabel_read(vd, data, blk * DEV_BSIZE, length); + n = vd_slice_flabel_read(vd, data, blk * bsize, length); if (n == -1) return (EINVAL); - ASSERT(n % DEV_BSIZE == 0); + ASSERT(n % bsize == 0); /* adjust I/O arguments */ data += n; - blk += n / DEV_BSIZE; + blk += n / bsize; length -= n; /* check if there's something else to process */ @@ -1791,7 +1802,7 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, } if (vd->vdisk_label == VD_DISK_LABEL_EFI) { - asize = EFI_MIN_RESV_SIZE + 33; + asize = EFI_MIN_RESV_SIZE + (EFI_MIN_ARRAY_SIZE / bsize) + 1; ablk = vd->vdisk_size - asize; } else { ASSERT(vd->vdisk_label == VD_DISK_LABEL_VTOC); @@ -1802,7 +1813,7 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, asize = vd->dk_geom.dkg_acyl * csize; } - alen = length / DEV_BSIZE; + alen = length / bsize; aoff = blk; /* if we have reached the last block then the I/O is completed */ @@ -1834,10 +1845,10 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, alen = ablk + asize - aoff; } - alen *= DEV_BSIZE; + alen *= bsize; if (operation == VD_OP_BREAD) { - bzero(data + (aoff - blk) * DEV_BSIZE, alen); + bzero(data + (aoff - blk) * bsize, alen); if (vd->vdisk_label == VD_DISK_LABEL_VTOC) { /* check if we read backup labels */ @@ -1848,9 +1859,9 @@ vd_slice_fake_rdwr(vd_t *vd, int slice, int operation, caddr_t *datap, for (sec = 1; (sec < 5 * 2 + 1); sec += 2) { if (ablk + sec >= blk && - ablk + sec < blk + (length / DEV_BSIZE)) { + ablk + sec < blk + (length / bsize)) { bcopy(label, data + - (ablk + sec - blk) * DEV_BSIZE, + (ablk + sec - blk) * bsize, sizeof (struct dk_label)); } } @@ -1899,6 +1910,8 @@ vd_bio_task(void *arg) ssize_t resid; int status; + ASSERT(vd->vdisk_bsize == DEV_BSIZE); + if (vd->zvol) { status = ldi_strategy(vd->ldi_handle[0], buf); @@ -2162,6 +2175,9 @@ vd_start_bio(vd_task_t *task) buf->b_flags |= B_WRITE; } + /* convert VIO block number to buf block number */ + buf->b_lblkno = offset << vd->vio_bshift; + request->status = ldi_strategy(vd->ldi_handle[slice], buf); } @@ -3101,7 +3117,8 @@ vd_do_slice_ioctl(vd_t *vd, int cmd, void *ioctl_arg) switch (cmd) { case DKIOCGETEFI: len = vd_slice_flabel_read(vd, - (caddr_t)dk_ioc->dki_data, lba * DEV_BSIZE, len); + (caddr_t)dk_ioc->dki_data, + lba * vd->vdisk_bsize, len); ASSERT(len > 0); @@ -3237,7 +3254,8 @@ vd_dskimg_validate_geometry(vd_t *vd) } vd->vdisk_label = VD_DISK_LABEL_UNK; - vd_build_default_label(vd->dskimg_size, &label); + vd_build_default_label(vd->dskimg_size, vd->vdisk_bsize, + &label); status = EINVAL; } else { vd->vdisk_label = VD_DISK_LABEL_VTOC; @@ -3835,7 +3853,7 @@ vd_get_capacity(vd_task_t *task) request->status = 0; - vd_cap.vdisk_block_size = vd->vdisk_block_size; + vd_cap.vdisk_block_size = vd->vdisk_bsize; vd_cap.vdisk_size = vd->vdisk_size; if ((rv = ldc_mem_copy(vd->ldc_handle, (char *)&vd_cap, 0, &nbytes, @@ -4480,7 +4498,7 @@ vd_process_attr_msg(vd_t *vd, vio_msg_t *msg, size_t msglen) * Must first get the maximum transfer size in bytes. */ size_t max_xfer_bytes = attr_msg->vdisk_block_size ? - attr_msg->vdisk_block_size*attr_msg->max_xfer_sz : + attr_msg->vdisk_block_size * attr_msg->max_xfer_sz : attr_msg->max_xfer_sz; size_t max_inband_msglen = sizeof (vd_dring_inband_msg_t) + @@ -4506,7 +4524,7 @@ vd_process_attr_msg(vd_t *vd, vio_msg_t *msg, size_t msglen) } /* Return the device's block size and max transfer size to the client */ - attr_msg->vdisk_block_size = vd->vdisk_block_size; + attr_msg->vdisk_block_size = vd->vdisk_bsize; attr_msg->max_xfer_sz = vd->max_xfer_sz; attr_msg->vdisk_size = vd->vdisk_size; @@ -5442,7 +5460,7 @@ vd_dskimg_is_iso_image(vd_t *vd) * Standard Identifier and is set to CD001 for a CD-ROM compliant * to the ISO 9660 standard. */ - sec = (ISO_VOLDESC_SEC * ISO_SECTOR_SIZE) / vd->vdisk_block_size; + sec = (ISO_VOLDESC_SEC * ISO_SECTOR_SIZE) / vd->vdisk_bsize; rv = vd_dskimg_rw(vd, VD_SLICE_NONE, VD_OP_BREAD, (caddr_t)iso_buf, sec, ISO_SECTOR_SIZE); @@ -5507,16 +5525,13 @@ vd_setup_full_disk(vd_t *vd) ASSERT(vd->vdisk_type == VD_DISK_TYPE_DISK); - vd->vdisk_block_size = DEV_BSIZE; - /* set the disk size, block size and the media type of the disk */ status = vd_backend_check_size(vd); if (status != 0) { if (!vd->scsi) { /* unexpected failure */ - PRN("ldi_ioctl(DKIOCGMEDIAINFO) returned errno %d", - status); + PRN("Failed to check backend size (errno %d)", status); return (status); } @@ -5526,7 +5541,8 @@ vd_setup_full_disk(vd_t *vd) * size of the disk and the block size. */ vd->vdisk_size = VD_SIZE_UNKNOWN; - vd->block_size = 0; + vd->vdisk_bsize = 0; + vd->backend_bsize = 0; vd->vdisk_media = VD_MEDIA_FIXED; } @@ -5697,7 +5713,7 @@ vd_setup_partition_vtoc(vd_t *vd) vd->vtoc.v_part[VD_ENTIRE_DISK_SLICE].p_size = vd->dk_geom.dkg_ncyl * csize; - vd_get_readable_size(vd->vdisk_size * vd->vdisk_block_size, + vd_get_readable_size(vd->vdisk_size * vd->vdisk_bsize, &size, &unit); /* @@ -5723,7 +5739,7 @@ vd_setup_partition_vtoc(vd_t *vd) /* create a fake label from the vtoc and geometry */ vd->flabel_limit = (uint_t)csize; - vd->flabel_size = VD_LABEL_VTOC_SIZE; + vd->flabel_size = VD_LABEL_VTOC_SIZE(vd->vdisk_bsize); vd->flabel = kmem_zalloc(vd->flabel_size, KM_SLEEP); vd_vtocgeom_to_label(&vd->vtoc, &vd->dk_geom, VD_LABEL_VTOC(vd)); @@ -5741,7 +5757,7 @@ vd_setup_partition_vtoc(vd_t *vd) * as a slice without the addition of any metadata. * * So when exporting the disk as an EFI disk, we fake a disk with the following - * layout: + * layout: (assuming the block size is 512 bytes) * * flabel +--- flabel_limit * <------> v @@ -5776,9 +5792,8 @@ vd_setup_partition_vtoc(vd_t *vd) * - blocks 34+N+1 to P define a fake reserved partition and backup label, it * returns 0 * - * Note: if the backend size is not a multiple of the vdisk block size - * (DEV_BSIZE = 512 byte) then the very end of the backend will not map to - * any block of the virtual disk. + * Note: if the backend size is not a multiple of the vdisk block size then + * the very end of the backend will not map to any block of the virtual disk. */ static int vd_setup_partition_efi(vd_t *vd) @@ -5788,23 +5803,35 @@ vd_setup_partition_efi(vd_t *vd) struct uuid uuid = EFI_USR; struct uuid efi_reserved = EFI_RESERVED; uint32_t crc; - uint64_t s0_start, s0_end; + uint64_t s0_start, s0_end, first_u_lba; + size_t bsize; - vd->flabel_limit = 34; - vd->flabel_size = VD_LABEL_EFI_SIZE; + ASSERT(vd->vdisk_bsize > 0); + + bsize = vd->vdisk_bsize; + /* + * The minimum size for the label is 16K (EFI_MIN_ARRAY_SIZE) + * for GPEs plus one block for the GPT and one for PMBR. + */ + first_u_lba = (EFI_MIN_ARRAY_SIZE / bsize) + 2; + vd->flabel_limit = (uint_t)first_u_lba; + vd->flabel_size = VD_LABEL_EFI_SIZE(bsize); vd->flabel = kmem_zalloc(vd->flabel_size, KM_SLEEP); - gpt = VD_LABEL_EFI_GPT(vd); - gpe = VD_LABEL_EFI_GPE(vd); + gpt = VD_LABEL_EFI_GPT(vd, bsize); + gpe = VD_LABEL_EFI_GPE(vd, bsize); - /* adjust the vdisk_size, we emulate the first 34 blocks */ - vd->vdisk_size += 34; - s0_start = 34; + /* + * Adjust the vdisk_size, we emulate the first few blocks + * for the disk label. + */ + vd->vdisk_size += first_u_lba; + s0_start = first_u_lba; s0_end = vd->vdisk_size - 1; gpt->efi_gpt_Signature = LE_64(EFI_SIGNATURE); gpt->efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT); gpt->efi_gpt_HeaderSize = LE_32(sizeof (efi_gpt_t)); - gpt->efi_gpt_FirstUsableLBA = LE_64(34ULL); + gpt->efi_gpt_FirstUsableLBA = LE_64(first_u_lba); gpt->efi_gpt_PartitionEntryLBA = LE_64(2ULL); gpt->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (efi_gpe_t)); @@ -5834,7 +5861,8 @@ vd_setup_partition_efi(vd_t *vd) gpt->efi_gpt_LastUsableLBA = LE_64(vd->vdisk_size - 1); /* adjust the vdisk size for the backup GPT and GPE */ - vd->vdisk_size += 33; + vd->vdisk_size += (EFI_MIN_ARRAY_SIZE / bsize) + 1; + gpt->efi_gpt_AlternateLBA = LE_64(vd->vdisk_size - 1); CRC32(crc, gpe, sizeof (efi_gpe_t) * VD_MAXPART, -1U, crc32_table); gpt->efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); @@ -5854,7 +5882,6 @@ static int vd_setup_backend_vnode(vd_t *vd) { int rval, status; - vattr_t vattr; dev_t dev; char *file_path = vd->device_path; ldi_handle_t lhandle; @@ -5874,20 +5901,6 @@ vd_setup_backend_vnode(vd_t *vd) */ vd->file = B_TRUE; - vattr.va_mask = AT_SIZE; - if ((status = VOP_GETATTR(vd->file_vnode, &vattr, 0, kcred, NULL)) - != 0) { - PRN("VOP_GETATTR(%s) = errno %d", file_path, status); - return (EIO); - } - - vd->dskimg_size = vattr.va_size; - - if (vd->file_vnode->v_flag & VNOMAP) { - PRN("File %s cannot be mapped", file_path); - return (EIO); - } - vd->max_xfer_sz = maxphys / DEV_BSIZE; /* default transfer size */ /* @@ -5938,10 +5951,6 @@ vd_setup_slice_image(vd_t *vd) struct dk_label label; int status; - /* sector size = block size = DEV_BSIZE */ - vd->block_size = DEV_BSIZE; - vd->vdisk_block_size = DEV_BSIZE; - vd->vdisk_size = vd->dskimg_size / DEV_BSIZE; vd->vdisk_media = VD_MEDIA_FIXED; vd->vdisk_label = (vd_slice_label == VD_DISK_LABEL_UNK)? vd_file_slice_label : vd_slice_label; @@ -5956,7 +5965,8 @@ vd_setup_slice_image(vd_t *vd) * adjust the vtoc so that it defines a single-slice * disk. */ - vd_build_default_label(vd->dskimg_size, &label); + vd_build_default_label(vd->dskimg_size, vd->vdisk_bsize, + &label); vd_label_to_vtocgeom(&label, &vd->vtoc, &vd->dk_geom); status = vd_setup_partition_vtoc(vd); } @@ -5970,6 +5980,12 @@ vd_setup_disk_image(vd_t *vd) int status; char *backend_path = vd->device_path; + if ((status = vd_backend_check_size(vd)) != 0) { + PRN("Fail to check size of %s (errno %d)", + backend_path, status); + return (EIO); + } + /* size should be at least sizeof(dk_label) */ if (vd->dskimg_size < sizeof (struct dk_label)) { PRN("Size of file has to be at least %ld bytes", @@ -5977,11 +5993,6 @@ vd_setup_disk_image(vd_t *vd) return (EIO); } - /* sector size = block size = DEV_BSIZE */ - vd->block_size = DEV_BSIZE; - vd->vdisk_block_size = DEV_BSIZE; - vd->vdisk_size = vd->dskimg_size / DEV_BSIZE; - /* * Find and validate the geometry of a disk image. */ @@ -5997,7 +6008,7 @@ vd_setup_disk_image(vd_t *vd) * of the ISO image (images for both drive types are stored * in the ISO-9600 format). CDs can store up to just under 1Gb */ - if ((vd->vdisk_size * vd->vdisk_block_size) > ONE_GIGABYTE) + if ((vd->vdisk_size * vd->vdisk_bsize) > ONE_GIGABYTE) vd->vdisk_media = VD_MEDIA_DVD; else vd->vdisk_media = VD_MEDIA_CD; @@ -6179,14 +6190,6 @@ vd_setup_backend_ldi(vd_t *vd) if (vd->vdisk_type == VD_DISK_TYPE_DISK) { if (vd->volume) { - /* get size of backing device */ - if (ldi_get_size(vd->ldi_handle[0], &vd->dskimg_size) != - DDI_SUCCESS) { - PRN("ldi_get_size() failed for %s", - device_path); - return (EIO); - } - /* setup disk image */ return (vd_setup_disk_image(vd)); } @@ -6220,14 +6223,6 @@ vd_setup_single_slice_disk(vd_t *vd) char *device_path = vd->device_path; struct vtoc vtoc; - /* Get size of backing device */ - if (ldi_get_size(vd->ldi_handle[0], &vd->vdisk_size) != DDI_SUCCESS) { - PRN("ldi_get_size() failed for %s", device_path); - return (EIO); - } - vd->vdisk_size = lbtodb(vd->vdisk_size); /* convert to blocks */ - vd->block_size = DEV_BSIZE; - vd->vdisk_block_size = DEV_BSIZE; vd->vdisk_media = VD_MEDIA_FIXED; if (vd->volume) { @@ -6241,6 +6236,12 @@ vd_setup_single_slice_disk(vd_t *vd) vd->vdisk_type = VD_DISK_TYPE_SLICE; vd->nslices = 1; + /* Get size of backing device */ + if ((status = vd_backend_check_size(vd)) != 0) { + PRN("Fail to check size of %s (errno %d)", device_path, status); + return (EIO); + } + /* * When exporting a slice or a device as a single slice disk, we don't * care about any partitioning exposed by the backend. The goal is just @@ -6251,7 +6252,7 @@ vd_setup_single_slice_disk(vd_t *vd) * variable. */ if (vd_slice_label == VD_DISK_LABEL_EFI || - vd->vdisk_size >= ONE_TERABYTE / DEV_BSIZE) { + vd->vdisk_size >= ONE_TERABYTE / vd->vdisk_bsize) { vd->vdisk_label = VD_DISK_LABEL_EFI; } else { status = ldi_ioctl(vd->ldi_handle[0], DKIOCGEXTVTOC, @@ -6281,8 +6282,8 @@ vd_setup_single_slice_disk(vd_t *vd) } else if (vd_slice_label == VD_DISK_LABEL_VTOC) { vd->vdisk_label = VD_DISK_LABEL_VTOC; - vd_build_default_label(vd->vdisk_size * DEV_BSIZE, - &label); + vd_build_default_label(vd->vdisk_size * vd->vdisk_bsize, + vd->vdisk_bsize, &label); vd_label_to_vtocgeom(&label, &vd->vtoc, &vd->dk_geom); } else { @@ -6302,13 +6303,50 @@ vd_setup_single_slice_disk(vd_t *vd) return (status); } +/* + * This function is invoked when setting up the vdisk backend and to process + * the VD_OP_GET_CAPACITY operation. It checks the backend size and set the + * following attributes of the vd structure: + * + * - vdisk_bsize: block size for the virtual disk used by the VIO protocol. Its + * value is 512 bytes (DEV_BSIZE) when the backend is a file, a volume or a + * CD/DVD. When the backend is a disk or a disk slice then it has the value + * of the logical block size of that disk (as returned by the DKIOCGMEDIAINFO + * ioctl). This block size is expected to be a power of 2 and a multiple of + * 512. + * + * - vdisk_size: size of the virtual disk expressed as a number of vdisk_bsize + * blocks. + * + * vdisk_size and vdisk_bsize are sent to the vdisk client during the connection + * handshake and in the result of a VD_OP_GET_CAPACITY operation. + * + * - backend_bsize: block size of the backend device. backend_bsize has the same + * value as vdisk_bsize except when the backend is a CD/DVD. In that case, + * vdisk_bsize is set to 512 (DEV_BSIZE) while backend_bsize is set to the + * effective logical block size of the CD/DVD (usually 2048). + * + * - dskimg_size: size of the backend when the backend is a disk image. This + * attribute is set only when the backend is a file or a volume, otherwise it + * is unused. + * + * - vio_bshift: number of bit to shift to convert a VIO block number (which + * uses a block size of vdisk_bsize) to a buf(9s) block number (which uses a + * block size of 512 bytes) i.e. we have vdisk_bsize = 512 x 2 ^ vio_bshift + * + * - vdisk_media: media of the virtual disk. This function only sets this + * attribute for physical disk and CD/DVD. For other backend types, this + * attribute is set in the setup function of the backend. + */ static int vd_backend_check_size(vd_t *vd) { - size_t backend_size, old_size, new_size; + size_t backend_size, backend_bsize, vdisk_bsize; + size_t old_size, new_size; struct dk_minfo minfo; vattr_t vattr; - int rval, rv; + int rval, rv, media, nshift = 0; + uint32_t n; if (vd->file) { @@ -6320,20 +6358,23 @@ vd_backend_check_size(vd_t *vd) return (rv); } backend_size = vattr.va_size; + backend_bsize = DEV_BSIZE; + vdisk_bsize = DEV_BSIZE; - } else if (vd->volume || vd->vdisk_type == VD_DISK_TYPE_SLICE) { + } else if (vd->volume) { - /* physical slice or volume (slice or full disk) */ + /* volume (slice or full disk) */ rv = ldi_get_size(vd->ldi_handle[0], &backend_size); if (rv != DDI_SUCCESS) { PR0("ldi_get_size() failed for %s", vd->device_path); return (EIO); } + backend_bsize = DEV_BSIZE; + vdisk_bsize = DEV_BSIZE; } else { - /* physical disk */ - ASSERT(vd->vdisk_type == VD_DISK_TYPE_DISK); + /* physical disk or slice */ rv = ldi_ioctl(vd->ldi_handle[0], DKIOCGMEDIAINFO, (intptr_t)&minfo, (vd->open_flags | FKIOCTL), kcred, &rval); @@ -6342,17 +6383,58 @@ vd_backend_check_size(vd_t *vd) vd->device_path, rv); return (rv); } - backend_size = minfo.dki_capacity * minfo.dki_lbsize; + + if (vd->vdisk_type == VD_DISK_TYPE_SLICE) { + rv = ldi_get_size(vd->ldi_handle[0], &backend_size); + if (rv != DDI_SUCCESS) { + PR0("ldi_get_size() failed for %s", + vd->device_path); + return (EIO); + } + } else { + ASSERT(vd->vdisk_type == VD_DISK_TYPE_DISK); + backend_size = minfo.dki_capacity * minfo.dki_lbsize; + } + + backend_bsize = minfo.dki_lbsize; + media = DK_MEDIATYPE2VD_MEDIATYPE(minfo.dki_media_type); + + /* + * If the device is a CD or a DVD then we force the vdisk block + * size to 512 bytes (DEV_BSIZE). In that case, vdisk_bsize can + * be different from backend_size. + */ + if (media == VD_MEDIA_CD || media == VD_MEDIA_DVD) + vdisk_bsize = DEV_BSIZE; + else + vdisk_bsize = backend_bsize; } + /* check vdisk block size */ + if (vdisk_bsize == 0 || vdisk_bsize % DEV_BSIZE != 0) + return (EINVAL); + old_size = vd->vdisk_size; - new_size = backend_size / DEV_BSIZE; + new_size = backend_size / vdisk_bsize; /* check if size has changed */ - if (old_size != VD_SIZE_UNKNOWN && old_size == new_size) + if (old_size != VD_SIZE_UNKNOWN && old_size == new_size && + vd->vdisk_bsize == vdisk_bsize) return (0); + /* cache info for blk conversion */ + for (n = vdisk_bsize / DEV_BSIZE; n > 1; n >>= 1) { + if ((n & 0x1) != 0) { + /* blk_size is not a power of 2 */ + return (EINVAL); + } + nshift++; + } + + vd->vio_bshift = nshift; vd->vdisk_size = new_size; + vd->vdisk_bsize = vdisk_bsize; + vd->backend_bsize = backend_bsize; if (vd->file || vd->volume) vd->dskimg_size = backend_size; @@ -6384,9 +6466,7 @@ vd_backend_check_size(vd_t *vd) } else if (!vd->file && !vd->volume) { /* physical disk */ ASSERT(vd->vdisk_type == VD_DISK_TYPE_DISK); - vd->block_size = minfo.dki_lbsize; - vd->vdisk_media = - DK_MEDIATYPE2VD_MEDIATYPE(minfo.dki_media_type); + vd->vdisk_media = media; } return (0); |