1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2012 DEY Storage Systems, Inc.  All rights reserved.
  24  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  * Copyright 2016 Toomas Soome <tsoome@me.com>
  27  */
  28 
  29 /*
  30  * This module provides support for labeling operations for target
  31  * drivers.
  32  */
  33 
  34 #include <sys/scsi/scsi.h>
  35 #include <sys/sunddi.h>
  36 #include <sys/dklabel.h>
  37 #include <sys/dkio.h>
  38 #include <sys/vtoc.h>
  39 #include <sys/dktp/fdisk.h>
  40 #include <sys/vtrace.h>
  41 #include <sys/efi_partition.h>
  42 #include <sys/cmlb.h>
  43 #include <sys/cmlb_impl.h>
  44 #if defined(__i386) || defined(__amd64)
  45 #include <sys/fs/dv_node.h>
  46 #endif
  47 #include <sys/ddi_impldefs.h>
  48 
  49 /*
  50  * Driver minor node structure and data table
  51  */
  52 struct driver_minor_data {
  53         char    *name;
  54         minor_t minor;
  55         int     type;
  56 };
  57 
  58 static struct driver_minor_data dk_minor_data[] = {
  59         {"a", 0, S_IFBLK},
  60         {"b", 1, S_IFBLK},
  61         {"c", 2, S_IFBLK},
  62         {"d", 3, S_IFBLK},
  63         {"e", 4, S_IFBLK},
  64         {"f", 5, S_IFBLK},
  65         {"g", 6, S_IFBLK},
  66         {"h", 7, S_IFBLK},
  67 #if defined(_SUNOS_VTOC_16)
  68         {"i", 8, S_IFBLK},
  69         {"j", 9, S_IFBLK},
  70         {"k", 10, S_IFBLK},
  71         {"l", 11, S_IFBLK},
  72         {"m", 12, S_IFBLK},
  73         {"n", 13, S_IFBLK},
  74         {"o", 14, S_IFBLK},
  75         {"p", 15, S_IFBLK},
  76 #endif                  /* defined(_SUNOS_VTOC_16) */
  77 #if defined(_FIRMWARE_NEEDS_FDISK)
  78         {"q", 16, S_IFBLK},
  79         {"r", 17, S_IFBLK},
  80         {"s", 18, S_IFBLK},
  81         {"t", 19, S_IFBLK},
  82         {"u", 20, S_IFBLK},
  83 #endif                  /* defined(_FIRMWARE_NEEDS_FDISK) */
  84         {"a,raw", 0, S_IFCHR},
  85         {"b,raw", 1, S_IFCHR},
  86         {"c,raw", 2, S_IFCHR},
  87         {"d,raw", 3, S_IFCHR},
  88         {"e,raw", 4, S_IFCHR},
  89         {"f,raw", 5, S_IFCHR},
  90         {"g,raw", 6, S_IFCHR},
  91         {"h,raw", 7, S_IFCHR},
  92 #if defined(_SUNOS_VTOC_16)
  93         {"i,raw", 8, S_IFCHR},
  94         {"j,raw", 9, S_IFCHR},
  95         {"k,raw", 10, S_IFCHR},
  96         {"l,raw", 11, S_IFCHR},
  97         {"m,raw", 12, S_IFCHR},
  98         {"n,raw", 13, S_IFCHR},
  99         {"o,raw", 14, S_IFCHR},
 100         {"p,raw", 15, S_IFCHR},
 101 #endif                  /* defined(_SUNOS_VTOC_16) */
 102 #if defined(_FIRMWARE_NEEDS_FDISK)
 103         {"q,raw", 16, S_IFCHR},
 104         {"r,raw", 17, S_IFCHR},
 105         {"s,raw", 18, S_IFCHR},
 106         {"t,raw", 19, S_IFCHR},
 107         {"u,raw", 20, S_IFCHR},
 108 #endif                  /* defined(_FIRMWARE_NEEDS_FDISK) */
 109         {0}
 110 };
 111 
 112 #if defined(__i386) || defined(__amd64)
 113 #if defined(_FIRMWARE_NEEDS_FDISK)
 114 static struct driver_minor_data dk_ext_minor_data[] = {
 115         {"p5", 21, S_IFBLK},
 116         {"p6", 22, S_IFBLK},
 117         {"p7", 23, S_IFBLK},
 118         {"p8", 24, S_IFBLK},
 119         {"p9", 25, S_IFBLK},
 120         {"p10", 26, S_IFBLK},
 121         {"p11", 27, S_IFBLK},
 122         {"p12", 28, S_IFBLK},
 123         {"p13", 29, S_IFBLK},
 124         {"p14", 30, S_IFBLK},
 125         {"p15", 31, S_IFBLK},
 126         {"p16", 32, S_IFBLK},
 127         {"p17", 33, S_IFBLK},
 128         {"p18", 34, S_IFBLK},
 129         {"p19", 35, S_IFBLK},
 130         {"p20", 36, S_IFBLK},
 131         {"p21", 37, S_IFBLK},
 132         {"p22", 38, S_IFBLK},
 133         {"p23", 39, S_IFBLK},
 134         {"p24", 40, S_IFBLK},
 135         {"p25", 41, S_IFBLK},
 136         {"p26", 42, S_IFBLK},
 137         {"p27", 43, S_IFBLK},
 138         {"p28", 44, S_IFBLK},
 139         {"p29", 45, S_IFBLK},
 140         {"p30", 46, S_IFBLK},
 141         {"p31", 47, S_IFBLK},
 142         {"p32", 48, S_IFBLK},
 143         {"p33", 49, S_IFBLK},
 144         {"p34", 50, S_IFBLK},
 145         {"p35", 51, S_IFBLK},
 146         {"p36", 52, S_IFBLK},
 147         {"p5,raw", 21, S_IFCHR},
 148         {"p6,raw", 22, S_IFCHR},
 149         {"p7,raw", 23, S_IFCHR},
 150         {"p8,raw", 24, S_IFCHR},
 151         {"p9,raw", 25, S_IFCHR},
 152         {"p10,raw", 26, S_IFCHR},
 153         {"p11,raw", 27, S_IFCHR},
 154         {"p12,raw", 28, S_IFCHR},
 155         {"p13,raw", 29, S_IFCHR},
 156         {"p14,raw", 30, S_IFCHR},
 157         {"p15,raw", 31, S_IFCHR},
 158         {"p16,raw", 32, S_IFCHR},
 159         {"p17,raw", 33, S_IFCHR},
 160         {"p18,raw", 34, S_IFCHR},
 161         {"p19,raw", 35, S_IFCHR},
 162         {"p20,raw", 36, S_IFCHR},
 163         {"p21,raw", 37, S_IFCHR},
 164         {"p22,raw", 38, S_IFCHR},
 165         {"p23,raw", 39, S_IFCHR},
 166         {"p24,raw", 40, S_IFCHR},
 167         {"p25,raw", 41, S_IFCHR},
 168         {"p26,raw", 42, S_IFCHR},
 169         {"p27,raw", 43, S_IFCHR},
 170         {"p28,raw", 44, S_IFCHR},
 171         {"p29,raw", 45, S_IFCHR},
 172         {"p30,raw", 46, S_IFCHR},
 173         {"p31,raw", 47, S_IFCHR},
 174         {"p32,raw", 48, S_IFCHR},
 175         {"p33,raw", 49, S_IFCHR},
 176         {"p34,raw", 50, S_IFCHR},
 177         {"p35,raw", 51, S_IFCHR},
 178         {"p36,raw", 52, S_IFCHR},
 179         {0}
 180 };
 181 #endif                  /* defined(_FIRMWARE_NEEDS_FDISK) */
 182 #endif                  /* if defined(__i386) || defined(__amd64) */
 183 
 184 static struct driver_minor_data dk_minor_data_efi[] = {
 185         {"a", 0, S_IFBLK},
 186         {"b", 1, S_IFBLK},
 187         {"c", 2, S_IFBLK},
 188         {"d", 3, S_IFBLK},
 189         {"e", 4, S_IFBLK},
 190         {"f", 5, S_IFBLK},
 191         {"g", 6, S_IFBLK},
 192         {"wd", 7, S_IFBLK},
 193 #if defined(_SUNOS_VTOC_16)
 194         {"i", 8, S_IFBLK},
 195         {"j", 9, S_IFBLK},
 196         {"k", 10, S_IFBLK},
 197         {"l", 11, S_IFBLK},
 198         {"m", 12, S_IFBLK},
 199         {"n", 13, S_IFBLK},
 200         {"o", 14, S_IFBLK},
 201         {"p", 15, S_IFBLK},
 202 #endif                  /* defined(_SUNOS_VTOC_16) */
 203 #if defined(_FIRMWARE_NEEDS_FDISK)
 204         {"q", 16, S_IFBLK},
 205         {"r", 17, S_IFBLK},
 206         {"s", 18, S_IFBLK},
 207         {"t", 19, S_IFBLK},
 208         {"u", 20, S_IFBLK},
 209 #endif                  /* defined(_FIRMWARE_NEEDS_FDISK) */
 210         {"a,raw", 0, S_IFCHR},
 211         {"b,raw", 1, S_IFCHR},
 212         {"c,raw", 2, S_IFCHR},
 213         {"d,raw", 3, S_IFCHR},
 214         {"e,raw", 4, S_IFCHR},
 215         {"f,raw", 5, S_IFCHR},
 216         {"g,raw", 6, S_IFCHR},
 217         {"wd,raw", 7, S_IFCHR},
 218 #if defined(_SUNOS_VTOC_16)
 219         {"i,raw", 8, S_IFCHR},
 220         {"j,raw", 9, S_IFCHR},
 221         {"k,raw", 10, S_IFCHR},
 222         {"l,raw", 11, S_IFCHR},
 223         {"m,raw", 12, S_IFCHR},
 224         {"n,raw", 13, S_IFCHR},
 225         {"o,raw", 14, S_IFCHR},
 226         {"p,raw", 15, S_IFCHR},
 227 #endif                  /* defined(_SUNOS_VTOC_16) */
 228 #if defined(_FIRMWARE_NEEDS_FDISK)
 229         {"q,raw", 16, S_IFCHR},
 230         {"r,raw", 17, S_IFCHR},
 231         {"s,raw", 18, S_IFCHR},
 232         {"t,raw", 19, S_IFCHR},
 233         {"u,raw", 20, S_IFCHR},
 234 #endif                  /* defined(_FIRMWARE_NEEDS_FDISK) */
 235         {0}
 236 };
 237 
 238 /*
 239  * Declare the dynamic properties implemented in prop_op(9E) implementation
 240  * that we want to have show up in a di_init(3DEVINFO) device tree snapshot
 241  * of drivers that call cmlb_attach().
 242  */
 243 static i_ddi_prop_dyn_t cmlb_prop_dyn[] = {
 244         {"Nblocks",             DDI_PROP_TYPE_INT64,    S_IFBLK},
 245         {"Size",                DDI_PROP_TYPE_INT64,    S_IFCHR},
 246         {"device-nblocks",      DDI_PROP_TYPE_INT64},
 247         {"device-blksize",      DDI_PROP_TYPE_INT},
 248         {"device-solid-state",  DDI_PROP_TYPE_INT},
 249         {"device-rotational",   DDI_PROP_TYPE_INT},
 250         {NULL}
 251 };
 252 
 253 /*
 254  * This implies an upper limit of 8192 GPT partitions
 255  * in one transfer for GUID Partition Entry Array.
 256  */
 257 len_t cmlb_tg_max_efi_xfer = 1024 * 1024;
 258 
 259 /*
 260  * External kernel interfaces
 261  */
 262 extern struct mod_ops mod_miscops;
 263 
 264 extern int ddi_create_internal_pathname(dev_info_t *dip, char *name,
 265     int spec_type, minor_t minor_num);
 266 
 267 /*
 268  * Global buffer and mutex for debug logging
 269  */
 270 static char     cmlb_log_buffer[1024];
 271 static kmutex_t cmlb_log_mutex;
 272 
 273 
 274 struct cmlb_lun *cmlb_debug_cl = NULL;
 275 uint_t cmlb_level_mask = 0x0;
 276 
 277 int cmlb_rot_delay = 4; /* default rotational delay */
 278 
 279 static struct modlmisc modlmisc = {
 280         &mod_miscops,   /* Type of module */
 281         "Common Labeling module"
 282 };
 283 
 284 static struct modlinkage modlinkage = {
 285         MODREV_1, (void *)&modlmisc, NULL
 286 };
 287 
 288 /* Local function prototypes */
 289 static dev_t cmlb_make_device(struct cmlb_lun *cl);
 290 static int cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid,
 291     int flags, void *tg_cookie);
 292 static void cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
 293     void *tg_cookie);
 294 static int cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity,
 295     void *tg_cookie);
 296 static void cmlb_swap_efi_gpt(efi_gpt_t *e);
 297 static void cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p);
 298 static int cmlb_validate_efi(efi_gpt_t *labp);
 299 static int cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
 300     void *tg_cookie);
 301 static void cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie);
 302 static int  cmlb_uselabel(struct cmlb_lun *cl,  struct dk_label *l, int flags);
 303 #if defined(_SUNOS_VTOC_8)
 304 static void cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
 305 #endif
 306 static int cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc);
 307 static int cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie);
 308 static int cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl,
 309     void *tg_cookie);
 310 static void cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie);
 311 static void cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie);
 312 static void cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie);
 313 static int cmlb_create_minor_nodes(struct cmlb_lun *cl);
 314 static int cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie);
 315 static boolean_t cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr);
 316 
 317 #if defined(__i386) || defined(__amd64)
 318 static int cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie);
 319 #endif
 320 
 321 #if defined(_FIRMWARE_NEEDS_FDISK)
 322 static boolean_t  cmlb_has_max_chs_vals(struct ipart *fdp);
 323 #endif
 324 
 325 #if defined(_SUNOS_VTOC_16)
 326 static void cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
 327     struct dk_geom *cl_g, void *tg_cookie);
 328 #endif
 329 
 330 static int cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
 331     void *tg_cookie);
 332 static int cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag);
 333 static int cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
 334     void *tg_cookie);
 335 static int cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag);
 336 static int cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag,
 337     void *tg_cookie);
 338 static int cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
 339     int flag, void *tg_cookie);
 340 static int cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
 341     void *tg_cookie);
 342 static int cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
 343     void *tg_cookie);
 344 static int cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
 345     int flag, void *tg_cookie);
 346 static int cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
 347     int flag, void *tg_cookie);
 348 static int cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
 349     void *tg_cookie);
 350 static int cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag,
 351     void *tg_cookie);
 352 static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
 353     void *tg_cookie);
 354 
 355 #if defined(__i386) || defined(__amd64)
 356 static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
 357     void *tg_cookie);
 358 static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart,
 359     uint32_t start, uint32_t size);
 360 static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
 361     void *tg_cookie);
 362 static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
 363 static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
 364     void *tg_cookie);
 365 static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
 366     int flag);
 367 static int cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
 368     int flag);
 369 #endif
 370 
 371 static void cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...);
 372 static void cmlb_v_log(dev_info_t *dev, const char *label, uint_t level,
 373     const char *fmt, va_list ap);
 374 static void cmlb_log(dev_info_t *dev, const char *label, uint_t level,
 375     const char *fmt, ...);
 376 
 377 int
 378 _init(void)
 379 {
 380         mutex_init(&cmlb_log_mutex, NULL, MUTEX_DRIVER, NULL);
 381         return (mod_install(&modlinkage));
 382 }
 383 
 384 int
 385 _info(struct modinfo *modinfop)
 386 {
 387         return (mod_info(&modlinkage, modinfop));
 388 }
 389 
 390 int
 391 _fini(void)
 392 {
 393         int err;
 394 
 395         if ((err = mod_remove(&modlinkage)) != 0) {
 396                 return (err);
 397         }
 398 
 399         mutex_destroy(&cmlb_log_mutex);
 400         return (err);
 401 }
 402 
 403 /*
 404  * cmlb_dbg is used for debugging to log additional info
 405  * Level of output is controlled via cmlb_level_mask setting.
 406  */
 407 static void
 408 cmlb_dbg(uint_t comp, struct cmlb_lun *cl, const char *fmt, ...)
 409 {
 410         va_list         ap;
 411         dev_info_t      *dev;
 412         uint_t          level_mask = 0;
 413 
 414         ASSERT(cl != NULL);
 415         dev = CMLB_DEVINFO(cl);
 416         ASSERT(dev != NULL);
 417         /*
 418          * Filter messages based on the global component and level masks,
 419          * also print if cl matches the value of cmlb_debug_cl, or if
 420          * cmlb_debug_cl is set to NULL.
 421          */
 422         if (comp & CMLB_TRACE)
 423                 level_mask |= CMLB_LOGMASK_TRACE;
 424 
 425         if (comp & CMLB_INFO)
 426                 level_mask |= CMLB_LOGMASK_INFO;
 427 
 428         if (comp & CMLB_ERROR)
 429                 level_mask |= CMLB_LOGMASK_ERROR;
 430 
 431         if ((cmlb_level_mask & level_mask) &&
 432             ((cmlb_debug_cl == NULL) || (cmlb_debug_cl == cl))) {
 433                 va_start(ap, fmt);
 434                 cmlb_v_log(dev, CMLB_LABEL(cl), CE_CONT, fmt, ap);
 435                 va_end(ap);
 436         }
 437 }
 438 
 439 /*
 440  * cmlb_log is basically a duplicate of scsi_log. It is redefined here
 441  * so that this module does not depend on scsi module.
 442  */
 443 static void
 444 cmlb_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt, ...)
 445 {
 446         va_list         ap;
 447 
 448         va_start(ap, fmt);
 449         cmlb_v_log(dev, label, level, fmt, ap);
 450         va_end(ap);
 451 }
 452 
 453 static void
 454 cmlb_v_log(dev_info_t *dev, const char *label, uint_t level, const char *fmt,
 455     va_list ap)
 456 {
 457         static char     name[256];
 458         int             log_only = 0;
 459         int             boot_only = 0;
 460         int             console_only = 0;
 461 
 462         mutex_enter(&cmlb_log_mutex);
 463 
 464         if (dev) {
 465                 if (level == CE_PANIC || level == CE_WARN ||
 466                     level == CE_NOTE) {
 467                         (void) sprintf(name, "%s (%s%d):\n",
 468                             ddi_pathname(dev, cmlb_log_buffer),
 469                             label, ddi_get_instance(dev));
 470                 } else {
 471                         name[0] = '\0';
 472                 }
 473         } else {
 474                 (void) sprintf(name, "%s:", label);
 475         }
 476 
 477         (void) vsprintf(cmlb_log_buffer, fmt, ap);
 478 
 479         switch (cmlb_log_buffer[0]) {
 480         case '!':
 481                 log_only = 1;
 482                 break;
 483         case '?':
 484                 boot_only = 1;
 485                 break;
 486         case '^':
 487                 console_only = 1;
 488                 break;
 489         }
 490 
 491         switch (level) {
 492         case CE_NOTE:
 493                 level = CE_CONT;
 494                 /* FALLTHROUGH */
 495         case CE_CONT:
 496         case CE_WARN:
 497         case CE_PANIC:
 498                 if (boot_only) {
 499                         cmn_err(level, "?%s\t%s", name, &cmlb_log_buffer[1]);
 500                 } else if (console_only) {
 501                         cmn_err(level, "^%s\t%s", name, &cmlb_log_buffer[1]);
 502                 } else if (log_only) {
 503                         cmn_err(level, "!%s\t%s", name, &cmlb_log_buffer[1]);
 504                 } else {
 505                         cmn_err(level, "%s\t%s", name, cmlb_log_buffer);
 506                 }
 507                 break;
 508         case CE_IGNORE:
 509                 break;
 510         default:
 511                 cmn_err(CE_CONT, "^DEBUG: %s\t%s", name, cmlb_log_buffer);
 512                 break;
 513         }
 514         mutex_exit(&cmlb_log_mutex);
 515 }
 516 
 517 
 518 /*
 519  * cmlb_alloc_handle:
 520  *
 521  *      Allocates a handle.
 522  *
 523  * Arguments:
 524  *      cmlbhandlep     pointer to handle
 525  *
 526  * Notes:
 527  *      Allocates a handle and stores the allocated handle in the area
 528  *      pointed to by cmlbhandlep
 529  *
 530  * Context:
 531  *      Kernel thread only (can sleep).
 532  */
 533 void
 534 cmlb_alloc_handle(cmlb_handle_t *cmlbhandlep)
 535 {
 536         struct cmlb_lun         *cl;
 537 
 538         cl = kmem_zalloc(sizeof (struct cmlb_lun), KM_SLEEP);
 539         ASSERT(cmlbhandlep != NULL);
 540 
 541         cl->cl_state = CMLB_INITED;
 542         cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
 543         mutex_init(CMLB_MUTEX(cl), NULL, MUTEX_DRIVER, NULL);
 544 
 545         *cmlbhandlep = (cmlb_handle_t)(cl);
 546 }
 547 
 548 /*
 549  * cmlb_free_handle
 550  *
 551  *      Frees handle.
 552  *
 553  * Arguments:
 554  *      cmlbhandlep     pointer to handle
 555  */
 556 void
 557 cmlb_free_handle(cmlb_handle_t *cmlbhandlep)
 558 {
 559         struct cmlb_lun         *cl;
 560 
 561         cl = (struct cmlb_lun *)*cmlbhandlep;
 562         if (cl != NULL) {
 563                 mutex_destroy(CMLB_MUTEX(cl));
 564                 kmem_free(cl, sizeof (struct cmlb_lun));
 565         }
 566 
 567 }
 568 
 569 /*
 570  * cmlb_attach:
 571  *
 572  *      Attach handle to device, create minor nodes for device.
 573  *
 574  * Arguments:
 575  *      devi            pointer to device's dev_info structure.
 576  *      tgopsp          pointer to array of functions cmlb can use to callback
 577  *                      to target driver.
 578  *
 579  *      device_type     Peripheral device type as defined in
 580  *                      scsi/generic/inquiry.h
 581  *
 582  *      is_removable    whether or not device is removable.
 583  *
 584  *      is_hotpluggable whether or not device is hotpluggable.
 585  *
 586  *      node_type       minor node type (as used by ddi_create_minor_node)
 587  *
 588  *      alter_behavior
 589  *                      bit flags:
 590  *
 591  *                      CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT: create
 592  *                      an alternate slice for the default label, if
 593  *                      device type is DTYPE_DIRECT an architectures default
 594  *                      label type is VTOC16.
 595  *                      Otherwise alternate slice will no be created.
 596  *
 597  *
 598  *                      CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8: report a default
 599  *                      geometry and label for DKIOCGGEOM and DKIOCGVTOC
 600  *                      on architecture with VTOC8 label types.
 601  *
 602  *                      CMLB_OFF_BY_ONE: do the workaround for legacy off-by-
 603  *                      one bug in obtaining capacity (in sd):
 604  *                      SCSI READ_CAPACITY command returns the LBA number of the
 605  *                      last logical block, but sd once treated this number as
 606  *                      disks' capacity on x86 platform. And LBAs are addressed
 607  *                      based 0. So the last block was lost on x86 platform.
 608  *
 609  *                      Now, we remove this workaround. In order for present sd
 610  *                      driver to work with disks which are labeled/partitioned
 611  *                      via previous sd, we add workaround as follows:
 612  *
 613  *                      1) Locate backup EFI label: cmlb searches the next to
 614  *                         last
 615  *                         block for backup EFI label. If fails, it will
 616  *                         turn to the last block for backup EFI label;
 617  *
 618  *                      2) Clear backup EFI label: cmlb first search the last
 619  *                         block for backup EFI label, and will search the
 620  *                         next to last block only if failed for the last
 621  *                         block.
 622  *
 623  *                      3) Calculate geometry:refer to cmlb_convert_geometry()
 624  *                         If capacity increasing by 1 causes disks' capacity
 625  *                         to cross over the limits in geometry calculation,
 626  *                         geometry info will change. This will raise an issue:
 627  *                         In case that primary VTOC label is destroyed, format
 628  *                         commandline can restore it via backup VTOC labels.
 629  *                         And format locates backup VTOC labels by use of
 630  *                         geometry. So changing geometry will
 631  *                         prevent format from finding backup VTOC labels. To
 632  *                         eliminate this side effect for compatibility,
 633  *                         sd uses (capacity -1) to calculate geometry;
 634  *
 635  *                      4) 1TB disks: some important data structures use
 636  *                         32-bit signed long/int (for example, daddr_t),
 637  *                         so that sd doesn't support a disk with capacity
 638  *                         larger than 1TB on 32-bit platform. However,
 639  *                         for exactly 1TB disk, it was treated as (1T - 512)B
 640  *                         in the past, and could have valid Solaris
 641  *                         partitions. To workaround this, if an exactly 1TB
 642  *                         disk has Solaris fdisk partition, it will be allowed
 643  *                         to work with sd.
 644  *
 645  *
 646  *
 647  *                      CMLB_FAKE_LABEL_ONE_PARTITION: create s0 and s2 covering
 648  *                      the entire disk, if there is no valid partition info.
 649  *                      If there is a valid Solaris partition, s0 and s2 will
 650  *                      only cover the entire Solaris partition.
 651  *
 652  *                      CMLB_CREATE_P0_MINOR_NODE: create p0 node covering
 653  *                      the entire disk. Used by lofi to ensure presence of
 654  *                      whole disk device node in case of LOFI_MAP_FILE ioctl.
 655  *
 656  *      cmlbhandle      cmlb handle associated with device
 657  *
 658  *      tg_cookie       cookie from target driver to be passed back to target
 659  *                      driver when we call back to it through tg_ops.
 660  *
 661  * Notes:
 662  *      Assumes a default label based on capacity for non-removable devices.
 663  *      If capacity > 1TB, EFI is assumed otherwise VTOC (default VTOC
 664  *      for the architecture).
 665  *
 666  *      For removable devices, default label type is assumed to be VTOC
 667  *      type. Create minor nodes based on a default label type.
 668  *      Label on the media is not validated.
 669  *      minor number consists of:
 670  *              if _SUNOS_VTOC_8 is defined
 671  *                      lowest 3 bits is taken as partition number
 672  *                      the rest is instance number
 673  *              if _SUNOS_VTOC_16 is defined
 674  *                      lowest 6 bits is taken as partition number
 675  *                      the rest is instance number
 676  *
 677  *
 678  * Return values:
 679  *      0       Success
 680  *      ENXIO   creating minor nodes failed.
 681  *      EINVAL  invalid arg, unsupported tg_ops version
 682  */
 683 int
 684 cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type,
 685     boolean_t is_removable, boolean_t is_hotpluggable, char *node_type,
 686     int alter_behavior, cmlb_handle_t cmlbhandle, void *tg_cookie)
 687 {
 688 
 689         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 690         diskaddr_t      cap;
 691         int             status;
 692 
 693         ASSERT(VALID_BOOLEAN(is_removable));
 694         ASSERT(VALID_BOOLEAN(is_hotpluggable));
 695 
 696         if (tgopsp->tg_version < TG_DK_OPS_VERSION_1)
 697                 return (EINVAL);
 698 
 699         mutex_enter(CMLB_MUTEX(cl));
 700 
 701         CMLB_DEVINFO(cl) = devi;
 702         cl->cmlb_tg_ops = tgopsp;
 703         cl->cl_device_type = device_type;
 704         cl->cl_is_removable = is_removable;
 705         cl->cl_is_hotpluggable = is_hotpluggable;
 706         cl->cl_node_type = node_type;
 707         cl->cl_sys_blocksize = DEV_BSIZE;
 708         cl->cl_f_geometry_is_valid = B_FALSE;
 709         cl->cl_def_labeltype = CMLB_LABEL_VTOC;
 710         cl->cl_alter_behavior = alter_behavior;
 711         cl->cl_reserved = -1;
 712         cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
 713 #if defined(__i386) || defined(__amd64)
 714         cl->cl_logical_drive_count = 0;
 715 #endif
 716 
 717         if (!is_removable) {
 718                 mutex_exit(CMLB_MUTEX(cl));
 719                 status = DK_TG_GETCAP(cl, &cap, tg_cookie);
 720                 mutex_enter(CMLB_MUTEX(cl));
 721                 if (status == 0 && cap > CMLB_EXTVTOC_LIMIT) {
 722                         /* set default EFI if > 2TB */
 723                         cl->cl_def_labeltype = CMLB_LABEL_EFI;
 724                 }
 725         }
 726 
 727         /* create minor nodes based on default label type */
 728         cl->cl_last_labeltype = CMLB_LABEL_UNDEF;
 729         cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
 730 
 731         if (cmlb_create_minor_nodes(cl) != 0) {
 732                 mutex_exit(CMLB_MUTEX(cl));
 733                 return (ENXIO);
 734         }
 735 
 736         /* Define the dynamic properties for devinfo spapshots. */
 737         i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), cmlb_prop_dyn);
 738 
 739         cl->cl_state = CMLB_ATTACHED;
 740 
 741         mutex_exit(CMLB_MUTEX(cl));
 742         return (0);
 743 }
 744 
 745 /*
 746  * cmlb_detach:
 747  *
 748  * Invalidate in-core labeling data and remove all minor nodes for
 749  * the device associate with handle.
 750  *
 751  * Arguments:
 752  *      cmlbhandle      cmlb handle associated with device.
 753  *
 754  *      tg_cookie       cookie from target driver to be passed back to target
 755  *                      driver when we call back to it through tg_ops.
 756  *
 757  */
 758 /*ARGSUSED1*/
 759 void
 760 cmlb_detach(cmlb_handle_t cmlbhandle, void *tg_cookie)
 761 {
 762         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 763 
 764         mutex_enter(CMLB_MUTEX(cl));
 765         cl->cl_def_labeltype = CMLB_LABEL_UNDEF;
 766         cl->cl_f_geometry_is_valid = B_FALSE;
 767         ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
 768         i_ddi_prop_dyn_driver_set(CMLB_DEVINFO(cl), NULL);
 769         cl->cl_state = CMLB_INITED;
 770         mutex_exit(CMLB_MUTEX(cl));
 771 }
 772 
 773 /*
 774  * cmlb_validate:
 775  *
 776  *      Validates label.
 777  *
 778  * Arguments
 779  *      cmlbhandle      cmlb handle associated with device.
 780  *
 781  *      flags           operation flags. used for verbosity control
 782  *
 783  *      tg_cookie       cookie from target driver to be passed back to target
 784  *                      driver when we call back to it through tg_ops.
 785  *
 786  *
 787  * Notes:
 788  *      If new label type is different from the current, adjust minor nodes
 789  *      accordingly.
 790  *
 791  * Return values:
 792  *      0               success
 793  *                      Note: having fdisk but no solaris partition is assumed
 794  *                      success.
 795  *
 796  *      ENOMEM          memory allocation failed
 797  *      EIO             i/o errors during read or get capacity
 798  *      EACCESS         reservation conflicts
 799  *      EINVAL          label was corrupt, or no default label was assumed
 800  *      ENXIO           invalid handle
 801  */
 802 int
 803 cmlb_validate(cmlb_handle_t cmlbhandle, int flags, void *tg_cookie)
 804 {
 805         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 806         int             rval;
 807         int             ret = 0;
 808 
 809         /*
 810          * Temp work-around checking cl for NULL since there is a bug
 811          * in sd_detach calling this routine from taskq_dispatch
 812          * inited function.
 813          */
 814         if (cl == NULL)
 815                 return (ENXIO);
 816 
 817         mutex_enter(CMLB_MUTEX(cl));
 818         if (cl->cl_state < CMLB_ATTACHED) {
 819                 mutex_exit(CMLB_MUTEX(cl));
 820                 return (ENXIO);
 821         }
 822 
 823         rval = cmlb_validate_geometry((struct cmlb_lun *)cmlbhandle, B_TRUE,
 824             flags, tg_cookie);
 825 
 826         if (rval == ENOTSUP) {
 827                 if (cl->cl_f_geometry_is_valid) {
 828                         cl->cl_cur_labeltype = CMLB_LABEL_EFI;
 829                         ret = 0;
 830                 } else {
 831                         ret = EINVAL;
 832                 }
 833         } else {
 834                 ret = rval;
 835                 if (ret == 0)
 836                         cl->cl_cur_labeltype = CMLB_LABEL_VTOC;
 837         }
 838 
 839         if (ret == 0)
 840                 (void) cmlb_create_minor_nodes(cl);
 841 
 842         mutex_exit(CMLB_MUTEX(cl));
 843         return (ret);
 844 }
 845 
 846 /*
 847  * cmlb_invalidate:
 848  *      Invalidate in core label data
 849  *
 850  * Arguments:
 851  *      cmlbhandle      cmlb handle associated with device.
 852  *      tg_cookie       cookie from target driver to be passed back to target
 853  *                      driver when we call back to it through tg_ops.
 854  */
 855 /*ARGSUSED1*/
 856 void
 857 cmlb_invalidate(cmlb_handle_t cmlbhandle, void *tg_cookie)
 858 {
 859         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 860 
 861         if (cl == NULL)
 862                 return;
 863 
 864         mutex_enter(CMLB_MUTEX(cl));
 865         cl->cl_f_geometry_is_valid = B_FALSE;
 866         mutex_exit(CMLB_MUTEX(cl));
 867 }
 868 
 869 /*
 870  * cmlb_is_valid
 871  *      Get status on whether the incore label/geom data is valid
 872  *
 873  * Arguments:
 874  *      cmlbhandle      cmlb handle associated with device.
 875  *
 876  * Return values:
 877  *      B_TRUE if incore label/geom data is valid.
 878  *      B_FALSE otherwise.
 879  *
 880  */
 881 
 882 
 883 boolean_t
 884 cmlb_is_valid(cmlb_handle_t cmlbhandle)
 885 {
 886         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 887 
 888         if (cmlbhandle == NULL)
 889                 return (B_FALSE);
 890 
 891         return (cl->cl_f_geometry_is_valid);
 892 
 893 }
 894 
 895 
 896 
 897 /*
 898  * cmlb_close:
 899  *
 900  * Close the device, revert to a default label minor node for the device,
 901  * if it is removable.
 902  *
 903  * Arguments:
 904  *      cmlbhandle      cmlb handle associated with device.
 905  *
 906  *      tg_cookie       cookie from target driver to be passed back to target
 907  *                      driver when we call back to it through tg_ops.
 908  * Return values:
 909  *      0       Success
 910  *      ENXIO   Re-creating minor node failed.
 911  */
 912 /*ARGSUSED1*/
 913 int
 914 cmlb_close(cmlb_handle_t cmlbhandle, void *tg_cookie)
 915 {
 916         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 917 
 918         mutex_enter(CMLB_MUTEX(cl));
 919         cl->cl_f_geometry_is_valid = B_FALSE;
 920 
 921         /* revert to default minor node for this device */
 922         if (ISREMOVABLE(cl)) {
 923                 cl->cl_cur_labeltype = CMLB_LABEL_UNDEF;
 924                 (void) cmlb_create_minor_nodes(cl);
 925         }
 926 
 927         mutex_exit(CMLB_MUTEX(cl));
 928         return (0);
 929 }
 930 
 931 /*
 932  * cmlb_get_devid_block:
 933  *       get the block number where device id is stored.
 934  *
 935  * Arguments:
 936  *      cmlbhandle      cmlb handle associated with device.
 937  *      devidblockp     pointer to block number.
 938  *      tg_cookie       cookie from target driver to be passed back to target
 939  *                      driver when we call back to it through tg_ops.
 940  *
 941  * Notes:
 942  *      It stores the block number of device id in the area pointed to
 943  *      by devidblockp.
 944  *      with the block number of device id.
 945  *
 946  * Return values:
 947  *      0       success
 948  *      EINVAL  device id does not apply to current label type.
 949  */
 950 /*ARGSUSED2*/
 951 int
 952 cmlb_get_devid_block(cmlb_handle_t cmlbhandle, diskaddr_t *devidblockp,
 953     void *tg_cookie)
 954 {
 955         daddr_t                 spc, blk, head, cyl;
 956         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
 957 
 958         mutex_enter(CMLB_MUTEX(cl));
 959         if (cl->cl_state < CMLB_ATTACHED) {
 960                 mutex_exit(CMLB_MUTEX(cl));
 961                 return (EINVAL);
 962         }
 963 
 964         if ((!cl->cl_f_geometry_is_valid) ||
 965             (cl->cl_solaris_size < DK_LABEL_LOC)) {
 966                 mutex_exit(CMLB_MUTEX(cl));
 967                 return (EINVAL);
 968         }
 969 
 970         if (cl->cl_cur_labeltype == CMLB_LABEL_EFI) {
 971                 if (cl->cl_reserved != -1) {
 972                         blk = cl->cl_map[cl->cl_reserved].dkl_cylno;
 973                 } else {
 974                         mutex_exit(CMLB_MUTEX(cl));
 975                         return (EINVAL);
 976                 }
 977         } else {
 978                 /* if the disk is unlabeled, don't write a devid to it */
 979                 if (cl->cl_label_from_media != CMLB_LABEL_VTOC) {
 980                         mutex_exit(CMLB_MUTEX(cl));
 981                         return (EINVAL);
 982                 }
 983 
 984                 /* this geometry doesn't allow us to write a devid */
 985                 if (cl->cl_g.dkg_acyl < 2) {
 986                         mutex_exit(CMLB_MUTEX(cl));
 987                         return (EINVAL);
 988                 }
 989 
 990                 /*
 991                  * Subtract 2 guarantees that the next to last cylinder
 992                  * is used
 993                  */
 994                 cyl  = cl->cl_g.dkg_ncyl  + cl->cl_g.dkg_acyl - 2;
 995                 spc  = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
 996                 head = cl->cl_g.dkg_nhead - 1;
 997                 blk  = cl->cl_solaris_offset +
 998                     (cyl * (spc - cl->cl_g.dkg_apc)) +
 999                     (head * cl->cl_g.dkg_nsect) + 1;
1000         }
1001 
1002         *devidblockp = blk;
1003         mutex_exit(CMLB_MUTEX(cl));
1004         return (0);
1005 }
1006 
1007 /*
1008  * cmlb_partinfo:
1009  *      Get partition info for specified partition number.
1010  *
1011  * Arguments:
1012  *      cmlbhandle      cmlb handle associated with device.
1013  *      part            partition number
1014  *      nblocksp        pointer to number of blocks
1015  *      startblockp     pointer to starting block
1016  *      partnamep       pointer to name of partition
1017  *      tagp            pointer to tag info
1018  *      tg_cookie       cookie from target driver to be passed back to target
1019  *                      driver when we call back to it through tg_ops.
1020  *
1021  *
1022  * Notes:
1023  *      If in-core label is not valid, this functions tries to revalidate
1024  *      the label. If label is valid, it stores the total number of blocks
1025  *      in this partition in the area pointed to by nblocksp, starting
1026  *      block number in area pointed to by startblockp,  pointer to partition
1027  *      name in area pointed to by partnamep, and tag value in area
1028  *      pointed by tagp.
1029  *      For EFI labels, tag value will be set to 0.
1030  *
1031  *      For all nblocksp, startblockp and partnamep, tagp, a value of NULL
1032  *      indicates the corresponding info is not requested.
1033  *
1034  *
1035  * Return values:
1036  *      0       success
1037  *      EINVAL  no valid label or requested partition number is invalid.
1038  *
1039  */
1040 int
1041 cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp,
1042     diskaddr_t *startblockp, char **partnamep, uint16_t *tagp, void *tg_cookie)
1043 {
1044 
1045         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
1046         int rval;
1047 #if defined(__i386) || defined(__amd64)
1048         int ext_part;
1049 #endif
1050 
1051         ASSERT(cl != NULL);
1052         mutex_enter(CMLB_MUTEX(cl));
1053         if (cl->cl_state < CMLB_ATTACHED) {
1054                 mutex_exit(CMLB_MUTEX(cl));
1055                 return (EINVAL);
1056         }
1057 
1058         if (part  < 0 || part >= MAXPART) {
1059                 rval = EINVAL;
1060         } else {
1061                 if (!cl->cl_f_geometry_is_valid)
1062                         (void) cmlb_validate_geometry((struct cmlb_lun *)cl,
1063                             B_FALSE, 0, tg_cookie);
1064 
1065                 if (((!cl->cl_f_geometry_is_valid) ||
1066                     (part < NDKMAP && cl->cl_solaris_size == 0)) &&
1067                     (part != P0_RAW_DISK)) {
1068                         rval = EINVAL;
1069                 } else {
1070                         if (startblockp != NULL)
1071                                 *startblockp = (diskaddr_t)cl->cl_offset[part];
1072 
1073                         if (nblocksp != NULL)
1074                                 *nblocksp = (diskaddr_t)
1075                                     cl->cl_map[part].dkl_nblk;
1076 
1077                         if (tagp != NULL)
1078                                 *tagp =
1079                                     ((cl->cl_cur_labeltype == CMLB_LABEL_EFI) ||
1080                                     (part >= NDKMAP)) ? V_UNASSIGNED :
1081                                     cl->cl_vtoc.v_part[part].p_tag;
1082                         rval = 0;
1083                 }
1084 
1085                 /* consistent with behavior of sd for getting minor name */
1086                 if (partnamep != NULL) {
1087 #if defined(__i386) || defined(__amd64)
1088 #if defined(_FIRMWARE_NEEDS_FDISK)
1089                 if (part > FDISK_P4) {
1090                         ext_part = part-FDISK_P4-1;
1091                         *partnamep = dk_ext_minor_data[ext_part].name;
1092                 } else
1093 #endif
1094 #endif
1095                         *partnamep = dk_minor_data[part].name;
1096                 }
1097 
1098         }
1099 
1100         mutex_exit(CMLB_MUTEX(cl));
1101         return (rval);
1102 }
1103 
1104 /*
1105  * cmlb_efi_label_capacity:
1106  *      Get capacity stored in EFI disk label.
1107  *
1108  * Arguments:
1109  *      cmlbhandle      cmlb handle associated with device.
1110  *      capacity        pointer to capacity stored in EFI disk label.
1111  *      tg_cookie       cookie from target driver to be passed back to target
1112  *                      driver when we call back to it through tg_ops.
1113  *
1114  *
1115  * Notes:
1116  *      If in-core label is not valid, this functions tries to revalidate
1117  *      the label. If label is valid and is an EFI label, it stores the capacity
1118  *      in disk label in the area pointed to by capacity.
1119  *
1120  *
1121  * Return values:
1122  *      0       success
1123  *      EINVAL  no valid EFI label or capacity is NULL.
1124  *
1125  */
1126 int
1127 cmlb_efi_label_capacity(cmlb_handle_t cmlbhandle, diskaddr_t *capacity,
1128     void *tg_cookie)
1129 {
1130         struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
1131         int rval;
1132 
1133         ASSERT(cl != NULL);
1134         mutex_enter(CMLB_MUTEX(cl));
1135         if (cl->cl_state < CMLB_ATTACHED) {
1136                 mutex_exit(CMLB_MUTEX(cl));
1137                 return (EINVAL);
1138         }
1139 
1140         if (!cl->cl_f_geometry_is_valid)
1141                 (void) cmlb_validate_geometry((struct cmlb_lun *)cl, B_FALSE,
1142                     0, tg_cookie);
1143 
1144         if ((!cl->cl_f_geometry_is_valid) || (capacity == NULL) ||
1145             (cl->cl_cur_labeltype != CMLB_LABEL_EFI)) {
1146                 rval = EINVAL;
1147         } else {
1148                 *capacity = (diskaddr_t)cl->cl_map[WD_NODE].dkl_nblk;
1149                 rval = 0;
1150         }
1151 
1152         mutex_exit(CMLB_MUTEX(cl));
1153         return (rval);
1154 }
1155 
1156 /* Caller should make sure Test Unit Ready succeeds before calling this. */
1157 /*ARGSUSED*/
1158 int
1159 cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg,
1160     int flag, cred_t *cred_p, int *rval_p, void *tg_cookie)
1161 {
1162 
1163         int err;
1164         struct cmlb_lun *cl;
1165 
1166         cl = (struct cmlb_lun *)cmlbhandle;
1167 
1168         ASSERT(cl != NULL);
1169 
1170         mutex_enter(CMLB_MUTEX(cl));
1171         if (cl->cl_state < CMLB_ATTACHED) {
1172                 mutex_exit(CMLB_MUTEX(cl));
1173                 return (EIO);
1174         }
1175 
1176         switch (cmd) {
1177                 case DKIOCSEXTVTOC:
1178                 case DKIOCSGEOM:
1179                 case DKIOCSETEFI:
1180                 case DKIOCSMBOOT:
1181 #if defined(__i386) || defined(__amd64)
1182                 case DKIOCSETEXTPART:
1183 #endif
1184                         break;
1185                 case DKIOCSVTOC:
1186 #if defined(__i386) || defined(__amd64)
1187                 case DKIOCPARTINFO:
1188 #endif
1189                         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
1190                                 mutex_exit(CMLB_MUTEX(cl));
1191                                 return (EOVERFLOW);
1192                         }
1193                         break;
1194                 default:
1195                         (void) cmlb_validate_geometry(cl, 1, CMLB_SILENT,
1196                             tg_cookie);
1197 
1198                         switch (cmd) {
1199                         case DKIOCGVTOC:
1200                         case DKIOCGAPART:
1201                         case DKIOCSAPART:
1202 
1203                                 if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
1204                                         /* GPT label on disk */
1205                                         mutex_exit(CMLB_MUTEX(cl));
1206                                         return (ENOTSUP);
1207                                 } else if
1208                                     (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
1209                                         mutex_exit(CMLB_MUTEX(cl));
1210                                         return (EOVERFLOW);
1211                                 }
1212                                 break;
1213 
1214                         case DKIOCGGEOM:
1215                                 if (cl->cl_label_from_media == CMLB_LABEL_EFI) {
1216                                         /* GPT label on disk */
1217                                         mutex_exit(CMLB_MUTEX(cl));
1218                                         return (ENOTSUP);
1219                                 }
1220                                 break;
1221                         default:
1222                                 break;
1223                         }
1224         }
1225 
1226         mutex_exit(CMLB_MUTEX(cl));
1227 
1228         switch (cmd) {
1229         case DKIOCGGEOM:
1230                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGGEOM\n");
1231                 err = cmlb_dkio_get_geometry(cl, (caddr_t)arg, flag, tg_cookie);
1232                 break;
1233 
1234         case DKIOCSGEOM:
1235                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSGEOM\n");
1236                 err = cmlb_dkio_set_geometry(cl, (caddr_t)arg, flag);
1237                 break;
1238 
1239         case DKIOCGAPART:
1240                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGAPART\n");
1241                 err = cmlb_dkio_get_partition(cl, (caddr_t)arg,
1242                     flag, tg_cookie);
1243                 break;
1244 
1245         case DKIOCSAPART:
1246                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSAPART\n");
1247                 err = cmlb_dkio_set_partition(cl, (caddr_t)arg, flag);
1248                 break;
1249 
1250         case DKIOCGVTOC:
1251                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
1252                 err = cmlb_dkio_get_vtoc(cl, (caddr_t)arg, flag, tg_cookie);
1253                 break;
1254 
1255         case DKIOCGEXTVTOC:
1256                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGVTOC\n");
1257                 err = cmlb_dkio_get_extvtoc(cl, (caddr_t)arg, flag, tg_cookie);
1258                 break;
1259 
1260         case DKIOCGETEFI:
1261                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGETEFI\n");
1262                 err = cmlb_dkio_get_efi(cl, (caddr_t)arg, flag, tg_cookie);
1263                 break;
1264 
1265         case DKIOCPARTITION:
1266                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTITION\n");
1267                 err = cmlb_dkio_partition(cl, (caddr_t)arg, flag, tg_cookie);
1268                 break;
1269 
1270         case DKIOCSVTOC:
1271                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
1272                 err = cmlb_dkio_set_vtoc(cl, dev, (caddr_t)arg, flag,
1273                     tg_cookie);
1274                 break;
1275 
1276         case DKIOCSEXTVTOC:
1277                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSVTOC\n");
1278                 err = cmlb_dkio_set_extvtoc(cl, dev, (caddr_t)arg, flag,
1279                     tg_cookie);
1280                 break;
1281 
1282         case DKIOCSETEFI:
1283                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEFI\n");
1284                 err = cmlb_dkio_set_efi(cl, dev, (caddr_t)arg, flag, tg_cookie);
1285                 break;
1286 
1287         case DKIOCGMBOOT:
1288                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCGMBOOT\n");
1289                 err = cmlb_dkio_get_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1290                 break;
1291 
1292         case DKIOCSMBOOT:
1293                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSMBOOT\n");
1294                 err = cmlb_dkio_set_mboot(cl, (caddr_t)arg, flag, tg_cookie);
1295                 break;
1296         case DKIOCG_PHYGEOM:
1297                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_PHYGEOM\n");
1298 #if defined(__i386) || defined(__amd64)
1299                 err = cmlb_dkio_get_phygeom(cl, (caddr_t)arg, flag, tg_cookie);
1300 #else
1301                 err = ENOTTY;
1302 #endif
1303                 break;
1304         case DKIOCG_VIRTGEOM:
1305                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCG_VIRTGEOM\n");
1306 #if defined(__i386) || defined(__amd64)
1307                 err = cmlb_dkio_get_virtgeom(cl, (caddr_t)arg, flag);
1308 #else
1309                 err = ENOTTY;
1310 #endif
1311                 break;
1312         case DKIOCPARTINFO:
1313                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
1314 #if defined(__i386) || defined(__amd64)
1315                 err = cmlb_dkio_partinfo(cl, dev, (caddr_t)arg, flag);
1316 #else
1317                 err = ENOTTY;
1318 #endif
1319                 break;
1320         case DKIOCEXTPARTINFO:
1321                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCPARTINFO");
1322 #if defined(__i386) || defined(__amd64)
1323                 err = cmlb_dkio_extpartinfo(cl, dev, (caddr_t)arg, flag);
1324 #else
1325                 err = ENOTTY;
1326 #endif
1327                 break;
1328 #if defined(__i386) || defined(__amd64)
1329         case DKIOCSETEXTPART:
1330                 cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEXTPART");
1331                 err = cmlb_dkio_set_ext_part(cl, (caddr_t)arg, flag, tg_cookie);
1332                 break;
1333 #endif
1334         default:
1335                 err = ENOTTY;
1336 
1337         }
1338 
1339         /*
1340          * An ioctl that succeeds and changed ('set') size(9P) information
1341          * needs to invalidate the cached devinfo snapshot to avoid having
1342          * old information being returned in a snapshots.
1343          *
1344          * NB: When available, call ddi_change_minor_node() to clear
1345          * SSIZEVALID in specfs vnodes via spec_size_invalidate().
1346          */
1347         if (err == 0) {
1348                 switch (cmd) {
1349                 case DKIOCSGEOM:
1350                 case DKIOCSAPART:
1351                 case DKIOCSVTOC:
1352                 case DKIOCSEXTVTOC:
1353                 case DKIOCSETEFI:
1354                         i_ddi_prop_dyn_cache_invalidate(CMLB_DEVINFO(cl),
1355                             i_ddi_prop_dyn_driver_get(CMLB_DEVINFO(cl)));
1356                 }
1357         }
1358         return (err);
1359 }
1360 
1361 dev_t
1362 cmlb_make_device(struct cmlb_lun *cl)
1363 {
1364         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) {
1365                 return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)),
1366                     ddi_get_instance(
1367                     CMLB_DEVINFO(cl)) << CMLBUNIT_FORCE_P0_SHIFT));
1368         } else {
1369                 return (makedevice(ddi_driver_major(CMLB_DEVINFO(cl)),
1370                     ddi_get_instance(CMLB_DEVINFO(cl)) << CMLBUNIT_SHIFT));
1371         }
1372 }
1373 
1374 /*
1375  * Function: cmlb_check_update_blockcount
1376  *
1377  * Description: If current capacity value is invalid, obtains the
1378  *              current capacity from target driver.
1379  *
1380  * Return Code: 0       success
1381  *              EIO     failure
1382  */
1383 static int
1384 cmlb_check_update_blockcount(struct cmlb_lun *cl, void *tg_cookie)
1385 {
1386         int status;
1387         diskaddr_t capacity;
1388         uint32_t lbasize;
1389 
1390         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1391 
1392         if (cl->cl_f_geometry_is_valid)
1393                 return (0);
1394 
1395         mutex_exit(CMLB_MUTEX(cl));
1396         status = DK_TG_GETCAP(cl, &capacity, tg_cookie);
1397         if (status != 0) {
1398                 mutex_enter(CMLB_MUTEX(cl));
1399                 return (EIO);
1400         }
1401 
1402         status = DK_TG_GETBLOCKSIZE(cl, &lbasize, tg_cookie);
1403         mutex_enter(CMLB_MUTEX(cl));
1404         if (status != 0)
1405                 return (EIO);
1406 
1407         if ((capacity != 0) && (lbasize != 0)) {
1408                 cl->cl_blockcount = capacity;
1409                 cl->cl_tgt_blocksize = lbasize;
1410                 if (!cl->cl_is_removable) {
1411                         cl->cl_sys_blocksize = lbasize;
1412                 }
1413                 return (0);
1414         } else {
1415                 return (EIO);
1416         }
1417 }
1418 
1419 static int
1420 cmlb_create_minor(dev_info_t *dip, char *name, int spec_type,
1421     minor_t minor_num, char *node_type, int flag, boolean_t internal)
1422 {
1423         ASSERT(VALID_BOOLEAN(internal));
1424 
1425         if (internal)
1426                 return (ddi_create_internal_pathname(dip,
1427                     name, spec_type, minor_num));
1428         else
1429                 return (ddi_create_minor_node(dip,
1430                     name, spec_type, minor_num, node_type, flag));
1431 }
1432 
1433 /*
1434  *    Function: cmlb_create_minor_nodes
1435  *
1436  * Description: Create or adjust the minor device nodes for the instance.
1437  *              Minor nodes are created based on default label type,
1438  *              current label type and last label type we created
1439  *              minor nodes based on.
1440  *
1441  *
1442  *   Arguments: cl - driver soft state (unit) structure
1443  *
1444  * Return Code: 0 success
1445  *              ENXIO   failure.
1446  *
1447  *     Context: Kernel thread context
1448  */
1449 static int
1450 cmlb_create_minor_nodes(struct cmlb_lun *cl)
1451 {
1452         struct driver_minor_data        *dmdp;
1453         int                             instance, shift;
1454         char                            name[48];
1455         cmlb_label_t                    newlabeltype;
1456         boolean_t                       internal;
1457 
1458         ASSERT(cl != NULL);
1459         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1460 
1461         internal = VOID2BOOLEAN(
1462             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
1463 
1464         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
1465                 shift = CMLBUNIT_FORCE_P0_SHIFT;
1466         else
1467                 shift = CMLBUNIT_SHIFT;
1468 
1469         /* check the most common case */
1470         if (cl->cl_cur_labeltype != CMLB_LABEL_UNDEF &&
1471             cl->cl_last_labeltype == cl->cl_cur_labeltype) {
1472                 /* do nothing */
1473                 return (0);
1474         }
1475 
1476         if (cl->cl_def_labeltype == CMLB_LABEL_UNDEF) {
1477                 /* we should never get here */
1478                 return (ENXIO);
1479         }
1480 
1481         if (cl->cl_last_labeltype == CMLB_LABEL_UNDEF) {
1482                 /* first time during attach */
1483                 newlabeltype = cl->cl_def_labeltype;
1484 
1485                 instance = ddi_get_instance(CMLB_DEVINFO(cl));
1486 
1487                 /* Create all the minor nodes for this target. */
1488                 dmdp = (newlabeltype == CMLB_LABEL_EFI) ? dk_minor_data_efi :
1489                     dk_minor_data;
1490                 while (dmdp->name != NULL) {
1491 
1492                         (void) sprintf(name, "%s", dmdp->name);
1493 
1494                         if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
1495                             dmdp->type,
1496                             (instance << shift) | dmdp->minor,
1497                             cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
1498                                 /*
1499                                  * Clean up any nodes that may have been
1500                                  * created, in case this fails in the middle
1501                                  * of the loop.
1502                                  */
1503                                 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
1504                                 return (ENXIO);
1505                         }
1506                         dmdp++;
1507                 }
1508                 cl->cl_last_labeltype = newlabeltype;
1509 #if defined(_SUNOS_VTOC_8)
1510                 /*
1511                  * "emulate" p0 device for sparc, used by lofi
1512                  */
1513                 if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE) {
1514                         if (cmlb_create_minor(CMLB_DEVINFO(cl), "q", S_IFBLK,
1515                             (instance << CMLBUNIT_FORCE_P0_SHIFT) | P0_RAW_DISK,
1516                             cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
1517                                 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
1518                                 return (ENXIO);
1519                         }
1520 
1521                         if (cmlb_create_minor(CMLB_DEVINFO(cl), "q,raw",
1522                             S_IFCHR,
1523                             (instance << CMLBUNIT_FORCE_P0_SHIFT) | P0_RAW_DISK,
1524                             cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
1525                                 ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
1526                                 return (ENXIO);
1527                         }
1528                 }
1529 #endif  /* defined(_SUNOS_VTOC_8) */
1530                 return (0);
1531         }
1532 
1533         /* Not first time  */
1534         if (cl->cl_cur_labeltype == CMLB_LABEL_UNDEF) {
1535                 if (cl->cl_last_labeltype != cl->cl_def_labeltype) {
1536                         /* close time, revert to default. */
1537                         newlabeltype = cl->cl_def_labeltype;
1538                 } else {
1539                         /*
1540                          * do nothing since the type for which we last created
1541                          * nodes matches the default
1542                          */
1543                         return (0);
1544                 }
1545         } else {
1546                 if (cl->cl_cur_labeltype != cl->cl_last_labeltype) {
1547                         /* We are not closing, use current label type */
1548                         newlabeltype = cl->cl_cur_labeltype;
1549                 } else {
1550                         /*
1551                          * do nothing since the type for which we last created
1552                          * nodes matches the current label type
1553                          */
1554                         return (0);
1555                 }
1556         }
1557 
1558         instance = ddi_get_instance(CMLB_DEVINFO(cl));
1559 
1560         /*
1561          * Currently we only fix up the s7 node when we are switching
1562          * label types from or to EFI. This is consistent with
1563          * current behavior of sd.
1564          */
1565         if (newlabeltype == CMLB_LABEL_EFI &&
1566             cl->cl_last_labeltype != CMLB_LABEL_EFI) {
1567                 /* from vtoc to EFI */
1568                 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
1569                 ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
1570                 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
1571                     S_IFBLK, (instance << shift) | WD_NODE,
1572                     cl->cl_node_type, NULL, internal);
1573                 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
1574                     S_IFCHR, (instance << shift) | WD_NODE,
1575                     cl->cl_node_type, NULL, internal);
1576         } else {
1577                 /* from efi to vtoc */
1578                 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
1579                 ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
1580                 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
1581                     S_IFBLK, (instance << shift) | WD_NODE,
1582                     cl->cl_node_type, NULL, internal);
1583                 (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
1584                     S_IFCHR, (instance << shift) | WD_NODE,
1585                     cl->cl_node_type, NULL, internal);
1586         }
1587 
1588         cl->cl_last_labeltype = newlabeltype;
1589         return (0);
1590 }
1591 
1592 /*
1593  *    Function: cmlb_validate_geometry
1594  *
1595  * Description: Read the label from the disk (if present). Update the unit's
1596  *              geometry and vtoc information from the data in the label.
1597  *              Verify that the label is valid.
1598  *
1599  *   Arguments:
1600  *      cl              driver soft state (unit) structure
1601  *
1602  *      forcerevalid    force revalidation even if we are already valid.
1603  *      flags           operation flags from target driver. Used for verbosity
1604  *                      control at this time.
1605  *      tg_cookie       cookie from target driver to be passed back to target
1606  *                      driver when we call back to it through tg_ops.
1607  *
1608  * Return Code: 0 - Successful completion
1609  *              EINVAL  - Invalid value in cl->cl_tgt_blocksize or
1610  *                        cl->cl_blockcount; or label on disk is corrupted
1611  *                        or unreadable.
1612  *              EACCES  - Reservation conflict at the device.
1613  *              ENOMEM  - Resource allocation error
1614  *              ENOTSUP - geometry not applicable
1615  *
1616  *     Context: Kernel thread only (can sleep).
1617  */
1618 static int
1619 cmlb_validate_geometry(struct cmlb_lun *cl, boolean_t forcerevalid, int flags,
1620     void *tg_cookie)
1621 {
1622         int             label_error = 0;
1623         diskaddr_t      capacity;
1624         int             count;
1625 
1626         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1627         ASSERT(VALID_BOOLEAN(forcerevalid));
1628 
1629         if ((cl->cl_f_geometry_is_valid) && (!forcerevalid)) {
1630                 if (cl->cl_cur_labeltype == CMLB_LABEL_EFI)
1631                         return (ENOTSUP);
1632                 return (0);
1633         }
1634 
1635         if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
1636                 return (EIO);
1637 
1638         capacity = cl->cl_blockcount;
1639 
1640         /*
1641          * Set up the "whole disk" fdisk partition; this should always
1642          * exist, regardless of whether the disk contains an fdisk table
1643          * or vtoc.
1644          */
1645         cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
1646         cl->cl_offset[P0_RAW_DISK] = 0;
1647         /*
1648          * note if capacity > int32_max(1TB) we are in 64bit environment
1649          * so no truncation happens
1650          */
1651         cl->cl_map[P0_RAW_DISK].dkl_nblk  = capacity;
1652 
1653         /*
1654          * Refresh the logical and physical geometry caches.
1655          * (data from MODE SENSE format/rigid disk geometry pages,
1656          * and scsi_ifgetcap("geometry").
1657          */
1658         cmlb_resync_geom_caches(cl, capacity, tg_cookie);
1659 
1660         cl->cl_label_from_media = CMLB_LABEL_UNDEF;
1661         label_error = cmlb_use_efi(cl, capacity, flags, tg_cookie);
1662         if (label_error == 0) {
1663 
1664                 /* found a valid EFI label */
1665                 cmlb_dbg(CMLB_TRACE, cl,
1666                     "cmlb_validate_geometry: found EFI label\n");
1667                 /*
1668                  * solaris_size and geometry_is_valid are set in
1669                  * cmlb_use_efi
1670                  */
1671                 return (ENOTSUP);
1672         }
1673 
1674         /* NO EFI label found */
1675 
1676         if (capacity > CMLB_EXTVTOC_LIMIT) {
1677                 if (label_error == ESRCH) {
1678                         /*
1679                          * they've configured a LUN over 2TB, but used
1680                          * format.dat to restrict format's view of the
1681                          * capacity to be under 2TB in some earlier Solaris
1682                          * release.
1683                          */
1684                         /* i.e > 2TB with a VTOC < 2TB */
1685                         if (!(flags & CMLB_SILENT) &&
1686                             (cl->cl_msglog_flag & CMLB_ALLOW_2TB_WARN)) {
1687 
1688                                 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
1689                                     CE_NOTE, "!Disk (%s%d) is limited to 2 TB "
1690                                     "due to VTOC label. To use the full "
1691                                     "capacity of the disk, use format(1M) to "
1692                                     "relabel the disk with EFI/GPT label.\n",
1693                                     CMLB_LABEL(cl),
1694                                     ddi_get_instance(CMLB_DEVINFO(cl)));
1695 
1696                                 cl->cl_msglog_flag &= ~CMLB_ALLOW_2TB_WARN;
1697                         }
1698                 } else {
1699                                 return (ENOTSUP);
1700                 }
1701         }
1702 
1703         label_error = 0;
1704 
1705         /*
1706          * at this point it is either labeled with a VTOC or it is
1707          * under 1TB (<= 1TB actually for off-by-1)
1708          */
1709 
1710         /*
1711          * Only DIRECT ACCESS devices will have Scl labels.
1712          * CD's supposedly have a Scl label, too
1713          */
1714         if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
1715                 struct  dk_label *dkl;
1716                 offset_t label_addr;
1717                 int     rval;
1718                 size_t  buffer_size;
1719 
1720                 /*
1721                  * Note: This will set up cl->cl_solaris_size and
1722                  * cl->cl_solaris_offset.
1723                  */
1724                 rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
1725                 if ((rval != 0) && !ISCD(cl)) {
1726                         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1727                         return (rval);
1728                 }
1729 
1730                 if (cl->cl_solaris_size <= DK_LABEL_LOC) {
1731                         /*
1732                          * Found fdisk table but no Solaris partition entry,
1733                          * so don't call cmlb_uselabel() and don't create
1734                          * a default label.
1735                          */
1736                         label_error = 0;
1737                         cl->cl_f_geometry_is_valid = B_TRUE;
1738                         goto no_solaris_partition;
1739                 }
1740 
1741                 label_addr = (daddr_t)(cl->cl_solaris_offset + DK_LABEL_LOC);
1742 
1743                 buffer_size = cl->cl_sys_blocksize;
1744 
1745                 cmlb_dbg(CMLB_TRACE, cl, "cmlb_validate_geometry: "
1746                     "label_addr: 0x%x allocation size: 0x%x\n",
1747                     label_addr, buffer_size);
1748 
1749                 if ((dkl = kmem_zalloc(buffer_size, KM_NOSLEEP)) == NULL)
1750                         return (ENOMEM);
1751 
1752                 mutex_exit(CMLB_MUTEX(cl));
1753                 rval = DK_TG_READ(cl, dkl, label_addr, buffer_size, tg_cookie);
1754                 mutex_enter(CMLB_MUTEX(cl));
1755 
1756                 switch (rval) {
1757                 case 0:
1758                         /*
1759                          * cmlb_uselabel will establish that the geometry
1760                          * is valid.
1761                          */
1762                         if (cmlb_uselabel(cl,
1763                             (struct dk_label *)(uintptr_t)dkl, flags) !=
1764                             CMLB_LABEL_IS_VALID) {
1765                                 label_error = EINVAL;
1766                         } else
1767                                 cl->cl_label_from_media = CMLB_LABEL_VTOC;
1768                         break;
1769                 case EACCES:
1770                         label_error = EACCES;
1771                         break;
1772                 default:
1773                         label_error = EINVAL;
1774                         break;
1775                 }
1776 
1777                 kmem_free(dkl, buffer_size);
1778         }
1779 
1780         /*
1781          * If a valid label was not found, AND if no reservation conflict
1782          * was detected, then go ahead and create a default label (4069506).
1783          *
1784          * Note: currently, for VTOC_8 devices, the default label is created
1785          * for removables and hotpluggables only.  For VTOC_16 devices, the
1786          * default label will be created for all devices.
1787          * (see cmlb_build_default_label)
1788          */
1789 #if defined(_SUNOS_VTOC_8)
1790         if ((ISREMOVABLE(cl) || ISHOTPLUGGABLE(cl)) &&
1791             (label_error != EACCES)) {
1792 #elif defined(_SUNOS_VTOC_16)
1793         if (label_error != EACCES) {
1794 #endif
1795                 if (!cl->cl_f_geometry_is_valid) {
1796                         cmlb_build_default_label(cl, tg_cookie);
1797                 }
1798                 label_error = 0;
1799         }
1800 
1801 no_solaris_partition:
1802 
1803 #if defined(_SUNOS_VTOC_16)
1804         /*
1805          * If we have valid geometry, set up the remaining fdisk partitions.
1806          * Note that dkl_cylno is not used for the fdisk map entries, so
1807          * we set it to an entirely bogus value.
1808          */
1809         for (count = 0; count < FDISK_PARTS; count++) {
1810                 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX;
1811                 cl->cl_map[FDISK_P1 + count].dkl_nblk =
1812                     cl->cl_fmap[count].fmap_nblk;
1813 
1814                 cl->cl_offset[FDISK_P1 + count] =
1815                     cl->cl_fmap[count].fmap_start;
1816         }
1817 #endif
1818 
1819         for (count = 0; count < NDKMAP; count++) {
1820 #if defined(_SUNOS_VTOC_8)
1821                 struct dk_map *lp  = &cl->cl_map[count];
1822                 cl->cl_offset[count] =
1823                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
1824 #elif defined(_SUNOS_VTOC_16)
1825                 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
1826 
1827                 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
1828 #else
1829 #error "No VTOC format defined."
1830 #endif
1831         }
1832 
1833         return (label_error);
1834 }
1835 
1836 #if defined(_SUNOS_VTOC_16)
1837 /*
1838  *    Function: cmlb_convert_geometry
1839  *
1840  * Description: Convert physical geometry into a dk_geom structure. In
1841  *              other words, make sure we don't wrap 16-bit values.
1842  *              e.g. converting from geom_cache to dk_geom
1843  *
1844  *     Context: Kernel thread only
1845  */
1846 static void
1847 cmlb_convert_geometry(struct cmlb_lun *cl, diskaddr_t capacity,
1848     struct dk_geom *cl_g, void *tg_cookie)
1849 {
1850 
1851         ASSERT(cl != NULL);
1852         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1853 
1854         /* Unlabeled SCSI floppy device */
1855         if (capacity < 160) {
1856                 /* Less than 80K */
1857                 cl_g->dkg_nhead = 1;
1858                 cl_g->dkg_ncyl = capacity;
1859                 cl_g->dkg_nsect = 1;
1860                 return;
1861         } else if (capacity <= 0x1000) {
1862                 cl_g->dkg_nhead = 2;
1863                 cl_g->dkg_ncyl = 80;
1864                 cl_g->dkg_nsect = capacity / (cl_g->dkg_nhead * cl_g->dkg_ncyl);
1865                 return;
1866         }
1867 
1868         /*
1869          * For all devices we calculate cylinders using the heads and sectors
1870          * we assign based on capacity of the device.  The algorithm is
1871          * designed to be compatible with the way other operating systems
1872          * lay out fdisk tables for X86 and to insure that the cylinders never
1873          * exceed 65535 to prevent problems with X86 ioctls that report
1874          * geometry.
1875          * For some smaller disk sizes we report geometry that matches those
1876          * used by X86 BIOS usage. For larger disks, we use SPT that are
1877          * multiples of 63, since other OSes that are not limited to 16-bits
1878          * for cylinders stop at 63 SPT we make do by using multiples of 63 SPT.
1879          *
1880          * The following table (in order) illustrates some end result
1881          * calculations:
1882          *
1883          * Maximum number of blocks             nhead   nsect
1884          *
1885          * 2097152 (1GB)                        64      32
1886          * 16777216 (8GB)                       128     32
1887          * 1052819775 (502.02GB)                255     63
1888          * 2105639550 (0.98TB)                  255     126
1889          * 3158459325 (1.47TB)                  255     189
1890          * 4211279100 (1.96TB)                  255     252
1891          * 5264098875 (2.45TB)                  255     315
1892          * ...
1893          *
1894          * For Solid State Drive(SSD), it uses 4K page size inside and may be
1895          * double with every new generation. If the I/O is not aligned with
1896          * page size on SSDs, SSDs perform a lot slower.
1897          * By default, Solaris partition starts from cylinder 1. It will be
1898          * misaligned even with 4K if using heads(255) and SPT(63). To
1899          * workaround the problem, if the device is SSD, we use heads(224) and
1900          * SPT multiple of 56. Thus the default Solaris partition starts from
1901          * a position that aligns with 128K on a 512 bytes sector size SSD.
1902          */
1903 
1904         if (capacity <= 0x200000) {
1905                 cl_g->dkg_nhead = 64;
1906                 cl_g->dkg_nsect = 32;
1907         } else if (capacity <= 0x01000000) {
1908                 cl_g->dkg_nhead = 128;
1909                 cl_g->dkg_nsect = 32;
1910         } else {
1911                 tg_attribute_t tgattribute;
1912                 int is_solid_state;
1913                 unsigned short nhead;
1914                 unsigned short nsect;
1915 
1916                 bzero(&tgattribute, sizeof (tg_attribute_t));
1917 
1918                 mutex_exit(CMLB_MUTEX(cl));
1919                 is_solid_state =
1920                     (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
1921                     tgattribute.media_is_solid_state : FALSE;
1922                 mutex_enter(CMLB_MUTEX(cl));
1923 
1924                 if (is_solid_state) {
1925                         nhead = 224;
1926                         nsect = 56;
1927                 } else {
1928                         nhead = 255;
1929                         nsect = 63;
1930                 }
1931 
1932                 cl_g->dkg_nhead = nhead;
1933 
1934                 /* make dkg_nsect be smallest multiple of nsect */
1935                 cl_g->dkg_nsect = ((capacity +
1936                     (UINT16_MAX * nhead * nsect) - 1) /
1937                     (UINT16_MAX * nhead * nsect)) * nsect;
1938 
1939                 if (cl_g->dkg_nsect == 0)
1940                         cl_g->dkg_nsect = (UINT16_MAX / nsect) * nsect;
1941         }
1942 
1943 }
1944 #endif
1945 
1946 /*
1947  *    Function: cmlb_resync_geom_caches
1948  *
1949  * Description: (Re)initialize both geometry caches: the virtual geometry
1950  *            information is extracted from the HBA (the "geometry"
1951  *            capability), and the physical geometry cache data is
1952  *            generated by issuing MODE SENSE commands.
1953  *
1954  *   Arguments:
1955  *      cl              driver soft state (unit) structure
1956  *      capacity        disk capacity in #blocks
1957  *      tg_cookie       cookie from target driver to be passed back to target
1958  *                      driver when we call back to it through tg_ops.
1959  *
1960  *     Context: Kernel thread only (can sleep).
1961  */
1962 static void
1963 cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
1964     void *tg_cookie)
1965 {
1966         struct  cmlb_geom       pgeom;
1967         struct  cmlb_geom       lgeom;
1968         struct  cmlb_geom       *pgeomp = &pgeom;
1969         unsigned short          nhead;
1970         unsigned short          nsect;
1971         int                     spc;
1972         int                     ret;
1973 
1974         ASSERT(cl != NULL);
1975         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
1976 
1977         /*
1978          * Ask the controller for its logical geometry.
1979          * Note: if the HBA does not support scsi_ifgetcap("geometry"),
1980          * then the lgeom cache will be invalid.
1981          */
1982         mutex_exit(CMLB_MUTEX(cl));
1983         bzero(&lgeom, sizeof (struct cmlb_geom));
1984         ret = DK_TG_GETVIRTGEOM(cl, &lgeom, tg_cookie);
1985         mutex_enter(CMLB_MUTEX(cl));
1986 
1987         bcopy(&lgeom, &cl->cl_lgeom, sizeof (cl->cl_lgeom));
1988 
1989         /*
1990          * Initialize the pgeom cache from lgeom, so that if MODE SENSE
1991          * doesn't work, DKIOCG_PHYSGEOM can return reasonable values.
1992          */
1993         if (ret != 0 || cl->cl_lgeom.g_nsect == 0 ||
1994             cl->cl_lgeom.g_nhead == 0) {
1995                 /*
1996                  * Note: Perhaps this needs to be more adaptive? The rationale
1997                  * is that, if there's no HBA geometry from the HBA driver, any
1998                  * guess is good, since this is the physical geometry. If MODE
1999                  * SENSE fails this gives a max cylinder size for non-LBA access
2000                  */
2001                 nhead = 255;
2002                 nsect = 63;
2003         } else {
2004                 nhead = cl->cl_lgeom.g_nhead;
2005                 nsect = cl->cl_lgeom.g_nsect;
2006         }
2007 
2008         if (ISCD(cl)) {
2009                 pgeomp->g_nhead = 1;
2010                 pgeomp->g_nsect = nsect * nhead;
2011         } else {
2012                 pgeomp->g_nhead = nhead;
2013                 pgeomp->g_nsect = nsect;
2014         }
2015 
2016         spc = pgeomp->g_nhead * pgeomp->g_nsect;
2017         pgeomp->g_capacity = capacity;
2018         if (spc == 0)
2019                 pgeomp->g_ncyl = 0;
2020         else
2021                 pgeomp->g_ncyl = pgeomp->g_capacity / spc;
2022         pgeomp->g_acyl = 0;
2023 
2024         /*
2025          * Retrieve fresh geometry data from the hardware, stash it
2026          * here temporarily before we rebuild the incore label.
2027          *
2028          * We want to use the MODE SENSE commands to derive the
2029          * physical geometry of the device, but if either command
2030          * fails, the logical geometry is used as the fallback for
2031          * disk label geometry.
2032          */
2033 
2034         mutex_exit(CMLB_MUTEX(cl));
2035         (void) DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
2036         mutex_enter(CMLB_MUTEX(cl));
2037 
2038         /*
2039          * Now update the real copy while holding the mutex. This
2040          * way the global copy is never in an inconsistent state.
2041          */
2042         bcopy(pgeomp, &cl->cl_pgeom,  sizeof (cl->cl_pgeom));
2043 
2044         cmlb_dbg(CMLB_INFO, cl, "cmlb_resync_geom_caches: "
2045             "(cached from lgeom)\n");
2046         cmlb_dbg(CMLB_INFO,  cl,
2047             "   ncyl: %ld; acyl: %d; nhead: %d; nsect: %d\n",
2048             cl->cl_pgeom.g_ncyl, cl->cl_pgeom.g_acyl,
2049             cl->cl_pgeom.g_nhead, cl->cl_pgeom.g_nsect);
2050         cmlb_dbg(CMLB_INFO,  cl, "   lbasize: %d; capacity: %ld; "
2051             "intrlv: %d; rpm: %d\n", cl->cl_pgeom.g_secsize,
2052             cl->cl_pgeom.g_capacity, cl->cl_pgeom.g_intrlv,
2053             cl->cl_pgeom.g_rpm);
2054 }
2055 
2056 
2057 #if defined(__i386) || defined(__amd64)
2058 /*
2059  *    Function: cmlb_update_ext_minor_nodes
2060  *
2061  * Description: Routine to add/remove extended partition device nodes
2062  *
2063  *   Arguments:
2064  *      cl              driver soft state (unit) structure
2065  *      num_parts       Number of logical drives found on the LUN
2066  *
2067  * Should be called with the mutex held
2068  *
2069  * Return Code: 0 for success
2070  *
2071  *     Context: User and Kernel thread
2072  *
2073  */
2074 static int
2075 cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts)
2076 {
2077         int                             i, count, shift;
2078         char                            name[48];
2079         int                             instance;
2080         struct driver_minor_data        *demdp, *demdpr;
2081         char                            *devnm;
2082         dev_info_t                      *pdip;
2083         boolean_t                       internal;
2084 
2085         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2086         ASSERT(cl->cl_update_ext_minor_nodes == 1);
2087 
2088         internal = VOID2BOOLEAN(
2089             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
2090         instance = ddi_get_instance(CMLB_DEVINFO(cl));
2091         demdp = dk_ext_minor_data;
2092         demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
2093 
2094         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
2095                 shift = CMLBUNIT_FORCE_P0_SHIFT;
2096         else
2097                 shift = CMLBUNIT_SHIFT;
2098 
2099         if (cl->cl_logical_drive_count) {
2100                 for (i = 0; i < cl->cl_logical_drive_count; i++) {
2101                         (void) sprintf(name, "%s", demdp->name);
2102                         ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
2103                         (void) sprintf(name, "%s", demdpr->name);
2104                         ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
2105                         demdp++;
2106                         demdpr++;
2107                 }
2108                 /* There are existing device nodes. Remove them */
2109                 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
2110                 (void) ddi_deviname(cl->cl_devi, devnm);
2111                 pdip = ddi_get_parent(cl->cl_devi);
2112                 (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
2113                 kmem_free(devnm, MAXNAMELEN + 1);
2114         }
2115 
2116         demdp = dk_ext_minor_data;
2117         demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
2118 
2119         for (i = 0; i < num_parts; i++) {
2120                 (void) sprintf(name, "%s", demdp->name);
2121                 if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
2122                     demdp->type,
2123                     (instance << shift) | demdp->minor,
2124                     cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
2125                         /*
2126                          * Clean up any nodes that may have been
2127                          * created, in case this fails in the middle
2128                          * of the loop.
2129                          */
2130                         ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
2131                         cl->cl_logical_drive_count = 0;
2132                         return (ENXIO);
2133                 }
2134                 (void) sprintf(name, "%s", demdpr->name);
2135                 if (ddi_create_minor_node(CMLB_DEVINFO(cl), name,
2136                     demdpr->type,
2137                     (instance << shift) | demdpr->minor,
2138                     cl->cl_node_type, NULL) == DDI_FAILURE) {
2139                         /*
2140                          * Clean up any nodes that may have been
2141                          * created, in case this fails in the middle
2142                          * of the loop.
2143                          */
2144                         ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
2145                         cl->cl_logical_drive_count = 0;
2146                         return (ENXIO);
2147                 }
2148                 demdp++;
2149                 demdpr++;
2150         }
2151 
2152         /* Update the cl_map array for logical drives */
2153         for (count = 0; count < MAX_EXT_PARTS; count++) {
2154                 cl->cl_map[FDISK_P4 + 1 + count].dkl_cylno = UINT32_MAX;
2155                 cl->cl_map[FDISK_P4 + 1 + count].dkl_nblk =
2156                     cl->cl_fmap[FD_NUMPART + count].fmap_nblk;
2157                 cl->cl_offset[FDISK_P4 + 1 + count] =
2158                     cl->cl_fmap[FD_NUMPART + count].fmap_start;
2159         }
2160 
2161         cl->cl_logical_drive_count = i;
2162         cl->cl_update_ext_minor_nodes = 0;
2163         return (0);
2164 }
2165 /*
2166  *    Function: cmlb_validate_ext_part
2167  *
2168  * Description: utility routine to validate an extended partition's
2169  *              metadata as found on disk
2170  *
2171  *   Arguments:
2172  *      cl              driver soft state (unit) structure
2173  *      part            partition number of the extended partition
2174  *      epart           partition number of the logical drive
2175  *      start           absolute sector number of the start of the logical
2176  *                      drive being validated
2177  *      size            size of logical drive being validated
2178  *
2179  * Return Code: 0 for success
2180  *
2181  *     Context: User and Kernel thread
2182  *
2183  * Algorithm :
2184  * Error cases are :
2185  *      1. If start block is lesser than or equal to the end block
2186  *      2. If either start block or end block is beyond the bounadry
2187  *         of the extended partition.
2188  *      3. start or end block overlap with existing partitions.
2189  *              To check this, first make sure that the start block doesnt
2190  *              overlap with existing partitions. Then, calculate the
2191  *              possible end block for the given start block that doesnt
2192  *              overlap with existing partitions. This can be calculated by
2193  *              first setting the possible end block to the end of the
2194  *              extended partition (optimistic) and then, checking if there
2195  *              is any other partition that lies after the start of the
2196  *              partition being validated. If so, set the possible end to
2197  *              one block less than the beginning of the next nearest partition
2198  *              If the actual end block is greater than the calculated end
2199  *              block, we have an overlap.
2200  *
2201  */
2202 static int
2203 cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, uint32_t start,
2204     uint32_t size)
2205 {
2206         int i;
2207         uint32_t end = start + size - 1;
2208         uint32_t ext_start = cl->cl_fmap[part].fmap_start;
2209         uint32_t ext_end = ext_start + cl->cl_fmap[part].fmap_nblk - 1;
2210         uint32_t ts, te;
2211         uint32_t poss_end = ext_end;
2212 
2213         if (end <= start) {
2214                 return (1);
2215         }
2216 
2217         /*
2218          * Check if the logical drive boundaries are within that of the
2219          * extended partition.
2220          */
2221         if (start <= ext_start || start > ext_end || end <= ext_start ||
2222             end > ext_end) {
2223                 return (1);
2224         }
2225 
2226         /*
2227          * epart will be equal to FD_NUMPART if it is the first logical drive.
2228          * There is no need to check for overlaps with other logical drives,
2229          * since it is the only logical drive that we have come across so far.
2230          */
2231         if (epart == FD_NUMPART) {
2232                 return (0);
2233         }
2234 
2235         /* Check for overlaps with existing logical drives */
2236         i = FD_NUMPART;
2237         ts = cl->cl_fmap[FD_NUMPART].fmap_start;
2238         te = ts + cl->cl_fmap[FD_NUMPART].fmap_nblk - 1;
2239 
2240         while ((i < epart) && ts && te) {
2241                 if (start >= ts && start <= te) {
2242                         return (1);
2243                 }
2244 
2245                 if ((ts < poss_end) && (ts > start)) {
2246                         poss_end = ts - 1;
2247                 }
2248 
2249                 i++;
2250                 ts = cl->cl_fmap[i].fmap_start;
2251                 te = ts + cl->cl_fmap[i].fmap_nblk - 1;
2252         }
2253 
2254         if (end > poss_end) {
2255                 return (1);
2256         }
2257 
2258         return (0);
2259 }
2260 
2261 
2262 /*
2263  *    Function: cmlb_is_linux_swap
2264  *
2265  * Description: utility routine to verify if a partition is a linux swap
2266  *              partition or not.
2267  *
2268  *   Arguments:
2269  *      cl              driver soft state (unit) structure
2270  *      part_start      absolute sector number of the start of the partition
2271  *                      being verified
2272  *      tg_cookie       cookie from target driver to be passed back to target
2273  *                      driver when we call back to it through tg_ops.
2274  *
2275  * Return Code: 0 for success
2276  *
2277  *     Context: User and Kernel thread
2278  *
2279  * Notes:
2280  *      The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
2281  *      last 10 bytes of a disk block whose size is that of the linux page
2282  *      size. This disk block is found at the beginning of the swap partition.
2283  */
2284 static int
2285 cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, void *tg_cookie)
2286 {
2287         int             i;
2288         int             rval = -1;
2289         uint32_t        seek_offset;
2290         uint32_t        linux_pg_size;
2291         char            *buf, *linux_swap_magic;
2292         int             sec_sz = cl->cl_sys_blocksize;
2293         /* Known linux kernel page sizes */
2294         uint32_t        linux_pg_size_arr[] = {4096, };
2295 
2296         ASSERT(cl != NULL);
2297         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2298 
2299         if ((buf = kmem_zalloc(sec_sz, KM_NOSLEEP)) == NULL) {
2300                 return (ENOMEM);
2301         }
2302 
2303         /*
2304          * Check if there is a sane Solaris VTOC
2305          * If there is a valid vtoc, no need to lookup
2306          * for the linux swap signature.
2307          */
2308         mutex_exit(CMLB_MUTEX(cl));
2309         rval = DK_TG_READ(cl, buf, part_start + DK_LABEL_LOC,
2310             sec_sz, tg_cookie);
2311         mutex_enter(CMLB_MUTEX(cl));
2312         if (rval != 0) {
2313                 cmlb_dbg(CMLB_ERROR,  cl,
2314                     "cmlb_is_linux_swap: disk vtoc read err\n");
2315                 rval = EIO;
2316                 goto done;
2317         }
2318 
2319         if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) &&
2320             (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) {
2321                 rval = -1;
2322                 goto done;
2323         }
2324 
2325 
2326         /* No valid vtoc, so check for linux swap signature */
2327         linux_swap_magic = buf + sec_sz - 10;
2328 
2329         for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
2330                 linux_pg_size = linux_pg_size_arr[i];
2331                 seek_offset = linux_pg_size/sec_sz - 1;
2332                 seek_offset += part_start;
2333 
2334                 mutex_exit(CMLB_MUTEX(cl));
2335                 rval = DK_TG_READ(cl, buf, seek_offset, sec_sz, tg_cookie);
2336                 mutex_enter(CMLB_MUTEX(cl));
2337 
2338                 if (rval != 0) {
2339                         cmlb_dbg(CMLB_ERROR,  cl,
2340                             "cmlb_is_linux_swap: disk read err\n");
2341                         rval = EIO;
2342                         break;
2343                 }
2344 
2345                 rval = -1;
2346 
2347                 if ((strncmp(linux_swap_magic, "SWAP-SPACE", 10) == 0) ||
2348                     (strncmp(linux_swap_magic, "SWAPSPACE2", 10) == 0)) {
2349                         /* Found a linux swap */
2350                         rval = 0;
2351                         break;
2352                 }
2353         }
2354 
2355 done:
2356         kmem_free(buf, sec_sz);
2357         return (rval);
2358 }
2359 #endif
2360 
2361 /*
2362  *    Function: cmlb_read_fdisk
2363  *
2364  * Description: utility routine to read the fdisk table.
2365  *
2366  *   Arguments:
2367  *      cl              driver soft state (unit) structure
2368  *      capacity        disk capacity in #blocks
2369  *      tg_cookie       cookie from target driver to be passed back to target
2370  *                      driver when we call back to it through tg_ops.
2371  *
2372  * Return Code: 0 for success (includes not reading for no_fdisk_present case
2373  *              errnos from tg_rw if failed to read the first block.
2374  *
2375  *     Context: Kernel thread only (can sleep).
2376  */
2377 /*ARGSUSED*/
2378 static int
2379 cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
2380 {
2381 #if defined(_NO_FDISK_PRESENT)
2382 
2383         cl->cl_solaris_offset = 0;
2384         cl->cl_solaris_size = capacity;
2385         bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2386         return (0);
2387 
2388 #elif defined(_FIRMWARE_NEEDS_FDISK)
2389 
2390         struct ipart    *fdp;
2391         struct mboot    *mbp;
2392         struct ipart    fdisk[FD_NUMPART];
2393         int             i, k;
2394         char            sigbuf[2];
2395         caddr_t         bufp;
2396         int             uidx;
2397         int             rval;
2398         int             lba = 0;
2399         uint_t          solaris_offset; /* offset to solaris part. */
2400         daddr_t         solaris_size;   /* size of solaris partition */
2401         uint32_t        blocksize;
2402 #if defined(__i386) || defined(__amd64)
2403         struct ipart    eparts[2];
2404         struct ipart    *efdp1 = &eparts[0];
2405         struct ipart    *efdp2 = &eparts[1];
2406         int             ext_part_exists = 0;
2407         int             ld_count = 0;
2408 #endif
2409 
2410         ASSERT(cl != NULL);
2411         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2412 
2413         /*
2414          * Start off assuming no fdisk table
2415          */
2416         solaris_offset = 0;
2417         solaris_size   = capacity;
2418 
2419         blocksize = cl->cl_tgt_blocksize;
2420 
2421         bufp = kmem_zalloc(blocksize, KM_SLEEP);
2422 
2423         mutex_exit(CMLB_MUTEX(cl));
2424         rval = DK_TG_READ(cl, bufp, 0, blocksize, tg_cookie);
2425         mutex_enter(CMLB_MUTEX(cl));
2426 
2427         if (rval != 0) {
2428                 cmlb_dbg(CMLB_ERROR,  cl,
2429                     "cmlb_read_fdisk: fdisk read err\n");
2430                 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2431                 goto done;
2432         }
2433 
2434         mbp = (struct mboot *)bufp;
2435 
2436         /*
2437          * The fdisk table does not begin on a 4-byte boundary within the
2438          * master boot record, so we copy it to an aligned structure to avoid
2439          * alignment exceptions on some processors.
2440          */
2441         bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2442 
2443         /*
2444          * Check for lba support before verifying sig; sig might not be
2445          * there, say on a blank disk, but the max_chs mark may still
2446          * be present.
2447          *
2448          * Note: LBA support and BEFs are an x86-only concept but this
2449          * code should work OK on SPARC as well.
2450          */
2451 
2452         /*
2453          * First, check for lba-access-ok on root node (or prom root node)
2454          * if present there, don't need to search fdisk table.
2455          */
2456         if (ddi_getprop(DDI_DEV_T_ANY, ddi_root_node(), 0,
2457             "lba-access-ok", 0) != 0) {
2458                 /* All drives do LBA; don't search fdisk table */
2459                 lba = 1;
2460         } else {
2461                 /* Okay, look for mark in fdisk table */
2462                 for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2463                         /* accumulate "lba" value from all partitions */
2464                         lba = (lba || cmlb_has_max_chs_vals(fdp));
2465                 }
2466         }
2467 
2468         if (lba != 0) {
2469                 dev_t dev = cmlb_make_device(cl);
2470 
2471                 if (ddi_getprop(dev, CMLB_DEVINFO(cl), DDI_PROP_DONTPASS,
2472                     "lba-access-ok", 0) == 0) {
2473                         /* not found; create it */
2474                         if (ddi_prop_create(dev, CMLB_DEVINFO(cl), 0,
2475                             "lba-access-ok", (caddr_t)NULL, 0) !=
2476                             DDI_PROP_SUCCESS) {
2477                                 cmlb_dbg(CMLB_ERROR,  cl,
2478                                     "cmlb_read_fdisk: Can't create lba "
2479                                     "property for instance %d\n",
2480                                     ddi_get_instance(CMLB_DEVINFO(cl)));
2481                         }
2482                 }
2483         }
2484 
2485         bcopy(&mbp->signature, sigbuf, sizeof (sigbuf));
2486 
2487         /*
2488          * Endian-independent signature check
2489          */
2490         if (((sigbuf[1] & 0xFF) != ((MBB_MAGIC >> 8) & 0xFF)) ||
2491             (sigbuf[0] != (MBB_MAGIC & 0xFF))) {
2492                 cmlb_dbg(CMLB_ERROR,  cl,
2493                     "cmlb_read_fdisk: no fdisk\n");
2494                 bzero(cl->cl_fmap, sizeof (struct fmap) * FD_NUMPART);
2495                 goto done;
2496         }
2497 
2498 #ifdef CMLBDEBUG
2499         if (cmlb_level_mask & CMLB_LOGMASK_INFO) {
2500                 fdp = fdisk;
2501                 cmlb_dbg(CMLB_INFO,  cl, "cmlb_read_fdisk:\n");
2502                 cmlb_dbg(CMLB_INFO,  cl, "         relsect    "
2503                     "numsect         sysid       bootid\n");
2504                 for (i = 0; i < FD_NUMPART; i++, fdp++) {
2505                         cmlb_dbg(CMLB_INFO,  cl,
2506                             "    %d:  %8d   %8d     0x%08x     0x%08x\n",
2507                             i, fdp->relsect, fdp->numsect,
2508                             fdp->systid, fdp->bootid);
2509                 }
2510         }
2511 #endif
2512 
2513         /*
2514          * Try to find the unix partition
2515          */
2516         uidx = -1;
2517         solaris_offset = 0;
2518         solaris_size   = 0;
2519 
2520         for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2521                 uint32_t relsect;
2522                 uint32_t numsect;
2523                 uchar_t systid;
2524 #if defined(__i386) || defined(__amd64)
2525                 /*
2526                  * Stores relative block offset from the beginning of the
2527                  * Extended Partition.
2528                  */
2529                 int     ext_relsect = 0;
2530 #endif
2531 
2532                 if (fdp->numsect == 0) {
2533                         cl->cl_fmap[i].fmap_start = 0;
2534                         cl->cl_fmap[i].fmap_nblk  = 0;
2535                         continue;
2536                 }
2537 
2538                 /*
2539                  * Data in the fdisk table is little-endian.
2540                  */
2541                 relsect = LE_32(fdp->relsect);
2542                 numsect = LE_32(fdp->numsect);
2543 
2544                 cl->cl_fmap[i].fmap_start = relsect;
2545                 cl->cl_fmap[i].fmap_nblk  = numsect;
2546                 cl->cl_fmap[i].fmap_systid = LE_8(fdp->systid);
2547 
2548 #if defined(__i386) || defined(__amd64)
2549                 /* Support only one extended partition per LUN */
2550                 if ((fdp->systid == EXTDOS || fdp->systid == FDISK_EXTLBA) &&
2551                     (ext_part_exists == 0)) {
2552                         int j;
2553                         uint32_t logdrive_offset;
2554                         uint32_t ext_numsect;
2555                         uint32_t abs_secnum;
2556 
2557                         ext_part_exists = 1;
2558 
2559                         for (j = FD_NUMPART; j < FDISK_PARTS; j++) {
2560                                 mutex_exit(CMLB_MUTEX(cl));
2561                                 rval = DK_TG_READ(cl, bufp,
2562                                     (relsect + ext_relsect), blocksize,
2563                                     tg_cookie);
2564                                 mutex_enter(CMLB_MUTEX(cl));
2565 
2566                                 if (rval != 0) {
2567                                         cmlb_dbg(CMLB_ERROR,  cl,
2568                                             "cmlb_read_fdisk: Extended "
2569                                             "partition read err\n");
2570                                         goto done;
2571                                 }
2572                                 /*
2573                                  * The first ipart entry provides the offset
2574                                  * at which the logical drive starts off from
2575                                  * the beginning of the container partition
2576                                  * and the size of the logical drive.
2577                                  * The second ipart entry provides the offset
2578                                  * of the next container partition from the
2579                                  * beginning of the extended partition.
2580                                  */
2581                                 bcopy(&bufp[FDISK_PART_TABLE_START], eparts,
2582                                     sizeof (eparts));
2583                                 logdrive_offset = LE_32(efdp1->relsect);
2584                                 ext_numsect = LE_32(efdp1->numsect);
2585                                 systid = LE_8(efdp1->systid);
2586                                 if (logdrive_offset <= 0 || ext_numsect <= 0)
2587                                         break;
2588                                 abs_secnum = relsect + ext_relsect +
2589                                     logdrive_offset;
2590 
2591                                 /* Boundary condition and overlap checking */
2592                                 if (cmlb_validate_ext_part(cl, i, j, abs_secnum,
2593                                     ext_numsect)) {
2594                                         break;
2595                                 }
2596 
2597                                 if ((cl->cl_fmap[j].fmap_start != abs_secnum) ||
2598                                     (cl->cl_fmap[j].fmap_nblk != ext_numsect) ||
2599                                     (cl->cl_fmap[j].fmap_systid != systid)) {
2600                                         /*
2601                                          * Indicates change from previous
2602                                          * partinfo. Need to recreate
2603                                          * logical device nodes.
2604                                          */
2605                                         cl->cl_update_ext_minor_nodes = 1;
2606                                 }
2607                                 cl->cl_fmap[j].fmap_start = abs_secnum;
2608                                 cl->cl_fmap[j].fmap_nblk  = ext_numsect;
2609                                 cl->cl_fmap[j].fmap_systid = systid;
2610                                 ld_count++;
2611 
2612                                 if ((efdp1->systid == SUNIXOS &&
2613                                     (cmlb_is_linux_swap(cl, abs_secnum,
2614                                     tg_cookie) != 0)) ||
2615                                     efdp1->systid == SUNIXOS2) {
2616                                         if (uidx == -1) {
2617                                                 uidx = 0;
2618                                                 solaris_offset = abs_secnum;
2619                                                 solaris_size = ext_numsect;
2620                                         }
2621                                 }
2622 
2623                                 if ((ext_relsect = LE_32(efdp2->relsect)) == 0)
2624                                         break;
2625                         }
2626                 }
2627 
2628 #endif
2629 
2630                 if (fdp->systid != SUNIXOS &&
2631                     fdp->systid != SUNIXOS2 &&
2632                     fdp->systid != EFI_PMBR) {
2633                         continue;
2634                 }
2635 
2636                 /*
2637                  * use the last active solaris partition id found
2638                  * (there should only be 1 active partition id)
2639                  *
2640                  * if there are no active solaris partition id
2641                  * then use the first inactive solaris partition id
2642                  */
2643                 if ((uidx == -1) || (fdp->bootid == ACTIVE)) {
2644 #if defined(__i386) || defined(__amd64)
2645                         if (fdp->systid != SUNIXOS ||
2646                             (fdp->systid == SUNIXOS &&
2647                             (cmlb_is_linux_swap(cl, relsect,
2648                             tg_cookie) != 0))) {
2649 #endif
2650                                 uidx = i;
2651                                 solaris_offset = relsect;
2652                                 solaris_size   = numsect;
2653 #if defined(__i386) || defined(__amd64)
2654                         }
2655 #endif
2656                 }
2657         }
2658 #if defined(__i386) || defined(__amd64)
2659         if (ld_count < cl->cl_logical_drive_count) {
2660                 /*
2661                  * Some/all logical drives were deleted. Clear out
2662                  * the fmap entries correspoding to those deleted drives.
2663                  */
2664                 for (k = ld_count + FD_NUMPART;
2665                     k < cl->cl_logical_drive_count + FD_NUMPART; k++) {
2666                         cl->cl_fmap[k].fmap_start = 0;
2667                         cl->cl_fmap[k].fmap_nblk  = 0;
2668                         cl->cl_fmap[k].fmap_systid = 0;
2669                 }
2670                 cl->cl_update_ext_minor_nodes = 1;
2671         }
2672         if (cl->cl_update_ext_minor_nodes) {
2673                 rval = cmlb_update_ext_minor_nodes(cl, ld_count);
2674                 if (rval != 0) {
2675                         goto done;
2676                 }
2677         }
2678 #endif
2679         cmlb_dbg(CMLB_INFO,  cl, "fdisk 0x%x 0x%lx",
2680             cl->cl_solaris_offset, cl->cl_solaris_size);
2681 done:
2682 
2683         /*
2684          * Clear the VTOC info, only if the Solaris partition entry
2685          * has moved, changed size, been deleted, or if the size of
2686          * the partition is too small to even fit the label sector.
2687          */
2688         if ((cl->cl_solaris_offset != solaris_offset) ||
2689             (cl->cl_solaris_size != solaris_size) ||
2690             solaris_size <= DK_LABEL_LOC) {
2691                 cmlb_dbg(CMLB_INFO,  cl, "fdisk moved 0x%x 0x%lx",
2692                     solaris_offset, solaris_size);
2693                 bzero(&cl->cl_g, sizeof (struct dk_geom));
2694                 bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
2695                 bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
2696                 cl->cl_f_geometry_is_valid = B_FALSE;
2697         }
2698         cl->cl_solaris_offset = solaris_offset;
2699         cl->cl_solaris_size = solaris_size;
2700         kmem_free(bufp, blocksize);
2701         return (rval);
2702 
2703 #else   /* #elif defined(_FIRMWARE_NEEDS_FDISK) */
2704 #error "fdisk table presence undetermined for this platform."
2705 #endif  /* #if defined(_NO_FDISK_PRESENT) */
2706 }
2707 
2708 static void
2709 cmlb_swap_efi_gpt(efi_gpt_t *e)
2710 {
2711         e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature);
2712         e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision);
2713         e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize);
2714         e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32);
2715         e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA);
2716         e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA);
2717         e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA);
2718         e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA);
2719         UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID);
2720         e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA);
2721         e->efi_gpt_NumberOfPartitionEntries =
2722             LE_32(e->efi_gpt_NumberOfPartitionEntries);
2723         e->efi_gpt_SizeOfPartitionEntry =
2724             LE_32(e->efi_gpt_SizeOfPartitionEntry);
2725         e->efi_gpt_PartitionEntryArrayCRC32 =
2726             LE_32(e->efi_gpt_PartitionEntryArrayCRC32);
2727 }
2728 
2729 static void
2730 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p)
2731 {
2732         int i;
2733 
2734         for (i = 0; i < nparts; i++) {
2735                 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID,
2736                     p[i].efi_gpe_PartitionTypeGUID);
2737                 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA);
2738                 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA);
2739                 /* PartitionAttrs */
2740         }
2741 }
2742 
2743 static int
2744 cmlb_validate_efi(efi_gpt_t *labp)
2745 {
2746         if (labp->efi_gpt_Signature != EFI_SIGNATURE)
2747                 return (EINVAL);
2748         /* at least 96 bytes in this version of the spec. */
2749         if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) >
2750             labp->efi_gpt_HeaderSize)
2751                 return (EINVAL);
2752         /* this should be 128 bytes */
2753         if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t))
2754                 return (EINVAL);
2755         return (0);
2756 }
2757 
2758 /*
2759  * This function returns B_FALSE if there is a valid MBR signature and no
2760  * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
2761  *
2762  * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
2763  * recognize the disk as GPT partitioned. However, some other OS creates an MBR
2764  * where a PMBR entry is not the only one. Also, if the first block has been
2765  * corrupted, currently best attempt to allow data access would be to try to
2766  * check for GPT headers. Hence in case of more than one partition entry, but
2767  * at least one EFI_PMBR partition type or no valid magic number, the function
2768  * returns B_TRUE to continue with looking for GPT header.
2769  */
2770 
2771 static boolean_t
2772 cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr)
2773 {
2774         struct ipart    *fdp;
2775         struct mboot    *mbp = (struct mboot *)buf;
2776         struct ipart    fdisk[FD_NUMPART];
2777         int             i;
2778 
2779         if (is_mbr != NULL)
2780                 *is_mbr = B_TRUE;
2781 
2782         if (LE_16(mbp->signature) != MBB_MAGIC) {
2783                 if (is_mbr != NULL)
2784                         *is_mbr = B_FALSE;
2785                 return (B_TRUE);
2786         }
2787 
2788         bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2789 
2790         for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2791                 if (fdp->systid == EFI_PMBR)
2792                         return (B_TRUE);
2793         }
2794 
2795         return (B_FALSE);
2796 }
2797 
2798 static int
2799 cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
2800     void *tg_cookie)
2801 {
2802         int             i;
2803         int             rval = 0;
2804         efi_gpe_t       *partitions;
2805         uchar_t         *buf;
2806         uint_t          lbasize;        /* is really how much to read */
2807         diskaddr_t      cap = 0;
2808         uint_t          nparts;
2809         diskaddr_t      gpe_lba;
2810         diskaddr_t      alternate_lba;
2811         int             iofailed = 0;
2812         struct uuid     uuid_type_reserved = EFI_RESERVED;
2813 #if defined(_FIRMWARE_NEEDS_FDISK)
2814         boolean_t       is_mbr;
2815 #endif
2816 
2817         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2818 
2819         lbasize = cl->cl_sys_blocksize;
2820 
2821         cl->cl_reserved = -1;
2822         mutex_exit(CMLB_MUTEX(cl));
2823 
2824         buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
2825 
2826         rval = DK_TG_READ(cl, buf,  0, lbasize, tg_cookie);
2827         if (rval) {
2828                 iofailed = 1;
2829                 goto done_err;
2830         }
2831         if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) {
2832                 /* not ours */
2833                 rval = ESRCH;
2834                 goto done_err;
2835         }
2836 
2837 #if defined(_FIRMWARE_NEEDS_FDISK)
2838         if (!cmlb_check_efi_mbr(buf, &is_mbr)) {
2839                 if (is_mbr)
2840                         rval = ESRCH;
2841                 else
2842                         rval = EINVAL;
2843                 goto done_err;
2844         }
2845 #else
2846         if (!cmlb_check_efi_mbr(buf, NULL)) {
2847                 rval = EINVAL;
2848                 goto done_err;
2849         }
2850 
2851 #endif
2852 
2853         rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie);
2854         if (rval) {
2855                 iofailed = 1;
2856                 goto done_err;
2857         }
2858         cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2859 
2860         if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2861                 /*
2862                  * Couldn't read the primary, try the backup.  Our
2863                  * capacity at this point could be based on CHS, so
2864                  * check what the device reports.
2865                  */
2866                 rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
2867                 if (rval) {
2868                         iofailed = 1;
2869                         goto done_err;
2870                 }
2871 
2872                 /*
2873                  * CMLB_OFF_BY_ONE case, we check the next to last block first
2874                  * for backup GPT header, otherwise check the last block.
2875                  */
2876 
2877                 if ((rval = DK_TG_READ(cl, buf,
2878                     cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1),
2879                     lbasize, tg_cookie))
2880                     != 0) {
2881                         iofailed = 1;
2882                         goto done_err;
2883                 }
2884                 cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2885 
2886                 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2887 
2888                         if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE))
2889                                 goto done_err;
2890                         if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize,
2891                             tg_cookie)) != 0)
2892                                 goto done_err;
2893                         cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2894                         if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0)
2895                                 goto done_err;
2896                 }
2897                 if (!(flags & CMLB_SILENT))
2898                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
2899                             "primary label corrupt; using backup\n");
2900         }
2901 
2902         nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries;
2903         gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA;
2904         alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA;
2905 
2906         rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie);
2907         if (rval) {
2908                 iofailed = 1;
2909                 goto done_err;
2910         }
2911         partitions = (efi_gpe_t *)buf;
2912 
2913         if (nparts > MAXPART) {
2914                 nparts = MAXPART;
2915         }
2916         cmlb_swap_efi_gpe(nparts, partitions);
2917 
2918         mutex_enter(CMLB_MUTEX(cl));
2919 
2920         /* Fill in partition table. */
2921         for (i = 0; i < nparts; i++) {
2922                 if (partitions->efi_gpe_StartingLBA != 0 ||
2923                     partitions->efi_gpe_EndingLBA != 0) {
2924                         cl->cl_map[i].dkl_cylno =
2925                             partitions->efi_gpe_StartingLBA;
2926                         cl->cl_map[i].dkl_nblk =
2927                             partitions->efi_gpe_EndingLBA -
2928                             partitions->efi_gpe_StartingLBA + 1;
2929                         cl->cl_offset[i] =
2930                             partitions->efi_gpe_StartingLBA;
2931                 }
2932 
2933                 if (cl->cl_reserved == -1) {
2934                         if (bcmp(&partitions->efi_gpe_PartitionTypeGUID,
2935                             &uuid_type_reserved, sizeof (struct uuid)) == 0) {
2936                                 cl->cl_reserved = i;
2937                         }
2938                 }
2939                 if (i == WD_NODE) {
2940                         /*
2941                          * minor number 7 corresponds to the whole disk
2942                          * if the disk capacity is expanded after disk is
2943                          * labeled, minor number 7 represents the capacity
2944                          * indicated by the disk label.
2945                          */
2946                         cl->cl_map[i].dkl_cylno = 0;
2947                         if (alternate_lba == 1) {
2948                                 /*
2949                                  * We are using backup label. Since we can
2950                                  * find a valid label at the end of disk,
2951                                  * the disk capacity is not expanded.
2952                                  */
2953                                 cl->cl_map[i].dkl_nblk = capacity;
2954                         } else {
2955                                 cl->cl_map[i].dkl_nblk = alternate_lba + 1;
2956                         }
2957                         cl->cl_offset[i] = 0;
2958                 }
2959                 partitions++;
2960         }
2961         cl->cl_solaris_offset = 0;
2962         cl->cl_solaris_size = capacity;
2963         cl->cl_label_from_media = CMLB_LABEL_EFI;
2964         cl->cl_f_geometry_is_valid = B_TRUE;
2965 
2966         /* clear the vtoc label */
2967         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
2968 
2969         kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2970         return (0);
2971 
2972 done_err:
2973         kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2974         mutex_enter(CMLB_MUTEX(cl));
2975 done_err1:
2976         /*
2977          * if we didn't find something that could look like a VTOC
2978          * and the disk is over 1TB, we know there isn't a valid label.
2979          * Otherwise let cmlb_uselabel decide what to do.  We only
2980          * want to invalidate this if we're certain the label isn't
2981          * valid because cmlb_prop_op will now fail, which in turn
2982          * causes things like opens and stats on the partition to fail.
2983          */
2984         if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) {
2985                 cl->cl_f_geometry_is_valid = B_FALSE;
2986         }
2987         return (rval);
2988 }
2989 
2990 
2991 /*
2992  *    Function: cmlb_uselabel
2993  *
2994  * Description: Validate the disk label and update the relevant data (geometry,
2995  *              partition, vtoc, and capacity data) in the cmlb_lun struct.
2996  *              Marks the geometry of the unit as being valid.
2997  *
2998  *   Arguments: cl: unit struct.
2999  *              dk_label: disk label
3000  *
3001  * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
3002  *              partition, vtoc, and capacity data are good.
3003  *
3004  *              CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
3005  *              label; or computed capacity does not jibe with capacity
3006  *              reported from the READ CAPACITY command.
3007  *
3008  *     Context: Kernel thread only (can sleep).
3009  */
3010 static int
3011 cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags)
3012 {
3013         short           *sp;
3014         short           sum;
3015         short           count;
3016         int             label_error = CMLB_LABEL_IS_VALID;
3017         int             i;
3018         diskaddr_t      label_capacity;
3019         uint32_t        part_end;
3020         diskaddr_t      track_capacity;
3021 #if defined(_SUNOS_VTOC_16)
3022         struct  dkl_partition   *vpartp;
3023 #endif
3024         ASSERT(cl != NULL);
3025         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3026 
3027         /* Validate the magic number of the label. */
3028         if (labp->dkl_magic != DKL_MAGIC) {
3029 #if defined(__sparc)
3030                 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3031                         if (!(flags & CMLB_SILENT))
3032                                 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3033                                     CE_WARN,
3034                                     "Corrupt label; wrong magic number\n");
3035                 }
3036 #endif
3037                 return (CMLB_LABEL_IS_INVALID);
3038         }
3039 
3040         /* Validate the checksum of the label. */
3041         sp  = (short *)labp;
3042         sum = 0;
3043         count = sizeof (struct dk_label) / sizeof (short);
3044         while (count--)  {
3045                 sum ^= *sp++;
3046         }
3047 
3048         if (sum != 0) {
3049 #if defined(_SUNOS_VTOC_16)
3050                 if (!ISCD(cl)) {
3051 #elif defined(_SUNOS_VTOC_8)
3052                 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3053 #endif
3054                         if (!(flags & CMLB_SILENT))
3055                                 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3056                                     CE_WARN,
3057                                     "Corrupt label - label checksum failed\n");
3058                 }
3059                 return (CMLB_LABEL_IS_INVALID);
3060         }
3061 
3062 
3063         /*
3064          * Fill in geometry structure with data from label.
3065          */
3066         bzero(&cl->cl_g, sizeof (struct dk_geom));
3067         cl->cl_g.dkg_ncyl   = labp->dkl_ncyl;
3068         cl->cl_g.dkg_acyl   = labp->dkl_acyl;
3069         cl->cl_g.dkg_bcyl   = 0;
3070         cl->cl_g.dkg_nhead  = labp->dkl_nhead;
3071         cl->cl_g.dkg_nsect  = labp->dkl_nsect;
3072         cl->cl_g.dkg_intrlv = labp->dkl_intrlv;
3073 
3074 #if defined(_SUNOS_VTOC_8)
3075         cl->cl_g.dkg_gap1   = labp->dkl_gap1;
3076         cl->cl_g.dkg_gap2   = labp->dkl_gap2;
3077         cl->cl_g.dkg_bhead  = labp->dkl_bhead;
3078 #endif
3079 #if defined(_SUNOS_VTOC_16)
3080         cl->cl_dkg_skew = labp->dkl_skew;
3081 #endif
3082 
3083 #if defined(__i386) || defined(__amd64)
3084         cl->cl_g.dkg_apc = labp->dkl_apc;
3085 #endif
3086 
3087         /*
3088          * Currently we rely on the values in the label being accurate. If
3089          * dkl_rpm or dkl_pcly are zero in the label, use a default value.
3090          *
3091          * Note: In the future a MODE SENSE may be used to retrieve this data,
3092          * although this command is optional in SCSI-2.
3093          */
3094         cl->cl_g.dkg_rpm  = (labp->dkl_rpm  != 0) ? labp->dkl_rpm  : 3600;
3095         cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl :
3096             (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl);
3097 
3098         /*
3099          * The Read and Write reinstruct values may not be valid
3100          * for older disks.
3101          */
3102         cl->cl_g.dkg_read_reinstruct  = labp->dkl_read_reinstruct;
3103         cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct;
3104 
3105         /* Fill in partition table. */
3106 #if defined(_SUNOS_VTOC_8)
3107         for (i = 0; i < NDKMAP; i++) {
3108                 cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno;
3109                 cl->cl_map[i].dkl_nblk  = labp->dkl_map[i].dkl_nblk;
3110         }
3111 #endif
3112 #if  defined(_SUNOS_VTOC_16)
3113         vpartp          = labp->dkl_vtoc.v_part;
3114         track_capacity  = labp->dkl_nhead * labp->dkl_nsect;
3115 
3116         /* Prevent divide by zero */
3117         if (track_capacity == 0) {
3118                 if (!(flags & CMLB_SILENT))
3119                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3120                             "Corrupt label - zero nhead or nsect value\n");
3121 
3122                 return (CMLB_LABEL_IS_INVALID);
3123         }
3124 
3125         for (i = 0; i < NDKMAP; i++, vpartp++) {
3126                 cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity;
3127                 cl->cl_map[i].dkl_nblk  = vpartp->p_size;
3128         }
3129 #endif
3130 
3131         /* Fill in VTOC Structure. */
3132         bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc));
3133 #if defined(_SUNOS_VTOC_8)
3134         /*
3135          * The 8-slice vtoc does not include the ascii label; save it into
3136          * the device's soft state structure here.
3137          */
3138         bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
3139 #endif
3140 
3141         /* Now look for a valid capacity. */
3142         track_capacity  = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect);
3143         label_capacity  = (cl->cl_g.dkg_ncyl  * track_capacity);
3144 
3145         if (cl->cl_g.dkg_acyl) {
3146 #if defined(__i386) || defined(__amd64)
3147                 /* we may have > 1 alts cylinder */
3148                 label_capacity += (track_capacity * cl->cl_g.dkg_acyl);
3149 #else
3150                 label_capacity += track_capacity;
3151 #endif
3152         }
3153 
3154         /*
3155          * Force check here to ensure the computed capacity is valid.
3156          * If capacity is zero, it indicates an invalid label and
3157          * we should abort updating the relevant data then.
3158          */
3159         if (label_capacity == 0) {
3160                 if (!(flags & CMLB_SILENT))
3161                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3162                             "Corrupt label - no valid capacity could be "
3163                             "retrieved\n");
3164 
3165                 return (CMLB_LABEL_IS_INVALID);
3166         }
3167 
3168         /* Mark the geometry as valid. */
3169         cl->cl_f_geometry_is_valid = B_TRUE;
3170 
3171         /*
3172          * if we got invalidated when mutex exit and entered again,
3173          * if blockcount different than when we came in, need to
3174          * retry from beginning of cmlb_validate_geometry.
3175          * revisit this on next phase of utilizing this for
3176          * sd.
3177          */
3178 
3179         if (label_capacity <= cl->cl_blockcount) {
3180 #if defined(_SUNOS_VTOC_8)
3181                 /*
3182                  * We can't let this happen on drives that are subdivided
3183                  * into logical disks (i.e., that have an fdisk table).
3184                  * The cl_blockcount field should always hold the full media
3185                  * size in sectors, period.  This code would overwrite
3186                  * cl_blockcount with the size of the Solaris fdisk partition.
3187                  */
3188                 cmlb_dbg(CMLB_ERROR,  cl,
3189                     "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
3190                     label_capacity, cl->cl_blockcount);
3191                 cl->cl_solaris_size = label_capacity;
3192 
3193 #endif  /* defined(_SUNOS_VTOC_8) */
3194                 goto done;
3195         }
3196 
3197         if (ISCD(cl)) {
3198                 /* For CDROMs, we trust that the data in the label is OK. */
3199 #if defined(_SUNOS_VTOC_8)
3200                 for (i = 0; i < NDKMAP; i++) {
3201                         part_end = labp->dkl_nhead * labp->dkl_nsect *
3202                             labp->dkl_map[i].dkl_cylno +
3203                             labp->dkl_map[i].dkl_nblk  - 1;
3204 
3205                         if ((labp->dkl_map[i].dkl_nblk) &&
3206                             (part_end > cl->cl_blockcount)) {
3207                                 cl->cl_f_geometry_is_valid = B_FALSE;
3208                                 break;
3209                         }
3210                 }
3211 #endif
3212 #if defined(_SUNOS_VTOC_16)
3213                 vpartp = &(labp->dkl_vtoc.v_part[0]);
3214                 for (i = 0; i < NDKMAP; i++, vpartp++) {
3215                         part_end = vpartp->p_start + vpartp->p_size;
3216                         if ((vpartp->p_size > 0) &&
3217                             (part_end > cl->cl_blockcount)) {
3218                                 cl->cl_f_geometry_is_valid = B_FALSE;
3219                                 break;
3220                         }
3221                 }
3222 #endif
3223         } else {
3224                 /* label_capacity > cl->cl_blockcount */
3225                 if (!(flags & CMLB_SILENT)) {
3226                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3227                             "Corrupt label - bad geometry\n");
3228                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT,
3229                             "Label says %llu blocks; Drive says %llu blocks\n",
3230                             label_capacity, cl->cl_blockcount);
3231                 }
3232                 cl->cl_f_geometry_is_valid = B_FALSE;
3233                 label_error = CMLB_LABEL_IS_INVALID;
3234         }
3235 
3236 done:
3237 
3238         cmlb_dbg(CMLB_INFO,  cl, "cmlb_uselabel: (label geometry)\n");
3239         cmlb_dbg(CMLB_INFO,  cl,
3240             "   ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
3241             cl->cl_g.dkg_ncyl,  cl->cl_g.dkg_acyl,
3242             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3243 
3244         cmlb_dbg(CMLB_INFO,  cl,
3245             "   label_capacity: %d; intrlv: %d; rpm: %d\n",
3246             cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm);
3247         cmlb_dbg(CMLB_INFO,  cl, "   wrt_reinstr: %d; rd_reinstr: %d\n",
3248             cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct);
3249 
3250         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3251 
3252         return (label_error);
3253 }
3254 
3255 
3256 /*
3257  *    Function: cmlb_build_default_label
3258  *
3259  * Description: Generate a default label for those devices that do not have
3260  *              one, e.g., new media, removable cartridges, etc..
3261  *
3262  *     Context: Kernel thread only
3263  */
3264 /*ARGSUSED*/
3265 static void
3266 cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie)
3267 {
3268 #if defined(_SUNOS_VTOC_16)
3269         uint_t  phys_spc;
3270         uint_t  disksize;
3271         struct  dk_geom cl_g;
3272         diskaddr_t capacity;
3273 #endif
3274 
3275         ASSERT(cl != NULL);
3276         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3277 
3278 #if defined(_SUNOS_VTOC_8)
3279         /*
3280          * Note: This is a legacy check for non-removable devices on VTOC_8
3281          * only. This may be a valid check for VTOC_16 as well.
3282          * Once we understand why there is this difference between SPARC and
3283          * x86 platform, we could remove this legacy check.
3284          */
3285         if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3286                 return;
3287         }
3288 #endif
3289 
3290         bzero(&cl->cl_g, sizeof (struct dk_geom));
3291         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
3292         bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
3293 
3294 #if defined(_SUNOS_VTOC_8)
3295 
3296         /*
3297          * It's a REMOVABLE media, therefore no label (on sparc, anyway).
3298          * But it is still necessary to set up various geometry information,
3299          * and we are doing this here.
3300          */
3301 
3302         /*
3303          * For the rpm, we use the minimum for the disk.  For the head, cyl,
3304          * and number of sector per track, if the capacity <= 1GB, head = 64,
3305          * sect = 32.  else head = 255, sect 63 Note: the capacity should be
3306          * equal to C*H*S values.  This will cause some truncation of size due
3307          * to round off errors. For CD-ROMs, this truncation can have adverse
3308          * side effects, so returning ncyl and nhead as 1. The nsect will
3309          * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
3310          */
3311         cl->cl_solaris_size = cl->cl_blockcount;
3312         if (ISCD(cl)) {
3313                 tg_attribute_t tgattribute;
3314                 int is_writable;
3315                 /*
3316                  * Preserve the old behavior for non-writable
3317                  * medias. Since dkg_nsect is a ushort, it
3318                  * will lose bits as cdroms have more than
3319                  * 65536 sectors. So if we recalculate
3320                  * capacity, it will become much shorter.
3321                  * But the dkg_* information is not
3322                  * used for CDROMs so it is OK. But for
3323                  * Writable CDs we need this information
3324                  * to be valid (for newfs say). So we
3325                  * make nsect and nhead > 1 that way
3326                  * nsect can still stay within ushort limit
3327                  * without losing any bits.
3328                  */
3329 
3330                 bzero(&tgattribute, sizeof (tg_attribute_t));
3331 
3332                 mutex_exit(CMLB_MUTEX(cl));
3333                 is_writable =
3334                     (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
3335                     tgattribute.media_is_writable : 1;
3336                 mutex_enter(CMLB_MUTEX(cl));
3337 
3338                 if (is_writable) {
3339                         cl->cl_g.dkg_nhead = 64;
3340                         cl->cl_g.dkg_nsect = 32;
3341                         cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
3342                         cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl *
3343                             cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3344                 } else {
3345                         cl->cl_g.dkg_ncyl  = 1;
3346                         cl->cl_g.dkg_nhead = 1;
3347                         cl->cl_g.dkg_nsect = cl->cl_blockcount;
3348                 }
3349         } else {
3350                 if (cl->cl_blockcount < 160) {
3351                         /* Less than 80K */
3352                         cl->cl_g.dkg_nhead = 1;
3353                         cl->cl_g.dkg_ncyl = cl->cl_blockcount;
3354                         cl->cl_g.dkg_nsect = 1;
3355                 } else if (cl->cl_blockcount <= 0x1000) {
3356                         /* unlabeled SCSI floppy device */
3357                         cl->cl_g.dkg_nhead = 2;
3358                         cl->cl_g.dkg_ncyl = 80;
3359                         cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
3360                 } else if (cl->cl_blockcount <= 0x200000) {
3361                         cl->cl_g.dkg_nhead = 64;
3362                         cl->cl_g.dkg_nsect = 32;
3363                         cl->cl_g.dkg_ncyl  = cl->cl_blockcount / (64 * 32);
3364                 } else {
3365                         cl->cl_g.dkg_nhead = 255;
3366 
3367                         cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
3368                             (UINT16_MAX * 255 * 63) - 1) /
3369                             (UINT16_MAX * 255 * 63)) * 63;
3370 
3371                         if (cl->cl_g.dkg_nsect == 0)
3372                                 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
3373 
3374                         cl->cl_g.dkg_ncyl = cl->cl_blockcount /
3375                             (255 * cl->cl_g.dkg_nsect);
3376                 }
3377 
3378                 cl->cl_solaris_size =
3379                     (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead *
3380                     cl->cl_g.dkg_nsect;
3381 
3382         }
3383 
3384         cl->cl_g.dkg_acyl    = 0;
3385         cl->cl_g.dkg_bcyl    = 0;
3386         cl->cl_g.dkg_rpm     = 200;
3387         cl->cl_asciilabel[0] = '\0';
3388         cl->cl_g.dkg_pcyl    = cl->cl_g.dkg_ncyl;
3389 
3390         cl->cl_map[0].dkl_cylno = 0;
3391         cl->cl_map[0].dkl_nblk  = cl->cl_solaris_size;
3392 
3393         cl->cl_map[2].dkl_cylno = 0;
3394         cl->cl_map[2].dkl_nblk  = cl->cl_solaris_size;
3395 
3396 #elif defined(_SUNOS_VTOC_16)
3397 
3398         if (cl->cl_solaris_size == 0) {
3399                 /*
3400                  * Got fdisk table but no solaris entry therefore
3401                  * don't create a default label
3402                  */
3403                 cl->cl_f_geometry_is_valid = B_TRUE;
3404                 return;
3405         }
3406 
3407         /*
3408          * For CDs we continue to use the physical geometry to calculate
3409          * number of cylinders. All other devices must convert the
3410          * physical geometry (cmlb_geom) to values that will fit
3411          * in a dk_geom structure.
3412          */
3413         if (ISCD(cl)) {
3414                 phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect;
3415         } else {
3416                 /* Convert physical geometry to disk geometry */
3417                 bzero(&cl_g, sizeof (struct dk_geom));
3418 
3419                 /*
3420                  * Refer to comments related to off-by-1 at the
3421                  * header of this file.
3422                  * Before calculating geometry, capacity should be
3423                  * decreased by 1.
3424                  */
3425 
3426                 if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
3427                         capacity = cl->cl_blockcount - 1;
3428                 else
3429                         capacity = cl->cl_blockcount;
3430 
3431 
3432                 cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie);
3433                 bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g));
3434                 phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3435         }
3436 
3437         if (phys_spc == 0)
3438                 return;
3439         cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc;
3440         if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3441                 /* disable devid */
3442                 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl;
3443                 disksize = cl->cl_solaris_size;
3444         } else {
3445                 cl->cl_g.dkg_acyl = DK_ACYL;
3446                 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL;
3447                 disksize = cl->cl_g.dkg_ncyl * phys_spc;
3448         }
3449 
3450         if (ISCD(cl)) {
3451                 /*
3452                  * CD's don't use the "heads * sectors * cyls"-type of
3453                  * geometry, but instead use the entire capacity of the media.
3454                  */
3455                 disksize = cl->cl_solaris_size;
3456                 cl->cl_g.dkg_nhead = 1;
3457                 cl->cl_g.dkg_nsect = 1;
3458                 cl->cl_g.dkg_rpm =
3459                     (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm;
3460 
3461                 cl->cl_vtoc.v_part[0].p_start = 0;
3462                 cl->cl_vtoc.v_part[0].p_size  = disksize;
3463                 cl->cl_vtoc.v_part[0].p_tag   = V_BACKUP;
3464                 cl->cl_vtoc.v_part[0].p_flag  = V_UNMNT;
3465 
3466                 cl->cl_map[0].dkl_cylno = 0;
3467                 cl->cl_map[0].dkl_nblk  = disksize;
3468                 cl->cl_offset[0] = 0;
3469 
3470         } else {
3471                 /*
3472                  * Hard disks and removable media cartridges
3473                  */
3474                 cl->cl_g.dkg_rpm =
3475                     (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm;
3476                 cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize;
3477 
3478                 /* Add boot slice */
3479                 cl->cl_vtoc.v_part[8].p_start = 0;
3480                 cl->cl_vtoc.v_part[8].p_size  = phys_spc;
3481                 cl->cl_vtoc.v_part[8].p_tag   = V_BOOT;
3482                 cl->cl_vtoc.v_part[8].p_flag  = V_UNMNT;
3483 
3484                 cl->cl_map[8].dkl_cylno = 0;
3485                 cl->cl_map[8].dkl_nblk  = phys_spc;
3486                 cl->cl_offset[8] = 0;
3487 
3488                 if ((cl->cl_alter_behavior &
3489                     CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) &&
3490                     cl->cl_device_type == DTYPE_DIRECT) {
3491                         cl->cl_vtoc.v_part[9].p_start = phys_spc;
3492                         cl->cl_vtoc.v_part[9].p_size  = 2 * phys_spc;
3493                         cl->cl_vtoc.v_part[9].p_tag   = V_ALTSCTR;
3494                         cl->cl_vtoc.v_part[9].p_flag  = 0;
3495 
3496                         cl->cl_map[9].dkl_cylno = 1;
3497                         cl->cl_map[9].dkl_nblk  = 2 * phys_spc;
3498                         cl->cl_offset[9] = phys_spc;
3499                 }
3500         }
3501 
3502         cl->cl_g.dkg_apc = 0;
3503 
3504         /* Add backup slice */
3505         cl->cl_vtoc.v_part[2].p_start = 0;
3506         cl->cl_vtoc.v_part[2].p_size  = disksize;
3507         cl->cl_vtoc.v_part[2].p_tag   = V_BACKUP;
3508         cl->cl_vtoc.v_part[2].p_flag  = V_UNMNT;
3509 
3510         cl->cl_map[2].dkl_cylno = 0;
3511         cl->cl_map[2].dkl_nblk  = disksize;
3512         cl->cl_offset[2] = 0;
3513 
3514         /*
3515          * single slice (s0) covering the entire disk
3516          */
3517         if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3518                 cl->cl_vtoc.v_part[0].p_start = 0;
3519                 cl->cl_vtoc.v_part[0].p_tag   = V_UNASSIGNED;
3520                 cl->cl_vtoc.v_part[0].p_flag  = 0;
3521                 cl->cl_vtoc.v_part[0].p_size  = disksize;
3522                 cl->cl_map[0].dkl_cylno = 0;
3523                 cl->cl_map[0].dkl_nblk  = disksize;
3524                 cl->cl_offset[0] = 0;
3525         }
3526 
3527         (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d"
3528             " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
3529             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3530 
3531 #else
3532 #error "No VTOC format defined."
3533 #endif
3534 
3535         cl->cl_g.dkg_read_reinstruct  = 0;
3536         cl->cl_g.dkg_write_reinstruct = 0;
3537 
3538         cl->cl_g.dkg_intrlv = 1;
3539 
3540         cl->cl_vtoc.v_sanity  = VTOC_SANE;
3541         cl->cl_vtoc.v_nparts = V_NUMPAR;
3542         cl->cl_vtoc.v_version = V_VERSION;
3543 
3544         cl->cl_f_geometry_is_valid = B_TRUE;
3545         cl->cl_label_from_media = CMLB_LABEL_UNDEF;
3546 
3547         cmlb_dbg(CMLB_INFO,  cl,
3548             "cmlb_build_default_label: Default label created: "
3549             "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
3550             cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead,
3551             cl->cl_g.dkg_nsect, cl->cl_blockcount);
3552 }
3553 
3554 
3555 #if defined(_FIRMWARE_NEEDS_FDISK)
3556 /*
3557  * Max CHS values, as they are encoded into bytes, for 1022/254/63
3558  */
3559 #define LBA_MAX_SECT    (63 | ((1022 & 0x300) >> 2))
3560 #define LBA_MAX_CYL     (1022 & 0xFF)
3561 #define LBA_MAX_HEAD    (254)
3562 
3563 
3564 /*
3565  *    Function: cmlb_has_max_chs_vals
3566  *
3567  * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum.
3568  *
3569  *   Arguments: fdp - ptr to CHS info
3570  *
3571  * Return Code: True or false
3572  *
3573  *     Context: Any.
3574  */
3575 static boolean_t
3576 cmlb_has_max_chs_vals(struct ipart *fdp)
3577 {
3578         return ((fdp->begcyl  == LBA_MAX_CYL)        &&
3579             (fdp->beghead == LBA_MAX_HEAD)   &&
3580             (fdp->begsect == LBA_MAX_SECT)   &&
3581             (fdp->endcyl  == LBA_MAX_CYL)    &&
3582             (fdp->endhead == LBA_MAX_HEAD)   &&
3583             (fdp->endsect == LBA_MAX_SECT));
3584 }
3585 #endif
3586 
3587 /*
3588  *    Function: cmlb_dkio_get_geometry
3589  *
3590  * Description: This routine is the driver entry point for handling user
3591  *              requests to get the device geometry (DKIOCGGEOM).
3592  *
3593  *   Arguments:
3594  *      arg             pointer to user provided dk_geom structure specifying
3595  *                      the controller's notion of the current geometry.
3596  *
3597  *      flag            this argument is a pass through to ddi_copyxxx()
3598  *                      directly from the mode argument of ioctl().
3599  *
3600  *      tg_cookie       cookie from target driver to be passed back to target
3601  *                      driver when we call back to it through tg_ops.
3602  *
3603  * Return Code: 0
3604  *              EFAULT
3605  *              ENXIO
3606  *              EIO
3607  */
3608 static int
3609 cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
3610     void *tg_cookie)
3611 {
3612         struct dk_geom  *tmp_geom = NULL;
3613         int             rval = 0;
3614 
3615         /*
3616          * cmlb_validate_geometry does not spin a disk up
3617          * if it was spcl down. We need to make sure it
3618          * is ready.
3619          */
3620         mutex_enter(CMLB_MUTEX(cl));
3621         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3622 #if defined(_SUNOS_VTOC_8)
3623         if (rval == EINVAL &&
3624             cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
3625                 /*
3626                  * This is to return a default label geometry even when we
3627                  * do not really assume a default label for the device.
3628                  * dad driver utilizes this.
3629                  */
3630                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3631                         cmlb_setup_default_geometry(cl, tg_cookie);
3632                         rval = 0;
3633                 }
3634         }
3635 #endif
3636         if (rval) {
3637                 mutex_exit(CMLB_MUTEX(cl));
3638                 return (rval);
3639         }
3640 
3641 #if defined(__i386) || defined(__amd64)
3642         if (cl->cl_solaris_size == 0) {
3643                 mutex_exit(CMLB_MUTEX(cl));
3644                 return (EIO);
3645         }
3646 #endif
3647 
3648         /*
3649          * Make a local copy of the soft state geometry to avoid some potential
3650          * race conditions associated with holding the mutex and updating the
3651          * write_reinstruct value
3652          */
3653         tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3654         bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom));
3655 
3656         if (tmp_geom->dkg_write_reinstruct == 0) {
3657                 tmp_geom->dkg_write_reinstruct =
3658                     (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm *
3659                     cmlb_rot_delay) / (int)60000);
3660         }
3661         mutex_exit(CMLB_MUTEX(cl));
3662 
3663         rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom),
3664             flag);
3665         if (rval != 0) {
3666                 rval = EFAULT;
3667         }
3668 
3669         kmem_free(tmp_geom, sizeof (struct dk_geom));
3670         return (rval);
3671 
3672 }
3673 
3674 
3675 /*
3676  *    Function: cmlb_dkio_set_geometry
3677  *
3678  * Description: This routine is the driver entry point for handling user
3679  *              requests to set the device geometry (DKIOCSGEOM). The actual
3680  *              device geometry is not updated, just the driver "notion" of it.
3681  *
3682  *   Arguments:
3683  *      arg             pointer to user provided dk_geom structure used to set
3684  *                      the controller's notion of the current geometry.
3685  *
3686  *      flag            this argument is a pass through to ddi_copyxxx()
3687  *                      directly from the mode argument of ioctl().
3688  *
3689  *      tg_cookie       cookie from target driver to be passed back to target
3690  *                      driver when we call back to it through tg_ops.
3691  *
3692  * Return Code: 0
3693  *              EFAULT
3694  *              ENXIO
3695  *              EIO
3696  */
3697 static int
3698 cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag)
3699 {
3700         struct dk_geom  *tmp_geom;
3701         struct dk_map   *lp;
3702         int             rval = 0;
3703         int             i;
3704 
3705 
3706 #if defined(__i386) || defined(__amd64)
3707         if (cl->cl_solaris_size == 0) {
3708                 return (EIO);
3709         }
3710 #endif
3711         /*
3712          * We need to copy the user specified geometry into local
3713          * storage and then update the softstate. We don't want to hold
3714          * the mutex and copyin directly from the user to the soft state
3715          */
3716         tmp_geom = (struct dk_geom *)
3717             kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3718         rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag);
3719         if (rval != 0) {
3720                 kmem_free(tmp_geom, sizeof (struct dk_geom));
3721                 return (EFAULT);
3722         }
3723 
3724         mutex_enter(CMLB_MUTEX(cl));
3725         bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom));
3726         for (i = 0; i < NDKMAP; i++) {
3727                 lp  = &cl->cl_map[i];
3728                 cl->cl_offset[i] =
3729                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3730 #if defined(__i386) || defined(__amd64)
3731                 cl->cl_offset[i] += cl->cl_solaris_offset;
3732 #endif
3733         }
3734         cl->cl_f_geometry_is_valid = B_FALSE;
3735         mutex_exit(CMLB_MUTEX(cl));
3736         kmem_free(tmp_geom, sizeof (struct dk_geom));
3737 
3738         return (rval);
3739 }
3740 
3741 /*
3742  *    Function: cmlb_dkio_get_partition
3743  *
3744  * Description: This routine is the driver entry point for handling user
3745  *              requests to get the partition table (DKIOCGAPART).
3746  *
3747  *   Arguments:
3748  *      arg             pointer to user provided dk_allmap structure specifying
3749  *                      the controller's notion of the current partition table.
3750  *
3751  *      flag            this argument is a pass through to ddi_copyxxx()
3752  *                      directly from the mode argument of ioctl().
3753  *
3754  *      tg_cookie       cookie from target driver to be passed back to target
3755  *                      driver when we call back to it through tg_ops.
3756  *
3757  * Return Code: 0
3758  *              EFAULT
3759  *              ENXIO
3760  *              EIO
3761  */
3762 static int
3763 cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
3764     void *tg_cookie)
3765 {
3766         int             rval = 0;
3767         int             size;
3768 
3769         /*
3770          * Make sure the geometry is valid before getting the partition
3771          * information.
3772          */
3773         mutex_enter(CMLB_MUTEX(cl));
3774         if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) {
3775                 mutex_exit(CMLB_MUTEX(cl));
3776                 return (rval);
3777         }
3778         mutex_exit(CMLB_MUTEX(cl));
3779 
3780 #if defined(__i386) || defined(__amd64)
3781         if (cl->cl_solaris_size == 0) {
3782                 return (EIO);
3783         }
3784 #endif
3785 
3786 #ifdef _MULTI_DATAMODEL
3787         switch (ddi_model_convert_from(flag & FMODELS)) {
3788         case DDI_MODEL_ILP32: {
3789                 struct dk_map32 dk_map32[NDKMAP];
3790                 int             i;
3791 
3792                 for (i = 0; i < NDKMAP; i++) {
3793                         dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
3794                         dk_map32[i].dkl_nblk  = cl->cl_map[i].dkl_nblk;
3795                 }
3796                 size = NDKMAP * sizeof (struct dk_map32);
3797                 rval = ddi_copyout(dk_map32, (void *)arg, size, flag);
3798                 if (rval != 0) {
3799                         rval = EFAULT;
3800                 }
3801                 break;
3802         }
3803         case DDI_MODEL_NONE:
3804                 size = NDKMAP * sizeof (struct dk_map);
3805                 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3806                 if (rval != 0) {
3807                         rval = EFAULT;
3808                 }
3809                 break;
3810         }
3811 #else /* ! _MULTI_DATAMODEL */
3812         size = NDKMAP * sizeof (struct dk_map);
3813         rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3814         if (rval != 0) {
3815                 rval = EFAULT;
3816         }
3817 #endif /* _MULTI_DATAMODEL */
3818         return (rval);
3819 }
3820 
3821 /*
3822  *    Function: cmlb_dkio_set_partition
3823  *
3824  * Description: This routine is the driver entry point for handling user
3825  *              requests to set the partition table (DKIOCSAPART). The actual
3826  *              device partition is not updated.
3827  *
3828  *   Arguments:
3829  *              arg  - pointer to user provided dk_allmap structure used to set
3830  *                      the controller's notion of the partition table.
3831  *              flag - this argument is a pass through to ddi_copyxxx()
3832  *                     directly from the mode argument of ioctl().
3833  *
3834  * Return Code: 0
3835  *              EINVAL
3836  *              EFAULT
3837  *              ENXIO
3838  *              EIO
3839  */
3840 static int
3841 cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag)
3842 {
3843         struct dk_map   dk_map[NDKMAP];
3844         struct dk_map   *lp;
3845         int             rval = 0;
3846         int             size;
3847         int             i;
3848 #if defined(_SUNOS_VTOC_16)
3849         struct dkl_partition    *vp;
3850 #endif
3851 
3852         /*
3853          * Set the map for all logical partitions.  We lock
3854          * the priority just to make sure an interrupt doesn't
3855          * come in while the map is half updated.
3856          */
3857         mutex_enter(CMLB_MUTEX(cl));
3858 
3859         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3860                 mutex_exit(CMLB_MUTEX(cl));
3861                 return (ENOTSUP);
3862         }
3863         mutex_exit(CMLB_MUTEX(cl));
3864         if (cl->cl_solaris_size == 0) {
3865                 return (EIO);
3866         }
3867 
3868 #ifdef _MULTI_DATAMODEL
3869         switch (ddi_model_convert_from(flag & FMODELS)) {
3870         case DDI_MODEL_ILP32: {
3871                 struct dk_map32 dk_map32[NDKMAP];
3872 
3873                 size = NDKMAP * sizeof (struct dk_map32);
3874                 rval = ddi_copyin((void *)arg, dk_map32, size, flag);
3875                 if (rval != 0) {
3876                         return (EFAULT);
3877                 }
3878                 for (i = 0; i < NDKMAP; i++) {
3879                         dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno;
3880                         dk_map[i].dkl_nblk  = dk_map32[i].dkl_nblk;
3881                 }
3882                 break;
3883         }
3884         case DDI_MODEL_NONE:
3885                 size = NDKMAP * sizeof (struct dk_map);
3886                 rval = ddi_copyin((void *)arg, dk_map, size, flag);
3887                 if (rval != 0) {
3888                         return (EFAULT);
3889                 }
3890                 break;
3891         }
3892 #else /* ! _MULTI_DATAMODEL */
3893         size = NDKMAP * sizeof (struct dk_map);
3894         rval = ddi_copyin((void *)arg, dk_map, size, flag);
3895         if (rval != 0) {
3896                 return (EFAULT);
3897         }
3898 #endif /* _MULTI_DATAMODEL */
3899 
3900         mutex_enter(CMLB_MUTEX(cl));
3901         /* Note: The size used in this bcopy is set based upon the data model */
3902         bcopy(dk_map, cl->cl_map, size);
3903 #if defined(_SUNOS_VTOC_16)
3904         vp = (struct dkl_partition *)&(cl->cl_vtoc);
3905 #endif  /* defined(_SUNOS_VTOC_16) */
3906         for (i = 0; i < NDKMAP; i++) {
3907                 lp  = &cl->cl_map[i];
3908                 cl->cl_offset[i] =
3909                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3910 #if defined(_SUNOS_VTOC_16)
3911                 vp->p_start = cl->cl_offset[i];
3912                 vp->p_size = lp->dkl_nblk;
3913                 vp++;
3914 #endif  /* defined(_SUNOS_VTOC_16) */
3915 #if defined(__i386) || defined(__amd64)
3916                 cl->cl_offset[i] += cl->cl_solaris_offset;
3917 #endif
3918         }
3919         mutex_exit(CMLB_MUTEX(cl));
3920         return (rval);
3921 }
3922 
3923 
3924 /*
3925  *    Function: cmlb_dkio_get_vtoc
3926  *
3927  * Description: This routine is the driver entry point for handling user
3928  *              requests to get the current volume table of contents
3929  *              (DKIOCGVTOC).
3930  *
3931  *   Arguments:
3932  *      arg             pointer to user provided vtoc structure specifying
3933  *                      the current vtoc.
3934  *
3935  *      flag            this argument is a pass through to ddi_copyxxx()
3936  *                      directly from the mode argument of ioctl().
3937  *
3938  *      tg_cookie       cookie from target driver to be passed back to target
3939  *                      driver when we call back to it through tg_ops.
3940  *
3941  * Return Code: 0
3942  *              EFAULT
3943  *              ENXIO
3944  *              EIO
3945  */
3946 static int
3947 cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
3948 {
3949 #if defined(_SUNOS_VTOC_8)
3950         struct vtoc     user_vtoc;
3951 #endif  /* defined(_SUNOS_VTOC_8) */
3952         int             rval = 0;
3953 
3954         mutex_enter(CMLB_MUTEX(cl));
3955         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3956                 mutex_exit(CMLB_MUTEX(cl));
3957                 return (EOVERFLOW);
3958         }
3959 
3960         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3961 
3962 #if defined(_SUNOS_VTOC_8)
3963         if (rval == EINVAL &&
3964             (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
3965                 /*
3966                  * This is to return a default label even when we do not
3967                  * really assume a default label for the device.
3968                  * dad driver utilizes this.
3969                  */
3970                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3971                         cmlb_setup_default_geometry(cl, tg_cookie);
3972                         rval = 0;
3973                 }
3974         }
3975 #endif
3976         if (rval) {
3977                 mutex_exit(CMLB_MUTEX(cl));
3978                 return (rval);
3979         }
3980 
3981 #if defined(_SUNOS_VTOC_8)
3982         cmlb_build_user_vtoc(cl, &user_vtoc);
3983         mutex_exit(CMLB_MUTEX(cl));
3984 
3985 #ifdef _MULTI_DATAMODEL
3986         switch (ddi_model_convert_from(flag & FMODELS)) {
3987         case DDI_MODEL_ILP32: {
3988                 struct vtoc32 user_vtoc32;
3989 
3990                 vtoctovtoc32(user_vtoc, user_vtoc32);
3991                 if (ddi_copyout(&user_vtoc32, (void *)arg,
3992                     sizeof (struct vtoc32), flag)) {
3993                         return (EFAULT);
3994                 }
3995                 break;
3996         }
3997 
3998         case DDI_MODEL_NONE:
3999                 if (ddi_copyout(&user_vtoc, (void *)arg,
4000                     sizeof (struct vtoc), flag)) {
4001                         return (EFAULT);
4002                 }
4003                 break;
4004         }
4005 #else /* ! _MULTI_DATAMODEL */
4006         if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) {
4007                 return (EFAULT);
4008         }
4009 #endif /* _MULTI_DATAMODEL */
4010 
4011 #elif defined(_SUNOS_VTOC_16)
4012         mutex_exit(CMLB_MUTEX(cl));
4013 
4014 #ifdef _MULTI_DATAMODEL
4015         /*
4016          * The cl_vtoc structure is a "struct dk_vtoc"  which is always
4017          * 32-bit to maintain compatibility with existing on-disk
4018          * structures.  Thus, we need to convert the structure when copying
4019          * it out to a datamodel-dependent "struct vtoc" in a 64-bit
4020          * program.  If the target is a 32-bit program, then no conversion
4021          * is necessary.
4022          */
4023         /* LINTED: logical expression always true: op "||" */
4024         ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32));
4025         switch (ddi_model_convert_from(flag & FMODELS)) {
4026         case DDI_MODEL_ILP32:
4027                 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg,
4028                     sizeof (cl->cl_vtoc), flag)) {
4029                         return (EFAULT);
4030                 }
4031                 break;
4032 
4033         case DDI_MODEL_NONE: {
4034                 struct vtoc user_vtoc;
4035 
4036                 vtoc32tovtoc(cl->cl_vtoc, user_vtoc);
4037                 if (ddi_copyout(&user_vtoc, (void *)arg,
4038                     sizeof (struct vtoc), flag)) {
4039                         return (EFAULT);
4040                 }
4041                 break;
4042         }
4043         }
4044 #else /* ! _MULTI_DATAMODEL */
4045         if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc),
4046             flag)) {
4047                 return (EFAULT);
4048         }
4049 #endif /* _MULTI_DATAMODEL */
4050 #else
4051 #error "No VTOC format defined."
4052 #endif
4053 
4054         return (rval);
4055 }
4056 
4057 
4058 /*
4059  *    Function: cmlb_dkio_get_extvtoc
4060  */
4061 static int
4062 cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
4063     void *tg_cookie)
4064 {
4065         struct extvtoc  ext_vtoc;
4066 #if defined(_SUNOS_VTOC_8)
4067         struct vtoc     user_vtoc;
4068 #endif  /* defined(_SUNOS_VTOC_8) */
4069         int             rval = 0;
4070 
4071         bzero(&ext_vtoc, sizeof (struct extvtoc));
4072         mutex_enter(CMLB_MUTEX(cl));
4073         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
4074 
4075 #if defined(_SUNOS_VTOC_8)
4076         if (rval == EINVAL &&
4077             (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
4078                 /*
4079                  * This is to return a default label even when we do not
4080                  * really assume a default label for the device.
4081                  * dad driver utilizes this.
4082                  */
4083                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
4084                         cmlb_setup_default_geometry(cl, tg_cookie);
4085                         rval = 0;
4086                 }
4087         }
4088 #endif
4089         if (rval) {
4090                 mutex_exit(CMLB_MUTEX(cl));
4091                 return (rval);
4092         }
4093 
4094 #if defined(_SUNOS_VTOC_8)
4095         cmlb_build_user_vtoc(cl, &user_vtoc);
4096         mutex_exit(CMLB_MUTEX(cl));
4097 
4098         /*
4099          * Checking callers data model does not make much sense here
4100          * since extvtoc will always be equivalent to 64bit vtoc.
4101          * What is important is whether the kernel is in 32 or 64 bit
4102          */
4103 
4104 #ifdef _LP64
4105                 if (ddi_copyout(&user_vtoc, (void *)arg,
4106                     sizeof (struct extvtoc), flag)) {
4107                         return (EFAULT);
4108                 }
4109 #else
4110                 vtoc32tovtoc(user_vtoc, ext_vtoc);
4111                 if (ddi_copyout(&ext_vtoc, (void *)arg,
4112                     sizeof (struct extvtoc), flag)) {
4113                         return (EFAULT);
4114                 }
4115 #endif
4116 
4117 #elif defined(_SUNOS_VTOC_16)
4118         /*
4119          * The cl_vtoc structure is a "struct dk_vtoc"  which is always
4120          * 32-bit to maintain compatibility with existing on-disk
4121          * structures.  Thus, we need to convert the structure when copying
4122          * it out to extvtoc
4123          */
4124         vtoc32tovtoc(cl->cl_vtoc, ext_vtoc);
4125         mutex_exit(CMLB_MUTEX(cl));
4126 
4127         if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag))
4128                 return (EFAULT);
4129 #else
4130 #error "No VTOC format defined."
4131 #endif
4132 
4133         return (rval);
4134 }
4135 
4136 /*
4137  * This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
4138  * used to read the GPT Partition Table Header (primary/backup), the GUID
4139  * partition Entry Array (primary/backup), and the MBR.
4140  */
4141 static int
4142 cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
4143 {
4144         dk_efi_t        user_efi;
4145         int             rval = 0;
4146         void            *buffer;
4147         diskaddr_t      tgt_lba;
4148 
4149         if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4150                 return (EFAULT);
4151 
4152         user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4153 
4154         if (user_efi.dki_length == 0 ||
4155             user_efi.dki_length > cmlb_tg_max_efi_xfer)
4156                 return (EINVAL);
4157 
4158         tgt_lba = user_efi.dki_lba;
4159 
4160         mutex_enter(CMLB_MUTEX(cl));
4161         if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4162             (cl->cl_tgt_blocksize == 0) ||
4163             (user_efi.dki_length % cl->cl_sys_blocksize)) {
4164                 mutex_exit(CMLB_MUTEX(cl));
4165                 return (EINVAL);
4166         }
4167         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
4168                 tgt_lba = tgt_lba * cl->cl_tgt_blocksize /
4169                     cl->cl_sys_blocksize;
4170         mutex_exit(CMLB_MUTEX(cl));
4171 
4172         buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
4173         rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie);
4174         if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data,
4175             user_efi.dki_length, flag) != 0)
4176                 rval = EFAULT;
4177 
4178         kmem_free(buffer, user_efi.dki_length);
4179         return (rval);
4180 }
4181 
4182 #if defined(_SUNOS_VTOC_8)
4183 /*
4184  *    Function: cmlb_build_user_vtoc
4185  *
4186  * Description: This routine populates a pass by reference variable with the
4187  *              current volume table of contents.
4188  *
4189  *   Arguments: cl - driver soft state (unit) structure
4190  *              user_vtoc - pointer to vtoc structure to be populated
4191  */
4192 static void
4193 cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4194 {
4195         struct dk_map2          *lpart;
4196         struct dk_map           *lmap;
4197         struct partition        *vpart;
4198         uint32_t                nblks;
4199         int                     i;
4200 
4201         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4202 
4203         /*
4204          * Return vtoc structure fields in the provided VTOC area, addressed
4205          * by *vtoc.
4206          */
4207         bzero(user_vtoc, sizeof (struct vtoc));
4208         user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0];
4209         user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1];
4210         user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2];
4211         user_vtoc->v_sanity  = VTOC_SANE;
4212         user_vtoc->v_version = cl->cl_vtoc.v_version;
4213         bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL);
4214         user_vtoc->v_sectorsz = cl->cl_sys_blocksize;
4215         user_vtoc->v_nparts = cl->cl_vtoc.v_nparts;
4216 
4217         for (i = 0; i < 10; i++)
4218                 user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i];
4219 
4220         /*
4221          * Convert partitioning information.
4222          *
4223          * Note the conversion from starting cylinder number
4224          * to starting sector number.
4225          */
4226         lmap = cl->cl_map;
4227         lpart = (struct dk_map2 *)cl->cl_vtoc.v_part;
4228         vpart = user_vtoc->v_part;
4229 
4230         nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4231 
4232         for (i = 0; i < V_NUMPAR; i++) {
4233                 vpart->p_tag = lpart->p_tag;
4234                 vpart->p_flag        = lpart->p_flag;
4235                 vpart->p_start       = lmap->dkl_cylno * nblks;
4236                 vpart->p_size        = lmap->dkl_nblk;
4237                 lmap++;
4238                 lpart++;
4239                 vpart++;
4240 
4241                 /* (4364927) */
4242                 user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i];
4243         }
4244 
4245         bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII);
4246 }
4247 #endif
4248 
4249 static int
4250 cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
4251     void *tg_cookie)
4252 {
4253         struct partition64      p64;
4254         int                     rval = 0;
4255         uint_t                  nparts;
4256         efi_gpe_t               *partitions;
4257         efi_gpt_t               *buffer;
4258         diskaddr_t              gpe_lba;
4259         int                     n_gpe_per_blk = 0;
4260 
4261         if (ddi_copyin((const void *)arg, &p64,
4262             sizeof (struct partition64), flag)) {
4263                 return (EFAULT);
4264         }
4265 
4266         buffer = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4267         rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie);
4268         if (rval != 0)
4269                 goto done_error;
4270 
4271         cmlb_swap_efi_gpt(buffer);
4272 
4273         if ((rval = cmlb_validate_efi(buffer)) != 0)
4274                 goto done_error;
4275 
4276         nparts = buffer->efi_gpt_NumberOfPartitionEntries;
4277         gpe_lba = buffer->efi_gpt_PartitionEntryLBA;
4278         if (p64.p_partno >= nparts) {
4279                 /* couldn't find it */
4280                 rval = ESRCH;
4281                 goto done_error;
4282         }
4283         /*
4284          * Read the block that contains the requested GPE.
4285          */
4286         n_gpe_per_blk = cl->cl_sys_blocksize / sizeof (efi_gpe_t);
4287         gpe_lba += p64.p_partno / n_gpe_per_blk;
4288         rval = DK_TG_READ(cl, buffer, gpe_lba, cl->cl_sys_blocksize, tg_cookie);
4289 
4290         if (rval) {
4291                 goto done_error;
4292         }
4293         partitions = (efi_gpe_t *)buffer;
4294         partitions += p64.p_partno % n_gpe_per_blk;
4295 
4296         /* Byte swap only the requested GPE */
4297         cmlb_swap_efi_gpe(1, partitions);
4298 
4299         bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type,
4300             sizeof (struct uuid));
4301         p64.p_start = partitions->efi_gpe_StartingLBA;
4302         p64.p_size = partitions->efi_gpe_EndingLBA -
4303             p64.p_start + 1;
4304 
4305         if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag))
4306                 rval = EFAULT;
4307 
4308 done_error:
4309         kmem_free(buffer, cl->cl_sys_blocksize);
4310         return (rval);
4311 }
4312 
4313 
4314 /*
4315  *    Function: cmlb_dkio_set_vtoc
4316  *
4317  * Description: This routine is the driver entry point for handling user
4318  *              requests to set the current volume table of contents
4319  *              (DKIOCSVTOC).
4320  *
4321  *   Arguments:
4322  *      dev             the device number
4323  *      arg             pointer to user provided vtoc structure used to set the
4324  *                      current vtoc.
4325  *
4326  *      flag            this argument is a pass through to ddi_copyxxx()
4327  *                      directly from the mode argument of ioctl().
4328  *
4329  *      tg_cookie       cookie from target driver to be passed back to target
4330  *                      driver when we call back to it through tg_ops.
4331  *
4332  * Return Code: 0
4333  *              EFAULT
4334  *              ENXIO
4335  *              EINVAL
4336  *              ENOTSUP
4337  */
4338 static int
4339 cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4340     void *tg_cookie)
4341 {
4342         struct vtoc     user_vtoc;
4343         int             shift, rval = 0;
4344         boolean_t       internal;
4345 
4346         internal = VOID2BOOLEAN(
4347             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4348 
4349         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4350                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4351         else
4352                 shift = CMLBUNIT_SHIFT;
4353 
4354 #ifdef _MULTI_DATAMODEL
4355         switch (ddi_model_convert_from(flag & FMODELS)) {
4356         case DDI_MODEL_ILP32: {
4357                 struct vtoc32 user_vtoc32;
4358 
4359                 if (ddi_copyin((const void *)arg, &user_vtoc32,
4360                     sizeof (struct vtoc32), flag)) {
4361                         return (EFAULT);
4362                 }
4363                 vtoc32tovtoc(user_vtoc32, user_vtoc);
4364                 break;
4365         }
4366 
4367         case DDI_MODEL_NONE:
4368                 if (ddi_copyin((const void *)arg, &user_vtoc,
4369                     sizeof (struct vtoc), flag)) {
4370                         return (EFAULT);
4371                 }
4372                 break;
4373         }
4374 #else /* ! _MULTI_DATAMODEL */
4375         if (ddi_copyin((const void *)arg, &user_vtoc,
4376             sizeof (struct vtoc), flag)) {
4377                 return (EFAULT);
4378         }
4379 #endif /* _MULTI_DATAMODEL */
4380 
4381         mutex_enter(CMLB_MUTEX(cl));
4382 
4383         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
4384                 mutex_exit(CMLB_MUTEX(cl));
4385                 return (EOVERFLOW);
4386         }
4387 
4388 #if defined(__i386) || defined(__amd64)
4389         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4390                 mutex_exit(CMLB_MUTEX(cl));
4391                 return (EINVAL);
4392         }
4393 #endif
4394 
4395         if (cl->cl_g.dkg_ncyl == 0) {
4396                 mutex_exit(CMLB_MUTEX(cl));
4397                 return (EINVAL);
4398         }
4399 
4400         mutex_exit(CMLB_MUTEX(cl));
4401         cmlb_clear_efi(cl, tg_cookie);
4402         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4403         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4404 
4405         /*
4406          * cmlb_dkio_set_vtoc creates duplicate minor nodes when
4407          * relabeling an SMI disk. To avoid that we remove them
4408          * before creating.
4409          * It should be OK to remove a non-existed minor node.
4410          */
4411         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4412         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4413 
4414         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4415             S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4416             cl->cl_node_type, NULL, internal);
4417         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4418             S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4419             cl->cl_node_type, NULL, internal);
4420         mutex_enter(CMLB_MUTEX(cl));
4421 
4422         if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4423                 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4424                         if (cmlb_validate_geometry(cl,
4425                             B_TRUE, 0, tg_cookie) != 0) {
4426                                 cmlb_dbg(CMLB_ERROR, cl,
4427                                     "cmlb_dkio_set_vtoc: "
4428                                     "Failed validate geometry\n");
4429                         }
4430                         cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
4431                 }
4432         }
4433         mutex_exit(CMLB_MUTEX(cl));
4434         return (rval);
4435 }
4436 
4437 /*
4438  *    Function: cmlb_dkio_set_extvtoc
4439  */
4440 static int
4441 cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4442     void *tg_cookie)
4443 {
4444         int             shift, rval = 0;
4445         struct vtoc     user_vtoc;
4446         boolean_t       internal;
4447 
4448         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4449                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4450         else
4451                 shift = CMLBUNIT_SHIFT;
4452 
4453         /*
4454          * Checking callers data model does not make much sense here
4455          * since extvtoc will always be equivalent to 64bit vtoc.
4456          * What is important is whether the kernel is in 32 or 64 bit
4457          */
4458 
4459 #ifdef _LP64
4460         if (ddi_copyin((const void *)arg, &user_vtoc,
4461                     sizeof (struct extvtoc), flag)) {
4462                         return (EFAULT);
4463         }
4464 #else
4465         struct  extvtoc user_extvtoc;
4466         if (ddi_copyin((const void *)arg, &user_extvtoc,
4467                     sizeof (struct extvtoc), flag)) {
4468                         return (EFAULT);
4469         }
4470 
4471         vtoctovtoc32(user_extvtoc, user_vtoc);
4472 #endif
4473 
4474         internal = VOID2BOOLEAN(
4475             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4476         mutex_enter(CMLB_MUTEX(cl));
4477 #if defined(__i386) || defined(__amd64)
4478         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4479                 mutex_exit(CMLB_MUTEX(cl));
4480                 return (EINVAL);
4481         }
4482 #endif
4483 
4484         if (cl->cl_g.dkg_ncyl == 0) {
4485                 mutex_exit(CMLB_MUTEX(cl));
4486                 return (EINVAL);
4487         }
4488 
4489         mutex_exit(CMLB_MUTEX(cl));
4490         cmlb_clear_efi(cl, tg_cookie);
4491         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4492         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4493         /*
4494          * cmlb_dkio_set_extvtoc creates duplicate minor nodes when
4495          * relabeling an SMI disk. To avoid that we remove them
4496          * before creating.
4497          * It should be OK to remove a non-existed minor node.
4498          */
4499         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4500         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4501 
4502         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4503             S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4504             cl->cl_node_type, NULL, internal);
4505         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4506             S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4507             cl->cl_node_type, NULL, internal);
4508 
4509         mutex_enter(CMLB_MUTEX(cl));
4510 
4511         if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4512                 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4513                         if (cmlb_validate_geometry(cl,
4514                             B_TRUE, 0, tg_cookie) != 0) {
4515                                 cmlb_dbg(CMLB_ERROR, cl,
4516                                     "cmlb_dkio_set_vtoc: "
4517                                     "Failed validate geometry\n");
4518                         }
4519                 }
4520         }
4521         mutex_exit(CMLB_MUTEX(cl));
4522         return (rval);
4523 }
4524 
4525 /*
4526  *    Function: cmlb_build_label_vtoc
4527  *
4528  * Description: This routine updates the driver soft state current volume table
4529  *              of contents based on a user specified vtoc.
4530  *
4531  *   Arguments: cl - driver soft state (unit) structure
4532  *              user_vtoc - pointer to vtoc structure specifying vtoc to be used
4533  *                          to update the driver soft state.
4534  *
4535  * Return Code: 0
4536  *              EINVAL
4537  */
4538 static int
4539 cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4540 {
4541         struct dk_map           *lmap;
4542         struct partition        *vpart;
4543         uint_t                  nblks;
4544 #if defined(_SUNOS_VTOC_8)
4545         int                     ncyl;
4546         struct dk_map2          *lpart;
4547 #endif  /* defined(_SUNOS_VTOC_8) */
4548         int                     i;
4549 
4550         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4551 
4552         /* Sanity-check the vtoc */
4553         if (user_vtoc->v_sanity != VTOC_SANE ||
4554             user_vtoc->v_sectorsz != cl->cl_sys_blocksize ||
4555             user_vtoc->v_nparts != V_NUMPAR) {
4556                 cmlb_dbg(CMLB_INFO,  cl,
4557                     "cmlb_build_label_vtoc: vtoc not valid\n");
4558                 return (EINVAL);
4559         }
4560 
4561         nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4562         if (nblks == 0) {
4563                 cmlb_dbg(CMLB_INFO,  cl,
4564                     "cmlb_build_label_vtoc: geom nblks is 0\n");
4565                 return (EINVAL);
4566         }
4567 
4568 #if defined(_SUNOS_VTOC_8)
4569         vpart = user_vtoc->v_part;
4570         for (i = 0; i < V_NUMPAR; i++) {
4571                 if (((unsigned)vpart->p_start % nblks) != 0) {
4572                         cmlb_dbg(CMLB_INFO,  cl,
4573                             "cmlb_build_label_vtoc: p_start not multiply of"
4574                             "nblks part %d p_start %d nblks %d\n", i,
4575                             vpart->p_start, nblks);
4576                         return (EINVAL);
4577                 }
4578                 ncyl = (unsigned)vpart->p_start / nblks;
4579                 ncyl += (unsigned)vpart->p_size / nblks;
4580                 if (((unsigned)vpart->p_size % nblks) != 0) {
4581                         ncyl++;
4582                 }
4583                 if (ncyl > (int)cl->cl_g.dkg_ncyl) {
4584                         cmlb_dbg(CMLB_INFO,  cl,
4585                             "cmlb_build_label_vtoc: ncyl %d  > dkg_ncyl %d"
4586                             "p_size %ld p_start %ld nblks %d  part number %d"
4587                             "tag %d\n",
4588                             ncyl, cl->cl_g.dkg_ncyl, vpart->p_size,
4589                             vpart->p_start, nblks,
4590                             i, vpart->p_tag);
4591 
4592                         return (EINVAL);
4593                 }
4594                 vpart++;
4595         }
4596 #endif  /* defined(_SUNOS_VTOC_8) */
4597 
4598         /* Put appropriate vtoc structure fields into the disk label */
4599 #if defined(_SUNOS_VTOC_16)
4600         /*
4601          * The vtoc is always a 32bit data structure to maintain the
4602          * on-disk format. Convert "in place" instead of doing bcopy.
4603          */
4604         vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc))));
4605 
4606         /*
4607          * in the 16-slice vtoc, starting sectors are expressed in
4608          * numbers *relative* to the start of the Solaris fdisk partition.
4609          */
4610         lmap = cl->cl_map;
4611         vpart = user_vtoc->v_part;
4612 
4613         for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) {
4614                 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4615                 lmap->dkl_nblk = (unsigned)vpart->p_size;
4616         }
4617 
4618 #elif defined(_SUNOS_VTOC_8)
4619 
4620         cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0];
4621         cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1];
4622         cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2];
4623 
4624         cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity;
4625         cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version;
4626 
4627         bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL);
4628 
4629         cl->cl_vtoc.v_nparts = user_vtoc->v_nparts;
4630 
4631         for (i = 0; i < 10; i++)
4632                 cl->cl_vtoc.v_reserved[i] =  user_vtoc->v_reserved[i];
4633 
4634         /*
4635          * Note the conversion from starting sector number
4636          * to starting cylinder number.
4637          * Return error if division results in a remainder.
4638          */
4639         lmap = cl->cl_map;
4640         lpart = cl->cl_vtoc.v_part;
4641         vpart = user_vtoc->v_part;
4642 
4643         for (i = 0; i < (int)user_vtoc->v_nparts; i++) {
4644                 lpart->p_tag  = vpart->p_tag;
4645                 lpart->p_flag = vpart->p_flag;
4646                 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4647                 lmap->dkl_nblk = (unsigned)vpart->p_size;
4648 
4649                 lmap++;
4650                 lpart++;
4651                 vpart++;
4652 
4653                 /* (4387723) */
4654 #ifdef _LP64
4655                 if (user_vtoc->timestamp[i] > TIME32_MAX) {
4656                         cl->cl_vtoc.v_timestamp[i] = TIME32_MAX;
4657                 } else {
4658                         cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4659                 }
4660 #else
4661                 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4662 #endif
4663         }
4664 
4665         bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
4666 #else
4667 #error "No VTOC format defined."
4668 #endif
4669         return (0);
4670 }
4671 
4672 /*
4673  *    Function: cmlb_clear_efi
4674  *
4675  * Description: This routine clears all EFI labels.
4676  *
4677  *   Arguments:
4678  *      cl               driver soft state (unit) structure
4679  *
4680  *      tg_cookie       cookie from target driver to be passed back to target
4681  *                      driver when we call back to it through tg_ops.
4682  * Return Code: void
4683  */
4684 static void
4685 cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie)
4686 {
4687         efi_gpt_t       *gpt;
4688         diskaddr_t      cap;
4689         int             rval;
4690 
4691         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
4692 
4693         mutex_enter(CMLB_MUTEX(cl));
4694         cl->cl_reserved = -1;
4695         mutex_exit(CMLB_MUTEX(cl));
4696 
4697         gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4698 
4699         if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) {
4700                 goto done;
4701         }
4702 
4703         cmlb_swap_efi_gpt(gpt);
4704         rval = cmlb_validate_efi(gpt);
4705         if (rval == 0) {
4706                 /* clear primary */
4707                 bzero(gpt, sizeof (efi_gpt_t));
4708                 if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize,
4709                     tg_cookie)) {
4710                         cmlb_dbg(CMLB_INFO,  cl,
4711                             "cmlb_clear_efi: clear primary label failed\n");
4712                 }
4713         }
4714         /* the backup */
4715         rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
4716         if (rval) {
4717                 goto done;
4718         }
4719 
4720         if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize,
4721             tg_cookie)) != 0) {
4722                 goto done;
4723         }
4724         cmlb_swap_efi_gpt(gpt);
4725         rval = cmlb_validate_efi(gpt);
4726         if (rval == 0) {
4727                 /* clear backup */
4728                 cmlb_dbg(CMLB_TRACE,  cl,
4729                     "cmlb_clear_efi clear backup@%lu\n", cap - 1);
4730                 bzero(gpt, sizeof (efi_gpt_t));
4731                 if ((rval = DK_TG_WRITE(cl,  gpt, cap - 1, cl->cl_sys_blocksize,
4732                     tg_cookie))) {
4733                         cmlb_dbg(CMLB_INFO,  cl,
4734                             "cmlb_clear_efi: clear backup label failed\n");
4735                 }
4736         } else {
4737                 /*
4738                  * Refer to comments related to off-by-1 at the
4739                  * header of this file
4740                  */
4741                 if ((rval = DK_TG_READ(cl, gpt, cap - 2,
4742                     cl->cl_sys_blocksize, tg_cookie)) != 0) {
4743                         goto done;
4744                 }
4745                 cmlb_swap_efi_gpt(gpt);
4746                 rval = cmlb_validate_efi(gpt);
4747                 if (rval == 0) {
4748                         /* clear legacy backup EFI label */
4749                         cmlb_dbg(CMLB_TRACE,  cl,
4750                             "cmlb_clear_efi clear legacy backup@%lu\n",
4751                             cap - 2);
4752                         bzero(gpt, sizeof (efi_gpt_t));
4753                         if ((rval = DK_TG_WRITE(cl,  gpt, cap - 2,
4754                             cl->cl_sys_blocksize, tg_cookie))) {
4755                                 cmlb_dbg(CMLB_INFO,  cl,
4756                                 "cmlb_clear_efi: clear legacy backup label "
4757                                 "failed\n");
4758                         }
4759                 }
4760         }
4761 
4762 done:
4763         kmem_free(gpt, cl->cl_sys_blocksize);
4764 }
4765 
4766 /*
4767  *    Function: cmlb_set_vtoc
4768  *
4769  * Description: This routine writes data to the appropriate positions
4770  *
4771  *   Arguments:
4772  *      cl              driver soft state (unit) structure
4773  *
4774  *      dkl             the data to be written
4775  *
4776  *      tg_cookie       cookie from target driver to be passed back to target
4777  *                      driver when we call back to it through tg_ops.
4778  *
4779  * Return: void
4780  */
4781 static int
4782 cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie)
4783 {
4784         uint_t  label_addr;
4785         int     sec;
4786         diskaddr_t      blk;
4787         int     head;
4788         int     cyl;
4789         int     rval;
4790 
4791 #if defined(__i386) || defined(__amd64)
4792         label_addr = cl->cl_solaris_offset + DK_LABEL_LOC;
4793 #else
4794         /* Write the primary label at block 0 of the solaris partition. */
4795         label_addr = 0;
4796 #endif
4797 
4798         rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize,
4799             tg_cookie);
4800 
4801         if (rval != 0) {
4802                 return (rval);
4803         }
4804 
4805         /*
4806          * Calculate where the backup labels go.  They are always on
4807          * the last alternate cylinder, but some older drives put them
4808          * on head 2 instead of the last head.  They are always on the
4809          * first 5 odd sectors of the appropriate track.
4810          *
4811          * We have no choice at this point, but to believe that the
4812          * disk label is valid.  Use the geometry of the disk
4813          * as described in the label.
4814          */
4815         cyl  = dkl->dkl_ncyl  + dkl->dkl_acyl - 1;
4816         head = dkl->dkl_nhead - 1;
4817 
4818         /*
4819          * Write and verify the backup labels. Make sure we don't try to
4820          * write past the last cylinder.
4821          */
4822         for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) {
4823                 blk = (diskaddr_t)(
4824                     (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) +
4825                     (head * dkl->dkl_nsect) + sec);
4826 #if defined(__i386) || defined(__amd64)
4827                 blk += cl->cl_solaris_offset;
4828 #endif
4829                 rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize,
4830                     tg_cookie);
4831                 cmlb_dbg(CMLB_INFO,  cl,
4832                 "cmlb_set_vtoc: wrote backup label %llx\n", blk);
4833                 if (rval != 0) {
4834                         goto exit;
4835                 }
4836         }
4837 exit:
4838         return (rval);
4839 }
4840 
4841 /*
4842  *    Function: cmlb_clear_vtoc
4843  *
4844  * Description: This routine clears out the VTOC labels.
4845  *
4846  *   Arguments:
4847  *      cl              driver soft state (unit) structure
4848  *
4849  *      tg_cookie       cookie from target driver to be passed back to target
4850  *                      driver when we call back to it through tg_ops.
4851  *
4852  * Return: void
4853  */
4854 static void
4855 cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie)
4856 {
4857         struct dk_label         *dkl;
4858 
4859         mutex_exit(CMLB_MUTEX(cl));
4860         dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4861         mutex_enter(CMLB_MUTEX(cl));
4862         /*
4863          * cmlb_set_vtoc uses these fields in order to figure out
4864          * where to overwrite the backup labels
4865          */
4866         dkl->dkl_apc    = cl->cl_g.dkg_apc;
4867         dkl->dkl_ncyl   = cl->cl_g.dkg_ncyl;
4868         dkl->dkl_acyl   = cl->cl_g.dkg_acyl;
4869         dkl->dkl_nhead  = cl->cl_g.dkg_nhead;
4870         dkl->dkl_nsect  = cl->cl_g.dkg_nsect;
4871         mutex_exit(CMLB_MUTEX(cl));
4872         (void) cmlb_set_vtoc(cl, dkl, tg_cookie);
4873         kmem_free(dkl, cl->cl_sys_blocksize);
4874 
4875         mutex_enter(CMLB_MUTEX(cl));
4876 }
4877 
4878 /*
4879  *    Function: cmlb_write_label
4880  *
4881  * Description: This routine will validate and write the driver soft state vtoc
4882  *              contents to the device.
4883  *
4884  *   Arguments:
4885  *      cl              cmlb handle
4886  *
4887  *      tg_cookie       cookie from target driver to be passed back to target
4888  *                      driver when we call back to it through tg_ops.
4889  *
4890  *
4891  * Return Code: the code returned by cmlb_send_scsi_cmd()
4892  *              0
4893  *              EINVAL
4894  *              ENXIO
4895  *              ENOMEM
4896  */
4897 static int
4898 cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie)
4899 {
4900         struct dk_label *dkl;
4901         short           sum;
4902         short           *sp;
4903         int             i;
4904         int             rval;
4905 
4906         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4907         mutex_exit(CMLB_MUTEX(cl));
4908         dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4909         mutex_enter(CMLB_MUTEX(cl));
4910 
4911         bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc));
4912         dkl->dkl_rpm = cl->cl_g.dkg_rpm;
4913         dkl->dkl_pcyl        = cl->cl_g.dkg_pcyl;
4914         dkl->dkl_apc = cl->cl_g.dkg_apc;
4915         dkl->dkl_intrlv = cl->cl_g.dkg_intrlv;
4916         dkl->dkl_ncyl        = cl->cl_g.dkg_ncyl;
4917         dkl->dkl_acyl        = cl->cl_g.dkg_acyl;
4918         dkl->dkl_nhead       = cl->cl_g.dkg_nhead;
4919         dkl->dkl_nsect       = cl->cl_g.dkg_nsect;
4920 
4921 #if defined(_SUNOS_VTOC_8)
4922         dkl->dkl_obs1        = cl->cl_g.dkg_obs1;
4923         dkl->dkl_obs2        = cl->cl_g.dkg_obs2;
4924         dkl->dkl_obs3        = cl->cl_g.dkg_obs3;
4925         for (i = 0; i < NDKMAP; i++) {
4926                 dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
4927                 dkl->dkl_map[i].dkl_nblk  = cl->cl_map[i].dkl_nblk;
4928         }
4929         bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII);
4930 #elif defined(_SUNOS_VTOC_16)
4931         dkl->dkl_skew        = cl->cl_dkg_skew;
4932 #else
4933 #error "No VTOC format defined."
4934 #endif
4935 
4936         dkl->dkl_magic                       = DKL_MAGIC;
4937         dkl->dkl_write_reinstruct    = cl->cl_g.dkg_write_reinstruct;
4938         dkl->dkl_read_reinstruct     = cl->cl_g.dkg_read_reinstruct;
4939 
4940         /* Construct checksum for the new disk label */
4941         sum = 0;
4942         sp = (short *)dkl;
4943         i = sizeof (struct dk_label) / sizeof (short);
4944         while (i--) {
4945                 sum ^= *sp++;
4946         }
4947         dkl->dkl_cksum = sum;
4948 
4949         mutex_exit(CMLB_MUTEX(cl));
4950 
4951         rval = cmlb_set_vtoc(cl, dkl, tg_cookie);
4952 exit:
4953         kmem_free(dkl, cl->cl_sys_blocksize);
4954         mutex_enter(CMLB_MUTEX(cl));
4955         return (rval);
4956 }
4957 
4958 /*
4959  * This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
4960  * used to write (or clear) the GPT Partition Table header (primary/backup)
4961  * and GUID partition Entry Array (primary/backup). It is also used to write
4962  * the Protective MBR.
4963  */
4964 static int
4965 cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4966     void *tg_cookie)
4967 {
4968         dk_efi_t        user_efi;
4969         int             shift, rval = 0;
4970         void            *buffer;
4971         diskaddr_t      tgt_lba;
4972         boolean_t       internal;
4973 
4974         if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4975                 return (EFAULT);
4976 
4977         internal = VOID2BOOLEAN(
4978             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4979 
4980         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4981                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4982         else
4983                 shift = CMLBUNIT_SHIFT;
4984 
4985         user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4986 
4987         if (user_efi.dki_length == 0 ||
4988             user_efi.dki_length > cmlb_tg_max_efi_xfer)
4989                 return (EINVAL);
4990 
4991         tgt_lba = user_efi.dki_lba;
4992 
4993         mutex_enter(CMLB_MUTEX(cl));
4994         if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4995             (cl->cl_tgt_blocksize == 0) ||
4996             (user_efi.dki_length % cl->cl_sys_blocksize)) {
4997                 mutex_exit(CMLB_MUTEX(cl));
4998                 return (EINVAL);
4999         }
5000         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
5001                 tgt_lba = tgt_lba *
5002                     cl->cl_tgt_blocksize / cl->cl_sys_blocksize;
5003         mutex_exit(CMLB_MUTEX(cl));
5004 
5005         buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
5006         if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) {
5007                 rval = EFAULT;
5008         } else {
5009                 /*
5010                  * let's clear the vtoc labels and clear the softstate
5011                  * vtoc.
5012                  */
5013                 mutex_enter(CMLB_MUTEX(cl));
5014                 if (cl->cl_vtoc.v_sanity == VTOC_SANE) {
5015                         cmlb_dbg(CMLB_TRACE,  cl,
5016                             "cmlb_dkio_set_efi: CLEAR VTOC\n");
5017                         if (cl->cl_label_from_media == CMLB_LABEL_VTOC)
5018                                 cmlb_clear_vtoc(cl, tg_cookie);
5019                         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
5020                         mutex_exit(CMLB_MUTEX(cl));
5021                         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
5022                         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
5023                         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
5024                             S_IFBLK,
5025                             (CMLBUNIT(dev, shift) << shift) | WD_NODE,
5026                             cl->cl_node_type, NULL, internal);
5027                         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
5028                             S_IFCHR,
5029                             (CMLBUNIT(dev, shift) << shift) | WD_NODE,
5030                             cl->cl_node_type, NULL, internal);
5031                 } else
5032                         mutex_exit(CMLB_MUTEX(cl));
5033 
5034                 rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length,
5035                     tg_cookie);
5036 
5037                 if (rval == 0) {
5038                         mutex_enter(CMLB_MUTEX(cl));
5039                         cl->cl_f_geometry_is_valid = B_FALSE;
5040                         mutex_exit(CMLB_MUTEX(cl));
5041                 }
5042         }
5043         kmem_free(buffer, user_efi.dki_length);
5044         return (rval);
5045 }
5046 
5047 /*
5048  *    Function: cmlb_dkio_get_mboot
5049  *
5050  * Description: This routine is the driver entry point for handling user
5051  *              requests to get the current device mboot (DKIOCGMBOOT)
5052  *
5053  *   Arguments:
5054  *      arg             pointer to user provided mboot structure specifying
5055  *                      the current mboot.
5056  *
5057  *      flag            this argument is a pass through to ddi_copyxxx()
5058  *                      directly from the mode argument of ioctl().
5059  *
5060  *      tg_cookie       cookie from target driver to be passed back to target
5061  *                      driver when we call back to it through tg_ops.
5062  *
5063  * Return Code: 0
5064  *              EINVAL
5065  *              EFAULT
5066  *              ENXIO
5067  */
5068 static int
5069 cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5070 {
5071         struct mboot    *mboot;
5072         int             rval;
5073         size_t          buffer_size;
5074 
5075 
5076 #if defined(_SUNOS_VTOC_8)
5077         if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) {
5078 #elif defined(_SUNOS_VTOC_16)
5079         if (arg == NULL) {
5080 #endif
5081                 return (EINVAL);
5082         }
5083 
5084         /*
5085          * Read the mboot block, located at absolute block 0 on the target.
5086          */
5087         buffer_size = cl->cl_sys_blocksize;
5088 
5089         cmlb_dbg(CMLB_TRACE,  cl,
5090             "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
5091 
5092         mboot = kmem_zalloc(buffer_size, KM_SLEEP);
5093         if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) {
5094                 if (ddi_copyout(mboot, (void *)arg,
5095                     sizeof (struct mboot), flag) != 0) {
5096                         rval = EFAULT;
5097                 }
5098         }
5099         kmem_free(mboot, buffer_size);
5100         return (rval);
5101 }
5102 
5103 
5104 /*
5105  *    Function: cmlb_dkio_set_mboot
5106  *
5107  * Description: This routine is the driver entry point for handling user
5108  *              requests to validate and set the device master boot
5109  *              (DKIOCSMBOOT).
5110  *
5111  *   Arguments:
5112  *      arg             pointer to user provided mboot structure used to set the
5113  *                      master boot.
5114  *
5115  *      flag            this argument is a pass through to ddi_copyxxx()
5116  *                      directly from the mode argument of ioctl().
5117  *
5118  *      tg_cookie       cookie from target driver to be passed back to target
5119  *                      driver when we call back to it through tg_ops.
5120  *
5121  * Return Code: 0
5122  *              EINVAL
5123  *              EFAULT
5124  *              ENXIO
5125  */
5126 static int
5127 cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5128 {
5129         struct mboot    *mboot = NULL;
5130         int             rval;
5131         ushort_t        magic;
5132 
5133 
5134         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5135 
5136 #if defined(_SUNOS_VTOC_8)
5137         if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
5138                 return (EINVAL);
5139         }
5140 #endif
5141 
5142         if (arg == NULL) {
5143                 return (EINVAL);
5144         }
5145 
5146         mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
5147 
5148         if (ddi_copyin((const void *)arg, mboot,
5149             cl->cl_sys_blocksize, flag) != 0) {
5150                 kmem_free(mboot, cl->cl_sys_blocksize);
5151                 return (EFAULT);
5152         }
5153 
5154         /* Is this really a master boot record? */
5155         magic = LE_16(mboot->signature);
5156         if (magic != MBB_MAGIC) {
5157                 kmem_free(mboot, cl->cl_sys_blocksize);
5158                 return (EINVAL);
5159         }
5160 
5161         rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie);
5162 
5163         mutex_enter(CMLB_MUTEX(cl));
5164 #if defined(__i386) || defined(__amd64)
5165         if (rval == 0) {
5166                 /*
5167                  * mboot has been written successfully.
5168                  * update the fdisk and vtoc tables in memory
5169                  */
5170                 rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie);
5171                 if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) {
5172                         mutex_exit(CMLB_MUTEX(cl));
5173                         kmem_free(mboot, cl->cl_sys_blocksize);
5174                         return (rval);
5175                 }
5176         }
5177 #else
5178         if (rval == 0) {
5179                 /*
5180                  * mboot has been written successfully.
5181                  * set up the default geometry and VTOC
5182                  */
5183                 if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT)
5184                         cmlb_setup_default_geometry(cl, tg_cookie);
5185         }
5186 #endif
5187         cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
5188         mutex_exit(CMLB_MUTEX(cl));
5189         kmem_free(mboot, cl->cl_sys_blocksize);
5190         return (rval);
5191 }
5192 
5193 
5194 #if defined(__i386) || defined(__amd64)
5195 /*ARGSUSED*/
5196 static int
5197 cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
5198     void *tg_cookie)
5199 {
5200         int fdisk_rval;
5201         diskaddr_t capacity;
5202 
5203         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5204 
5205         mutex_enter(CMLB_MUTEX(cl));
5206         capacity = cl->cl_blockcount;
5207         fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5208         if (fdisk_rval != 0) {
5209                 mutex_exit(CMLB_MUTEX(cl));
5210                 return (fdisk_rval);
5211         }
5212 
5213         mutex_exit(CMLB_MUTEX(cl));
5214         return (fdisk_rval);
5215 }
5216 #endif
5217 
5218 /*
5219  *    Function: cmlb_setup_default_geometry
5220  *
5221  * Description: This local utility routine sets the default geometry as part of
5222  *              setting the device mboot.
5223  *
5224  *   Arguments:
5225  *      cl              driver soft state (unit) structure
5226  *
5227  *      tg_cookie       cookie from target driver to be passed back to target
5228  *                      driver when we call back to it through tg_ops.
5229  *
5230  *
5231  * Note: This may be redundant with cmlb_build_default_label.
5232  */
5233 static void
5234 cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie)
5235 {
5236         struct cmlb_geom        pgeom;
5237         struct cmlb_geom        *pgeomp = &pgeom;
5238         int                     ret;
5239         int                     geom_base_cap = 1;
5240 
5241 
5242         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5243 
5244         /* zero out the soft state geometry and partition table. */
5245         bzero(&cl->cl_g, sizeof (struct dk_geom));
5246         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
5247         bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
5248 
5249         /*
5250          * For the rpm, we use the minimum for the disk.
5251          * For the head, cyl and number of sector per track,
5252          * if the capacity <= 1GB, head = 64, sect = 32.
5253          * else head = 255, sect 63
5254          * Note: the capacity should be equal to C*H*S values.
5255          * This will cause some truncation of size due to
5256          * round off errors. For CD-ROMs, this truncation can
5257          * have adverse side effects, so returning ncyl and
5258          * nhead as 1. The nsect will overflow for most of
5259          * CD-ROMs as nsect is of type ushort.
5260          */
5261         if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
5262                 /*
5263                  * newfs currently can not handle 255 ntracks for SPARC
5264                  * so get the geometry from target driver instead of coming up
5265                  * with one based on capacity.
5266                  */
5267                 mutex_exit(CMLB_MUTEX(cl));
5268                 ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
5269                 mutex_enter(CMLB_MUTEX(cl));
5270 
5271                 if (ret == 0) {
5272                         geom_base_cap = 0;
5273                 } else {
5274                         cmlb_dbg(CMLB_ERROR,  cl,
5275                             "cmlb_setup_default_geometry: "
5276                             "tg_getphygeom failed %d\n", ret);
5277 
5278                         /* do default setting, geometry based on capacity */
5279                 }
5280         }
5281 
5282         if (geom_base_cap) {
5283                 if (ISCD(cl)) {
5284                         cl->cl_g.dkg_ncyl = 1;
5285                         cl->cl_g.dkg_nhead = 1;
5286                         cl->cl_g.dkg_nsect = cl->cl_blockcount;
5287                 } else if (cl->cl_blockcount < 160) {
5288                         /* Less than 80K */
5289                         cl->cl_g.dkg_nhead = 1;
5290                         cl->cl_g.dkg_ncyl = cl->cl_blockcount;
5291                         cl->cl_g.dkg_nsect = 1;
5292                 } else if (cl->cl_blockcount <= 0x1000) {
5293                         /* Needed for unlabeled SCSI floppies. */
5294                         cl->cl_g.dkg_nhead = 2;
5295                         cl->cl_g.dkg_ncyl = 80;
5296                         cl->cl_g.dkg_pcyl = 80;
5297                         cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
5298                 } else if (cl->cl_blockcount <= 0x200000) {
5299                         cl->cl_g.dkg_nhead = 64;
5300                         cl->cl_g.dkg_nsect = 32;
5301                         cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
5302                 } else {
5303                         cl->cl_g.dkg_nhead = 255;
5304 
5305                         cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
5306                             (UINT16_MAX * 255 * 63) - 1) /
5307                             (UINT16_MAX * 255 * 63)) * 63;
5308 
5309                         if (cl->cl_g.dkg_nsect == 0)
5310                                 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
5311 
5312                         cl->cl_g.dkg_ncyl = cl->cl_blockcount /
5313                             (255 * cl->cl_g.dkg_nsect);
5314                 }
5315 
5316                 cl->cl_g.dkg_acyl = 0;
5317                 cl->cl_g.dkg_bcyl = 0;
5318                 cl->cl_g.dkg_intrlv = 1;
5319                 cl->cl_g.dkg_rpm = 200;
5320                 if (cl->cl_g.dkg_pcyl == 0)
5321                         cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl +
5322                             cl->cl_g.dkg_acyl;
5323         } else {
5324                 cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl;
5325                 cl->cl_g.dkg_acyl = pgeomp->g_acyl;
5326                 cl->cl_g.dkg_nhead = pgeomp->g_nhead;
5327                 cl->cl_g.dkg_nsect = pgeomp->g_nsect;
5328                 cl->cl_g.dkg_intrlv = pgeomp->g_intrlv;
5329                 cl->cl_g.dkg_rpm = pgeomp->g_rpm;
5330                 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl;
5331         }
5332 
5333         cl->cl_g.dkg_read_reinstruct = 0;
5334         cl->cl_g.dkg_write_reinstruct = 0;
5335         cl->cl_solaris_size = cl->cl_g.dkg_ncyl *
5336             cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
5337 
5338         cl->cl_map['a'-'a'].dkl_cylno = 0;
5339         cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size;
5340 
5341         cl->cl_map['c'-'a'].dkl_cylno = 0;
5342         cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size;
5343 
5344         cl->cl_vtoc.v_part[2].p_tag   = V_BACKUP;
5345         cl->cl_vtoc.v_part[2].p_flag  = V_UNMNT;
5346         cl->cl_vtoc.v_nparts = V_NUMPAR;
5347         cl->cl_vtoc.v_version = V_VERSION;
5348         (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d"
5349             " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
5350             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
5351 
5352         cl->cl_f_geometry_is_valid = B_FALSE;
5353 }
5354 
5355 
5356 #if defined(__i386) || defined(__amd64)
5357 /*
5358  *    Function: cmlb_update_fdisk_and_vtoc
5359  *
5360  * Description: This local utility routine updates the device fdisk and vtoc
5361  *              as part of setting the device mboot.
5362  *
5363  *   Arguments:
5364  *      cl              driver soft state (unit) structure
5365  *
5366  *      tg_cookie       cookie from target driver to be passed back to target
5367  *                      driver when we call back to it through tg_ops.
5368  *
5369  *
5370  * Return Code: 0 for success or errno-type return code.
5371  *
5372  *    Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
5373  *              these did exist separately in x86 sd.c.
5374  */
5375 static int
5376 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie)
5377 {
5378         int             count;
5379         int             label_rc = 0;
5380         int             fdisk_rval;
5381         diskaddr_t      capacity;
5382 
5383         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5384 
5385         if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
5386                 return (EINVAL);
5387 
5388         /*
5389          * Set up the "whole disk" fdisk partition; this should always
5390          * exist, regardless of whether the disk contains an fdisk table
5391          * or vtoc.
5392          */
5393         cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
5394         cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount;
5395 
5396         /*
5397          * copy the lbasize and capacity so that if they're
5398          * reset while we're not holding the CMLB_MUTEX(cl), we will
5399          * continue to use valid values after the CMLB_MUTEX(cl) is
5400          * reacquired.
5401          */
5402         capacity = cl->cl_blockcount;
5403 
5404         /*
5405          * refresh the logical and physical geometry caches.
5406          * (data from mode sense format/rigid disk geometry pages,
5407          * and scsi_ifgetcap("geometry").
5408          */
5409         cmlb_resync_geom_caches(cl, capacity, tg_cookie);
5410 
5411         /*
5412          * Only DIRECT ACCESS devices will have Scl labels.
5413          * CD's supposedly have a Scl label, too
5414          */
5415         if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
5416                 fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5417                 if (fdisk_rval != 0) {
5418                         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5419                         return (fdisk_rval);
5420                 }
5421 
5422                 if (cl->cl_solaris_size <= DK_LABEL_LOC) {
5423                         /*
5424                          * Found fdisk table but no Solaris partition entry,
5425                          * so don't call cmlb_uselabel() and don't create
5426                          * a default label.
5427                          */
5428                         label_rc = 0;
5429                         cl->cl_f_geometry_is_valid = B_TRUE;
5430                         goto no_solaris_partition;
5431                 }
5432         } else if (capacity < 0) {
5433                 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5434                 return (EINVAL);
5435         }
5436 
5437         /*
5438          * For Removable media We reach here if we have found a
5439          * SOLARIS PARTITION.
5440          * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS
5441          * PARTITION has changed from the previous one, hence we will setup a
5442          * default VTOC in this case.
5443          */
5444         if (!cl->cl_f_geometry_is_valid) {
5445                 /* if we get here it is writable */
5446                 /* we are called from SMBOOT, and after a write of fdisk */
5447                 cmlb_build_default_label(cl, tg_cookie);
5448                 label_rc = 0;
5449         }
5450 
5451 no_solaris_partition:
5452 
5453 #if defined(_SUNOS_VTOC_16)
5454         /*
5455          * If we have valid geometry, set up the remaining fdisk partitions.
5456          * Note that dkl_cylno is not used for the fdisk map entries, so
5457          * we set it to an entirely bogus value.
5458          */
5459         for (count = 0; count < FDISK_PARTS; count++) {
5460                 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX;
5461                 cl->cl_map[FDISK_P1 + count].dkl_nblk =
5462                     cl->cl_fmap[count].fmap_nblk;
5463                 cl->cl_offset[FDISK_P1 + count] =
5464                     cl->cl_fmap[count].fmap_start;
5465         }
5466 #endif
5467 
5468         for (count = 0; count < NDKMAP; count++) {
5469 #if defined(_SUNOS_VTOC_8)
5470                 struct dk_map *lp  = &cl->cl_map[count];
5471                 cl->cl_offset[count] =
5472                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
5473 #elif defined(_SUNOS_VTOC_16)
5474                 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
5475                 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
5476 #else
5477 #error "No VTOC format defined."
5478 #endif
5479         }
5480 
5481         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5482         return (label_rc);
5483 }
5484 #endif
5485 
5486 #if defined(__i386) || defined(__amd64)
5487 static int
5488 cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag)
5489 {
5490         int err = 0;
5491 
5492         /* Return the driver's notion of the media's logical geometry */
5493         struct dk_geom  disk_geom;
5494         struct dk_geom  *dkgp = &disk_geom;
5495 
5496         mutex_enter(CMLB_MUTEX(cl));
5497         /*
5498          * If there is no HBA geometry available, or
5499          * if the HBA returned us something that doesn't
5500          * really fit into an Int 13/function 8 geometry
5501          * result, just fail the ioctl.  See PSARC 1998/313.
5502          */
5503         if (cl->cl_lgeom.g_nhead == 0 ||
5504             cl->cl_lgeom.g_nsect == 0 ||
5505             cl->cl_lgeom.g_ncyl > 1024) {
5506                 mutex_exit(CMLB_MUTEX(cl));
5507                 err = EINVAL;
5508         } else {
5509                 dkgp->dkg_ncyl       = cl->cl_lgeom.g_ncyl;
5510                 dkgp->dkg_acyl       = cl->cl_lgeom.g_acyl;
5511                 dkgp->dkg_pcyl       = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5512                 dkgp->dkg_nhead      = cl->cl_lgeom.g_nhead;
5513                 dkgp->dkg_nsect      = cl->cl_lgeom.g_nsect;
5514 
5515                 mutex_exit(CMLB_MUTEX(cl));
5516                 if (ddi_copyout(dkgp, (void *)arg,
5517                     sizeof (struct dk_geom), flag)) {
5518                         err = EFAULT;
5519                 } else {
5520                         err = 0;
5521                 }
5522         }
5523         return (err);
5524 }
5525 #endif
5526 
5527 #if defined(__i386) || defined(__amd64)
5528 static int
5529 cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
5530     void *tg_cookie)
5531 {
5532         int err = 0;
5533         diskaddr_t capacity;
5534 
5535 
5536         /* Return the driver's notion of the media physical geometry */
5537         struct dk_geom  disk_geom;
5538         struct dk_geom  *dkgp = &disk_geom;
5539 
5540         mutex_enter(CMLB_MUTEX(cl));
5541 
5542         if (cl->cl_g.dkg_nhead != 0 &&
5543             cl->cl_g.dkg_nsect != 0) {
5544                 /*
5545                  * We succeeded in getting a geometry, but
5546                  * right now it is being reported as just the
5547                  * Solaris fdisk partition, just like for
5548                  * DKIOCGGEOM. We need to change that to be
5549                  * correct for the entire disk now.
5550                  */
5551                 bcopy(&cl->cl_g, dkgp, sizeof (*dkgp));
5552                 dkgp->dkg_acyl = 0;
5553                 dkgp->dkg_ncyl = cl->cl_blockcount /
5554                     (dkgp->dkg_nhead * dkgp->dkg_nsect);
5555         } else {
5556                 bzero(dkgp, sizeof (struct dk_geom));
5557                 /*
5558                  * This disk does not have a Solaris VTOC
5559                  * so we must present a physical geometry
5560                  * that will remain consistent regardless
5561                  * of how the disk is used. This will ensure
5562                  * that the geometry does not change regardless
5563                  * of the fdisk partition type (ie. EFI, FAT32,
5564                  * Solaris, etc).
5565                  */
5566                 if (ISCD(cl)) {
5567                         dkgp->dkg_nhead = cl->cl_pgeom.g_nhead;
5568                         dkgp->dkg_nsect = cl->cl_pgeom.g_nsect;
5569                         dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl;
5570                         dkgp->dkg_acyl = cl->cl_pgeom.g_acyl;
5571                 } else {
5572                         /*
5573                          * Invalid cl_blockcount can generate invalid
5574                          * dk_geom and may result in division by zero
5575                          * system failure. Should make sure blockcount
5576                          * is valid before using it here.
5577                          */
5578                         if (cl->cl_blockcount == 0) {
5579                                 mutex_exit(CMLB_MUTEX(cl));
5580                                 err = EIO;
5581                                 return (err);
5582                         }
5583                         /*
5584                          * Refer to comments related to off-by-1 at the
5585                          * header of this file
5586                          */
5587                         if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
5588                                 capacity = cl->cl_blockcount - 1;
5589                         else
5590                                 capacity = cl->cl_blockcount;
5591 
5592                         cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie);
5593                         dkgp->dkg_acyl = 0;
5594                         dkgp->dkg_ncyl = capacity /
5595                             (dkgp->dkg_nhead * dkgp->dkg_nsect);
5596                 }
5597         }
5598         dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5599 
5600         mutex_exit(CMLB_MUTEX(cl));
5601         if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag))
5602                 err = EFAULT;
5603 
5604         return (err);
5605 }
5606 #endif
5607 
5608 #if defined(__i386) || defined(__amd64)
5609 static int
5610 cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t  arg, int flag)
5611 {
5612         int err = 0;
5613 
5614         /*
5615          * Return parameters describing the selected disk slice.
5616          * Note: this ioctl is for the intel platform only
5617          */
5618         int part;
5619 
5620         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
5621                 part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1);
5622         else
5623                 part = CMLBPART(dev);
5624 
5625         mutex_enter(CMLB_MUTEX(cl));
5626         /* don't check cl_solaris_size for pN */
5627         if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5628                 err = EIO;
5629                 mutex_exit(CMLB_MUTEX(cl));
5630         } else {
5631                 struct part_info p;
5632 
5633                 p.p_start = (daddr_t)cl->cl_offset[part];
5634                 p.p_length = (int)cl->cl_map[part].dkl_nblk;
5635                 mutex_exit(CMLB_MUTEX(cl));
5636 #ifdef _MULTI_DATAMODEL
5637                 switch (ddi_model_convert_from(flag & FMODELS)) {
5638                 case DDI_MODEL_ILP32:
5639                 {
5640                         struct part_info32 p32;
5641 
5642                         p32.p_start = (daddr32_t)p.p_start;
5643                         p32.p_length = p.p_length;
5644                         if (ddi_copyout(&p32, (void *)arg,
5645                             sizeof (p32), flag))
5646                                 err = EFAULT;
5647                         break;
5648                 }
5649 
5650                 case DDI_MODEL_NONE:
5651                 {
5652                         if (ddi_copyout(&p, (void *)arg, sizeof (p),
5653                             flag))
5654                                 err = EFAULT;
5655                         break;
5656                 }
5657                 }
5658 #else /* ! _MULTI_DATAMODEL */
5659                 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5660                         err = EFAULT;
5661 #endif /* _MULTI_DATAMODEL */
5662         }
5663         return (err);
5664 }
5665 static int
5666 cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t  arg, int flag)
5667 {
5668         int err = 0;
5669 
5670         /*
5671          * Return parameters describing the selected disk slice.
5672          * Note: this ioctl is for the intel platform only
5673          */
5674         int part;
5675 
5676         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
5677                 part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1);
5678         else
5679                 part = CMLBPART(dev);
5680 
5681         mutex_enter(CMLB_MUTEX(cl));
5682         /* don't check cl_solaris_size for pN */
5683         if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5684                 err = EIO;
5685                 mutex_exit(CMLB_MUTEX(cl));
5686         } else {
5687                 struct extpart_info p;
5688 
5689                 p.p_start = (diskaddr_t)cl->cl_offset[part];
5690                 p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk;
5691                 mutex_exit(CMLB_MUTEX(cl));
5692                 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5693                         err = EFAULT;
5694         }
5695         return (err);
5696 }
5697 #endif
5698 
5699 int
5700 cmlb_prop_op(cmlb_handle_t cmlbhandle,
5701     dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
5702     char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie)
5703 {
5704         struct cmlb_lun *cl;
5705         diskaddr_t      capacity;
5706         uint32_t        lbasize;
5707         enum            dp { DP_NBLOCKS, DP_BLKSIZE, DP_SSD, DP_ROT } dp;
5708         int             callers_length;
5709         caddr_t         buffer;
5710         uint64_t        nblocks64;
5711         uint_t          dblk;
5712         tg_attribute_t  tgattr;
5713 
5714         /* Always fallback to ddi_prop_op... */
5715         cl = (struct cmlb_lun *)cmlbhandle;
5716         if (cl == NULL) {
5717 fallback:       return (ddi_prop_op(dev, dip, prop_op, mod_flags,
5718                     name, valuep, lengthp));
5719         }
5720 
5721         /* Pick up capacity and blocksize information. */
5722         capacity = cl->cl_blockcount;
5723         if (capacity == 0)
5724                 goto fallback;
5725         lbasize = cl->cl_tgt_blocksize;
5726         if (lbasize == 0)
5727                 lbasize = DEV_BSIZE;    /* 0 -> DEV_BSIZE units */
5728 
5729         /* Check for dynamic property of whole device. */
5730         if (dev == DDI_DEV_T_ANY) {
5731                 /* Fallback to ddi_prop_op if we don't understand.  */
5732                 if (strcmp(name, "device-nblocks") == 0)
5733                         dp = DP_NBLOCKS;
5734                 else if (strcmp(name, "device-blksize") == 0)
5735                         dp = DP_BLKSIZE;
5736                 else if (strcmp(name, "device-solid-state") == 0)
5737                         dp = DP_SSD;
5738                 else if (strcmp(name, "device-rotational") == 0)
5739                         dp = DP_ROT;
5740                 else
5741                         goto fallback;
5742 
5743                 /* get callers length, establish length of our dynamic prop */
5744                 callers_length = *lengthp;
5745                 if (dp == DP_NBLOCKS)
5746                         *lengthp = sizeof (uint64_t);
5747                 else if ((dp == DP_BLKSIZE) || (dp == DP_SSD))
5748                         *lengthp = sizeof (uint32_t);
5749 
5750                 /* service request for the length of the property */
5751                 if (prop_op == PROP_LEN)
5752                         return (DDI_PROP_SUCCESS);
5753 
5754                 switch (prop_op) {
5755                 case PROP_LEN_AND_VAL_ALLOC:
5756                         if ((buffer = kmem_alloc(*lengthp,
5757                             (mod_flags & DDI_PROP_CANSLEEP) ?
5758                             KM_SLEEP : KM_NOSLEEP)) == NULL)
5759                                 return (DDI_PROP_NO_MEMORY);
5760                         *(caddr_t *)valuep = buffer;    /* set callers buf */
5761                         break;
5762 
5763                 case PROP_LEN_AND_VAL_BUF:
5764                         /* the length of the prop and the request must match */
5765                         if (callers_length != *lengthp)
5766                                 return (DDI_PROP_INVAL_ARG);
5767                         buffer = valuep;                /* get callers buf */
5768                         break;
5769 
5770                 default:
5771                         return (DDI_PROP_INVAL_ARG);
5772                 }
5773 
5774                 /* transfer the value into the buffer */
5775                 switch (dp) {
5776                 case DP_NBLOCKS:
5777                         *((uint64_t *)buffer) = capacity;
5778                         break;
5779                 case DP_BLKSIZE:
5780                         *((uint32_t *)buffer) = lbasize;
5781                         break;
5782                 case DP_SSD:
5783                         if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5784                                 tgattr.media_is_solid_state = B_FALSE;
5785                         *((uint32_t *)buffer) =
5786                             tgattr.media_is_solid_state ? 1 : 0;
5787                         break;
5788                 case DP_ROT:
5789                         if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5790                                 tgattr.media_is_rotational = B_TRUE;
5791                         *((uint32_t *)buffer) =
5792                             tgattr.media_is_rotational ? 1 : 0;
5793                         break;
5794                 }
5795                 return (DDI_PROP_SUCCESS);
5796         }
5797 
5798         /*
5799          * Support dynamic size oriented properties of partition. Requests
5800          * issued under conditions where size is valid are passed to
5801          * ddi_prop_op_nblocks with the size information, otherwise the
5802          * request is passed to ddi_prop_op. Size depends on valid geometry.
5803          */
5804         if (!cmlb_is_valid(cmlbhandle))
5805                 goto fallback;
5806 
5807         /* Get partition nblocks value. */
5808         (void) cmlb_partinfo(cmlbhandle, part,
5809             (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie);
5810 
5811         /*
5812          * Assume partition information is in sys_blocksize units, compute
5813          * divisor for size(9P) property representation.
5814          */
5815         dblk = lbasize / cl->cl_sys_blocksize;
5816 
5817         /* Now let ddi_prop_op_nblocks_blksize() handle the request. */
5818         return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags,
5819             name, valuep, lengthp, nblocks64 / dblk, lbasize));
5820 }