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         _NOTE(ASSUMING_PROTECTED(*e))
2712         e->efi_gpt_Signature = LE_64(e->efi_gpt_Signature);
2713         e->efi_gpt_Revision = LE_32(e->efi_gpt_Revision);
2714         e->efi_gpt_HeaderSize = LE_32(e->efi_gpt_HeaderSize);
2715         e->efi_gpt_HeaderCRC32 = LE_32(e->efi_gpt_HeaderCRC32);
2716         e->efi_gpt_MyLBA = LE_64(e->efi_gpt_MyLBA);
2717         e->efi_gpt_AlternateLBA = LE_64(e->efi_gpt_AlternateLBA);
2718         e->efi_gpt_FirstUsableLBA = LE_64(e->efi_gpt_FirstUsableLBA);
2719         e->efi_gpt_LastUsableLBA = LE_64(e->efi_gpt_LastUsableLBA);
2720         UUID_LE_CONVERT(e->efi_gpt_DiskGUID, e->efi_gpt_DiskGUID);
2721         e->efi_gpt_PartitionEntryLBA = LE_64(e->efi_gpt_PartitionEntryLBA);
2722         e->efi_gpt_NumberOfPartitionEntries =
2723             LE_32(e->efi_gpt_NumberOfPartitionEntries);
2724         e->efi_gpt_SizeOfPartitionEntry =
2725             LE_32(e->efi_gpt_SizeOfPartitionEntry);
2726         e->efi_gpt_PartitionEntryArrayCRC32 =
2727             LE_32(e->efi_gpt_PartitionEntryArrayCRC32);
2728 }
2729 
2730 static void
2731 cmlb_swap_efi_gpe(int nparts, efi_gpe_t *p)
2732 {
2733         int i;
2734 
2735         _NOTE(ASSUMING_PROTECTED(*p))
2736         for (i = 0; i < nparts; i++) {
2737                 UUID_LE_CONVERT(p[i].efi_gpe_PartitionTypeGUID,
2738                     p[i].efi_gpe_PartitionTypeGUID);
2739                 p[i].efi_gpe_StartingLBA = LE_64(p[i].efi_gpe_StartingLBA);
2740                 p[i].efi_gpe_EndingLBA = LE_64(p[i].efi_gpe_EndingLBA);
2741                 /* PartitionAttrs */
2742         }
2743 }
2744 
2745 static int
2746 cmlb_validate_efi(efi_gpt_t *labp)
2747 {
2748         if (labp->efi_gpt_Signature != EFI_SIGNATURE)
2749                 return (EINVAL);
2750         /* at least 96 bytes in this version of the spec. */
2751         if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) >
2752             labp->efi_gpt_HeaderSize)
2753                 return (EINVAL);
2754         /* this should be 128 bytes */
2755         if (labp->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t))
2756                 return (EINVAL);
2757         return (0);
2758 }
2759 
2760 /*
2761  * This function returns B_FALSE if there is a valid MBR signature and no
2762  * partition table entries of type EFI_PMBR (0xEE). Otherwise it returns B_TRUE.
2763  *
2764  * The EFI spec (1.10 and later) requires having a Protective MBR (PMBR) to
2765  * recognize the disk as GPT partitioned. However, some other OS creates an MBR
2766  * where a PMBR entry is not the only one. Also, if the first block has been
2767  * corrupted, currently best attempt to allow data access would be to try to
2768  * check for GPT headers. Hence in case of more than one partition entry, but
2769  * at least one EFI_PMBR partition type or no valid magic number, the function
2770  * returns B_TRUE to continue with looking for GPT header.
2771  */
2772 
2773 static boolean_t
2774 cmlb_check_efi_mbr(uchar_t *buf, boolean_t *is_mbr)
2775 {
2776         struct ipart    *fdp;
2777         struct mboot    *mbp = (struct mboot *)buf;
2778         struct ipart    fdisk[FD_NUMPART];
2779         int             i;
2780 
2781         if (is_mbr != NULL)
2782                 *is_mbr = B_TRUE;
2783 
2784         if (LE_16(mbp->signature) != MBB_MAGIC) {
2785                 if (is_mbr != NULL)
2786                         *is_mbr = B_FALSE;
2787                 return (B_TRUE);
2788         }
2789 
2790         bcopy(&mbp->parts[0], fdisk, sizeof (fdisk));
2791 
2792         for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
2793                 if (fdp->systid == EFI_PMBR)
2794                         return (B_TRUE);
2795         }
2796 
2797         return (B_FALSE);
2798 }
2799 
2800 static int
2801 cmlb_use_efi(struct cmlb_lun *cl, diskaddr_t capacity, int flags,
2802     void *tg_cookie)
2803 {
2804         int             i;
2805         int             rval = 0;
2806         efi_gpe_t       *partitions;
2807         uchar_t         *buf;
2808         uint_t          lbasize;        /* is really how much to read */
2809         diskaddr_t      cap = 0;
2810         uint_t          nparts;
2811         diskaddr_t      gpe_lba;
2812         diskaddr_t      alternate_lba;
2813         int             iofailed = 0;
2814         struct uuid     uuid_type_reserved = EFI_RESERVED;
2815 #if defined(_FIRMWARE_NEEDS_FDISK)
2816         boolean_t       is_mbr;
2817 #endif
2818 
2819         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
2820 
2821         lbasize = cl->cl_sys_blocksize;
2822 
2823         cl->cl_reserved = -1;
2824         mutex_exit(CMLB_MUTEX(cl));
2825 
2826         buf = kmem_zalloc(EFI_MIN_ARRAY_SIZE, KM_SLEEP);
2827 
2828         rval = DK_TG_READ(cl, buf,  0, lbasize, tg_cookie);
2829         if (rval) {
2830                 iofailed = 1;
2831                 goto done_err;
2832         }
2833         if (((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) {
2834                 /* not ours */
2835                 rval = ESRCH;
2836                 goto done_err;
2837         }
2838 
2839 #if defined(_FIRMWARE_NEEDS_FDISK)
2840         if (!cmlb_check_efi_mbr(buf, &is_mbr)) {
2841                 if (is_mbr)
2842                         rval = ESRCH;
2843                 else
2844                         rval = EINVAL;
2845                 goto done_err;
2846         }
2847 #else
2848         if (!cmlb_check_efi_mbr(buf, NULL)) {
2849                 rval = EINVAL;
2850                 goto done_err;
2851         }
2852 
2853 #endif
2854 
2855         rval = DK_TG_READ(cl, buf, 1, lbasize, tg_cookie);
2856         if (rval) {
2857                 iofailed = 1;
2858                 goto done_err;
2859         }
2860         cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2861 
2862         if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2863                 /*
2864                  * Couldn't read the primary, try the backup.  Our
2865                  * capacity at this point could be based on CHS, so
2866                  * check what the device reports.
2867                  */
2868                 rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
2869                 if (rval) {
2870                         iofailed = 1;
2871                         goto done_err;
2872                 }
2873 
2874                 /*
2875                  * CMLB_OFF_BY_ONE case, we check the next to last block first
2876                  * for backup GPT header, otherwise check the last block.
2877                  */
2878 
2879                 if ((rval = DK_TG_READ(cl, buf,
2880                     cap - ((cl->cl_alter_behavior & CMLB_OFF_BY_ONE) ? 2 : 1),
2881                     lbasize, tg_cookie))
2882                     != 0) {
2883                         iofailed = 1;
2884                         goto done_err;
2885                 }
2886                 cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2887 
2888                 if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0) {
2889 
2890                         if (!(cl->cl_alter_behavior & CMLB_OFF_BY_ONE))
2891                                 goto done_err;
2892                         if ((rval = DK_TG_READ(cl, buf, cap - 1, lbasize,
2893                             tg_cookie)) != 0)
2894                                 goto done_err;
2895                         cmlb_swap_efi_gpt((efi_gpt_t *)buf);
2896                         if ((rval = cmlb_validate_efi((efi_gpt_t *)buf)) != 0)
2897                                 goto done_err;
2898                 }
2899                 if (!(flags & CMLB_SILENT))
2900                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
2901                             "primary label corrupt; using backup\n");
2902         }
2903 
2904         nparts = ((efi_gpt_t *)buf)->efi_gpt_NumberOfPartitionEntries;
2905         gpe_lba = ((efi_gpt_t *)buf)->efi_gpt_PartitionEntryLBA;
2906         alternate_lba = ((efi_gpt_t *)buf)->efi_gpt_AlternateLBA;
2907 
2908         rval = DK_TG_READ(cl, buf, gpe_lba, EFI_MIN_ARRAY_SIZE, tg_cookie);
2909         if (rval) {
2910                 iofailed = 1;
2911                 goto done_err;
2912         }
2913         partitions = (efi_gpe_t *)buf;
2914 
2915         if (nparts > MAXPART) {
2916                 nparts = MAXPART;
2917         }
2918         cmlb_swap_efi_gpe(nparts, partitions);
2919 
2920         mutex_enter(CMLB_MUTEX(cl));
2921 
2922         /* Fill in partition table. */
2923         for (i = 0; i < nparts; i++) {
2924                 if (partitions->efi_gpe_StartingLBA != 0 ||
2925                     partitions->efi_gpe_EndingLBA != 0) {
2926                         cl->cl_map[i].dkl_cylno =
2927                             partitions->efi_gpe_StartingLBA;
2928                         cl->cl_map[i].dkl_nblk =
2929                             partitions->efi_gpe_EndingLBA -
2930                             partitions->efi_gpe_StartingLBA + 1;
2931                         cl->cl_offset[i] =
2932                             partitions->efi_gpe_StartingLBA;
2933                 }
2934 
2935                 if (cl->cl_reserved == -1) {
2936                         if (bcmp(&partitions->efi_gpe_PartitionTypeGUID,
2937                             &uuid_type_reserved, sizeof (struct uuid)) == 0) {
2938                                 cl->cl_reserved = i;
2939                         }
2940                 }
2941                 if (i == WD_NODE) {
2942                         /*
2943                          * minor number 7 corresponds to the whole disk
2944                          * if the disk capacity is expanded after disk is
2945                          * labeled, minor number 7 represents the capacity
2946                          * indicated by the disk label.
2947                          */
2948                         cl->cl_map[i].dkl_cylno = 0;
2949                         if (alternate_lba == 1) {
2950                                 /*
2951                                  * We are using backup label. Since we can
2952                                  * find a valid label at the end of disk,
2953                                  * the disk capacity is not expanded.
2954                                  */
2955                                 cl->cl_map[i].dkl_nblk = capacity;
2956                         } else {
2957                                 cl->cl_map[i].dkl_nblk = alternate_lba + 1;
2958                         }
2959                         cl->cl_offset[i] = 0;
2960                 }
2961                 partitions++;
2962         }
2963         cl->cl_solaris_offset = 0;
2964         cl->cl_solaris_size = capacity;
2965         cl->cl_label_from_media = CMLB_LABEL_EFI;
2966         cl->cl_f_geometry_is_valid = B_TRUE;
2967 
2968         /* clear the vtoc label */
2969         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
2970 
2971         kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2972         return (0);
2973 
2974 done_err:
2975         kmem_free(buf, EFI_MIN_ARRAY_SIZE);
2976         mutex_enter(CMLB_MUTEX(cl));
2977 done_err1:
2978         /*
2979          * if we didn't find something that could look like a VTOC
2980          * and the disk is over 1TB, we know there isn't a valid label.
2981          * Otherwise let cmlb_uselabel decide what to do.  We only
2982          * want to invalidate this if we're certain the label isn't
2983          * valid because cmlb_prop_op will now fail, which in turn
2984          * causes things like opens and stats on the partition to fail.
2985          */
2986         if ((capacity > CMLB_EXTVTOC_LIMIT) && (rval != ESRCH) && !iofailed) {
2987                 cl->cl_f_geometry_is_valid = B_FALSE;
2988         }
2989         return (rval);
2990 }
2991 
2992 
2993 /*
2994  *    Function: cmlb_uselabel
2995  *
2996  * Description: Validate the disk label and update the relevant data (geometry,
2997  *              partition, vtoc, and capacity data) in the cmlb_lun struct.
2998  *              Marks the geometry of the unit as being valid.
2999  *
3000  *   Arguments: cl: unit struct.
3001  *              dk_label: disk label
3002  *
3003  * Return Code: CMLB_LABEL_IS_VALID: Label read from disk is OK; geometry,
3004  *              partition, vtoc, and capacity data are good.
3005  *
3006  *              CMLB_LABEL_IS_INVALID: Magic number or checksum error in the
3007  *              label; or computed capacity does not jibe with capacity
3008  *              reported from the READ CAPACITY command.
3009  *
3010  *     Context: Kernel thread only (can sleep).
3011  */
3012 static int
3013 cmlb_uselabel(struct cmlb_lun *cl, struct dk_label *labp, int flags)
3014 {
3015         short           *sp;
3016         short           sum;
3017         short           count;
3018         int             label_error = CMLB_LABEL_IS_VALID;
3019         int             i;
3020         diskaddr_t      label_capacity;
3021         uint32_t        part_end;
3022         diskaddr_t      track_capacity;
3023 #if defined(_SUNOS_VTOC_16)
3024         struct  dkl_partition   *vpartp;
3025 #endif
3026         ASSERT(cl != NULL);
3027         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3028 
3029         /* Validate the magic number of the label. */
3030         if (labp->dkl_magic != DKL_MAGIC) {
3031 #if defined(__sparc)
3032                 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3033                         if (!(flags & CMLB_SILENT))
3034                                 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3035                                     CE_WARN,
3036                                     "Corrupt label; wrong magic number\n");
3037                 }
3038 #endif
3039                 return (CMLB_LABEL_IS_INVALID);
3040         }
3041 
3042         /* Validate the checksum of the label. */
3043         sp  = (short *)labp;
3044         sum = 0;
3045         count = sizeof (struct dk_label) / sizeof (short);
3046         while (count--)  {
3047                 sum ^= *sp++;
3048         }
3049 
3050         if (sum != 0) {
3051 #if defined(_SUNOS_VTOC_16)
3052                 if (!ISCD(cl)) {
3053 #elif defined(_SUNOS_VTOC_8)
3054                 if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3055 #endif
3056                         if (!(flags & CMLB_SILENT))
3057                                 cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl),
3058                                     CE_WARN,
3059                                     "Corrupt label - label checksum failed\n");
3060                 }
3061                 return (CMLB_LABEL_IS_INVALID);
3062         }
3063 
3064 
3065         /*
3066          * Fill in geometry structure with data from label.
3067          */
3068         bzero(&cl->cl_g, sizeof (struct dk_geom));
3069         cl->cl_g.dkg_ncyl   = labp->dkl_ncyl;
3070         cl->cl_g.dkg_acyl   = labp->dkl_acyl;
3071         cl->cl_g.dkg_bcyl   = 0;
3072         cl->cl_g.dkg_nhead  = labp->dkl_nhead;
3073         cl->cl_g.dkg_nsect  = labp->dkl_nsect;
3074         cl->cl_g.dkg_intrlv = labp->dkl_intrlv;
3075 
3076 #if defined(_SUNOS_VTOC_8)
3077         cl->cl_g.dkg_gap1   = labp->dkl_gap1;
3078         cl->cl_g.dkg_gap2   = labp->dkl_gap2;
3079         cl->cl_g.dkg_bhead  = labp->dkl_bhead;
3080 #endif
3081 #if defined(_SUNOS_VTOC_16)
3082         cl->cl_dkg_skew = labp->dkl_skew;
3083 #endif
3084 
3085 #if defined(__i386) || defined(__amd64)
3086         cl->cl_g.dkg_apc = labp->dkl_apc;
3087 #endif
3088 
3089         /*
3090          * Currently we rely on the values in the label being accurate. If
3091          * dkl_rpm or dkl_pcly are zero in the label, use a default value.
3092          *
3093          * Note: In the future a MODE SENSE may be used to retrieve this data,
3094          * although this command is optional in SCSI-2.
3095          */
3096         cl->cl_g.dkg_rpm  = (labp->dkl_rpm  != 0) ? labp->dkl_rpm  : 3600;
3097         cl->cl_g.dkg_pcyl = (labp->dkl_pcyl != 0) ? labp->dkl_pcyl :
3098             (cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl);
3099 
3100         /*
3101          * The Read and Write reinstruct values may not be valid
3102          * for older disks.
3103          */
3104         cl->cl_g.dkg_read_reinstruct  = labp->dkl_read_reinstruct;
3105         cl->cl_g.dkg_write_reinstruct = labp->dkl_write_reinstruct;
3106 
3107         /* Fill in partition table. */
3108 #if defined(_SUNOS_VTOC_8)
3109         for (i = 0; i < NDKMAP; i++) {
3110                 cl->cl_map[i].dkl_cylno = labp->dkl_map[i].dkl_cylno;
3111                 cl->cl_map[i].dkl_nblk  = labp->dkl_map[i].dkl_nblk;
3112         }
3113 #endif
3114 #if  defined(_SUNOS_VTOC_16)
3115         vpartp          = labp->dkl_vtoc.v_part;
3116         track_capacity  = labp->dkl_nhead * labp->dkl_nsect;
3117 
3118         /* Prevent divide by zero */
3119         if (track_capacity == 0) {
3120                 if (!(flags & CMLB_SILENT))
3121                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3122                             "Corrupt label - zero nhead or nsect value\n");
3123 
3124                 return (CMLB_LABEL_IS_INVALID);
3125         }
3126 
3127         for (i = 0; i < NDKMAP; i++, vpartp++) {
3128                 cl->cl_map[i].dkl_cylno = vpartp->p_start / track_capacity;
3129                 cl->cl_map[i].dkl_nblk  = vpartp->p_size;
3130         }
3131 #endif
3132 
3133         /* Fill in VTOC Structure. */
3134         bcopy(&labp->dkl_vtoc, &cl->cl_vtoc, sizeof (struct dk_vtoc));
3135 #if defined(_SUNOS_VTOC_8)
3136         /*
3137          * The 8-slice vtoc does not include the ascii label; save it into
3138          * the device's soft state structure here.
3139          */
3140         bcopy(labp->dkl_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
3141 #endif
3142 
3143         /* Now look for a valid capacity. */
3144         track_capacity  = (cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect);
3145         label_capacity  = (cl->cl_g.dkg_ncyl  * track_capacity);
3146 
3147         if (cl->cl_g.dkg_acyl) {
3148 #if defined(__i386) || defined(__amd64)
3149                 /* we may have > 1 alts cylinder */
3150                 label_capacity += (track_capacity * cl->cl_g.dkg_acyl);
3151 #else
3152                 label_capacity += track_capacity;
3153 #endif
3154         }
3155 
3156         /*
3157          * Force check here to ensure the computed capacity is valid.
3158          * If capacity is zero, it indicates an invalid label and
3159          * we should abort updating the relevant data then.
3160          */
3161         if (label_capacity == 0) {
3162                 if (!(flags & CMLB_SILENT))
3163                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3164                             "Corrupt label - no valid capacity could be "
3165                             "retrieved\n");
3166 
3167                 return (CMLB_LABEL_IS_INVALID);
3168         }
3169 
3170         /* Mark the geometry as valid. */
3171         cl->cl_f_geometry_is_valid = B_TRUE;
3172 
3173         /*
3174          * if we got invalidated when mutex exit and entered again,
3175          * if blockcount different than when we came in, need to
3176          * retry from beginning of cmlb_validate_geometry.
3177          * revisit this on next phase of utilizing this for
3178          * sd.
3179          */
3180 
3181         if (label_capacity <= cl->cl_blockcount) {
3182 #if defined(_SUNOS_VTOC_8)
3183                 /*
3184                  * We can't let this happen on drives that are subdivided
3185                  * into logical disks (i.e., that have an fdisk table).
3186                  * The cl_blockcount field should always hold the full media
3187                  * size in sectors, period.  This code would overwrite
3188                  * cl_blockcount with the size of the Solaris fdisk partition.
3189                  */
3190                 cmlb_dbg(CMLB_ERROR,  cl,
3191                     "cmlb_uselabel: Label %d blocks; Drive %d blocks\n",
3192                     label_capacity, cl->cl_blockcount);
3193                 cl->cl_solaris_size = label_capacity;
3194 
3195 #endif  /* defined(_SUNOS_VTOC_8) */
3196                 goto done;
3197         }
3198 
3199         if (ISCD(cl)) {
3200                 /* For CDROMs, we trust that the data in the label is OK. */
3201 #if defined(_SUNOS_VTOC_8)
3202                 for (i = 0; i < NDKMAP; i++) {
3203                         part_end = labp->dkl_nhead * labp->dkl_nsect *
3204                             labp->dkl_map[i].dkl_cylno +
3205                             labp->dkl_map[i].dkl_nblk  - 1;
3206 
3207                         if ((labp->dkl_map[i].dkl_nblk) &&
3208                             (part_end > cl->cl_blockcount)) {
3209                                 cl->cl_f_geometry_is_valid = B_FALSE;
3210                                 break;
3211                         }
3212                 }
3213 #endif
3214 #if defined(_SUNOS_VTOC_16)
3215                 vpartp = &(labp->dkl_vtoc.v_part[0]);
3216                 for (i = 0; i < NDKMAP; i++, vpartp++) {
3217                         part_end = vpartp->p_start + vpartp->p_size;
3218                         if ((vpartp->p_size > 0) &&
3219                             (part_end > cl->cl_blockcount)) {
3220                                 cl->cl_f_geometry_is_valid = B_FALSE;
3221                                 break;
3222                         }
3223                 }
3224 #endif
3225         } else {
3226                 /* label_capacity > cl->cl_blockcount */
3227                 if (!(flags & CMLB_SILENT)) {
3228                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_WARN,
3229                             "Corrupt label - bad geometry\n");
3230                         cmlb_log(CMLB_DEVINFO(cl), CMLB_LABEL(cl), CE_CONT,
3231                             "Label says %llu blocks; Drive says %llu blocks\n",
3232                             label_capacity, cl->cl_blockcount);
3233                 }
3234                 cl->cl_f_geometry_is_valid = B_FALSE;
3235                 label_error = CMLB_LABEL_IS_INVALID;
3236         }
3237 
3238 done:
3239 
3240         cmlb_dbg(CMLB_INFO,  cl, "cmlb_uselabel: (label geometry)\n");
3241         cmlb_dbg(CMLB_INFO,  cl,
3242             "   ncyl: %d; acyl: %d; nhead: %d; nsect: %d\n",
3243             cl->cl_g.dkg_ncyl,  cl->cl_g.dkg_acyl,
3244             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3245 
3246         cmlb_dbg(CMLB_INFO,  cl,
3247             "   label_capacity: %d; intrlv: %d; rpm: %d\n",
3248             cl->cl_blockcount, cl->cl_g.dkg_intrlv, cl->cl_g.dkg_rpm);
3249         cmlb_dbg(CMLB_INFO,  cl, "   wrt_reinstr: %d; rd_reinstr: %d\n",
3250             cl->cl_g.dkg_write_reinstruct, cl->cl_g.dkg_read_reinstruct);
3251 
3252         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3253 
3254         return (label_error);
3255 }
3256 
3257 
3258 /*
3259  *    Function: cmlb_build_default_label
3260  *
3261  * Description: Generate a default label for those devices that do not have
3262  *              one, e.g., new media, removable cartridges, etc..
3263  *
3264  *     Context: Kernel thread only
3265  */
3266 /*ARGSUSED*/
3267 static void
3268 cmlb_build_default_label(struct cmlb_lun *cl, void *tg_cookie)
3269 {
3270 #if defined(_SUNOS_VTOC_16)
3271         uint_t  phys_spc;
3272         uint_t  disksize;
3273         struct  dk_geom cl_g;
3274         diskaddr_t capacity;
3275 #endif
3276 
3277         ASSERT(cl != NULL);
3278         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
3279 
3280 #if defined(_SUNOS_VTOC_8)
3281         /*
3282          * Note: This is a legacy check for non-removable devices on VTOC_8
3283          * only. This may be a valid check for VTOC_16 as well.
3284          * Once we understand why there is this difference between SPARC and
3285          * x86 platform, we could remove this legacy check.
3286          */
3287         if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
3288                 return;
3289         }
3290 #endif
3291 
3292         bzero(&cl->cl_g, sizeof (struct dk_geom));
3293         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
3294         bzero(&cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
3295 
3296 #if defined(_SUNOS_VTOC_8)
3297 
3298         /*
3299          * It's a REMOVABLE media, therefore no label (on sparc, anyway).
3300          * But it is still necessary to set up various geometry information,
3301          * and we are doing this here.
3302          */
3303 
3304         /*
3305          * For the rpm, we use the minimum for the disk.  For the head, cyl,
3306          * and number of sector per track, if the capacity <= 1GB, head = 64,
3307          * sect = 32.  else head = 255, sect 63 Note: the capacity should be
3308          * equal to C*H*S values.  This will cause some truncation of size due
3309          * to round off errors. For CD-ROMs, this truncation can have adverse
3310          * side effects, so returning ncyl and nhead as 1. The nsect will
3311          * overflow for most of CD-ROMs as nsect is of type ushort. (4190569)
3312          */
3313         cl->cl_solaris_size = cl->cl_blockcount;
3314         if (ISCD(cl)) {
3315                 tg_attribute_t tgattribute;
3316                 int is_writable;
3317                 /*
3318                  * Preserve the old behavior for non-writable
3319                  * medias. Since dkg_nsect is a ushort, it
3320                  * will lose bits as cdroms have more than
3321                  * 65536 sectors. So if we recalculate
3322                  * capacity, it will become much shorter.
3323                  * But the dkg_* information is not
3324                  * used for CDROMs so it is OK. But for
3325                  * Writable CDs we need this information
3326                  * to be valid (for newfs say). So we
3327                  * make nsect and nhead > 1 that way
3328                  * nsect can still stay within ushort limit
3329                  * without losing any bits.
3330                  */
3331 
3332                 bzero(&tgattribute, sizeof (tg_attribute_t));
3333 
3334                 mutex_exit(CMLB_MUTEX(cl));
3335                 is_writable =
3336                     (DK_TG_GETATTRIBUTE(cl, &tgattribute, tg_cookie) == 0) ?
3337                     tgattribute.media_is_writable : 1;
3338                 mutex_enter(CMLB_MUTEX(cl));
3339 
3340                 if (is_writable) {
3341                         cl->cl_g.dkg_nhead = 64;
3342                         cl->cl_g.dkg_nsect = 32;
3343                         cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
3344                         cl->cl_solaris_size = (diskaddr_t)cl->cl_g.dkg_ncyl *
3345                             cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3346                 } else {
3347                         cl->cl_g.dkg_ncyl  = 1;
3348                         cl->cl_g.dkg_nhead = 1;
3349                         cl->cl_g.dkg_nsect = cl->cl_blockcount;
3350                 }
3351         } else {
3352                 if (cl->cl_blockcount < 160) {
3353                         /* Less than 80K */
3354                         cl->cl_g.dkg_nhead = 1;
3355                         cl->cl_g.dkg_ncyl = cl->cl_blockcount;
3356                         cl->cl_g.dkg_nsect = 1;
3357                 } else if (cl->cl_blockcount <= 0x1000) {
3358                         /* unlabeled SCSI floppy device */
3359                         cl->cl_g.dkg_nhead = 2;
3360                         cl->cl_g.dkg_ncyl = 80;
3361                         cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
3362                 } else if (cl->cl_blockcount <= 0x200000) {
3363                         cl->cl_g.dkg_nhead = 64;
3364                         cl->cl_g.dkg_nsect = 32;
3365                         cl->cl_g.dkg_ncyl  = cl->cl_blockcount / (64 * 32);
3366                 } else {
3367                         cl->cl_g.dkg_nhead = 255;
3368 
3369                         cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
3370                             (UINT16_MAX * 255 * 63) - 1) /
3371                             (UINT16_MAX * 255 * 63)) * 63;
3372 
3373                         if (cl->cl_g.dkg_nsect == 0)
3374                                 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
3375 
3376                         cl->cl_g.dkg_ncyl = cl->cl_blockcount /
3377                             (255 * cl->cl_g.dkg_nsect);
3378                 }
3379 
3380                 cl->cl_solaris_size =
3381                     (diskaddr_t)cl->cl_g.dkg_ncyl * cl->cl_g.dkg_nhead *
3382                     cl->cl_g.dkg_nsect;
3383 
3384         }
3385 
3386         cl->cl_g.dkg_acyl    = 0;
3387         cl->cl_g.dkg_bcyl    = 0;
3388         cl->cl_g.dkg_rpm     = 200;
3389         cl->cl_asciilabel[0] = '\0';
3390         cl->cl_g.dkg_pcyl    = cl->cl_g.dkg_ncyl;
3391 
3392         cl->cl_map[0].dkl_cylno = 0;
3393         cl->cl_map[0].dkl_nblk  = cl->cl_solaris_size;
3394 
3395         cl->cl_map[2].dkl_cylno = 0;
3396         cl->cl_map[2].dkl_nblk  = cl->cl_solaris_size;
3397 
3398 #elif defined(_SUNOS_VTOC_16)
3399 
3400         if (cl->cl_solaris_size == 0) {
3401                 /*
3402                  * Got fdisk table but no solaris entry therefore
3403                  * don't create a default label
3404                  */
3405                 cl->cl_f_geometry_is_valid = B_TRUE;
3406                 return;
3407         }
3408 
3409         /*
3410          * For CDs we continue to use the physical geometry to calculate
3411          * number of cylinders. All other devices must convert the
3412          * physical geometry (cmlb_geom) to values that will fit
3413          * in a dk_geom structure.
3414          */
3415         if (ISCD(cl)) {
3416                 phys_spc = cl->cl_pgeom.g_nhead * cl->cl_pgeom.g_nsect;
3417         } else {
3418                 /* Convert physical geometry to disk geometry */
3419                 bzero(&cl_g, sizeof (struct dk_geom));
3420 
3421                 /*
3422                  * Refer to comments related to off-by-1 at the
3423                  * header of this file.
3424                  * Before calculating geometry, capacity should be
3425                  * decreased by 1.
3426                  */
3427 
3428                 if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
3429                         capacity = cl->cl_blockcount - 1;
3430                 else
3431                         capacity = cl->cl_blockcount;
3432 
3433 
3434                 cmlb_convert_geometry(cl, capacity, &cl_g, tg_cookie);
3435                 bcopy(&cl_g, &cl->cl_g, sizeof (cl->cl_g));
3436                 phys_spc = cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
3437         }
3438 
3439         if (phys_spc == 0)
3440                 return;
3441         cl->cl_g.dkg_pcyl = cl->cl_solaris_size / phys_spc;
3442         if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3443                 /* disable devid */
3444                 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl;
3445                 disksize = cl->cl_solaris_size;
3446         } else {
3447                 cl->cl_g.dkg_acyl = DK_ACYL;
3448                 cl->cl_g.dkg_ncyl = cl->cl_g.dkg_pcyl - DK_ACYL;
3449                 disksize = cl->cl_g.dkg_ncyl * phys_spc;
3450         }
3451 
3452         if (ISCD(cl)) {
3453                 /*
3454                  * CD's don't use the "heads * sectors * cyls"-type of
3455                  * geometry, but instead use the entire capacity of the media.
3456                  */
3457                 disksize = cl->cl_solaris_size;
3458                 cl->cl_g.dkg_nhead = 1;
3459                 cl->cl_g.dkg_nsect = 1;
3460                 cl->cl_g.dkg_rpm =
3461                     (cl->cl_pgeom.g_rpm == 0) ? 200 : cl->cl_pgeom.g_rpm;
3462 
3463                 cl->cl_vtoc.v_part[0].p_start = 0;
3464                 cl->cl_vtoc.v_part[0].p_size  = disksize;
3465                 cl->cl_vtoc.v_part[0].p_tag   = V_BACKUP;
3466                 cl->cl_vtoc.v_part[0].p_flag  = V_UNMNT;
3467 
3468                 cl->cl_map[0].dkl_cylno = 0;
3469                 cl->cl_map[0].dkl_nblk  = disksize;
3470                 cl->cl_offset[0] = 0;
3471 
3472         } else {
3473                 /*
3474                  * Hard disks and removable media cartridges
3475                  */
3476                 cl->cl_g.dkg_rpm =
3477                     (cl->cl_pgeom.g_rpm == 0) ? 3600: cl->cl_pgeom.g_rpm;
3478                 cl->cl_vtoc.v_sectorsz = cl->cl_sys_blocksize;
3479 
3480                 /* Add boot slice */
3481                 cl->cl_vtoc.v_part[8].p_start = 0;
3482                 cl->cl_vtoc.v_part[8].p_size  = phys_spc;
3483                 cl->cl_vtoc.v_part[8].p_tag   = V_BOOT;
3484                 cl->cl_vtoc.v_part[8].p_flag  = V_UNMNT;
3485 
3486                 cl->cl_map[8].dkl_cylno = 0;
3487                 cl->cl_map[8].dkl_nblk  = phys_spc;
3488                 cl->cl_offset[8] = 0;
3489 
3490                 if ((cl->cl_alter_behavior &
3491                     CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT) &&
3492                     cl->cl_device_type == DTYPE_DIRECT) {
3493                         cl->cl_vtoc.v_part[9].p_start = phys_spc;
3494                         cl->cl_vtoc.v_part[9].p_size  = 2 * phys_spc;
3495                         cl->cl_vtoc.v_part[9].p_tag   = V_ALTSCTR;
3496                         cl->cl_vtoc.v_part[9].p_flag  = 0;
3497 
3498                         cl->cl_map[9].dkl_cylno = 1;
3499                         cl->cl_map[9].dkl_nblk  = 2 * phys_spc;
3500                         cl->cl_offset[9] = phys_spc;
3501                 }
3502         }
3503 
3504         cl->cl_g.dkg_apc = 0;
3505 
3506         /* Add backup slice */
3507         cl->cl_vtoc.v_part[2].p_start = 0;
3508         cl->cl_vtoc.v_part[2].p_size  = disksize;
3509         cl->cl_vtoc.v_part[2].p_tag   = V_BACKUP;
3510         cl->cl_vtoc.v_part[2].p_flag  = V_UNMNT;
3511 
3512         cl->cl_map[2].dkl_cylno = 0;
3513         cl->cl_map[2].dkl_nblk  = disksize;
3514         cl->cl_offset[2] = 0;
3515 
3516         /*
3517          * single slice (s0) covering the entire disk
3518          */
3519         if (cl->cl_alter_behavior & CMLB_FAKE_LABEL_ONE_PARTITION) {
3520                 cl->cl_vtoc.v_part[0].p_start = 0;
3521                 cl->cl_vtoc.v_part[0].p_tag   = V_UNASSIGNED;
3522                 cl->cl_vtoc.v_part[0].p_flag  = 0;
3523                 cl->cl_vtoc.v_part[0].p_size  = disksize;
3524                 cl->cl_map[0].dkl_cylno = 0;
3525                 cl->cl_map[0].dkl_nblk  = disksize;
3526                 cl->cl_offset[0] = 0;
3527         }
3528 
3529         (void) sprintf(cl->cl_vtoc.v_asciilabel, "DEFAULT cyl %d alt %d"
3530             " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
3531             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
3532 
3533 #else
3534 #error "No VTOC format defined."
3535 #endif
3536 
3537         cl->cl_g.dkg_read_reinstruct  = 0;
3538         cl->cl_g.dkg_write_reinstruct = 0;
3539 
3540         cl->cl_g.dkg_intrlv = 1;
3541 
3542         cl->cl_vtoc.v_sanity  = VTOC_SANE;
3543         cl->cl_vtoc.v_nparts = V_NUMPAR;
3544         cl->cl_vtoc.v_version = V_VERSION;
3545 
3546         cl->cl_f_geometry_is_valid = B_TRUE;
3547         cl->cl_label_from_media = CMLB_LABEL_UNDEF;
3548 
3549         cmlb_dbg(CMLB_INFO,  cl,
3550             "cmlb_build_default_label: Default label created: "
3551             "cyl: %d\tacyl: %d\tnhead: %d\tnsect: %d\tcap: %d\n",
3552             cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl, cl->cl_g.dkg_nhead,
3553             cl->cl_g.dkg_nsect, cl->cl_blockcount);
3554 }
3555 
3556 
3557 #if defined(_FIRMWARE_NEEDS_FDISK)
3558 /*
3559  * Max CHS values, as they are encoded into bytes, for 1022/254/63
3560  */
3561 #define LBA_MAX_SECT    (63 | ((1022 & 0x300) >> 2))
3562 #define LBA_MAX_CYL     (1022 & 0xFF)
3563 #define LBA_MAX_HEAD    (254)
3564 
3565 
3566 /*
3567  *    Function: cmlb_has_max_chs_vals
3568  *
3569  * Description: Return B_TRUE if Cylinder-Head-Sector values are all at maximum.
3570  *
3571  *   Arguments: fdp - ptr to CHS info
3572  *
3573  * Return Code: True or false
3574  *
3575  *     Context: Any.
3576  */
3577 static boolean_t
3578 cmlb_has_max_chs_vals(struct ipart *fdp)
3579 {
3580         return ((fdp->begcyl  == LBA_MAX_CYL)        &&
3581             (fdp->beghead == LBA_MAX_HEAD)   &&
3582             (fdp->begsect == LBA_MAX_SECT)   &&
3583             (fdp->endcyl  == LBA_MAX_CYL)    &&
3584             (fdp->endhead == LBA_MAX_HEAD)   &&
3585             (fdp->endsect == LBA_MAX_SECT));
3586 }
3587 #endif
3588 
3589 /*
3590  *    Function: cmlb_dkio_get_geometry
3591  *
3592  * Description: This routine is the driver entry point for handling user
3593  *              requests to get the device geometry (DKIOCGGEOM).
3594  *
3595  *   Arguments:
3596  *      arg             pointer to user provided dk_geom structure specifying
3597  *                      the controller's notion of the current geometry.
3598  *
3599  *      flag            this argument is a pass through to ddi_copyxxx()
3600  *                      directly from the mode argument of ioctl().
3601  *
3602  *      tg_cookie       cookie from target driver to be passed back to target
3603  *                      driver when we call back to it through tg_ops.
3604  *
3605  * Return Code: 0
3606  *              EFAULT
3607  *              ENXIO
3608  *              EIO
3609  */
3610 static int
3611 cmlb_dkio_get_geometry(struct cmlb_lun *cl, caddr_t arg, int flag,
3612     void *tg_cookie)
3613 {
3614         struct dk_geom  *tmp_geom = NULL;
3615         int             rval = 0;
3616 
3617         /*
3618          * cmlb_validate_geometry does not spin a disk up
3619          * if it was spcl down. We need to make sure it
3620          * is ready.
3621          */
3622         mutex_enter(CMLB_MUTEX(cl));
3623         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3624 #if defined(_SUNOS_VTOC_8)
3625         if (rval == EINVAL &&
3626             cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
3627                 /*
3628                  * This is to return a default label geometry even when we
3629                  * do not really assume a default label for the device.
3630                  * dad driver utilizes this.
3631                  */
3632                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3633                         cmlb_setup_default_geometry(cl, tg_cookie);
3634                         rval = 0;
3635                 }
3636         }
3637 #endif
3638         if (rval) {
3639                 mutex_exit(CMLB_MUTEX(cl));
3640                 return (rval);
3641         }
3642 
3643 #if defined(__i386) || defined(__amd64)
3644         if (cl->cl_solaris_size == 0) {
3645                 mutex_exit(CMLB_MUTEX(cl));
3646                 return (EIO);
3647         }
3648 #endif
3649 
3650         /*
3651          * Make a local copy of the soft state geometry to avoid some potential
3652          * race conditions associated with holding the mutex and updating the
3653          * write_reinstruct value
3654          */
3655         tmp_geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3656         bcopy(&cl->cl_g, tmp_geom, sizeof (struct dk_geom));
3657 
3658         if (tmp_geom->dkg_write_reinstruct == 0) {
3659                 tmp_geom->dkg_write_reinstruct =
3660                     (int)((int)(tmp_geom->dkg_nsect * tmp_geom->dkg_rpm *
3661                     cmlb_rot_delay) / (int)60000);
3662         }
3663         mutex_exit(CMLB_MUTEX(cl));
3664 
3665         rval = ddi_copyout(tmp_geom, (void *)arg, sizeof (struct dk_geom),
3666             flag);
3667         if (rval != 0) {
3668                 rval = EFAULT;
3669         }
3670 
3671         kmem_free(tmp_geom, sizeof (struct dk_geom));
3672         return (rval);
3673 
3674 }
3675 
3676 
3677 /*
3678  *    Function: cmlb_dkio_set_geometry
3679  *
3680  * Description: This routine is the driver entry point for handling user
3681  *              requests to set the device geometry (DKIOCSGEOM). The actual
3682  *              device geometry is not updated, just the driver "notion" of it.
3683  *
3684  *   Arguments:
3685  *      arg             pointer to user provided dk_geom structure used to set
3686  *                      the controller's notion of the current geometry.
3687  *
3688  *      flag            this argument is a pass through to ddi_copyxxx()
3689  *                      directly from the mode argument of ioctl().
3690  *
3691  *      tg_cookie       cookie from target driver to be passed back to target
3692  *                      driver when we call back to it through tg_ops.
3693  *
3694  * Return Code: 0
3695  *              EFAULT
3696  *              ENXIO
3697  *              EIO
3698  */
3699 static int
3700 cmlb_dkio_set_geometry(struct cmlb_lun *cl, caddr_t arg, int flag)
3701 {
3702         struct dk_geom  *tmp_geom;
3703         struct dk_map   *lp;
3704         int             rval = 0;
3705         int             i;
3706 
3707 
3708 #if defined(__i386) || defined(__amd64)
3709         if (cl->cl_solaris_size == 0) {
3710                 return (EIO);
3711         }
3712 #endif
3713         /*
3714          * We need to copy the user specified geometry into local
3715          * storage and then update the softstate. We don't want to hold
3716          * the mutex and copyin directly from the user to the soft state
3717          */
3718         tmp_geom = (struct dk_geom *)
3719             kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP);
3720         rval = ddi_copyin(arg, tmp_geom, sizeof (struct dk_geom), flag);
3721         if (rval != 0) {
3722                 kmem_free(tmp_geom, sizeof (struct dk_geom));
3723                 return (EFAULT);
3724         }
3725 
3726         mutex_enter(CMLB_MUTEX(cl));
3727         bcopy(tmp_geom, &cl->cl_g, sizeof (struct dk_geom));
3728         for (i = 0; i < NDKMAP; i++) {
3729                 lp  = &cl->cl_map[i];
3730                 cl->cl_offset[i] =
3731                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3732 #if defined(__i386) || defined(__amd64)
3733                 cl->cl_offset[i] += cl->cl_solaris_offset;
3734 #endif
3735         }
3736         cl->cl_f_geometry_is_valid = B_FALSE;
3737         mutex_exit(CMLB_MUTEX(cl));
3738         kmem_free(tmp_geom, sizeof (struct dk_geom));
3739 
3740         return (rval);
3741 }
3742 
3743 /*
3744  *    Function: cmlb_dkio_get_partition
3745  *
3746  * Description: This routine is the driver entry point for handling user
3747  *              requests to get the partition table (DKIOCGAPART).
3748  *
3749  *   Arguments:
3750  *      arg             pointer to user provided dk_allmap structure specifying
3751  *                      the controller's notion of the current partition table.
3752  *
3753  *      flag            this argument is a pass through to ddi_copyxxx()
3754  *                      directly from the mode argument of ioctl().
3755  *
3756  *      tg_cookie       cookie from target driver to be passed back to target
3757  *                      driver when we call back to it through tg_ops.
3758  *
3759  * Return Code: 0
3760  *              EFAULT
3761  *              ENXIO
3762  *              EIO
3763  */
3764 static int
3765 cmlb_dkio_get_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
3766     void *tg_cookie)
3767 {
3768         int             rval = 0;
3769         int             size;
3770 
3771         /*
3772          * Make sure the geometry is valid before getting the partition
3773          * information.
3774          */
3775         mutex_enter(CMLB_MUTEX(cl));
3776         if ((rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie)) != 0) {
3777                 mutex_exit(CMLB_MUTEX(cl));
3778                 return (rval);
3779         }
3780         mutex_exit(CMLB_MUTEX(cl));
3781 
3782 #if defined(__i386) || defined(__amd64)
3783         if (cl->cl_solaris_size == 0) {
3784                 return (EIO);
3785         }
3786 #endif
3787 
3788 #ifdef _MULTI_DATAMODEL
3789         switch (ddi_model_convert_from(flag & FMODELS)) {
3790         case DDI_MODEL_ILP32: {
3791                 struct dk_map32 dk_map32[NDKMAP];
3792                 int             i;
3793 
3794                 for (i = 0; i < NDKMAP; i++) {
3795                         dk_map32[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
3796                         dk_map32[i].dkl_nblk  = cl->cl_map[i].dkl_nblk;
3797                 }
3798                 size = NDKMAP * sizeof (struct dk_map32);
3799                 rval = ddi_copyout(dk_map32, (void *)arg, size, flag);
3800                 if (rval != 0) {
3801                         rval = EFAULT;
3802                 }
3803                 break;
3804         }
3805         case DDI_MODEL_NONE:
3806                 size = NDKMAP * sizeof (struct dk_map);
3807                 rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3808                 if (rval != 0) {
3809                         rval = EFAULT;
3810                 }
3811                 break;
3812         }
3813 #else /* ! _MULTI_DATAMODEL */
3814         size = NDKMAP * sizeof (struct dk_map);
3815         rval = ddi_copyout(cl->cl_map, (void *)arg, size, flag);
3816         if (rval != 0) {
3817                 rval = EFAULT;
3818         }
3819 #endif /* _MULTI_DATAMODEL */
3820         return (rval);
3821 }
3822 
3823 /*
3824  *    Function: cmlb_dkio_set_partition
3825  *
3826  * Description: This routine is the driver entry point for handling user
3827  *              requests to set the partition table (DKIOCSAPART). The actual
3828  *              device partition is not updated.
3829  *
3830  *   Arguments:
3831  *              arg  - pointer to user provided dk_allmap structure used to set
3832  *                      the controller's notion of the partition table.
3833  *              flag - this argument is a pass through to ddi_copyxxx()
3834  *                     directly from the mode argument of ioctl().
3835  *
3836  * Return Code: 0
3837  *              EINVAL
3838  *              EFAULT
3839  *              ENXIO
3840  *              EIO
3841  */
3842 static int
3843 cmlb_dkio_set_partition(struct cmlb_lun *cl, caddr_t arg, int flag)
3844 {
3845         struct dk_map   dk_map[NDKMAP];
3846         struct dk_map   *lp;
3847         int             rval = 0;
3848         int             size;
3849         int             i;
3850 #if defined(_SUNOS_VTOC_16)
3851         struct dkl_partition    *vp;
3852 #endif
3853 
3854         /*
3855          * Set the map for all logical partitions.  We lock
3856          * the priority just to make sure an interrupt doesn't
3857          * come in while the map is half updated.
3858          */
3859         _NOTE(DATA_READABLE_WITHOUT_LOCK(cmlb_lun::cl_solaris_size))
3860         mutex_enter(CMLB_MUTEX(cl));
3861 
3862         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3863                 mutex_exit(CMLB_MUTEX(cl));
3864                 return (ENOTSUP);
3865         }
3866         mutex_exit(CMLB_MUTEX(cl));
3867         if (cl->cl_solaris_size == 0) {
3868                 return (EIO);
3869         }
3870 
3871 #ifdef _MULTI_DATAMODEL
3872         switch (ddi_model_convert_from(flag & FMODELS)) {
3873         case DDI_MODEL_ILP32: {
3874                 struct dk_map32 dk_map32[NDKMAP];
3875 
3876                 size = NDKMAP * sizeof (struct dk_map32);
3877                 rval = ddi_copyin((void *)arg, dk_map32, size, flag);
3878                 if (rval != 0) {
3879                         return (EFAULT);
3880                 }
3881                 for (i = 0; i < NDKMAP; i++) {
3882                         dk_map[i].dkl_cylno = dk_map32[i].dkl_cylno;
3883                         dk_map[i].dkl_nblk  = dk_map32[i].dkl_nblk;
3884                 }
3885                 break;
3886         }
3887         case DDI_MODEL_NONE:
3888                 size = NDKMAP * sizeof (struct dk_map);
3889                 rval = ddi_copyin((void *)arg, dk_map, size, flag);
3890                 if (rval != 0) {
3891                         return (EFAULT);
3892                 }
3893                 break;
3894         }
3895 #else /* ! _MULTI_DATAMODEL */
3896         size = NDKMAP * sizeof (struct dk_map);
3897         rval = ddi_copyin((void *)arg, dk_map, size, flag);
3898         if (rval != 0) {
3899                 return (EFAULT);
3900         }
3901 #endif /* _MULTI_DATAMODEL */
3902 
3903         mutex_enter(CMLB_MUTEX(cl));
3904         /* Note: The size used in this bcopy is set based upon the data model */
3905         bcopy(dk_map, cl->cl_map, size);
3906 #if defined(_SUNOS_VTOC_16)
3907         vp = (struct dkl_partition *)&(cl->cl_vtoc);
3908 #endif  /* defined(_SUNOS_VTOC_16) */
3909         for (i = 0; i < NDKMAP; i++) {
3910                 lp  = &cl->cl_map[i];
3911                 cl->cl_offset[i] =
3912                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
3913 #if defined(_SUNOS_VTOC_16)
3914                 vp->p_start = cl->cl_offset[i];
3915                 vp->p_size = lp->dkl_nblk;
3916                 vp++;
3917 #endif  /* defined(_SUNOS_VTOC_16) */
3918 #if defined(__i386) || defined(__amd64)
3919                 cl->cl_offset[i] += cl->cl_solaris_offset;
3920 #endif
3921         }
3922         mutex_exit(CMLB_MUTEX(cl));
3923         return (rval);
3924 }
3925 
3926 
3927 /*
3928  *    Function: cmlb_dkio_get_vtoc
3929  *
3930  * Description: This routine is the driver entry point for handling user
3931  *              requests to get the current volume table of contents
3932  *              (DKIOCGVTOC).
3933  *
3934  *   Arguments:
3935  *      arg             pointer to user provided vtoc structure specifying
3936  *                      the current vtoc.
3937  *
3938  *      flag            this argument is a pass through to ddi_copyxxx()
3939  *                      directly from the mode argument of ioctl().
3940  *
3941  *      tg_cookie       cookie from target driver to be passed back to target
3942  *                      driver when we call back to it through tg_ops.
3943  *
3944  * Return Code: 0
3945  *              EFAULT
3946  *              ENXIO
3947  *              EIO
3948  */
3949 static int
3950 cmlb_dkio_get_vtoc(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
3951 {
3952 #if defined(_SUNOS_VTOC_8)
3953         struct vtoc     user_vtoc;
3954 #endif  /* defined(_SUNOS_VTOC_8) */
3955         int             rval = 0;
3956 
3957         mutex_enter(CMLB_MUTEX(cl));
3958         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
3959                 mutex_exit(CMLB_MUTEX(cl));
3960                 return (EOVERFLOW);
3961         }
3962 
3963         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
3964 
3965 #if defined(_SUNOS_VTOC_8)
3966         if (rval == EINVAL &&
3967             (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
3968                 /*
3969                  * This is to return a default label even when we do not
3970                  * really assume a default label for the device.
3971                  * dad driver utilizes this.
3972                  */
3973                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
3974                         cmlb_setup_default_geometry(cl, tg_cookie);
3975                         rval = 0;
3976                 }
3977         }
3978 #endif
3979         if (rval) {
3980                 mutex_exit(CMLB_MUTEX(cl));
3981                 return (rval);
3982         }
3983 
3984 #if defined(_SUNOS_VTOC_8)
3985         cmlb_build_user_vtoc(cl, &user_vtoc);
3986         mutex_exit(CMLB_MUTEX(cl));
3987 
3988 #ifdef _MULTI_DATAMODEL
3989         switch (ddi_model_convert_from(flag & FMODELS)) {
3990         case DDI_MODEL_ILP32: {
3991                 struct vtoc32 user_vtoc32;
3992 
3993                 vtoctovtoc32(user_vtoc, user_vtoc32);
3994                 if (ddi_copyout(&user_vtoc32, (void *)arg,
3995                     sizeof (struct vtoc32), flag)) {
3996                         return (EFAULT);
3997                 }
3998                 break;
3999         }
4000 
4001         case DDI_MODEL_NONE:
4002                 if (ddi_copyout(&user_vtoc, (void *)arg,
4003                     sizeof (struct vtoc), flag)) {
4004                         return (EFAULT);
4005                 }
4006                 break;
4007         }
4008 #else /* ! _MULTI_DATAMODEL */
4009         if (ddi_copyout(&user_vtoc, (void *)arg, sizeof (struct vtoc), flag)) {
4010                 return (EFAULT);
4011         }
4012 #endif /* _MULTI_DATAMODEL */
4013 
4014 #elif defined(_SUNOS_VTOC_16)
4015         mutex_exit(CMLB_MUTEX(cl));
4016 
4017 #ifdef _MULTI_DATAMODEL
4018         /*
4019          * The cl_vtoc structure is a "struct dk_vtoc"  which is always
4020          * 32-bit to maintain compatibility with existing on-disk
4021          * structures.  Thus, we need to convert the structure when copying
4022          * it out to a datamodel-dependent "struct vtoc" in a 64-bit
4023          * program.  If the target is a 32-bit program, then no conversion
4024          * is necessary.
4025          */
4026         /* LINTED: logical expression always true: op "||" */
4027         ASSERT(sizeof (cl->cl_vtoc) == sizeof (struct vtoc32));
4028         switch (ddi_model_convert_from(flag & FMODELS)) {
4029         case DDI_MODEL_ILP32:
4030                 if (ddi_copyout(&(cl->cl_vtoc), (void *)arg,
4031                     sizeof (cl->cl_vtoc), flag)) {
4032                         return (EFAULT);
4033                 }
4034                 break;
4035 
4036         case DDI_MODEL_NONE: {
4037                 struct vtoc user_vtoc;
4038 
4039                 vtoc32tovtoc(cl->cl_vtoc, user_vtoc);
4040                 if (ddi_copyout(&user_vtoc, (void *)arg,
4041                     sizeof (struct vtoc), flag)) {
4042                         return (EFAULT);
4043                 }
4044                 break;
4045         }
4046         }
4047 #else /* ! _MULTI_DATAMODEL */
4048         if (ddi_copyout(&(cl->cl_vtoc), (void *)arg, sizeof (cl->cl_vtoc),
4049             flag)) {
4050                 return (EFAULT);
4051         }
4052 #endif /* _MULTI_DATAMODEL */
4053 #else
4054 #error "No VTOC format defined."
4055 #endif
4056 
4057         return (rval);
4058 }
4059 
4060 
4061 /*
4062  *    Function: cmlb_dkio_get_extvtoc
4063  */
4064 static int
4065 cmlb_dkio_get_extvtoc(struct cmlb_lun *cl, caddr_t arg, int flag,
4066     void *tg_cookie)
4067 {
4068         struct extvtoc  ext_vtoc;
4069 #if defined(_SUNOS_VTOC_8)
4070         struct vtoc     user_vtoc;
4071 #endif  /* defined(_SUNOS_VTOC_8) */
4072         int             rval = 0;
4073 
4074         bzero(&ext_vtoc, sizeof (struct extvtoc));
4075         mutex_enter(CMLB_MUTEX(cl));
4076         rval = cmlb_validate_geometry(cl, B_TRUE, 0, tg_cookie);
4077 
4078 #if defined(_SUNOS_VTOC_8)
4079         if (rval == EINVAL &&
4080             (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8)) {
4081                 /*
4082                  * This is to return a default label even when we do not
4083                  * really assume a default label for the device.
4084                  * dad driver utilizes this.
4085                  */
4086                 if (cl->cl_blockcount <= CMLB_OLDVTOC_LIMIT) {
4087                         cmlb_setup_default_geometry(cl, tg_cookie);
4088                         rval = 0;
4089                 }
4090         }
4091 #endif
4092         if (rval) {
4093                 mutex_exit(CMLB_MUTEX(cl));
4094                 return (rval);
4095         }
4096 
4097 #if defined(_SUNOS_VTOC_8)
4098         cmlb_build_user_vtoc(cl, &user_vtoc);
4099         mutex_exit(CMLB_MUTEX(cl));
4100 
4101         /*
4102          * Checking callers data model does not make much sense here
4103          * since extvtoc will always be equivalent to 64bit vtoc.
4104          * What is important is whether the kernel is in 32 or 64 bit
4105          */
4106 
4107 #ifdef _LP64
4108                 if (ddi_copyout(&user_vtoc, (void *)arg,
4109                     sizeof (struct extvtoc), flag)) {
4110                         return (EFAULT);
4111                 }
4112 #else
4113                 vtoc32tovtoc(user_vtoc, ext_vtoc);
4114                 if (ddi_copyout(&ext_vtoc, (void *)arg,
4115                     sizeof (struct extvtoc), flag)) {
4116                         return (EFAULT);
4117                 }
4118 #endif
4119 
4120 #elif defined(_SUNOS_VTOC_16)
4121         /*
4122          * The cl_vtoc structure is a "struct dk_vtoc"  which is always
4123          * 32-bit to maintain compatibility with existing on-disk
4124          * structures.  Thus, we need to convert the structure when copying
4125          * it out to extvtoc
4126          */
4127         vtoc32tovtoc(cl->cl_vtoc, ext_vtoc);
4128         mutex_exit(CMLB_MUTEX(cl));
4129 
4130         if (ddi_copyout(&ext_vtoc, (void *)arg, sizeof (struct extvtoc), flag))
4131                 return (EFAULT);
4132 #else
4133 #error "No VTOC format defined."
4134 #endif
4135 
4136         return (rval);
4137 }
4138 
4139 /*
4140  * This routine implements the DKIOCGETEFI ioctl. This ioctl is currently
4141  * used to read the GPT Partition Table Header (primary/backup), the GUID
4142  * partition Entry Array (primary/backup), and the MBR.
4143  */
4144 static int
4145 cmlb_dkio_get_efi(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
4146 {
4147         dk_efi_t        user_efi;
4148         int             rval = 0;
4149         void            *buffer;
4150         diskaddr_t      tgt_lba;
4151 
4152         if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4153                 return (EFAULT);
4154 
4155         user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4156 
4157         if (user_efi.dki_length == 0 ||
4158             user_efi.dki_length > cmlb_tg_max_efi_xfer)
4159                 return (EINVAL);
4160 
4161         tgt_lba = user_efi.dki_lba;
4162 
4163         mutex_enter(CMLB_MUTEX(cl));
4164         if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4165             (cl->cl_tgt_blocksize == 0) ||
4166             (user_efi.dki_length % cl->cl_sys_blocksize)) {
4167                 mutex_exit(CMLB_MUTEX(cl));
4168                 return (EINVAL);
4169         }
4170         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
4171                 tgt_lba = tgt_lba * cl->cl_tgt_blocksize /
4172                     cl->cl_sys_blocksize;
4173         mutex_exit(CMLB_MUTEX(cl));
4174 
4175         buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
4176         rval = DK_TG_READ(cl, buffer, tgt_lba, user_efi.dki_length, tg_cookie);
4177         if (rval == 0 && ddi_copyout(buffer, user_efi.dki_data,
4178             user_efi.dki_length, flag) != 0)
4179                 rval = EFAULT;
4180 
4181         kmem_free(buffer, user_efi.dki_length);
4182         return (rval);
4183 }
4184 
4185 #if defined(_SUNOS_VTOC_8)
4186 /*
4187  *    Function: cmlb_build_user_vtoc
4188  *
4189  * Description: This routine populates a pass by reference variable with the
4190  *              current volume table of contents.
4191  *
4192  *   Arguments: cl - driver soft state (unit) structure
4193  *              user_vtoc - pointer to vtoc structure to be populated
4194  */
4195 static void
4196 cmlb_build_user_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4197 {
4198         struct dk_map2          *lpart;
4199         struct dk_map           *lmap;
4200         struct partition        *vpart;
4201         uint32_t                nblks;
4202         int                     i;
4203 
4204         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4205 
4206         /*
4207          * Return vtoc structure fields in the provided VTOC area, addressed
4208          * by *vtoc.
4209          */
4210         bzero(user_vtoc, sizeof (struct vtoc));
4211         user_vtoc->v_bootinfo[0] = cl->cl_vtoc.v_bootinfo[0];
4212         user_vtoc->v_bootinfo[1] = cl->cl_vtoc.v_bootinfo[1];
4213         user_vtoc->v_bootinfo[2] = cl->cl_vtoc.v_bootinfo[2];
4214         user_vtoc->v_sanity  = VTOC_SANE;
4215         user_vtoc->v_version = cl->cl_vtoc.v_version;
4216         bcopy(cl->cl_vtoc.v_volume, user_vtoc->v_volume, LEN_DKL_VVOL);
4217         user_vtoc->v_sectorsz = cl->cl_sys_blocksize;
4218         user_vtoc->v_nparts = cl->cl_vtoc.v_nparts;
4219 
4220         for (i = 0; i < 10; i++)
4221                 user_vtoc->v_reserved[i] = cl->cl_vtoc.v_reserved[i];
4222 
4223         /*
4224          * Convert partitioning information.
4225          *
4226          * Note the conversion from starting cylinder number
4227          * to starting sector number.
4228          */
4229         lmap = cl->cl_map;
4230         lpart = (struct dk_map2 *)cl->cl_vtoc.v_part;
4231         vpart = user_vtoc->v_part;
4232 
4233         nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4234 
4235         for (i = 0; i < V_NUMPAR; i++) {
4236                 vpart->p_tag = lpart->p_tag;
4237                 vpart->p_flag        = lpart->p_flag;
4238                 vpart->p_start       = lmap->dkl_cylno * nblks;
4239                 vpart->p_size        = lmap->dkl_nblk;
4240                 lmap++;
4241                 lpart++;
4242                 vpart++;
4243 
4244                 /* (4364927) */
4245                 user_vtoc->timestamp[i] = (time_t)cl->cl_vtoc.v_timestamp[i];
4246         }
4247 
4248         bcopy(cl->cl_asciilabel, user_vtoc->v_asciilabel, LEN_DKL_ASCII);
4249 }
4250 #endif
4251 
4252 static int
4253 cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
4254     void *tg_cookie)
4255 {
4256         struct partition64      p64;
4257         int                     rval = 0;
4258         uint_t                  nparts;
4259         efi_gpe_t               *partitions;
4260         efi_gpt_t               *buffer;
4261         diskaddr_t              gpe_lba;
4262         int                     n_gpe_per_blk = 0;
4263 
4264         if (ddi_copyin((const void *)arg, &p64,
4265             sizeof (struct partition64), flag)) {
4266                 return (EFAULT);
4267         }
4268 
4269         buffer = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4270         rval = DK_TG_READ(cl, buffer, 1, cl->cl_sys_blocksize, tg_cookie);
4271         if (rval != 0)
4272                 goto done_error;
4273 
4274         cmlb_swap_efi_gpt(buffer);
4275 
4276         if ((rval = cmlb_validate_efi(buffer)) != 0)
4277                 goto done_error;
4278 
4279         nparts = buffer->efi_gpt_NumberOfPartitionEntries;
4280         gpe_lba = buffer->efi_gpt_PartitionEntryLBA;
4281         if (p64.p_partno >= nparts) {
4282                 /* couldn't find it */
4283                 rval = ESRCH;
4284                 goto done_error;
4285         }
4286         /*
4287          * Read the block that contains the requested GPE.
4288          */
4289         n_gpe_per_blk = cl->cl_sys_blocksize / sizeof (efi_gpe_t);
4290         gpe_lba += p64.p_partno / n_gpe_per_blk;
4291         rval = DK_TG_READ(cl, buffer, gpe_lba, cl->cl_sys_blocksize, tg_cookie);
4292 
4293         if (rval) {
4294                 goto done_error;
4295         }
4296         partitions = (efi_gpe_t *)buffer;
4297         partitions += p64.p_partno % n_gpe_per_blk;
4298 
4299         /* Byte swap only the requested GPE */
4300         cmlb_swap_efi_gpe(1, partitions);
4301 
4302         bcopy(&partitions->efi_gpe_PartitionTypeGUID, &p64.p_type,
4303             sizeof (struct uuid));
4304         p64.p_start = partitions->efi_gpe_StartingLBA;
4305         p64.p_size = partitions->efi_gpe_EndingLBA -
4306             p64.p_start + 1;
4307 
4308         if (ddi_copyout(&p64, (void *)arg, sizeof (struct partition64), flag))
4309                 rval = EFAULT;
4310 
4311 done_error:
4312         kmem_free(buffer, cl->cl_sys_blocksize);
4313         return (rval);
4314 }
4315 
4316 
4317 /*
4318  *    Function: cmlb_dkio_set_vtoc
4319  *
4320  * Description: This routine is the driver entry point for handling user
4321  *              requests to set the current volume table of contents
4322  *              (DKIOCSVTOC).
4323  *
4324  *   Arguments:
4325  *      dev             the device number
4326  *      arg             pointer to user provided vtoc structure used to set the
4327  *                      current vtoc.
4328  *
4329  *      flag            this argument is a pass through to ddi_copyxxx()
4330  *                      directly from the mode argument of ioctl().
4331  *
4332  *      tg_cookie       cookie from target driver to be passed back to target
4333  *                      driver when we call back to it through tg_ops.
4334  *
4335  * Return Code: 0
4336  *              EFAULT
4337  *              ENXIO
4338  *              EINVAL
4339  *              ENOTSUP
4340  */
4341 static int
4342 cmlb_dkio_set_vtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4343     void *tg_cookie)
4344 {
4345         struct vtoc     user_vtoc;
4346         int             shift, rval = 0;
4347         boolean_t       internal;
4348 
4349         internal = VOID2BOOLEAN(
4350             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4351 
4352         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4353                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4354         else
4355                 shift = CMLBUNIT_SHIFT;
4356 
4357 #ifdef _MULTI_DATAMODEL
4358         switch (ddi_model_convert_from(flag & FMODELS)) {
4359         case DDI_MODEL_ILP32: {
4360                 struct vtoc32 user_vtoc32;
4361 
4362                 if (ddi_copyin((const void *)arg, &user_vtoc32,
4363                     sizeof (struct vtoc32), flag)) {
4364                         return (EFAULT);
4365                 }
4366                 vtoc32tovtoc(user_vtoc32, user_vtoc);
4367                 break;
4368         }
4369 
4370         case DDI_MODEL_NONE:
4371                 if (ddi_copyin((const void *)arg, &user_vtoc,
4372                     sizeof (struct vtoc), flag)) {
4373                         return (EFAULT);
4374                 }
4375                 break;
4376         }
4377 #else /* ! _MULTI_DATAMODEL */
4378         if (ddi_copyin((const void *)arg, &user_vtoc,
4379             sizeof (struct vtoc), flag)) {
4380                 return (EFAULT);
4381         }
4382 #endif /* _MULTI_DATAMODEL */
4383 
4384         mutex_enter(CMLB_MUTEX(cl));
4385 
4386         if (cl->cl_blockcount > CMLB_OLDVTOC_LIMIT) {
4387                 mutex_exit(CMLB_MUTEX(cl));
4388                 return (EOVERFLOW);
4389         }
4390 
4391 #if defined(__i386) || defined(__amd64)
4392         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4393                 mutex_exit(CMLB_MUTEX(cl));
4394                 return (EINVAL);
4395         }
4396 #endif
4397 
4398         if (cl->cl_g.dkg_ncyl == 0) {
4399                 mutex_exit(CMLB_MUTEX(cl));
4400                 return (EINVAL);
4401         }
4402 
4403         mutex_exit(CMLB_MUTEX(cl));
4404         cmlb_clear_efi(cl, tg_cookie);
4405         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4406         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4407 
4408         /*
4409          * cmlb_dkio_set_vtoc creates duplicate minor nodes when
4410          * relabeling an SMI disk. To avoid that we remove them
4411          * before creating.
4412          * It should be OK to remove a non-existed minor node.
4413          */
4414         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4415         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4416 
4417         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4418             S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4419             cl->cl_node_type, NULL, internal);
4420         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4421             S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4422             cl->cl_node_type, NULL, internal);
4423         mutex_enter(CMLB_MUTEX(cl));
4424 
4425         if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4426                 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4427                         if (cmlb_validate_geometry(cl,
4428                             B_TRUE, 0, tg_cookie) != 0) {
4429                                 cmlb_dbg(CMLB_ERROR, cl,
4430                                     "cmlb_dkio_set_vtoc: "
4431                                     "Failed validate geometry\n");
4432                         }
4433                         cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
4434                 }
4435         }
4436         mutex_exit(CMLB_MUTEX(cl));
4437         return (rval);
4438 }
4439 
4440 /*
4441  *    Function: cmlb_dkio_set_extvtoc
4442  */
4443 static int
4444 cmlb_dkio_set_extvtoc(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4445     void *tg_cookie)
4446 {
4447         int             shift, rval = 0;
4448         struct vtoc     user_vtoc;
4449         boolean_t       internal;
4450 
4451         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4452                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4453         else
4454                 shift = CMLBUNIT_SHIFT;
4455 
4456         /*
4457          * Checking callers data model does not make much sense here
4458          * since extvtoc will always be equivalent to 64bit vtoc.
4459          * What is important is whether the kernel is in 32 or 64 bit
4460          */
4461 
4462 #ifdef _LP64
4463         if (ddi_copyin((const void *)arg, &user_vtoc,
4464                     sizeof (struct extvtoc), flag)) {
4465                         return (EFAULT);
4466         }
4467 #else
4468         struct  extvtoc user_extvtoc;
4469         if (ddi_copyin((const void *)arg, &user_extvtoc,
4470                     sizeof (struct extvtoc), flag)) {
4471                         return (EFAULT);
4472         }
4473 
4474         vtoctovtoc32(user_extvtoc, user_vtoc);
4475 #endif
4476 
4477         internal = VOID2BOOLEAN(
4478             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4479         mutex_enter(CMLB_MUTEX(cl));
4480 #if defined(__i386) || defined(__amd64)
4481         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize) {
4482                 mutex_exit(CMLB_MUTEX(cl));
4483                 return (EINVAL);
4484         }
4485 #endif
4486 
4487         if (cl->cl_g.dkg_ncyl == 0) {
4488                 mutex_exit(CMLB_MUTEX(cl));
4489                 return (EINVAL);
4490         }
4491 
4492         mutex_exit(CMLB_MUTEX(cl));
4493         cmlb_clear_efi(cl, tg_cookie);
4494         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd");
4495         ddi_remove_minor_node(CMLB_DEVINFO(cl), "wd,raw");
4496         /*
4497          * cmlb_dkio_set_extvtoc creates duplicate minor nodes when
4498          * relabeling an SMI disk. To avoid that we remove them
4499          * before creating.
4500          * It should be OK to remove a non-existed minor node.
4501          */
4502         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
4503         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
4504 
4505         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h",
4506             S_IFBLK, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4507             cl->cl_node_type, NULL, internal);
4508         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "h,raw",
4509             S_IFCHR, (CMLBUNIT(dev, shift) << shift) | WD_NODE,
4510             cl->cl_node_type, NULL, internal);
4511 
4512         mutex_enter(CMLB_MUTEX(cl));
4513 
4514         if ((rval = cmlb_build_label_vtoc(cl, &user_vtoc)) == 0) {
4515                 if ((rval = cmlb_write_label(cl, tg_cookie)) == 0) {
4516                         if (cmlb_validate_geometry(cl,
4517                             B_TRUE, 0, tg_cookie) != 0) {
4518                                 cmlb_dbg(CMLB_ERROR, cl,
4519                                     "cmlb_dkio_set_vtoc: "
4520                                     "Failed validate geometry\n");
4521                         }
4522                 }
4523         }
4524         mutex_exit(CMLB_MUTEX(cl));
4525         return (rval);
4526 }
4527 
4528 /*
4529  *    Function: cmlb_build_label_vtoc
4530  *
4531  * Description: This routine updates the driver soft state current volume table
4532  *              of contents based on a user specified vtoc.
4533  *
4534  *   Arguments: cl - driver soft state (unit) structure
4535  *              user_vtoc - pointer to vtoc structure specifying vtoc to be used
4536  *                          to update the driver soft state.
4537  *
4538  * Return Code: 0
4539  *              EINVAL
4540  */
4541 static int
4542 cmlb_build_label_vtoc(struct cmlb_lun *cl, struct vtoc *user_vtoc)
4543 {
4544         struct dk_map           *lmap;
4545         struct partition        *vpart;
4546         uint_t                  nblks;
4547 #if defined(_SUNOS_VTOC_8)
4548         int                     ncyl;
4549         struct dk_map2          *lpart;
4550 #endif  /* defined(_SUNOS_VTOC_8) */
4551         int                     i;
4552 
4553         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4554 
4555         /* Sanity-check the vtoc */
4556         if (user_vtoc->v_sanity != VTOC_SANE ||
4557             user_vtoc->v_sectorsz != cl->cl_sys_blocksize ||
4558             user_vtoc->v_nparts != V_NUMPAR) {
4559                 cmlb_dbg(CMLB_INFO,  cl,
4560                     "cmlb_build_label_vtoc: vtoc not valid\n");
4561                 return (EINVAL);
4562         }
4563 
4564         nblks = cl->cl_g.dkg_nsect * cl->cl_g.dkg_nhead;
4565         if (nblks == 0) {
4566                 cmlb_dbg(CMLB_INFO,  cl,
4567                     "cmlb_build_label_vtoc: geom nblks is 0\n");
4568                 return (EINVAL);
4569         }
4570 
4571 #if defined(_SUNOS_VTOC_8)
4572         vpart = user_vtoc->v_part;
4573         for (i = 0; i < V_NUMPAR; i++) {
4574                 if (((unsigned)vpart->p_start % nblks) != 0) {
4575                         cmlb_dbg(CMLB_INFO,  cl,
4576                             "cmlb_build_label_vtoc: p_start not multiply of"
4577                             "nblks part %d p_start %d nblks %d\n", i,
4578                             vpart->p_start, nblks);
4579                         return (EINVAL);
4580                 }
4581                 ncyl = (unsigned)vpart->p_start / nblks;
4582                 ncyl += (unsigned)vpart->p_size / nblks;
4583                 if (((unsigned)vpart->p_size % nblks) != 0) {
4584                         ncyl++;
4585                 }
4586                 if (ncyl > (int)cl->cl_g.dkg_ncyl) {
4587                         cmlb_dbg(CMLB_INFO,  cl,
4588                             "cmlb_build_label_vtoc: ncyl %d  > dkg_ncyl %d"
4589                             "p_size %ld p_start %ld nblks %d  part number %d"
4590                             "tag %d\n",
4591                             ncyl, cl->cl_g.dkg_ncyl, vpart->p_size,
4592                             vpart->p_start, nblks,
4593                             i, vpart->p_tag);
4594 
4595                         return (EINVAL);
4596                 }
4597                 vpart++;
4598         }
4599 #endif  /* defined(_SUNOS_VTOC_8) */
4600 
4601         /* Put appropriate vtoc structure fields into the disk label */
4602 #if defined(_SUNOS_VTOC_16)
4603         /*
4604          * The vtoc is always a 32bit data structure to maintain the
4605          * on-disk format. Convert "in place" instead of doing bcopy.
4606          */
4607         vtoctovtoc32((*user_vtoc), (*((struct vtoc32 *)&(cl->cl_vtoc))));
4608 
4609         /*
4610          * in the 16-slice vtoc, starting sectors are expressed in
4611          * numbers *relative* to the start of the Solaris fdisk partition.
4612          */
4613         lmap = cl->cl_map;
4614         vpart = user_vtoc->v_part;
4615 
4616         for (i = 0; i < (int)user_vtoc->v_nparts; i++, lmap++, vpart++) {
4617                 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4618                 lmap->dkl_nblk = (unsigned)vpart->p_size;
4619         }
4620 
4621 #elif defined(_SUNOS_VTOC_8)
4622 
4623         cl->cl_vtoc.v_bootinfo[0] = (uint32_t)user_vtoc->v_bootinfo[0];
4624         cl->cl_vtoc.v_bootinfo[1] = (uint32_t)user_vtoc->v_bootinfo[1];
4625         cl->cl_vtoc.v_bootinfo[2] = (uint32_t)user_vtoc->v_bootinfo[2];
4626 
4627         cl->cl_vtoc.v_sanity = (uint32_t)user_vtoc->v_sanity;
4628         cl->cl_vtoc.v_version = (uint32_t)user_vtoc->v_version;
4629 
4630         bcopy(user_vtoc->v_volume, cl->cl_vtoc.v_volume, LEN_DKL_VVOL);
4631 
4632         cl->cl_vtoc.v_nparts = user_vtoc->v_nparts;
4633 
4634         for (i = 0; i < 10; i++)
4635                 cl->cl_vtoc.v_reserved[i] =  user_vtoc->v_reserved[i];
4636 
4637         /*
4638          * Note the conversion from starting sector number
4639          * to starting cylinder number.
4640          * Return error if division results in a remainder.
4641          */
4642         lmap = cl->cl_map;
4643         lpart = cl->cl_vtoc.v_part;
4644         vpart = user_vtoc->v_part;
4645 
4646         for (i = 0; i < (int)user_vtoc->v_nparts; i++) {
4647                 lpart->p_tag  = vpart->p_tag;
4648                 lpart->p_flag = vpart->p_flag;
4649                 lmap->dkl_cylno = (unsigned)vpart->p_start / nblks;
4650                 lmap->dkl_nblk = (unsigned)vpart->p_size;
4651 
4652                 lmap++;
4653                 lpart++;
4654                 vpart++;
4655 
4656                 /* (4387723) */
4657 #ifdef _LP64
4658                 if (user_vtoc->timestamp[i] > TIME32_MAX) {
4659                         cl->cl_vtoc.v_timestamp[i] = TIME32_MAX;
4660                 } else {
4661                         cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4662                 }
4663 #else
4664                 cl->cl_vtoc.v_timestamp[i] = user_vtoc->timestamp[i];
4665 #endif
4666         }
4667 
4668         bcopy(user_vtoc->v_asciilabel, cl->cl_asciilabel, LEN_DKL_ASCII);
4669 #else
4670 #error "No VTOC format defined."
4671 #endif
4672         return (0);
4673 }
4674 
4675 /*
4676  *    Function: cmlb_clear_efi
4677  *
4678  * Description: This routine clears all EFI labels.
4679  *
4680  *   Arguments:
4681  *      cl               driver soft state (unit) structure
4682  *
4683  *      tg_cookie       cookie from target driver to be passed back to target
4684  *                      driver when we call back to it through tg_ops.
4685  * Return Code: void
4686  */
4687 static void
4688 cmlb_clear_efi(struct cmlb_lun *cl, void *tg_cookie)
4689 {
4690         efi_gpt_t       *gpt;
4691         diskaddr_t      cap;
4692         int             rval;
4693 
4694         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
4695 
4696         mutex_enter(CMLB_MUTEX(cl));
4697         cl->cl_reserved = -1;
4698         mutex_exit(CMLB_MUTEX(cl));
4699 
4700         gpt = kmem_alloc(cl->cl_sys_blocksize, KM_SLEEP);
4701 
4702         if (DK_TG_READ(cl, gpt, 1, cl->cl_sys_blocksize, tg_cookie) != 0) {
4703                 goto done;
4704         }
4705 
4706         cmlb_swap_efi_gpt(gpt);
4707         rval = cmlb_validate_efi(gpt);
4708         if (rval == 0) {
4709                 /* clear primary */
4710                 bzero(gpt, sizeof (efi_gpt_t));
4711                 if (rval = DK_TG_WRITE(cl, gpt, 1, cl->cl_sys_blocksize,
4712                     tg_cookie)) {
4713                         cmlb_dbg(CMLB_INFO,  cl,
4714                             "cmlb_clear_efi: clear primary label failed\n");
4715                 }
4716         }
4717         /* the backup */
4718         rval = DK_TG_GETCAP(cl, &cap, tg_cookie);
4719         if (rval) {
4720                 goto done;
4721         }
4722 
4723         if ((rval = DK_TG_READ(cl, gpt, cap - 1, cl->cl_sys_blocksize,
4724             tg_cookie)) != 0) {
4725                 goto done;
4726         }
4727         cmlb_swap_efi_gpt(gpt);
4728         rval = cmlb_validate_efi(gpt);
4729         if (rval == 0) {
4730                 /* clear backup */
4731                 cmlb_dbg(CMLB_TRACE,  cl,
4732                     "cmlb_clear_efi clear backup@%lu\n", cap - 1);
4733                 bzero(gpt, sizeof (efi_gpt_t));
4734                 if ((rval = DK_TG_WRITE(cl,  gpt, cap - 1, cl->cl_sys_blocksize,
4735                     tg_cookie))) {
4736                         cmlb_dbg(CMLB_INFO,  cl,
4737                             "cmlb_clear_efi: clear backup label failed\n");
4738                 }
4739         } else {
4740                 /*
4741                  * Refer to comments related to off-by-1 at the
4742                  * header of this file
4743                  */
4744                 if ((rval = DK_TG_READ(cl, gpt, cap - 2,
4745                     cl->cl_sys_blocksize, tg_cookie)) != 0) {
4746                         goto done;
4747                 }
4748                 cmlb_swap_efi_gpt(gpt);
4749                 rval = cmlb_validate_efi(gpt);
4750                 if (rval == 0) {
4751                         /* clear legacy backup EFI label */
4752                         cmlb_dbg(CMLB_TRACE,  cl,
4753                             "cmlb_clear_efi clear legacy backup@%lu\n",
4754                             cap - 2);
4755                         bzero(gpt, sizeof (efi_gpt_t));
4756                         if ((rval = DK_TG_WRITE(cl,  gpt, cap - 2,
4757                             cl->cl_sys_blocksize, tg_cookie))) {
4758                                 cmlb_dbg(CMLB_INFO,  cl,
4759                                 "cmlb_clear_efi: clear legacy backup label "
4760                                 "failed\n");
4761                         }
4762                 }
4763         }
4764 
4765 done:
4766         kmem_free(gpt, cl->cl_sys_blocksize);
4767 }
4768 
4769 /*
4770  *    Function: cmlb_set_vtoc
4771  *
4772  * Description: This routine writes data to the appropriate positions
4773  *
4774  *   Arguments:
4775  *      cl              driver soft state (unit) structure
4776  *
4777  *      dkl             the data to be written
4778  *
4779  *      tg_cookie       cookie from target driver to be passed back to target
4780  *                      driver when we call back to it through tg_ops.
4781  *
4782  * Return: void
4783  */
4784 static int
4785 cmlb_set_vtoc(struct cmlb_lun *cl, struct dk_label *dkl, void *tg_cookie)
4786 {
4787         uint_t  label_addr;
4788         int     sec;
4789         diskaddr_t      blk;
4790         int     head;
4791         int     cyl;
4792         int     rval;
4793 
4794 #if defined(__i386) || defined(__amd64)
4795         label_addr = cl->cl_solaris_offset + DK_LABEL_LOC;
4796 #else
4797         /* Write the primary label at block 0 of the solaris partition. */
4798         label_addr = 0;
4799 #endif
4800 
4801         rval = DK_TG_WRITE(cl, dkl, label_addr, cl->cl_sys_blocksize,
4802             tg_cookie);
4803 
4804         if (rval != 0) {
4805                 return (rval);
4806         }
4807 
4808         /*
4809          * Calculate where the backup labels go.  They are always on
4810          * the last alternate cylinder, but some older drives put them
4811          * on head 2 instead of the last head.  They are always on the
4812          * first 5 odd sectors of the appropriate track.
4813          *
4814          * We have no choice at this point, but to believe that the
4815          * disk label is valid.  Use the geometry of the disk
4816          * as described in the label.
4817          */
4818         cyl  = dkl->dkl_ncyl  + dkl->dkl_acyl - 1;
4819         head = dkl->dkl_nhead - 1;
4820 
4821         /*
4822          * Write and verify the backup labels. Make sure we don't try to
4823          * write past the last cylinder.
4824          */
4825         for (sec = 1; ((sec < 5 * 2 + 1) && (sec < dkl->dkl_nsect)); sec += 2) {
4826                 blk = (diskaddr_t)(
4827                     (cyl * ((dkl->dkl_nhead * dkl->dkl_nsect) - dkl->dkl_apc)) +
4828                     (head * dkl->dkl_nsect) + sec);
4829 #if defined(__i386) || defined(__amd64)
4830                 blk += cl->cl_solaris_offset;
4831 #endif
4832                 rval = DK_TG_WRITE(cl, dkl, blk, cl->cl_sys_blocksize,
4833                     tg_cookie);
4834                 cmlb_dbg(CMLB_INFO,  cl,
4835                 "cmlb_set_vtoc: wrote backup label %llx\n", blk);
4836                 if (rval != 0) {
4837                         goto exit;
4838                 }
4839         }
4840 exit:
4841         return (rval);
4842 }
4843 
4844 /*
4845  *    Function: cmlb_clear_vtoc
4846  *
4847  * Description: This routine clears out the VTOC labels.
4848  *
4849  *   Arguments:
4850  *      cl              driver soft state (unit) structure
4851  *
4852  *      tg_cookie       cookie from target driver to be passed back to target
4853  *                      driver when we call back to it through tg_ops.
4854  *
4855  * Return: void
4856  */
4857 static void
4858 cmlb_clear_vtoc(struct cmlb_lun *cl, void *tg_cookie)
4859 {
4860         struct dk_label         *dkl;
4861 
4862         mutex_exit(CMLB_MUTEX(cl));
4863         dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4864         mutex_enter(CMLB_MUTEX(cl));
4865         /*
4866          * cmlb_set_vtoc uses these fields in order to figure out
4867          * where to overwrite the backup labels
4868          */
4869         dkl->dkl_apc    = cl->cl_g.dkg_apc;
4870         dkl->dkl_ncyl   = cl->cl_g.dkg_ncyl;
4871         dkl->dkl_acyl   = cl->cl_g.dkg_acyl;
4872         dkl->dkl_nhead  = cl->cl_g.dkg_nhead;
4873         dkl->dkl_nsect  = cl->cl_g.dkg_nsect;
4874         mutex_exit(CMLB_MUTEX(cl));
4875         (void) cmlb_set_vtoc(cl, dkl, tg_cookie);
4876         kmem_free(dkl, cl->cl_sys_blocksize);
4877 
4878         mutex_enter(CMLB_MUTEX(cl));
4879 }
4880 
4881 /*
4882  *    Function: cmlb_write_label
4883  *
4884  * Description: This routine will validate and write the driver soft state vtoc
4885  *              contents to the device.
4886  *
4887  *   Arguments:
4888  *      cl              cmlb handle
4889  *
4890  *      tg_cookie       cookie from target driver to be passed back to target
4891  *                      driver when we call back to it through tg_ops.
4892  *
4893  *
4894  * Return Code: the code returned by cmlb_send_scsi_cmd()
4895  *              0
4896  *              EINVAL
4897  *              ENXIO
4898  *              ENOMEM
4899  */
4900 static int
4901 cmlb_write_label(struct cmlb_lun *cl, void *tg_cookie)
4902 {
4903         struct dk_label *dkl;
4904         short           sum;
4905         short           *sp;
4906         int             i;
4907         int             rval;
4908 
4909         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
4910         mutex_exit(CMLB_MUTEX(cl));
4911         dkl = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
4912         mutex_enter(CMLB_MUTEX(cl));
4913 
4914         bcopy(&cl->cl_vtoc, &dkl->dkl_vtoc, sizeof (struct dk_vtoc));
4915         dkl->dkl_rpm = cl->cl_g.dkg_rpm;
4916         dkl->dkl_pcyl        = cl->cl_g.dkg_pcyl;
4917         dkl->dkl_apc = cl->cl_g.dkg_apc;
4918         dkl->dkl_intrlv = cl->cl_g.dkg_intrlv;
4919         dkl->dkl_ncyl        = cl->cl_g.dkg_ncyl;
4920         dkl->dkl_acyl        = cl->cl_g.dkg_acyl;
4921         dkl->dkl_nhead       = cl->cl_g.dkg_nhead;
4922         dkl->dkl_nsect       = cl->cl_g.dkg_nsect;
4923 
4924 #if defined(_SUNOS_VTOC_8)
4925         dkl->dkl_obs1        = cl->cl_g.dkg_obs1;
4926         dkl->dkl_obs2        = cl->cl_g.dkg_obs2;
4927         dkl->dkl_obs3        = cl->cl_g.dkg_obs3;
4928         for (i = 0; i < NDKMAP; i++) {
4929                 dkl->dkl_map[i].dkl_cylno = cl->cl_map[i].dkl_cylno;
4930                 dkl->dkl_map[i].dkl_nblk  = cl->cl_map[i].dkl_nblk;
4931         }
4932         bcopy(cl->cl_asciilabel, dkl->dkl_asciilabel, LEN_DKL_ASCII);
4933 #elif defined(_SUNOS_VTOC_16)
4934         dkl->dkl_skew        = cl->cl_dkg_skew;
4935 #else
4936 #error "No VTOC format defined."
4937 #endif
4938 
4939         dkl->dkl_magic                       = DKL_MAGIC;
4940         dkl->dkl_write_reinstruct    = cl->cl_g.dkg_write_reinstruct;
4941         dkl->dkl_read_reinstruct     = cl->cl_g.dkg_read_reinstruct;
4942 
4943         /* Construct checksum for the new disk label */
4944         sum = 0;
4945         sp = (short *)dkl;
4946         i = sizeof (struct dk_label) / sizeof (short);
4947         while (i--) {
4948                 sum ^= *sp++;
4949         }
4950         dkl->dkl_cksum = sum;
4951 
4952         mutex_exit(CMLB_MUTEX(cl));
4953 
4954         rval = cmlb_set_vtoc(cl, dkl, tg_cookie);
4955 exit:
4956         kmem_free(dkl, cl->cl_sys_blocksize);
4957         mutex_enter(CMLB_MUTEX(cl));
4958         return (rval);
4959 }
4960 
4961 /*
4962  * This routine implements the DKIOCSETEFI ioctl. This ioctl is currently
4963  * used to write (or clear) the GPT Partition Table header (primary/backup)
4964  * and GUID partition Entry Array (primary/backup). It is also used to write
4965  * the Protective MBR.
4966  */
4967 static int
4968 cmlb_dkio_set_efi(struct cmlb_lun *cl, dev_t dev, caddr_t arg, int flag,
4969     void *tg_cookie)
4970 {
4971         dk_efi_t        user_efi;
4972         int             shift, rval = 0;
4973         void            *buffer;
4974         diskaddr_t      tgt_lba;
4975         boolean_t       internal;
4976 
4977         if (ddi_copyin(arg, &user_efi, sizeof (dk_efi_t), flag))
4978                 return (EFAULT);
4979 
4980         internal = VOID2BOOLEAN(
4981             (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
4982 
4983         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
4984                 shift = CMLBUNIT_FORCE_P0_SHIFT;
4985         else
4986                 shift = CMLBUNIT_SHIFT;
4987 
4988         user_efi.dki_data = (void *)(uintptr_t)user_efi.dki_data_64;
4989 
4990         if (user_efi.dki_length == 0 ||
4991             user_efi.dki_length > cmlb_tg_max_efi_xfer)
4992                 return (EINVAL);
4993 
4994         tgt_lba = user_efi.dki_lba;
4995 
4996         mutex_enter(CMLB_MUTEX(cl));
4997         if ((cmlb_check_update_blockcount(cl, tg_cookie) != 0) ||
4998             (cl->cl_tgt_blocksize == 0) ||
4999             (user_efi.dki_length % cl->cl_sys_blocksize)) {
5000                 mutex_exit(CMLB_MUTEX(cl));
5001                 return (EINVAL);
5002         }
5003         if (cl->cl_tgt_blocksize != cl->cl_sys_blocksize)
5004                 tgt_lba = tgt_lba *
5005                     cl->cl_tgt_blocksize / cl->cl_sys_blocksize;
5006         mutex_exit(CMLB_MUTEX(cl));
5007 
5008         buffer = kmem_alloc(user_efi.dki_length, KM_SLEEP);
5009         if (ddi_copyin(user_efi.dki_data, buffer, user_efi.dki_length, flag)) {
5010                 rval = EFAULT;
5011         } else {
5012                 /*
5013                  * let's clear the vtoc labels and clear the softstate
5014                  * vtoc.
5015                  */
5016                 mutex_enter(CMLB_MUTEX(cl));
5017                 if (cl->cl_vtoc.v_sanity == VTOC_SANE) {
5018                         cmlb_dbg(CMLB_TRACE,  cl,
5019                             "cmlb_dkio_set_efi: CLEAR VTOC\n");
5020                         if (cl->cl_label_from_media == CMLB_LABEL_VTOC)
5021                                 cmlb_clear_vtoc(cl, tg_cookie);
5022                         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
5023                         mutex_exit(CMLB_MUTEX(cl));
5024                         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h");
5025                         ddi_remove_minor_node(CMLB_DEVINFO(cl), "h,raw");
5026                         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd",
5027                             S_IFBLK,
5028                             (CMLBUNIT(dev, shift) << shift) | WD_NODE,
5029                             cl->cl_node_type, NULL, internal);
5030                         (void) cmlb_create_minor(CMLB_DEVINFO(cl), "wd,raw",
5031                             S_IFCHR,
5032                             (CMLBUNIT(dev, shift) << shift) | WD_NODE,
5033                             cl->cl_node_type, NULL, internal);
5034                 } else
5035                         mutex_exit(CMLB_MUTEX(cl));
5036 
5037                 rval = DK_TG_WRITE(cl, buffer, tgt_lba, user_efi.dki_length,
5038                     tg_cookie);
5039 
5040                 if (rval == 0) {
5041                         mutex_enter(CMLB_MUTEX(cl));
5042                         cl->cl_f_geometry_is_valid = B_FALSE;
5043                         mutex_exit(CMLB_MUTEX(cl));
5044                 }
5045         }
5046         kmem_free(buffer, user_efi.dki_length);
5047         return (rval);
5048 }
5049 
5050 /*
5051  *    Function: cmlb_dkio_get_mboot
5052  *
5053  * Description: This routine is the driver entry point for handling user
5054  *              requests to get the current device mboot (DKIOCGMBOOT)
5055  *
5056  *   Arguments:
5057  *      arg             pointer to user provided mboot structure specifying
5058  *                      the current mboot.
5059  *
5060  *      flag            this argument is a pass through to ddi_copyxxx()
5061  *                      directly from the mode argument of ioctl().
5062  *
5063  *      tg_cookie       cookie from target driver to be passed back to target
5064  *                      driver when we call back to it through tg_ops.
5065  *
5066  * Return Code: 0
5067  *              EINVAL
5068  *              EFAULT
5069  *              ENXIO
5070  */
5071 static int
5072 cmlb_dkio_get_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5073 {
5074         struct mboot    *mboot;
5075         int             rval;
5076         size_t          buffer_size;
5077 
5078 
5079 #if defined(_SUNOS_VTOC_8)
5080         if ((!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) || (arg == NULL)) {
5081 #elif defined(_SUNOS_VTOC_16)
5082         if (arg == NULL) {
5083 #endif
5084                 return (EINVAL);
5085         }
5086 
5087         /*
5088          * Read the mboot block, located at absolute block 0 on the target.
5089          */
5090         buffer_size = cl->cl_sys_blocksize;
5091 
5092         cmlb_dbg(CMLB_TRACE,  cl,
5093             "cmlb_dkio_get_mboot: allocation size: 0x%x\n", buffer_size);
5094 
5095         mboot = kmem_zalloc(buffer_size, KM_SLEEP);
5096         if ((rval = DK_TG_READ(cl, mboot, 0, buffer_size, tg_cookie)) == 0) {
5097                 if (ddi_copyout(mboot, (void *)arg,
5098                     sizeof (struct mboot), flag) != 0) {
5099                         rval = EFAULT;
5100                 }
5101         }
5102         kmem_free(mboot, buffer_size);
5103         return (rval);
5104 }
5105 
5106 
5107 /*
5108  *    Function: cmlb_dkio_set_mboot
5109  *
5110  * Description: This routine is the driver entry point for handling user
5111  *              requests to validate and set the device master boot
5112  *              (DKIOCSMBOOT).
5113  *
5114  *   Arguments:
5115  *      arg             pointer to user provided mboot structure used to set the
5116  *                      master boot.
5117  *
5118  *      flag            this argument is a pass through to ddi_copyxxx()
5119  *                      directly from the mode argument of ioctl().
5120  *
5121  *      tg_cookie       cookie from target driver to be passed back to target
5122  *                      driver when we call back to it through tg_ops.
5123  *
5124  * Return Code: 0
5125  *              EINVAL
5126  *              EFAULT
5127  *              ENXIO
5128  */
5129 static int
5130 cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
5131 {
5132         struct mboot    *mboot = NULL;
5133         int             rval;
5134         ushort_t        magic;
5135 
5136 
5137         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5138 
5139 #if defined(_SUNOS_VTOC_8)
5140         if (!ISREMOVABLE(cl) && !ISHOTPLUGGABLE(cl)) {
5141                 return (EINVAL);
5142         }
5143 #endif
5144 
5145         if (arg == NULL) {
5146                 return (EINVAL);
5147         }
5148 
5149         mboot = kmem_zalloc(cl->cl_sys_blocksize, KM_SLEEP);
5150 
5151         if (ddi_copyin((const void *)arg, mboot,
5152             cl->cl_sys_blocksize, flag) != 0) {
5153                 kmem_free(mboot, cl->cl_sys_blocksize);
5154                 return (EFAULT);
5155         }
5156 
5157         /* Is this really a master boot record? */
5158         magic = LE_16(mboot->signature);
5159         if (magic != MBB_MAGIC) {
5160                 kmem_free(mboot, cl->cl_sys_blocksize);
5161                 return (EINVAL);
5162         }
5163 
5164         rval = DK_TG_WRITE(cl, mboot, 0, cl->cl_sys_blocksize, tg_cookie);
5165 
5166         mutex_enter(CMLB_MUTEX(cl));
5167 #if defined(__i386) || defined(__amd64)
5168         if (rval == 0) {
5169                 /*
5170                  * mboot has been written successfully.
5171                  * update the fdisk and vtoc tables in memory
5172                  */
5173                 rval = cmlb_update_fdisk_and_vtoc(cl, tg_cookie);
5174                 if ((!cl->cl_f_geometry_is_valid) || (rval != 0)) {
5175                         mutex_exit(CMLB_MUTEX(cl));
5176                         kmem_free(mboot, cl->cl_sys_blocksize);
5177                         return (rval);
5178                 }
5179         }
5180 
5181 #ifdef __lock_lint
5182         cmlb_setup_default_geometry(cl, tg_cookie);
5183 #endif
5184 
5185 #else
5186         if (rval == 0) {
5187                 /*
5188                  * mboot has been written successfully.
5189                  * set up the default geometry and VTOC
5190                  */
5191                 if (cl->cl_blockcount <= CMLB_EXTVTOC_LIMIT)
5192                         cmlb_setup_default_geometry(cl, tg_cookie);
5193         }
5194 #endif
5195         cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
5196         mutex_exit(CMLB_MUTEX(cl));
5197         kmem_free(mboot, cl->cl_sys_blocksize);
5198         return (rval);
5199 }
5200 
5201 
5202 #if defined(__i386) || defined(__amd64)
5203 /*ARGSUSED*/
5204 static int
5205 cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
5206     void *tg_cookie)
5207 {
5208         int fdisk_rval;
5209         diskaddr_t capacity;
5210 
5211         ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
5212 
5213         mutex_enter(CMLB_MUTEX(cl));
5214         capacity = cl->cl_blockcount;
5215         fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5216         if (fdisk_rval != 0) {
5217                 mutex_exit(CMLB_MUTEX(cl));
5218                 return (fdisk_rval);
5219         }
5220 
5221         mutex_exit(CMLB_MUTEX(cl));
5222         return (fdisk_rval);
5223 }
5224 #endif
5225 
5226 /*
5227  *    Function: cmlb_setup_default_geometry
5228  *
5229  * Description: This local utility routine sets the default geometry as part of
5230  *              setting the device mboot.
5231  *
5232  *   Arguments:
5233  *      cl              driver soft state (unit) structure
5234  *
5235  *      tg_cookie       cookie from target driver to be passed back to target
5236  *                      driver when we call back to it through tg_ops.
5237  *
5238  *
5239  * Note: This may be redundant with cmlb_build_default_label.
5240  */
5241 static void
5242 cmlb_setup_default_geometry(struct cmlb_lun *cl, void *tg_cookie)
5243 {
5244         struct cmlb_geom        pgeom;
5245         struct cmlb_geom        *pgeomp = &pgeom;
5246         int                     ret;
5247         int                     geom_base_cap = 1;
5248 
5249 
5250         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5251 
5252         /* zero out the soft state geometry and partition table. */
5253         bzero(&cl->cl_g, sizeof (struct dk_geom));
5254         bzero(&cl->cl_vtoc, sizeof (struct dk_vtoc));
5255         bzero(cl->cl_map, NDKMAP * (sizeof (struct dk_map)));
5256 
5257         /*
5258          * For the rpm, we use the minimum for the disk.
5259          * For the head, cyl and number of sector per track,
5260          * if the capacity <= 1GB, head = 64, sect = 32.
5261          * else head = 255, sect 63
5262          * Note: the capacity should be equal to C*H*S values.
5263          * This will cause some truncation of size due to
5264          * round off errors. For CD-ROMs, this truncation can
5265          * have adverse side effects, so returning ncyl and
5266          * nhead as 1. The nsect will overflow for most of
5267          * CD-ROMs as nsect is of type ushort.
5268          */
5269         if (cl->cl_alter_behavior & CMLB_FAKE_GEOM_LABEL_IOCTLS_VTOC8) {
5270                 /*
5271                  * newfs currently can not handle 255 ntracks for SPARC
5272                  * so get the geometry from target driver instead of coming up
5273                  * with one based on capacity.
5274                  */
5275                 mutex_exit(CMLB_MUTEX(cl));
5276                 ret = DK_TG_GETPHYGEOM(cl, pgeomp, tg_cookie);
5277                 mutex_enter(CMLB_MUTEX(cl));
5278 
5279                 if (ret == 0) {
5280                         geom_base_cap = 0;
5281                 } else {
5282                         cmlb_dbg(CMLB_ERROR,  cl,
5283                             "cmlb_setup_default_geometry: "
5284                             "tg_getphygeom failed %d\n", ret);
5285 
5286                         /* do default setting, geometry based on capacity */
5287                 }
5288         }
5289 
5290         if (geom_base_cap) {
5291                 if (ISCD(cl)) {
5292                         cl->cl_g.dkg_ncyl = 1;
5293                         cl->cl_g.dkg_nhead = 1;
5294                         cl->cl_g.dkg_nsect = cl->cl_blockcount;
5295                 } else if (cl->cl_blockcount < 160) {
5296                         /* Less than 80K */
5297                         cl->cl_g.dkg_nhead = 1;
5298                         cl->cl_g.dkg_ncyl = cl->cl_blockcount;
5299                         cl->cl_g.dkg_nsect = 1;
5300                 } else if (cl->cl_blockcount <= 0x1000) {
5301                         /* Needed for unlabeled SCSI floppies. */
5302                         cl->cl_g.dkg_nhead = 2;
5303                         cl->cl_g.dkg_ncyl = 80;
5304                         cl->cl_g.dkg_pcyl = 80;
5305                         cl->cl_g.dkg_nsect = cl->cl_blockcount / (2 * 80);
5306                 } else if (cl->cl_blockcount <= 0x200000) {
5307                         cl->cl_g.dkg_nhead = 64;
5308                         cl->cl_g.dkg_nsect = 32;
5309                         cl->cl_g.dkg_ncyl = cl->cl_blockcount / (64 * 32);
5310                 } else {
5311                         cl->cl_g.dkg_nhead = 255;
5312 
5313                         cl->cl_g.dkg_nsect = ((cl->cl_blockcount +
5314                             (UINT16_MAX * 255 * 63) - 1) /
5315                             (UINT16_MAX * 255 * 63)) * 63;
5316 
5317                         if (cl->cl_g.dkg_nsect == 0)
5318                                 cl->cl_g.dkg_nsect = (UINT16_MAX / 63) * 63;
5319 
5320                         cl->cl_g.dkg_ncyl = cl->cl_blockcount /
5321                             (255 * cl->cl_g.dkg_nsect);
5322                 }
5323 
5324                 cl->cl_g.dkg_acyl = 0;
5325                 cl->cl_g.dkg_bcyl = 0;
5326                 cl->cl_g.dkg_intrlv = 1;
5327                 cl->cl_g.dkg_rpm = 200;
5328                 if (cl->cl_g.dkg_pcyl == 0)
5329                         cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl +
5330                             cl->cl_g.dkg_acyl;
5331         } else {
5332                 cl->cl_g.dkg_ncyl = (short)pgeomp->g_ncyl;
5333                 cl->cl_g.dkg_acyl = pgeomp->g_acyl;
5334                 cl->cl_g.dkg_nhead = pgeomp->g_nhead;
5335                 cl->cl_g.dkg_nsect = pgeomp->g_nsect;
5336                 cl->cl_g.dkg_intrlv = pgeomp->g_intrlv;
5337                 cl->cl_g.dkg_rpm = pgeomp->g_rpm;
5338                 cl->cl_g.dkg_pcyl = cl->cl_g.dkg_ncyl + cl->cl_g.dkg_acyl;
5339         }
5340 
5341         cl->cl_g.dkg_read_reinstruct = 0;
5342         cl->cl_g.dkg_write_reinstruct = 0;
5343         cl->cl_solaris_size = cl->cl_g.dkg_ncyl *
5344             cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect;
5345 
5346         cl->cl_map['a'-'a'].dkl_cylno = 0;
5347         cl->cl_map['a'-'a'].dkl_nblk = cl->cl_solaris_size;
5348 
5349         cl->cl_map['c'-'a'].dkl_cylno = 0;
5350         cl->cl_map['c'-'a'].dkl_nblk = cl->cl_solaris_size;
5351 
5352         cl->cl_vtoc.v_part[2].p_tag   = V_BACKUP;
5353         cl->cl_vtoc.v_part[2].p_flag  = V_UNMNT;
5354         cl->cl_vtoc.v_nparts = V_NUMPAR;
5355         cl->cl_vtoc.v_version = V_VERSION;
5356         (void) sprintf((char *)cl->cl_asciilabel, "DEFAULT cyl %d alt %d"
5357             " hd %d sec %d", cl->cl_g.dkg_ncyl, cl->cl_g.dkg_acyl,
5358             cl->cl_g.dkg_nhead, cl->cl_g.dkg_nsect);
5359 
5360         cl->cl_f_geometry_is_valid = B_FALSE;
5361 }
5362 
5363 
5364 #if defined(__i386) || defined(__amd64)
5365 /*
5366  *    Function: cmlb_update_fdisk_and_vtoc
5367  *
5368  * Description: This local utility routine updates the device fdisk and vtoc
5369  *              as part of setting the device mboot.
5370  *
5371  *   Arguments:
5372  *      cl              driver soft state (unit) structure
5373  *
5374  *      tg_cookie       cookie from target driver to be passed back to target
5375  *                      driver when we call back to it through tg_ops.
5376  *
5377  *
5378  * Return Code: 0 for success or errno-type return code.
5379  *
5380  *    Note:x86: This looks like a duplicate of cmlb_validate_geometry(), but
5381  *              these did exist separately in x86 sd.c.
5382  */
5383 static int
5384 cmlb_update_fdisk_and_vtoc(struct cmlb_lun *cl, void *tg_cookie)
5385 {
5386         int             count;
5387         int             label_rc = 0;
5388         int             fdisk_rval;
5389         diskaddr_t      capacity;
5390 
5391         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5392 
5393         if (cmlb_check_update_blockcount(cl, tg_cookie) != 0)
5394                 return (EINVAL);
5395 
5396         /*
5397          * Set up the "whole disk" fdisk partition; this should always
5398          * exist, regardless of whether the disk contains an fdisk table
5399          * or vtoc.
5400          */
5401         cl->cl_map[P0_RAW_DISK].dkl_cylno = 0;
5402         cl->cl_map[P0_RAW_DISK].dkl_nblk = cl->cl_blockcount;
5403 
5404         /*
5405          * copy the lbasize and capacity so that if they're
5406          * reset while we're not holding the CMLB_MUTEX(cl), we will
5407          * continue to use valid values after the CMLB_MUTEX(cl) is
5408          * reacquired.
5409          */
5410         capacity = cl->cl_blockcount;
5411 
5412         /*
5413          * refresh the logical and physical geometry caches.
5414          * (data from mode sense format/rigid disk geometry pages,
5415          * and scsi_ifgetcap("geometry").
5416          */
5417         cmlb_resync_geom_caches(cl, capacity, tg_cookie);
5418 
5419         /*
5420          * Only DIRECT ACCESS devices will have Scl labels.
5421          * CD's supposedly have a Scl label, too
5422          */
5423         if (cl->cl_device_type == DTYPE_DIRECT || ISREMOVABLE(cl)) {
5424                 fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
5425                 if (fdisk_rval != 0) {
5426                         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5427                         return (fdisk_rval);
5428                 }
5429 
5430                 if (cl->cl_solaris_size <= DK_LABEL_LOC) {
5431                         /*
5432                          * Found fdisk table but no Solaris partition entry,
5433                          * so don't call cmlb_uselabel() and don't create
5434                          * a default label.
5435                          */
5436                         label_rc = 0;
5437                         cl->cl_f_geometry_is_valid = B_TRUE;
5438                         goto no_solaris_partition;
5439                 }
5440         } else if (capacity < 0) {
5441                 ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5442                 return (EINVAL);
5443         }
5444 
5445         /*
5446          * For Removable media We reach here if we have found a
5447          * SOLARIS PARTITION.
5448          * If cl_f_geometry_is_valid is B_FALSE it indicates that the SOLARIS
5449          * PARTITION has changed from the previous one, hence we will setup a
5450          * default VTOC in this case.
5451          */
5452         if (!cl->cl_f_geometry_is_valid) {
5453                 /* if we get here it is writable */
5454                 /* we are called from SMBOOT, and after a write of fdisk */
5455                 cmlb_build_default_label(cl, tg_cookie);
5456                 label_rc = 0;
5457         }
5458 
5459 no_solaris_partition:
5460 
5461 #if defined(_SUNOS_VTOC_16)
5462         /*
5463          * If we have valid geometry, set up the remaining fdisk partitions.
5464          * Note that dkl_cylno is not used for the fdisk map entries, so
5465          * we set it to an entirely bogus value.
5466          */
5467         for (count = 0; count < FDISK_PARTS; count++) {
5468                 cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX;
5469                 cl->cl_map[FDISK_P1 + count].dkl_nblk =
5470                     cl->cl_fmap[count].fmap_nblk;
5471                 cl->cl_offset[FDISK_P1 + count] =
5472                     cl->cl_fmap[count].fmap_start;
5473         }
5474 #endif
5475 
5476         for (count = 0; count < NDKMAP; count++) {
5477 #if defined(_SUNOS_VTOC_8)
5478                 struct dk_map *lp  = &cl->cl_map[count];
5479                 cl->cl_offset[count] =
5480                     cl->cl_g.dkg_nhead * cl->cl_g.dkg_nsect * lp->dkl_cylno;
5481 #elif defined(_SUNOS_VTOC_16)
5482                 struct dkl_partition *vp = &cl->cl_vtoc.v_part[count];
5483                 cl->cl_offset[count] = vp->p_start + cl->cl_solaris_offset;
5484 #else
5485 #error "No VTOC format defined."
5486 #endif
5487         }
5488 
5489         ASSERT(mutex_owned(CMLB_MUTEX(cl)));
5490         return (label_rc);
5491 }
5492 #endif
5493 
5494 #if defined(__i386) || defined(__amd64)
5495 static int
5496 cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag)
5497 {
5498         int err = 0;
5499 
5500         /* Return the driver's notion of the media's logical geometry */
5501         struct dk_geom  disk_geom;
5502         struct dk_geom  *dkgp = &disk_geom;
5503 
5504         mutex_enter(CMLB_MUTEX(cl));
5505         /*
5506          * If there is no HBA geometry available, or
5507          * if the HBA returned us something that doesn't
5508          * really fit into an Int 13/function 8 geometry
5509          * result, just fail the ioctl.  See PSARC 1998/313.
5510          */
5511         if (cl->cl_lgeom.g_nhead == 0 ||
5512             cl->cl_lgeom.g_nsect == 0 ||
5513             cl->cl_lgeom.g_ncyl > 1024) {
5514                 mutex_exit(CMLB_MUTEX(cl));
5515                 err = EINVAL;
5516         } else {
5517                 dkgp->dkg_ncyl       = cl->cl_lgeom.g_ncyl;
5518                 dkgp->dkg_acyl       = cl->cl_lgeom.g_acyl;
5519                 dkgp->dkg_pcyl       = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5520                 dkgp->dkg_nhead      = cl->cl_lgeom.g_nhead;
5521                 dkgp->dkg_nsect      = cl->cl_lgeom.g_nsect;
5522 
5523                 mutex_exit(CMLB_MUTEX(cl));
5524                 if (ddi_copyout(dkgp, (void *)arg,
5525                     sizeof (struct dk_geom), flag)) {
5526                         err = EFAULT;
5527                 } else {
5528                         err = 0;
5529                 }
5530         }
5531         return (err);
5532 }
5533 #endif
5534 
5535 #if defined(__i386) || defined(__amd64)
5536 static int
5537 cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t  arg, int flag,
5538     void *tg_cookie)
5539 {
5540         int err = 0;
5541         diskaddr_t capacity;
5542 
5543 
5544         /* Return the driver's notion of the media physical geometry */
5545         struct dk_geom  disk_geom;
5546         struct dk_geom  *dkgp = &disk_geom;
5547 
5548         mutex_enter(CMLB_MUTEX(cl));
5549 
5550         if (cl->cl_g.dkg_nhead != 0 &&
5551             cl->cl_g.dkg_nsect != 0) {
5552                 /*
5553                  * We succeeded in getting a geometry, but
5554                  * right now it is being reported as just the
5555                  * Solaris fdisk partition, just like for
5556                  * DKIOCGGEOM. We need to change that to be
5557                  * correct for the entire disk now.
5558                  */
5559                 bcopy(&cl->cl_g, dkgp, sizeof (*dkgp));
5560                 dkgp->dkg_acyl = 0;
5561                 dkgp->dkg_ncyl = cl->cl_blockcount /
5562                     (dkgp->dkg_nhead * dkgp->dkg_nsect);
5563         } else {
5564                 bzero(dkgp, sizeof (struct dk_geom));
5565                 /*
5566                  * This disk does not have a Solaris VTOC
5567                  * so we must present a physical geometry
5568                  * that will remain consistent regardless
5569                  * of how the disk is used. This will ensure
5570                  * that the geometry does not change regardless
5571                  * of the fdisk partition type (ie. EFI, FAT32,
5572                  * Solaris, etc).
5573                  */
5574                 if (ISCD(cl)) {
5575                         dkgp->dkg_nhead = cl->cl_pgeom.g_nhead;
5576                         dkgp->dkg_nsect = cl->cl_pgeom.g_nsect;
5577                         dkgp->dkg_ncyl = cl->cl_pgeom.g_ncyl;
5578                         dkgp->dkg_acyl = cl->cl_pgeom.g_acyl;
5579                 } else {
5580                         /*
5581                          * Invalid cl_blockcount can generate invalid
5582                          * dk_geom and may result in division by zero
5583                          * system failure. Should make sure blockcount
5584                          * is valid before using it here.
5585                          */
5586                         if (cl->cl_blockcount == 0) {
5587                                 mutex_exit(CMLB_MUTEX(cl));
5588                                 err = EIO;
5589                                 return (err);
5590                         }
5591                         /*
5592                          * Refer to comments related to off-by-1 at the
5593                          * header of this file
5594                          */
5595                         if (cl->cl_alter_behavior & CMLB_OFF_BY_ONE)
5596                                 capacity = cl->cl_blockcount - 1;
5597                         else
5598                                 capacity = cl->cl_blockcount;
5599 
5600                         cmlb_convert_geometry(cl, capacity, dkgp, tg_cookie);
5601                         dkgp->dkg_acyl = 0;
5602                         dkgp->dkg_ncyl = capacity /
5603                             (dkgp->dkg_nhead * dkgp->dkg_nsect);
5604                 }
5605         }
5606         dkgp->dkg_pcyl = dkgp->dkg_ncyl + dkgp->dkg_acyl;
5607 
5608         mutex_exit(CMLB_MUTEX(cl));
5609         if (ddi_copyout(dkgp, (void *)arg, sizeof (struct dk_geom), flag))
5610                 err = EFAULT;
5611 
5612         return (err);
5613 }
5614 #endif
5615 
5616 #if defined(__i386) || defined(__amd64)
5617 static int
5618 cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t  arg, int flag)
5619 {
5620         int err = 0;
5621 
5622         /*
5623          * Return parameters describing the selected disk slice.
5624          * Note: this ioctl is for the intel platform only
5625          */
5626         int part;
5627 
5628         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
5629                 part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1);
5630         else
5631                 part = CMLBPART(dev);
5632 
5633         mutex_enter(CMLB_MUTEX(cl));
5634         /* don't check cl_solaris_size for pN */
5635         if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5636                 err = EIO;
5637                 mutex_exit(CMLB_MUTEX(cl));
5638         } else {
5639                 struct part_info p;
5640 
5641                 p.p_start = (daddr_t)cl->cl_offset[part];
5642                 p.p_length = (int)cl->cl_map[part].dkl_nblk;
5643                 mutex_exit(CMLB_MUTEX(cl));
5644 #ifdef _MULTI_DATAMODEL
5645                 switch (ddi_model_convert_from(flag & FMODELS)) {
5646                 case DDI_MODEL_ILP32:
5647                 {
5648                         struct part_info32 p32;
5649 
5650                         p32.p_start = (daddr32_t)p.p_start;
5651                         p32.p_length = p.p_length;
5652                         if (ddi_copyout(&p32, (void *)arg,
5653                             sizeof (p32), flag))
5654                                 err = EFAULT;
5655                         break;
5656                 }
5657 
5658                 case DDI_MODEL_NONE:
5659                 {
5660                         if (ddi_copyout(&p, (void *)arg, sizeof (p),
5661                             flag))
5662                                 err = EFAULT;
5663                         break;
5664                 }
5665                 }
5666 #else /* ! _MULTI_DATAMODEL */
5667                 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5668                         err = EFAULT;
5669 #endif /* _MULTI_DATAMODEL */
5670         }
5671         return (err);
5672 }
5673 static int
5674 cmlb_dkio_extpartinfo(struct cmlb_lun *cl, dev_t dev, caddr_t  arg, int flag)
5675 {
5676         int err = 0;
5677 
5678         /*
5679          * Return parameters describing the selected disk slice.
5680          * Note: this ioctl is for the intel platform only
5681          */
5682         int part;
5683 
5684         if (cl->cl_alter_behavior & CMLB_CREATE_P0_MINOR_NODE)
5685                 part = getminor(dev) & ((1 << CMLBUNIT_FORCE_P0_SHIFT) - 1);
5686         else
5687                 part = CMLBPART(dev);
5688 
5689         mutex_enter(CMLB_MUTEX(cl));
5690         /* don't check cl_solaris_size for pN */
5691         if (part < P0_RAW_DISK && cl->cl_solaris_size == 0) {
5692                 err = EIO;
5693                 mutex_exit(CMLB_MUTEX(cl));
5694         } else {
5695                 struct extpart_info p;
5696 
5697                 p.p_start = (diskaddr_t)cl->cl_offset[part];
5698                 p.p_length = (diskaddr_t)cl->cl_map[part].dkl_nblk;
5699                 mutex_exit(CMLB_MUTEX(cl));
5700                 if (ddi_copyout(&p, (void *)arg, sizeof (p), flag))
5701                         err = EFAULT;
5702         }
5703         return (err);
5704 }
5705 #endif
5706 
5707 int
5708 cmlb_prop_op(cmlb_handle_t cmlbhandle,
5709     dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
5710     char *name, caddr_t valuep, int *lengthp, int part, void *tg_cookie)
5711 {
5712         struct cmlb_lun *cl;
5713         diskaddr_t      capacity;
5714         uint32_t        lbasize;
5715         enum            dp { DP_NBLOCKS, DP_BLKSIZE, DP_SSD, DP_ROT } dp;
5716         int             callers_length;
5717         caddr_t         buffer;
5718         uint64_t        nblocks64;
5719         uint_t          dblk;
5720         tg_attribute_t  tgattr;
5721 
5722         /* Always fallback to ddi_prop_op... */
5723         cl = (struct cmlb_lun *)cmlbhandle;
5724         if (cl == NULL) {
5725 fallback:       return (ddi_prop_op(dev, dip, prop_op, mod_flags,
5726                     name, valuep, lengthp));
5727         }
5728 
5729         /* Pick up capacity and blocksize information. */
5730         capacity = cl->cl_blockcount;
5731         if (capacity == 0)
5732                 goto fallback;
5733         lbasize = cl->cl_tgt_blocksize;
5734         if (lbasize == 0)
5735                 lbasize = DEV_BSIZE;    /* 0 -> DEV_BSIZE units */
5736 
5737         /* Check for dynamic property of whole device. */
5738         if (dev == DDI_DEV_T_ANY) {
5739                 /* Fallback to ddi_prop_op if we don't understand.  */
5740                 if (strcmp(name, "device-nblocks") == 0)
5741                         dp = DP_NBLOCKS;
5742                 else if (strcmp(name, "device-blksize") == 0)
5743                         dp = DP_BLKSIZE;
5744                 else if (strcmp(name, "device-solid-state") == 0)
5745                         dp = DP_SSD;
5746                 else if (strcmp(name, "device-rotational") == 0)
5747                         dp = DP_ROT;
5748                 else
5749                         goto fallback;
5750 
5751                 /* get callers length, establish length of our dynamic prop */
5752                 callers_length = *lengthp;
5753                 if (dp == DP_NBLOCKS)
5754                         *lengthp = sizeof (uint64_t);
5755                 else if ((dp == DP_BLKSIZE) || (dp == DP_SSD))
5756                         *lengthp = sizeof (uint32_t);
5757 
5758                 /* service request for the length of the property */
5759                 if (prop_op == PROP_LEN)
5760                         return (DDI_PROP_SUCCESS);
5761 
5762                 switch (prop_op) {
5763                 case PROP_LEN_AND_VAL_ALLOC:
5764                         if ((buffer = kmem_alloc(*lengthp,
5765                             (mod_flags & DDI_PROP_CANSLEEP) ?
5766                             KM_SLEEP : KM_NOSLEEP)) == NULL)
5767                                 return (DDI_PROP_NO_MEMORY);
5768                         *(caddr_t *)valuep = buffer;    /* set callers buf */
5769                         break;
5770 
5771                 case PROP_LEN_AND_VAL_BUF:
5772                         /* the length of the prop and the request must match */
5773                         if (callers_length != *lengthp)
5774                                 return (DDI_PROP_INVAL_ARG);
5775                         buffer = valuep;                /* get callers buf */
5776                         break;
5777 
5778                 default:
5779                         return (DDI_PROP_INVAL_ARG);
5780                 }
5781 
5782                 /* transfer the value into the buffer */
5783                 switch (dp) {
5784                 case DP_NBLOCKS:
5785                         *((uint64_t *)buffer) = capacity;
5786                         break;
5787                 case DP_BLKSIZE:
5788                         *((uint32_t *)buffer) = lbasize;
5789                         break;
5790                 case DP_SSD:
5791                         if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5792                                 tgattr.media_is_solid_state = B_FALSE;
5793                         *((uint32_t *)buffer) =
5794                             tgattr.media_is_solid_state ? 1 : 0;
5795                         break;
5796                 case DP_ROT:
5797                         if (DK_TG_GETATTRIBUTE(cl, &tgattr, tg_cookie) != 0)
5798                                 tgattr.media_is_rotational = B_TRUE;
5799                         *((uint32_t *)buffer) =
5800                             tgattr.media_is_rotational ? 1 : 0;
5801                         break;
5802                 }
5803                 return (DDI_PROP_SUCCESS);
5804         }
5805 
5806         /*
5807          * Support dynamic size oriented properties of partition. Requests
5808          * issued under conditions where size is valid are passed to
5809          * ddi_prop_op_nblocks with the size information, otherwise the
5810          * request is passed to ddi_prop_op. Size depends on valid geometry.
5811          */
5812         if (!cmlb_is_valid(cmlbhandle))
5813                 goto fallback;
5814 
5815         /* Get partition nblocks value. */
5816         (void) cmlb_partinfo(cmlbhandle, part,
5817             (diskaddr_t *)&nblocks64, NULL, NULL, NULL, tg_cookie);
5818 
5819         /*
5820          * Assume partition information is in sys_blocksize units, compute
5821          * divisor for size(9P) property representation.
5822          */
5823         dblk = lbasize / cl->cl_sys_blocksize;
5824 
5825         /* Now let ddi_prop_op_nblocks_blksize() handle the request. */
5826         return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op, mod_flags,
5827             name, valuep, lengthp, nblocks64 / dblk, lbasize));
5828 }