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