#ifndef _VDSK_COMMON_H
#define _VDSK_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/efi_partition.h>
#include <sys/machparam.h>
#include <sys/vtoc.h>
#include <sys/ldc.h>
#include <sys/vio_common.h>
#include <sys/vio_mailbox.h>
#define VD_DRING_LEN 512
#define VD_DRING_ENTRY_SZ (sizeof (vd_dring_entry_t) + \
(sizeof (ldc_mem_cookie_t) * (VD_MAX_COOKIES - 1)))
#define VD_MAX_BLOCK_SIZE (256 * 1024)
#define VD_MAX_COOKIES ((VD_MAX_BLOCK_SIZE / PAGESIZE) + 1)
#define VD_USEC_TIMEOUT 20000
#define VD_LDC_IDS_PROP "ldc-ids"
#define VD_LDC_MTU 256
#define VD_COPYOUT 0x1
#define VD_COPYIN 0x2
#define VD_OP_BREAD 0x01
#define VD_OP_BWRITE 0x02
#define VD_OP_FLUSH 0x03
#define VD_OP_GET_WCE 0x04
#define VD_OP_SET_WCE 0x05
#define VD_OP_GET_VTOC 0x06
#define VD_OP_SET_VTOC 0x07
#define VD_OP_GET_DISKGEOM 0x08
#define VD_OP_SET_DISKGEOM 0x09
#define VD_OP_SCSICMD 0x0a
#define VD_OP_GET_DEVID 0x0b
#define VD_OP_GET_EFI 0x0c
#define VD_OP_SET_EFI 0x0d
#define VD_OP_RESET 0x0e
#define VD_OP_GET_ACCESS 0x0f
#define VD_OP_SET_ACCESS 0x10
#define VD_OP_GET_CAPACITY 0x11
#define VD_OP_MASK 0xFF
#define VD_OP_COUNT 0x11
#define VD_ACCESS_DENIED 0x00
#define VD_ACCESS_ALLOWED 0x01
#define VD_ACCESS_SET_CLEAR 0x00
#define VD_ACCESS_SET_EXCLUSIVE 0x01
#define VD_ACCESS_SET_PREEMPT 0x02
#define VD_ACCESS_SET_PRESERVE 0x04
#define VD_OP_MASK_READ \
((1 << VD_OP_BREAD) | \
(1 << VD_OP_GET_WCE) | \
(1 << VD_OP_GET_VTOC) | \
(1 << VD_OP_GET_DISKGEOM) | \
(1 << VD_OP_GET_DEVID) | \
(1 << VD_OP_GET_EFI))
#define VD_OP_MASK_WRITE \
((1 << VD_OP_BWRITE) | \
(1 << VD_OP_FLUSH) | \
(1 << VD_OP_SET_WCE) | \
(1 << VD_OP_SET_VTOC) | \
(1 << VD_OP_SET_DISKGEOM) | \
(1 << VD_OP_SET_EFI))
#define VD_OP_MASK_SCSI \
((1 << VD_OP_SCSICMD) | \
(1 << VD_OP_RESET) | \
(1 << VD_OP_GET_ACCESS) | \
(1 << VD_OP_SET_ACCESS))
#define VD_OP_SUPPORTED(ops_bitmask, op) ((ops_bitmask) & (1 << (op)))
#define VD_SLICE_NONE 0xFF
#define VD_EFI_WD_SLICE 7
typedef enum vd_disk_type {
VD_DISK_TYPE_UNK = 0,
VD_DISK_TYPE_SLICE,
VD_DISK_TYPE_DISK
} vd_disk_type_t;
typedef enum vd_disk_label {
VD_DISK_LABEL_UNK = 0,
VD_DISK_LABEL_VTOC,
VD_DISK_LABEL_EFI
} vd_disk_label_t;
typedef struct vd_dring_payload {
uint64_t req_id;
uint8_t operation;
uint8_t slice;
uint16_t resv1;
uint32_t status;
uint64_t addr;
uint64_t nbytes;
uint32_t ncookies;
uint32_t resv2;
ldc_mem_cookie_t cookie[1];
} vd_dring_payload_t;
typedef struct vd_dring_entry {
vio_dring_entry_hdr_t hdr;
vd_dring_payload_t payload;
} vd_dring_entry_t;
typedef struct vd_slice {
daddr_t start;
daddr_t nblocks;
} vd_slice_t;
typedef struct vd_geom {
uint16_t ncyl;
uint16_t acyl;
uint16_t bcyl;
uint16_t nhead;
uint16_t nsect;
uint16_t intrlv;
uint16_t apc;
uint16_t rpm;
uint16_t pcyl;
uint16_t write_reinstruct;
uint16_t read_reinstruct;
} vd_geom_t;
typedef struct vd_partition {
uint16_t id_tag;
uint16_t perm;
uint32_t reserved;
uint64_t start;
uint64_t nblocks;
} vd_partition_t;
#define VD_VOLNAME_LEN 8
#define VD_ASCIILABEL_LEN 128
typedef struct vd_vtoc {
char volume_name[VD_VOLNAME_LEN];
uint16_t sector_size;
uint16_t num_partitions;
char ascii_label[VD_ASCIILABEL_LEN];
vd_partition_t partition[V_NUMPAR];
} vd_vtoc_t;
typedef struct vd_efi {
uint64_t lba;
uint64_t length;
char data[1];
} vd_efi_t;
#define VD_DEVID_SIZE(l) (sizeof (vd_devid_t) - 1 + l)
#define VD_DEVID_DEFAULT_LEN 128
typedef struct vd_devid {
uint16_t reserved;
uint16_t type;
uint32_t length;
char id[1];
} vd_devid_t;
typedef struct vd_capacity {
uint32_t vdisk_block_size;
uint32_t reserved;
uint64_t vdisk_size;
} vd_capacity_t;
#define VD_SIZE_UNKNOWN -1
typedef struct vd_scsi {
uint8_t cmd_status;
uint8_t sense_status;
uint8_t task_attribute;
uint8_t task_priority;
uint8_t crn;
uint8_t reserved;
uint16_t timeout;
uint64_t options;
uint64_t cdb_len;
uint64_t sense_len;
uint64_t datain_len;
uint64_t dataout_len;
char data[1];
} vd_scsi_t;
#define VD_SCSI_SIZE (sizeof (vd_scsi_t) - sizeof (uint64_t))
#define VD_SCSI_DATA_CDB(vscsi) \
((union scsi_cdb *)(uintptr_t)((vscsi)->data))
#define VD_SCSI_DATA_SENSE(vscsi) \
((struct scsi_extended_sense *)(uintptr_t)((vscsi)->data + \
P2ROUNDUP((vscsi)->cdb_len, sizeof (uint64_t))))
#define VD_SCSI_DATA_IN(vscsi) \
((uintptr_t)((vscsi)->data + \
P2ROUNDUP((vscsi)->cdb_len, sizeof (uint64_t)) + \
P2ROUNDUP((vscsi)->sense_len, sizeof (uint64_t))))
#define VD_SCSI_DATA_OUT(vscsi) \
((uintptr_t)((vscsi)->data + \
P2ROUNDUP((vscsi)->cdb_len, sizeof (uint64_t)) + \
P2ROUNDUP((vscsi)->sense_len, sizeof (uint64_t)) + \
P2ROUNDUP((vscsi)->datain_len, sizeof (uint64_t))))
#define VD_SCSI_TASK_SIMPLE 0x01
#define VD_SCSI_TASK_ORDERED 0x02
#define VD_SCSI_TASK_HQUEUE 0x03
#define VD_SCSI_TASK_ACA 0x04
#define VD_SCSI_OPT_CRN 0x01
#define VD_SCSI_OPT_NORETRY 0x02
#define VD_GEOM2DK_GEOM(vd_geom, dk_geom) \
{ \
bzero((dk_geom), sizeof (*(dk_geom))); \
(dk_geom)->dkg_ncyl = (vd_geom)->ncyl; \
(dk_geom)->dkg_acyl = (vd_geom)->acyl; \
(dk_geom)->dkg_bcyl = (vd_geom)->bcyl; \
(dk_geom)->dkg_nhead = (vd_geom)->nhead; \
(dk_geom)->dkg_nsect = (vd_geom)->nsect; \
(dk_geom)->dkg_intrlv = (vd_geom)->intrlv; \
(dk_geom)->dkg_apc = (vd_geom)->apc; \
(dk_geom)->dkg_rpm = (vd_geom)->rpm; \
(dk_geom)->dkg_pcyl = (vd_geom)->pcyl; \
(dk_geom)->dkg_write_reinstruct = (vd_geom)->write_reinstruct; \
(dk_geom)->dkg_read_reinstruct = (vd_geom)->read_reinstruct; \
}
#define VD_VTOC2VTOC(vd_vtoc, vtoc) \
{ \
bzero((vtoc), sizeof (*(vtoc))); \
bcopy((vd_vtoc)->volume_name, (vtoc)->v_volume, \
MIN(sizeof ((vd_vtoc)->volume_name), \
sizeof ((vtoc)->v_volume))); \
bcopy((vd_vtoc)->ascii_label, (vtoc)->v_asciilabel, \
MIN(sizeof ((vd_vtoc)->ascii_label), \
sizeof ((vtoc)->v_asciilabel))); \
(vtoc)->v_sanity = VTOC_SANE; \
(vtoc)->v_version = V_VERSION; \
(vtoc)->v_sectorsz = (vd_vtoc)->sector_size; \
(vtoc)->v_nparts = (vd_vtoc)->num_partitions; \
for (int i = 0; i < (vd_vtoc)->num_partitions; i++) { \
(vtoc)->v_part[i].p_tag = (vd_vtoc)->partition[i].id_tag; \
(vtoc)->v_part[i].p_flag = (vd_vtoc)->partition[i].perm; \
(vtoc)->v_part[i].p_start = (vd_vtoc)->partition[i].start; \
(vtoc)->v_part[i].p_size = (vd_vtoc)->partition[i].nblocks; \
} \
}
#define DK_GEOM2VD_GEOM(dk_geom, vd_geom) \
{ \
bzero((vd_geom), sizeof (*(vd_geom))); \
(vd_geom)->ncyl = (dk_geom)->dkg_ncyl; \
(vd_geom)->acyl = (dk_geom)->dkg_acyl; \
(vd_geom)->bcyl = (dk_geom)->dkg_bcyl; \
(vd_geom)->nhead = (dk_geom)->dkg_nhead; \
(vd_geom)->nsect = (dk_geom)->dkg_nsect; \
(vd_geom)->intrlv = (dk_geom)->dkg_intrlv; \
(vd_geom)->apc = (dk_geom)->dkg_apc; \
(vd_geom)->rpm = (dk_geom)->dkg_rpm; \
(vd_geom)->pcyl = (dk_geom)->dkg_pcyl; \
(vd_geom)->write_reinstruct = (dk_geom)->dkg_write_reinstruct; \
(vd_geom)->read_reinstruct = (dk_geom)->dkg_read_reinstruct; \
}
#define VTOC2VD_VTOC(vtoc, vd_vtoc) \
{ \
bzero((vd_vtoc), sizeof (*(vd_vtoc))); \
bcopy((vtoc)->v_volume, (vd_vtoc)->volume_name, \
MIN(sizeof ((vtoc)->v_volume), \
sizeof ((vd_vtoc)->volume_name))); \
bcopy((vtoc)->v_asciilabel, (vd_vtoc)->ascii_label, \
MIN(sizeof ((vtoc)->v_asciilabel), \
sizeof ((vd_vtoc)->ascii_label))); \
(vd_vtoc)->sector_size = (vtoc)->v_sectorsz; \
(vd_vtoc)->num_partitions = (vtoc)->v_nparts; \
for (int i = 0; i < (vtoc)->v_nparts; i++) { \
(vd_vtoc)->partition[i].id_tag = (vtoc)->v_part[i].p_tag; \
(vd_vtoc)->partition[i].perm = (vtoc)->v_part[i].p_flag; \
(vd_vtoc)->partition[i].start = (vtoc)->v_part[i].p_start; \
(vd_vtoc)->partition[i].nblocks = (vtoc)->v_part[i].p_size; \
} \
}
#define VD_EFI2DK_EFI(vd_efi, dk_efi) \
{ \
(dk_efi)->dki_lba = (vd_efi)->lba; \
(dk_efi)->dki_length = (vd_efi)->length; \
bcopy((vd_efi)->data, (dk_efi)->dki_data, (dk_efi)->dki_length); \
}
#define DK_EFI2VD_EFI(dk_efi, vd_efi) \
{ \
(vd_efi)->lba = (dk_efi)->dki_lba; \
(vd_efi)->length = (dk_efi)->dki_length; \
bcopy((dk_efi)->dki_data, (vd_efi)->data, (vd_efi)->length); \
}
#define VD_MEDIATYPE2DK_MEDIATYPE(mt) \
((mt) == VD_MEDIA_FIXED ? DK_FIXED_DISK : \
(mt) == VD_MEDIA_CD ? DK_CDROM : \
(mt) == VD_MEDIA_DVD ? DK_DVDROM : \
DK_UNKNOWN)
#define DK_MEDIA_OPTICAL_MAX 0xFFFF
#define DK_MEDIATYPE2VD_MEDIATYPE(mt) \
(((mt) > DK_MEDIA_OPTICAL_MAX)? VD_MEDIA_FIXED : \
(mt) == DK_REMOVABLE_DISK ? VD_MEDIA_FIXED : \
(mt) == DK_MO_ERASABLE ? VD_MEDIA_FIXED : \
(mt) == DK_MO_WRITEONCE ? VD_MEDIA_FIXED : \
(mt) == DK_AS_MO ? VD_MEDIA_FIXED : \
(mt) == DK_CDROM ? VD_MEDIA_CD : \
(mt) == DK_CDR ? VD_MEDIA_CD : \
(mt) == DK_CDRW ? VD_MEDIA_CD : \
VD_MEDIA_DVD)
typedef int (*vd_efi_ioctl_func)(void *, int, uintptr_t);
typedef struct vd_efi_dev {
void *vdisk;
size_t block_size;
size_t disk_size;
vd_efi_ioctl_func vdisk_ioctl;
} vd_efi_dev_t;
#define VDSK_EFI_DEV_SET(efi_dev, vdsk, ioctl, bsize, dsize) \
(efi_dev).vdisk = vdsk; \
(efi_dev).vdisk_ioctl = ioctl; \
(efi_dev).block_size = bsize; \
(efi_dev).disk_size = dsize;
int vd_efi_alloc_and_read(vd_efi_dev_t *dev, efi_gpt_t **gpt, efi_gpe_t **gpe);
void vd_efi_free(vd_efi_dev_t *dev, efi_gpt_t *gpt, efi_gpe_t *gpe);
#define VD_UPDATE_IO_STATS(vd, op, len) \
{ \
ASSERT((vd) != NULL); \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
ASSERT(((op) == VD_OP_BREAD) || ((op) == VD_OP_BWRITE));\
if ((vd)->io_stats != NULL) { \
kstat_io_t *kip = KSTAT_IO_PTR((vd)->io_stats); \
if ((op) == VD_OP_BREAD) { \
kip->reads++; \
kip->nread += (len); \
} else { \
kip->writes++; \
kip->nwritten += (len); \
} \
} \
}
#define VD_KSTAT_WAITQ_ENTER(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_waitq_enter(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_KSTAT_WAITQ_EXIT(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_waitq_exit(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_KSTAT_WAITQ_TO_RUNQ(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_waitq_to_runq(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_KSTAT_RUNQ_BACK_TO_WAITQ(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_runq_back_to_waitq(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_KSTAT_RUNQ_ENTER(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_runq_enter(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_KSTAT_RUNQ_EXIT(vd) \
if ((vd)->io_stats != NULL) { \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
kstat_runq_exit(KSTAT_IO_PTR((vd)->io_stats)); \
}
#define VD_UPDATE_ERR_STATS(vd, stat_entry) \
{ \
ASSERT((vd) != NULL); \
ASSERT(MUTEX_HELD(&(vd)->lock)); \
if ((vd)->err_stats != NULL) { \
vd_err_stats_t *stp; \
stp = (vd_err_stats_t *)(vd)->err_stats->ks_data; \
stp->stat_entry.value.ui32++; \
} \
}
typedef struct vd_err_stats {
struct kstat_named vd_softerrs;
struct kstat_named vd_transerrs;
struct kstat_named vd_protoerrs;
struct kstat_named vd_vid;
struct kstat_named vd_pid;
struct kstat_named vd_capacity;
} vd_err_stats_t;
#ifdef __cplusplus
}
#endif
#endif