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