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 #pragma ident "@(#)daio_uscsi.c 1.13 09/05/26 SMI" 23 24 /* 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/scsi/impl/uscsi.h> 31 #include <sys/scsi/generic/commands.h> 32 #include <sys/scsi/impl/commands.h> 33 #include <errno.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <stdlib.h> 39 40 #include <diskomizer/daio_dev.h> 41 #include <diskomizer/daio.h> 42 #include <diskomizer/log.h> 43 #include "findap.h" 44 #include "daio_async.h" 45 #include "args.h" 46 47 #ifdef BIG_ENDIAN 48 #define CONV2INT(A) (A) 49 #else 50 #define SWABB(X) (((0xff & (X)) << 8) | (0xff00 & (X)) >> 8) 51 #define SWABS(X) ((SWABB(0xffff & (X)) << 16) |\ 52 SWABB((0xffff0000 & (X)) >> 16)) 53 #define CONV2INT(A) SWABS(A) 54 #endif 55 56 #define MAX_GROUP2OFF 0xffffffffLL 57 58 /* 59 * Group 4 Commands, Direct Access Devices 60 * 61 * The ifndef is required as on later releases these are or should be 62 * in the header files. 63 */ 64 #ifndef SCMD_READ_G4 65 #define SCMD_READ_G4 0x88 66 #endif 67 68 #ifndef SCMD_WRITE_G4 69 #define SCMD_WRITE_G4 0x8a 70 #endif 71 72 #ifndef SCMD_WRITE_VERIFY_G4 73 #define SCMD_WRITE_VERIFY_G4 0x8e 74 #endif 75 76 #ifndef FORMG4LONGADDR 77 #define FORMG4LONGADDR(cdb, addr) \ 78 (cdb)->g4_addr3 = (addr) >> 56; \ 79 (cdb)->g4_addr2 = ((addr) >> 48) & 0xFF; \ 80 (cdb)->g4_addr1 = ((addr) >> 40) & 0xFF; \ 81 (cdb)->g4_addr0 = ((addr) >> 32) & 0xFF; \ 82 (cdb)->g4_addtl_cdb_data3 = ((addr) >> 24) & 0xFF; \ 83 (cdb)->g4_addtl_cdb_data2 = ((addr) >> 16) & 0xFF; \ 84 (cdb)->g4_addtl_cdb_data1 = ((addr) >> 8) & 0xFF; \ 85 (cdb)->g4_addtl_cdb_data0 = (addr) & 0xFF 86 #endif 87 88 89 union lun_n_tag { 90 uchar_t data; 91 struct { 92 #if defined(_BIT_FIELDS_LTOH) 93 uchar_t reladdr:1; 94 uchar_t bytchk:1; 95 uchar_t res:1; 96 uchar_t fua:1; 97 uchar_t dpo:1; 98 uchar_t lun:3; 99 #elif defined(_BIT_FIELDS_HTOL) 100 uchar_t lun:3; 101 uchar_t dpo:1; 102 uchar_t fua:1; 103 uchar_t res:1; 104 uchar_t bytchk:1; 105 uchar_t reladdr:1; 106 #else 107 #error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined 108 #endif 109 } un; 110 }; 111 112 struct timeout_vals { 113 uint16_t (*set_timeout)(struct timeout_vals *v); 114 int16_t min; 115 int16_t diff; 116 }; 117 118 static union lun_n_tag wlun_n_tag; 119 static union lun_n_tag rlun_n_tag; 120 121 static int uscsi_open(const char *path, int oflag, mode_t mode); 122 static int uscsi_close(int fd); 123 static void *uscsi_read_disko_vtoc(int fd); 124 static ssize_t uscsi_pread(int fildes, void *buf, size_t nbyte, off_t offset); 125 static ssize_t uscsi_pwrite(int fildes, void *buf, size_t nbyte, off_t offset); 126 static int daio_uscsi_write(int fildes, uchar_t *bufp, int bufs, off_t 127 offset, daio_result_t *resultp, struct daio_id *id); 128 static int daio_uscsi_read(int fildes, uchar_t *bufp, int bufs, off_t 129 offset, daio_result_t *resultp, struct daio_id *id); 130 static int nodev(int, int); 131 132 struct daio_ops DAIO_OPS = { 133 daio_async_init, 134 daio_async_init_checker, 135 daio_async_get_checker, 136 findap, 137 (daio_open_t)uscsi_open, 138 uscsi_close, 139 unlink, 140 stat64, 141 fstat64, 142 ioctl, 143 ftruncate64, 144 nodev, /* drect io does not make sense for USCSI */ 145 uscsi_read_disko_vtoc, 146 daio_async_pwrite, 147 daio_async_pread, 148 daio_uscsi_write, 149 daio_uscsi_read, 150 daio_async_status, 151 daio_async_start_time, 152 daio_async_end_time, 153 daio_async_wait, 154 daio_async_cancel, 155 daio_async_fini, 156 daio_dev_dd 157 }; 158 159 struct uscsi_str { 160 void *handle; 161 uint_t v_sectorsz; 162 struct disko_partition part; 163 }; 164 165 static struct uscsi_str *uscsi_state; 166 static int maxfd = -1; 167 168 static struct timeout_vals uscsi_read_timeout; 169 static struct timeout_vals uscsi_write_timeout; 170 static int8_t write_cmd1; 171 static int8_t write_cmd4; 172 static int8_t allow_bad_vtoc; 173 static int8_t ignore_partitions = 0; 174 ssize_t (*pwrite_func)(int fildes, void *bufp, size_t bufs, 175 off_t off) = uscsi_pwrite; 176 ssize_t (*pread_func)(int fildes, void *bufp, size_t bufs, 177 off_t off) = uscsi_pread; 178 179 static int 180 nodev(int x, int b) 181 { 182 return (0); 183 } 184 185 static uint16_t 186 set_timeout_diff(struct timeout_vals *v) 187 { 188 return (v->min + (lrand48() % v->diff)); 189 } 190 191 static uint16_t 192 set_timeout_no_diff(struct timeout_vals *v) 193 { 194 return (v->min); 195 } 196 197 static void 198 io_timeouts(const struct option_ops *ops, char *base_str, 199 struct timeout_vals *v) 200 { 201 char *str; 202 203 if (ops->opt_short(base_str, &v->min) == OPT_OK) { 204 /* for comatability */ 205 plog(LOG_NOTICE, "%s %d second%s\n", 206 str, v->min, v->min == 1 ? "" : "s"); 207 v->diff = 0; 208 } else if ((str = malloc(strlen(base_str) + 5)) != NULL) { 209 int16_t max; 210 211 sprintf(str, "%s.min", base_str); 212 if (ops->opt_short(str, &v->min) != OPT_OK) { 213 v->min = 60; 214 } else { 215 plog(LOG_NOTICE, "%s %d second%s\n", 216 str, v->min, v->min == 1 ? "" : "s"); 217 } 218 sprintf(str, "%s.max", base_str); 219 if (ops->opt_short(str, &max) != OPT_OK) { 220 max = 60; 221 } else { 222 plog(LOG_NOTICE, "%s %d second%s\n", 223 str, max, max == 1 ? "" : "s"); 224 } 225 if (max < v->min) { 226 plog(LOG_WARNING, 227 "%s max (%d) less then min (%d)" 228 " setting min to max\n", base_str, max, v->min); 229 v->min = max; 230 v->diff = 0; 231 } else { 232 v->diff = max - v->min; 233 } 234 free(str); 235 } else { 236 v->min = 60; 237 v->diff = 0; 238 } 239 if (v->diff == 0) { 240 v->set_timeout = set_timeout_no_diff; 241 } else { 242 v->set_timeout = set_timeout_diff; 243 } 244 } 245 246 static void 247 uscsi_init(void) 248 { 249 const struct option_ops *ops; 250 char x; 251 252 ops = opts_init(); 253 254 plog(LOG_NOTICE, "DAIO_USCSI version %s\n", VERSION); 255 256 if (ops->opt_bool("DAIO_USCSI_IGNORE_PARTITIONS", &x) == 257 OPT_OK && x == 1) { 258 plog(LOG_NOTICE, "USCSI IGNORE_PARTITIONS on\n"); 259 ignore_partitions = 1; 260 } 261 262 if (ops->opt_bool("DAIO_USCSI_USE_PWRITE", &x) == OPT_OK && x == 1) { 263 if (ignore_partitions) { 264 plog(LOG_ERR, "DAIO_USCSI_USE_PWRITE and " 265 "DAIO_USCSI_IGNORE_PARTITIONS are mutually " 266 "exclusive\n"); 267 exit(1); 268 } 269 pwrite_func = 270 (ssize_t (*)(int, void *, size_t, off_t)) pwrite64; 271 } else { 272 273 if (ops->opt_bool("DAIO_USCSI_WRITE_VERIFY", &x) == OPT_OK && 274 x == 1) { 275 write_cmd1 = SCMD_WRITE_VERIFY; 276 write_cmd4 = SCMD_WRITE_VERIFY_G4; 277 plog(LOG_NOTICE, "USCSI WRITE_VERIFY on\n"); 278 if (ops->opt_bool("DAIO_USCSI_WRITE_VERIFY_BYTE_CHECK", 279 &x) == OPT_OK && x == 1) { 280 plog(LOG_NOTICE, 281 "USCSI WRITE VERIFY_BYTE_CHECK on\n"); 282 wlun_n_tag.un.bytchk = 1; 283 } 284 } else { 285 write_cmd1 = SCMD_WRITE_G1; 286 write_cmd4 = SCMD_WRITE_G4; 287 } 288 289 if (ops->opt_bool("DAIO_USCSI_WRITE_FORCE_UNIT_ACCESS", &x) == 290 OPT_OK && x == 1) { 291 plog(LOG_NOTICE, 292 "USCSI WRITE FORCE_UNIT_ACCESS on\n"); 293 wlun_n_tag.un.fua = 1; 294 } 295 296 if (ops->opt_bool("DAIO_USCSI_WRITE_DISABLE_PAGE_OUT", &x) == 297 OPT_OK && x == 1) { 298 plog(LOG_NOTICE, 299 "USCSI WRITE DISABLE_PAGE_OUT on\n"); 300 wlun_n_tag.un.dpo = 1; 301 } 302 303 io_timeouts(ops, "DAIO_USCSI_WRITE_TIMEOUT", 304 &uscsi_write_timeout); 305 } 306 307 if (ops->opt_bool("DAIO_USCSI_USE_PREAD", &x) == OPT_OK && x == 1) { 308 if (ignore_partitions) { 309 plog(LOG_ERR, "DAIO_USCSI_USE_PREAD and " 310 "DAIO_USCSI_IGNORE_PARTITIONS are mutually " 311 "exclusive\n"); 312 exit(1); 313 } 314 pread_func = pread64; 315 } else { 316 if (ops->opt_bool("DAIO_USCSI_READ_FORCE_UNIT_ACCESS", &x) == 317 OPT_OK && x == 1) { 318 plog(LOG_NOTICE, "USCSI READ_UNIT_ACCESS on\n"); 319 rlun_n_tag.un.fua = 1; 320 } 321 322 if (ops->opt_bool("DAIO_USCSI_READ_DISABLE_PAGE_OUT", &x) == 323 OPT_OK && x == 1) { 324 plog(LOG_NOTICE, 325 "USCSI READ DISABLE_PAGE_OUT on\n"); 326 rlun_n_tag.un.dpo = 1; 327 } 328 329 io_timeouts(ops, "DAIO_USCSI_READ_TIMEOUT", 330 &uscsi_read_timeout); 331 } 332 333 if (ops->opt_bool("DAIO_USCSI_ALLOW_BAD_VTOC", &x) == 334 OPT_OK && x == 1) { 335 plog(LOG_NOTICE, "USCSI ALLOW_BAD_VTOC on\n"); 336 allow_bad_vtoc = 1; 337 } 338 339 opts_fini(); 340 } 341 342 static int 343 uscsi_read_capacity(int fildes, uint32_t *bs, uint64_t *mba) 344 { 345 struct uscsi_cmd ucmd; 346 union scsi_cdb cdb; 347 struct buf { 348 uint32_t mba; 349 uint32_t bs; 350 } buf; 351 352 memset(&ucmd, 0, sizeof (struct uscsi_cmd)); 353 memset(&cdb, 0, sizeof (cdb)); 354 memset(&buf, 0, sizeof (buf)); 355 356 cdb.scc_cmd = SCMD_READ_CAPACITY; 357 ucmd.uscsi_cdblen = CDB_GROUP1; 358 ucmd.uscsi_flags = USCSI_READ; 359 ucmd.uscsi_cdb = (char *)&cdb; 360 ucmd.uscsi_bufaddr = (void *)&buf; 361 ucmd.uscsi_buflen = sizeof (buf); 362 ucmd.uscsi_resid = sizeof (buf); 363 364 if (ioctl(fildes, USCSICMD, &ucmd) == -1) { 365 return (-1); 366 } 367 368 if (ucmd.uscsi_status != 0) { 369 errno = EIO; 370 return (-1); 371 } 372 *bs = CONV2INT(buf.bs); 373 *mba = CONV2INT(buf.mba); 374 375 return (ucmd.uscsi_resid); 376 } 377 378 static int 379 uscsi_open(const char *path, int oflag, mode_t mode) 380 { 381 int fd; 382 if (uscsi_read_timeout.min == 0 && uscsi_read_timeout.diff == 0) { 383 uscsi_init(); 384 } 385 386 if ((fd = daio_dev_open(path, oflag, mode)) == -1) { 387 return (-1); 388 } 389 if (fd > maxfd) { 390 struct uscsi_str *tmp; 391 392 tmp = realloc(uscsi_state, (fd+1) * sizeof (struct uscsi_str)); 393 if (tmp == NULL) { 394 daio_dev_close(fd); 395 errno = ENOMEM; 396 return (-1); 397 } 398 memset(&tmp[maxfd+1], 0, 399 (fd - maxfd) * sizeof (struct uscsi_str)); 400 uscsi_state = tmp; 401 maxfd = fd; 402 } 403 uscsi_state[fd].handle = uscsi_read_disko_vtoc(fd); 404 plog(LOG_NOTICE, "USCSI %s\n", path); 405 plog(LOG_NOTICE, "USCSI sector size %d disk size %ld\n", 406 uscsi_state[fd].v_sectorsz, uscsi_state[fd].part.p_size); 407 return (fd); 408 } 409 410 static int 411 uscsi_close(int fd) 412 { 413 if (uscsi_state[fd].handle) { 414 disko_vtoc_free(uscsi_state[fd].handle); 415 } 416 memset(&uscsi_state[fd], 0, sizeof (uscsi_state[fd])); 417 return (daio_dev_close(fd)); 418 } 419 420 static struct disko_vtoc * 421 uscsi_read_capacity_vtoc(int fd) 422 { 423 struct disko_vtoc *dv; 424 425 if ((dv = alloc_disko_vtoc(1)) == NULL) { 426 return (NULL); 427 } 428 memset(&dv->v_volume[0], 0, sizeof (dv->v_volume)); 429 memset(&dv->v_asciilabel[0], 0, sizeof (dv->v_asciilabel)); 430 431 uscsi_state[fd].part.p_start = 0; 432 dv->v_sectorsz = uscsi_state[fd].v_sectorsz; 433 dv->v_nparts = 1; 434 dv->this_part = 0; 435 dv->v_part[0] = uscsi_state[fd].part; 436 plog(LOG_NOTICE, "USCSI read_capacity: file %s", 437 daio_dev_path(fd)); 438 plog(LOG_NOTICE, "USCSI read_capacity: " 439 "Number of sectors %lld sector size %d\n", 440 uscsi_state[fd].part.p_size, uscsi_state[fd].v_sectorsz); 441 return (dv); 442 } 443 444 static void * 445 uscsi_read_disko_vtoc(int fd) 446 { 447 void *handle; 448 449 if ((handle = uscsi_state[fd].handle) != NULL) { 450 /* 451 * We are no longer in cotrol of the memory associated with 452 * the handle. It will be freed by the caller so drop our 453 * copy of it. If we were to need the vtoc from the disk 454 * again we can get it from the disk. 455 * 456 * In practice we don't. 457 */ 458 uscsi_state[fd].handle = NULL; 459 return (handle); 460 } 461 if (ignore_partitions) { 462 return (uscsi_read_capacity_vtoc(fd)); 463 } 464 465 if ((handle = read_disko_vtoc(fd)) == NULL) { 466 struct disko_vtoc *dv; 467 if (!allow_bad_vtoc) { 468 return (NULL); 469 } 470 return (uscsi_read_capacity_vtoc(fd)); 471 } 472 uscsi_state[fd].v_sectorsz = disko_vtoc_sectorsz(handle); 473 uscsi_state[fd].part = *disko_vtoc_this_partition(handle); 474 return (handle); 475 } 476 477 static ssize_t 478 uscsi_prw(int fildes, void *buf, size_t nbyte, off_t offset, int cmd) 479 { 480 struct uscsi_cmd ucmd; 481 uint64_t lba; 482 uint32_t len; 483 union scsi_cdb cdb; 484 485 if (nbyte % uscsi_state[fildes].v_sectorsz != 0 || 486 offset % uscsi_state[fildes].v_sectorsz != 0) { 487 plog(LOG_ERR, 488 "USCSI io at 0x%llx length 0x%x to file %s not aligned " 489 "with 0x%x\n", 490 offset, nbyte, daio_dev_path(fildes), 491 uscsi_state[fildes].v_sectorsz); 492 errno = EINVAL; 493 return (-1); 494 } 495 lba = offset/uscsi_state[fildes].v_sectorsz; 496 len = nbyte/uscsi_state[fildes].v_sectorsz; 497 498 if (!ignore_partitions) { 499 if (lba + len > uscsi_state[fildes].part.p_size) { 500 errno = ENXIO; 501 return (-1); 502 } 503 lba += uscsi_state[fildes].part.p_start; 504 } 505 if (len > 256) { 506 plog(LOG_ERR, 507 "USCSI io at %lld length %d (%d) to file %s to big " 508 "for bs %d\n", 509 offset, nbyte, len, daio_dev_path(fildes), 510 uscsi_state[fildes].v_sectorsz); 511 errno = EINVAL; 512 return (-1); 513 } 514 515 memset(&ucmd, 0, sizeof (struct uscsi_cmd)); 516 memset(&cdb, 0, sizeof (cdb)); 517 518 if (cmd == USCSI_READ) { 519 if (lba > MAX_GROUP2OFF) { 520 cdb.scc_cmd = SCMD_READ_G4; 521 } else { 522 cdb.scc_cmd = SCMD_READ_G1; 523 } 524 cdb.scc_lun = rlun_n_tag.data; 525 ucmd.uscsi_timeout = 526 uscsi_read_timeout.set_timeout(&uscsi_read_timeout); 527 } else { 528 if (lba > MAX_GROUP2OFF) { 529 cdb.scc_cmd = write_cmd4; 530 } else { 531 cdb.scc_cmd = write_cmd1; 532 } 533 cdb.scc_lun = wlun_n_tag.data; 534 ucmd.uscsi_timeout = 535 uscsi_write_timeout.set_timeout(&uscsi_write_timeout); 536 } 537 538 if (lba > MAX_GROUP2OFF) { 539 FORMG4LONGADDR(&cdb, lba); 540 FORMG4COUNT(&cdb, len); 541 ucmd.uscsi_cdblen = CDB_GROUP4; 542 } else { 543 uint32_t lba32 = (uint32_t)lba; 544 FORMG1ADDR(&cdb, lba32); 545 FORMG1COUNT(&cdb, len); 546 ucmd.uscsi_cdblen = CDB_GROUP1; 547 } 548 ucmd.uscsi_flags = cmd; 549 ucmd.uscsi_cdb = (char *)&cdb; 550 ucmd.uscsi_bufaddr = buf; 551 ucmd.uscsi_buflen = nbyte; 552 ucmd.uscsi_resid = nbyte; 553 554 if (ioctl(fildes, USCSICMD, &ucmd) == -1) { 555 return (-1); 556 } 557 558 if (ucmd.uscsi_status != 0) { 559 plog(LOG_ERR, 560 "USCSI io at %x length %x to file %s status %d\n", 561 offset, nbyte, daio_dev_path(fildes), 562 ucmd.uscsi_status); 563 errno = EIO; 564 return (-1); 565 } 566 567 if (ucmd.uscsi_resid) { 568 plog(LOG_ERR, "nbyte %d ucmd.uscsi_resid %d\n", 569 nbyte, ucmd.uscsi_resid); 570 } 571 errno = 0; 572 return (nbyte - ucmd.uscsi_resid); 573 } 574 575 static ssize_t 576 uscsi_pread(int fildes, void *buf, size_t nbyte, off_t offset) 577 { 578 return (uscsi_prw(fildes, buf, nbyte, offset, USCSI_READ)); 579 } 580 581 static ssize_t 582 uscsi_pwrite(int fildes, void *buf, size_t nbyte, off_t offset) 583 { 584 return (uscsi_prw(fildes, buf, nbyte, offset, USCSI_WRITE)); 585 } 586 587 static int 588 daio_uscsi_read(int fildes, uchar_t *bufp, int bufs, off_t offset, 589 daio_result_t *resultp, struct daio_id *id) 590 { 591 return (daio_async_rw(fildes, bufp, bufs, offset, resultp, id, 592 pread_func, IS_READ)); 593 } 594 static int 595 daio_uscsi_write(int fildes, uchar_t *bufp, int bufs, off_t offset, 596 daio_result_t *resultp, struct daio_id *id) 597 { 598 return (daio_async_rw(fildes, bufp, bufs, offset, resultp, id, 599 pwrite_func, IS_WRITE)); 600 } 601