1 /*- 2 * Copyright (c) 2000 Matthew Jacob 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. The name of the author may not be used to endorse or promote products 12 * derived from this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 32 #include <sys/conf.h> 33 #include <sys/errno.h> 34 #include <sys/fcntl.h> 35 #include <sys/kernel.h> 36 #include <sys/kthread.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mutex.h> 40 #include <sys/queue.h> 41 #include <sys/sx.h> 42 #include <sys/systm.h> 43 #include <sys/sysctl.h> 44 #include <sys/types.h> 45 46 #include <machine/stdarg.h> 47 48 #include <cam/cam.h> 49 #include <cam/cam_ccb.h> 50 #include <cam/cam_debug.h> 51 #include <cam/cam_periph.h> 52 #include <cam/cam_xpt_periph.h> 53 54 #include <cam/scsi/scsi_all.h> 55 #include <cam/scsi/scsi_message.h> 56 #include <cam/scsi/scsi_enc.h> 57 #include <cam/scsi/scsi_enc_internal.h> 58 59 #include <opt_ses.h> 60 61 MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers"); 62 63 /* Enclosure type independent driver */ 64 65 static d_open_t enc_open; 66 static d_close_t enc_close; 67 static d_ioctl_t enc_ioctl; 68 static periph_init_t enc_init; 69 static periph_ctor_t enc_ctor; 70 static periph_oninv_t enc_oninvalidate; 71 static periph_dtor_t enc_dtor; 72 static periph_start_t enc_start; 73 74 static void enc_async(void *, uint32_t, struct cam_path *, void *); 75 static enctyp enc_type(struct ccb_getdev *); 76 77 SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0, 78 "CAM Enclosure Services driver"); 79 80 static struct periph_driver encdriver = { 81 enc_init, "ses", 82 TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 83 }; 84 85 PERIPHDRIVER_DECLARE(enc, encdriver); 86 87 static struct cdevsw enc_cdevsw = { 88 .d_version = D_VERSION, 89 .d_open = enc_open, 90 .d_close = enc_close, 91 .d_ioctl = enc_ioctl, 92 .d_name = "ses", 93 .d_flags = D_TRACKCLOSE, 94 }; 95 96 static void 97 enc_init(void) 98 { 99 cam_status status; 100 101 /* 102 * Install a global async callback. This callback will 103 * receive async callbacks like "new device found". 104 */ 105 status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL); 106 107 if (status != CAM_REQ_CMP) { 108 printf("enc: Failed to attach master async callback " 109 "due to status 0x%x!\n", status); 110 } 111 } 112 113 static void 114 enc_devgonecb(void *arg) 115 { 116 struct cam_sim *sim; 117 struct cam_periph *periph; 118 struct enc_softc *enc; 119 int i; 120 121 periph = (struct cam_periph *)arg; 122 sim = periph->sim; 123 enc = (struct enc_softc *)periph->softc; 124 125 mtx_lock(sim->mtx); 126 127 /* 128 * When we get this callback, we will get no more close calls from 129 * devfs. So if we have any dangling opens, we need to release the 130 * reference held for that particular context. 131 */ 132 for (i = 0; i < enc->open_count; i++) 133 cam_periph_release_locked(periph); 134 135 enc->open_count = 0; 136 137 /* 138 * Release the reference held for the device node, it is gone now. 139 */ 140 cam_periph_release_locked(periph); 141 142 /* 143 * We reference the SIM lock directly here, instead of using 144 * cam_periph_unlock(). The reason is that the final call to 145 * cam_periph_release_locked() above could result in the periph 146 * getting freed. If that is the case, dereferencing the periph 147 * with a cam_periph_unlock() call would cause a page fault. 148 */ 149 mtx_unlock(sim->mtx); 150 } 151 152 static void 153 enc_oninvalidate(struct cam_periph *periph) 154 { 155 struct enc_softc *enc; 156 157 enc = periph->softc; 158 159 enc->enc_flags |= ENC_FLAG_INVALID; 160 161 /* If the sub-driver has an invalidate routine, call it */ 162 if (enc->enc_vec.softc_invalidate != NULL) 163 enc->enc_vec.softc_invalidate(enc); 164 165 /* 166 * Unregister any async callbacks. 167 */ 168 xpt_register_async(0, enc_async, periph, periph->path); 169 170 /* 171 * Shutdown our daemon. 172 */ 173 enc->enc_flags |= ENC_FLAG_SHUTDOWN; 174 if (enc->enc_daemon != NULL) { 175 /* Signal the ses daemon to terminate. */ 176 wakeup(enc->enc_daemon); 177 } 178 callout_drain(&enc->status_updater); 179 180 destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph); 181 182 xpt_print(periph->path, "lost device\n"); 183 } 184 185 static void 186 enc_dtor(struct cam_periph *periph) 187 { 188 struct enc_softc *enc; 189 190 enc = periph->softc; 191 192 xpt_print(periph->path, "removing device entry\n"); 193 194 195 /* If the sub-driver has a cleanup routine, call it */ 196 if (enc->enc_vec.softc_cleanup != NULL) 197 enc->enc_vec.softc_cleanup(enc); 198 199 if (enc->enc_boot_hold_ch.ich_func != NULL) { 200 config_intrhook_disestablish(&enc->enc_boot_hold_ch); 201 enc->enc_boot_hold_ch.ich_func = NULL; 202 } 203 204 ENC_FREE(enc); 205 } 206 207 static void 208 enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 209 { 210 struct cam_periph *periph; 211 212 periph = (struct cam_periph *)callback_arg; 213 214 switch(code) { 215 case AC_FOUND_DEVICE: 216 { 217 struct ccb_getdev *cgd; 218 cam_status status; 219 path_id_t path_id; 220 221 cgd = (struct ccb_getdev *)arg; 222 if (arg == NULL) { 223 break; 224 } 225 226 if (enc_type(cgd) == ENC_NONE) { 227 /* 228 * Schedule announcement of the ENC bindings for 229 * this device if it is managed by a SEP. 230 */ 231 path_id = xpt_path_path_id(path); 232 xpt_lock_buses(); 233 TAILQ_FOREACH(periph, &encdriver.units, unit_links) { 234 struct enc_softc *softc; 235 236 softc = (struct enc_softc *)periph->softc; 237 if (xpt_path_path_id(periph->path) != path_id 238 || softc == NULL 239 || (softc->enc_flags & ENC_FLAG_INITIALIZED) 240 == 0 241 || softc->enc_vec.device_found == NULL) 242 continue; 243 244 softc->enc_vec.device_found(softc); 245 } 246 xpt_unlock_buses(); 247 return; 248 } 249 250 status = cam_periph_alloc(enc_ctor, enc_oninvalidate, 251 enc_dtor, enc_start, "ses", CAM_PERIPH_BIO, 252 cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd); 253 254 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) { 255 printf("enc_async: Unable to probe new device due to " 256 "status 0x%x\n", status); 257 } 258 break; 259 } 260 default: 261 cam_periph_async(periph, code, path, arg); 262 break; 263 } 264 } 265 266 static int 267 enc_open(struct cdev *dev, int flags, int fmt, struct thread *td) 268 { 269 struct cam_periph *periph; 270 struct enc_softc *softc; 271 int error = 0; 272 273 periph = (struct cam_periph *)dev->si_drv1; 274 if (periph == NULL) { 275 return (ENXIO); 276 } 277 278 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 279 return (ENXIO); 280 281 cam_periph_lock(periph); 282 283 softc = (struct enc_softc *)periph->softc; 284 285 if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { 286 error = ENXIO; 287 goto out; 288 } 289 if (softc->enc_flags & ENC_FLAG_INVALID) { 290 error = ENXIO; 291 goto out; 292 } 293 out: 294 if (error != 0) 295 cam_periph_release_locked(periph); 296 else 297 softc->open_count++; 298 299 cam_periph_unlock(periph); 300 301 return (error); 302 } 303 304 static int 305 enc_close(struct cdev *dev, int flag, int fmt, struct thread *td) 306 { 307 struct cam_sim *sim; 308 struct cam_periph *periph; 309 struct enc_softc *enc; 310 311 periph = (struct cam_periph *)dev->si_drv1; 312 if (periph == NULL) 313 return (ENXIO); 314 315 sim = periph->sim; 316 enc = periph->softc; 317 318 mtx_lock(sim->mtx); 319 320 enc->open_count--; 321 322 cam_periph_release_locked(periph); 323 324 /* 325 * We reference the SIM lock directly here, instead of using 326 * cam_periph_unlock(). The reason is that the call to 327 * cam_periph_release_locked() above could result in the periph 328 * getting freed. If that is the case, dereferencing the periph 329 * with a cam_periph_unlock() call would cause a page fault. 330 * 331 * cam_periph_release() avoids this problem using the same method, 332 * but we're manually acquiring and dropping the lock here to 333 * protect the open count and avoid another lock acquisition and 334 * release. 335 */ 336 mtx_unlock(sim->mtx); 337 338 return (0); 339 } 340 341 static void 342 enc_start(struct cam_periph *p, union ccb *sccb) 343 { 344 struct enc_softc *enc; 345 346 enc = p->softc; 347 ENC_DLOG(enc, "%s enter imm=%d prio=%d\n", 348 __func__, p->immediate_priority, p->pinfo.priority); 349 if (p->immediate_priority <= p->pinfo.priority) { 350 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle); 351 p->immediate_priority = CAM_PRIORITY_NONE; 352 wakeup(&p->ccb_list); 353 } else 354 xpt_release_ccb(sccb); 355 ENC_DLOG(enc, "%s exit\n", __func__); 356 } 357 358 void 359 enc_done(struct cam_periph *periph, union ccb *dccb) 360 { 361 wakeup(&dccb->ccb_h.cbfcnp); 362 } 363 364 int 365 enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags) 366 { 367 struct enc_softc *softc; 368 struct cam_periph *periph; 369 370 periph = xpt_path_periph(ccb->ccb_h.path); 371 softc = (struct enc_softc *)periph->softc; 372 373 return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb)); 374 } 375 376 static int 377 enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, 378 struct thread *td) 379 { 380 struct cam_periph *periph; 381 encioc_enc_status_t tmp; 382 encioc_string_t sstr; 383 encioc_elm_status_t elms; 384 encioc_elm_desc_t elmd; 385 encioc_elm_devnames_t elmdn; 386 encioc_element_t *uelm; 387 enc_softc_t *enc; 388 enc_cache_t *cache; 389 void *addr; 390 int error, i; 391 392 393 if (arg_addr) 394 addr = *((caddr_t *) arg_addr); 395 else 396 addr = NULL; 397 398 periph = (struct cam_periph *)dev->si_drv1; 399 if (periph == NULL) 400 return (ENXIO); 401 402 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n")); 403 404 cam_periph_lock(periph); 405 enc = (struct enc_softc *)periph->softc; 406 cache = &enc->enc_cache; 407 408 /* 409 * Now check to see whether we're initialized or not. 410 * This actually should never fail as we're not supposed 411 * to get past enc_open w/o successfully initializing 412 * things. 413 */ 414 if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { 415 cam_periph_unlock(periph); 416 return (ENXIO); 417 } 418 cam_periph_unlock(periph); 419 420 error = 0; 421 422 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 423 ("trying to do ioctl %#lx\n", cmd)); 424 425 /* 426 * If this command can change the device's state, 427 * we must have the device open for writing. 428 * 429 * For commands that get information about the 430 * device- we don't need to lock the peripheral 431 * if we aren't running a command. The periph 432 * also can't go away while a user process has 433 * it open. 434 */ 435 switch (cmd) { 436 case ENCIOC_GETNELM: 437 case ENCIOC_GETELMMAP: 438 case ENCIOC_GETENCSTAT: 439 case ENCIOC_GETELMSTAT: 440 case ENCIOC_GETELMDESC: 441 case ENCIOC_GETELMDEVNAMES: 442 break; 443 default: 444 if ((flag & FWRITE) == 0) { 445 return (EBADF); 446 } 447 } 448 449 /* 450 * XXX The values read here are only valid for the current 451 * configuration generation. We need these ioctls 452 * to also pass in/out a generation number. 453 */ 454 sx_slock(&enc->enc_cache_lock); 455 switch (cmd) { 456 case ENCIOC_GETNELM: 457 error = copyout(&cache->nelms, addr, sizeof (cache->nelms)); 458 break; 459 460 case ENCIOC_GETELMMAP: 461 for (uelm = addr, i = 0; i != cache->nelms; i++) { 462 encioc_element_t kelm; 463 kelm.elm_idx = i; 464 kelm.elm_subenc_id = cache->elm_map[i].subenclosure; 465 kelm.elm_type = cache->elm_map[i].enctype; 466 error = copyout(&kelm, &uelm[i], sizeof(kelm)); 467 if (error) 468 break; 469 } 470 break; 471 472 case ENCIOC_GETENCSTAT: 473 cam_periph_lock(periph); 474 error = enc->enc_vec.get_enc_status(enc, 1); 475 if (error) { 476 cam_periph_unlock(periph); 477 break; 478 } 479 tmp = cache->enc_status; 480 cam_periph_unlock(periph); 481 error = copyout(&tmp, addr, sizeof(tmp)); 482 cache->enc_status = tmp; 483 break; 484 485 case ENCIOC_SETENCSTAT: 486 error = copyin(addr, &tmp, sizeof(tmp)); 487 if (error) 488 break; 489 cam_periph_lock(periph); 490 error = enc->enc_vec.set_enc_status(enc, tmp, 1); 491 cam_periph_unlock(periph); 492 break; 493 494 case ENCIOC_GETSTRING: 495 case ENCIOC_SETSTRING: 496 if (enc->enc_vec.handle_string == NULL) { 497 error = EINVAL; 498 break; 499 } 500 error = copyin(addr, &sstr, sizeof(sstr)); 501 if (error) 502 break; 503 cam_periph_lock(periph); 504 error = enc->enc_vec.handle_string(enc, &sstr, cmd); 505 cam_periph_unlock(periph); 506 break; 507 508 case ENCIOC_GETELMSTAT: 509 error = copyin(addr, &elms, sizeof(elms)); 510 if (error) 511 break; 512 if (elms.elm_idx >= cache->nelms) { 513 error = EINVAL; 514 break; 515 } 516 cam_periph_lock(periph); 517 error = enc->enc_vec.get_elm_status(enc, &elms, 1); 518 cam_periph_unlock(periph); 519 if (error) 520 break; 521 error = copyout(&elms, addr, sizeof(elms)); 522 break; 523 524 case ENCIOC_GETELMDESC: 525 error = copyin(addr, &elmd, sizeof(elmd)); 526 if (error) 527 break; 528 if (elmd.elm_idx >= cache->nelms) { 529 error = EINVAL; 530 break; 531 } 532 if (enc->enc_vec.get_elm_desc != NULL) { 533 error = enc->enc_vec.get_elm_desc(enc, &elmd); 534 if (error) 535 break; 536 } else 537 elmd.elm_desc_len = 0; 538 error = copyout(&elmd, addr, sizeof(elmd)); 539 break; 540 541 case ENCIOC_GETELMDEVNAMES: 542 if (enc->enc_vec.get_elm_devnames == NULL) { 543 error = EINVAL; 544 break; 545 } 546 error = copyin(addr, &elmdn, sizeof(elmdn)); 547 if (error) 548 break; 549 if (elmdn.elm_idx >= cache->nelms) { 550 error = EINVAL; 551 break; 552 } 553 cam_periph_lock(periph); 554 error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn); 555 cam_periph_unlock(periph); 556 if (error) 557 break; 558 error = copyout(&elmdn, addr, sizeof(elmdn)); 559 break; 560 561 case ENCIOC_SETELMSTAT: 562 error = copyin(addr, &elms, sizeof(elms)); 563 if (error) 564 break; 565 566 if (elms.elm_idx >= cache->nelms) { 567 error = EINVAL; 568 break; 569 } 570 cam_periph_lock(periph); 571 error = enc->enc_vec.set_elm_status(enc, &elms, 1); 572 cam_periph_unlock(periph); 573 574 break; 575 576 case ENCIOC_INIT: 577 578 cam_periph_lock(periph); 579 error = enc->enc_vec.init_enc(enc); 580 cam_periph_unlock(periph); 581 break; 582 583 default: 584 cam_periph_lock(periph); 585 error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error); 586 cam_periph_unlock(periph); 587 break; 588 } 589 sx_sunlock(&enc->enc_cache_lock); 590 return (error); 591 } 592 593 int 594 enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp) 595 { 596 int error, dlen, tdlen; 597 ccb_flags ddf; 598 union ccb *ccb; 599 600 CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE, 601 ("entering enc_runcmd\n")); 602 if (dptr) { 603 if ((dlen = *dlenp) < 0) { 604 dlen = -dlen; 605 ddf = CAM_DIR_OUT; 606 } else { 607 ddf = CAM_DIR_IN; 608 } 609 } else { 610 dlen = 0; 611 ddf = CAM_DIR_NONE; 612 } 613 614 if (cdbl > IOCDBLEN) { 615 cdbl = IOCDBLEN; 616 } 617 618 ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL); 619 if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) { 620 tdlen = min(dlen, 1020); 621 tdlen = (tdlen + 3) & ~3; 622 cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen, 623 30 * 1000); 624 if (cdb[0] == RECEIVE_DIAGNOSTIC) 625 ata_28bit_cmd(&ccb->ataio, 626 ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4); 627 else if (cdb[0] == SEND_DIAGNOSTIC) 628 ata_28bit_cmd(&ccb->ataio, 629 ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, 630 0x82, tdlen / 4); 631 else if (cdb[0] == READ_BUFFER) 632 ata_28bit_cmd(&ccb->ataio, 633 ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4); 634 else 635 ata_28bit_cmd(&ccb->ataio, 636 ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, 637 0x80, tdlen / 4); 638 } else { 639 tdlen = dlen; 640 cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG, 641 dptr, dlen, sizeof (struct scsi_sense_data), cdbl, 642 60 * 1000); 643 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl); 644 } 645 646 error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL); 647 if (error) { 648 if (dptr) { 649 *dlenp = dlen; 650 } 651 } else { 652 if (dptr) { 653 if (ccb->ccb_h.func_code == XPT_ATA_IO) 654 *dlenp = ccb->ataio.resid; 655 else 656 *dlenp = ccb->csio.resid; 657 *dlenp += tdlen - dlen; 658 } 659 } 660 xpt_release_ccb(ccb); 661 CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE, 662 ("exiting enc_runcmd: *dlenp = %d\n", *dlenp)); 663 return (error); 664 } 665 666 void 667 enc_log(struct enc_softc *enc, const char *fmt, ...) 668 { 669 va_list ap; 670 671 printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number); 672 va_start(ap, fmt); 673 vprintf(fmt, ap); 674 va_end(ap); 675 } 676 677 /* 678 * The code after this point runs on many platforms, 679 * so forgive the slightly awkward and nonconforming 680 * appearance. 681 */ 682 683 /* 684 * Is this a device that supports enclosure services? 685 * 686 * It's a pretty simple ruleset- if it is device type 687 * 0x0D (13), it's an ENCLOSURE device. 688 */ 689 690 #define SAFTE_START 44 691 #define SAFTE_END 50 692 #define SAFTE_LEN SAFTE_END-SAFTE_START 693 694 static enctyp 695 enc_type(struct ccb_getdev *cgd) 696 { 697 int buflen; 698 unsigned char *iqd; 699 700 if (cgd->protocol == PROTO_SEMB) { 701 iqd = (unsigned char *)&cgd->ident_data; 702 if (STRNCMP(iqd + 43, "S-E-S", 5) == 0) 703 return (ENC_SEMB_SES); 704 else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0) 705 return (ENC_SEMB_SAFT); 706 return (ENC_NONE); 707 708 } else if (cgd->protocol != PROTO_SCSI) 709 return (ENC_NONE); 710 711 iqd = (unsigned char *)&cgd->inq_data; 712 buflen = min(sizeof(cgd->inq_data), 713 SID_ADDITIONAL_LENGTH(&cgd->inq_data)); 714 715 if ((iqd[0] & 0x1f) == T_ENCLOSURE) { 716 if ((iqd[2] & 0x7) > 2) { 717 return (ENC_SES); 718 } else { 719 return (ENC_SES_SCSI2); 720 } 721 return (ENC_NONE); 722 } 723 724 #ifdef SES_ENABLE_PASSTHROUGH 725 if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) { 726 /* 727 * PassThrough Device. 728 */ 729 return (ENC_SES_PASSTHROUGH); 730 } 731 #endif 732 733 /* 734 * The comparison is short for a reason- 735 * some vendors were chopping it short. 736 */ 737 738 if (buflen < SAFTE_END - 2) { 739 return (ENC_NONE); 740 } 741 742 if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) { 743 return (ENC_SAFT); 744 } 745 return (ENC_NONE); 746 } 747 748 /*================== Enclosure Monitoring/Processing Daemon ==================*/ 749 /** 750 * \brief Queue an update request for a given action, if needed. 751 * 752 * \param enc SES softc to queue the request for. 753 * \param action Action requested. 754 */ 755 void 756 enc_update_request(enc_softc_t *enc, uint32_t action) 757 { 758 if ((enc->pending_actions & (0x1 << action)) == 0) { 759 enc->pending_actions |= (0x1 << action); 760 ENC_DLOG(enc, "%s: queing requested action %d\n", 761 __func__, action); 762 if (enc->current_action == ENC_UPDATE_NONE) 763 wakeup(enc->enc_daemon); 764 } else { 765 ENC_DLOG(enc, "%s: ignoring requested action %d - " 766 "Already queued\n", __func__, action); 767 } 768 } 769 770 /** 771 * \brief Invoke the handler of the highest priority pending 772 * state in the SES state machine. 773 * 774 * \param enc The SES instance invoking the state machine. 775 */ 776 static void 777 enc_fsm_step(enc_softc_t *enc) 778 { 779 union ccb *ccb; 780 uint8_t *buf; 781 struct enc_fsm_state *cur_state; 782 int error; 783 uint32_t xfer_len; 784 785 ENC_DLOG(enc, "%s enter %p\n", __func__, enc); 786 787 enc->current_action = ffs(enc->pending_actions) - 1; 788 enc->pending_actions &= ~(0x1 << enc->current_action); 789 790 cur_state = &enc->enc_fsm_states[enc->current_action]; 791 792 buf = NULL; 793 if (cur_state->buf_size != 0) { 794 cam_periph_unlock(enc->periph); 795 buf = malloc(cur_state->buf_size, M_SCSIENC, M_WAITOK|M_ZERO); 796 cam_periph_lock(enc->periph); 797 } 798 799 error = 0; 800 ccb = NULL; 801 if (cur_state->fill != NULL) { 802 ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL); 803 804 error = cur_state->fill(enc, cur_state, ccb, buf); 805 if (error != 0) 806 goto done; 807 808 error = cam_periph_runccb(ccb, cur_state->error, 809 ENC_CFLAGS, 810 ENC_FLAGS|SF_QUIET_IR, NULL); 811 } 812 813 if (ccb != NULL) { 814 if (ccb->ccb_h.func_code == XPT_ATA_IO) 815 xfer_len = ccb->ataio.dxfer_len - ccb->ataio.resid; 816 else 817 xfer_len = ccb->csio.dxfer_len - ccb->csio.resid; 818 } else 819 xfer_len = 0; 820 821 cam_periph_unlock(enc->periph); 822 cur_state->done(enc, cur_state, ccb, &buf, error, xfer_len); 823 cam_periph_lock(enc->periph); 824 825 done: 826 ENC_DLOG(enc, "%s exit - result %d\n", __func__, error); 827 ENC_FREE_AND_NULL(buf); 828 if (ccb != NULL) 829 xpt_release_ccb(ccb); 830 } 831 832 /** 833 * \invariant Called with cam_periph mutex held. 834 */ 835 static void 836 enc_status_updater(void *arg) 837 { 838 enc_softc_t *enc; 839 840 enc = arg; 841 if (enc->enc_vec.poll_status != NULL) 842 enc->enc_vec.poll_status(enc); 843 } 844 845 static void 846 enc_daemon(void *arg) 847 { 848 enc_softc_t *enc; 849 850 enc = arg; 851 852 cam_periph_lock(enc->periph); 853 while ((enc->enc_flags & ENC_FLAG_SHUTDOWN) == 0) { 854 if (enc->pending_actions == 0) { 855 struct intr_config_hook *hook; 856 857 /* 858 * Reset callout and msleep, or 859 * issue timed task completion 860 * status command. 861 */ 862 enc->current_action = ENC_UPDATE_NONE; 863 864 /* 865 * We've been through our state machine at least 866 * once. Allow the transition to userland. 867 */ 868 hook = &enc->enc_boot_hold_ch; 869 if (hook->ich_func != NULL) { 870 config_intrhook_disestablish(hook); 871 hook->ich_func = NULL; 872 } 873 874 callout_reset(&enc->status_updater, 60*hz, 875 enc_status_updater, enc); 876 877 cam_periph_sleep(enc->periph, enc->enc_daemon, 878 PUSER, "idle", 0); 879 } else { 880 enc_fsm_step(enc); 881 } 882 } 883 enc->enc_daemon = NULL; 884 cam_periph_unlock(enc->periph); 885 cam_periph_release(enc->periph); 886 kproc_exit(0); 887 } 888 889 static int 890 enc_kproc_init(enc_softc_t *enc) 891 { 892 int result; 893 894 callout_init_mtx(&enc->status_updater, enc->periph->sim->mtx, 0); 895 896 if (cam_periph_acquire(enc->periph) != CAM_REQ_CMP) 897 return (ENXIO); 898 899 result = kproc_create(enc_daemon, enc, &enc->enc_daemon, /*flags*/0, 900 /*stackpgs*/0, "enc_daemon%d", 901 enc->periph->unit_number); 902 if (result == 0) { 903 /* Do an initial load of all page data. */ 904 cam_periph_lock(enc->periph); 905 enc->enc_vec.poll_status(enc); 906 cam_periph_unlock(enc->periph); 907 } else 908 cam_periph_release(enc->periph); 909 return (result); 910 } 911 912 /** 913 * \brief Interrupt configuration hook callback associated with 914 * enc_boot_hold_ch. 915 * 916 * Since interrupts are always functional at the time of enclosure 917 * configuration, there is nothing to be done when the callback occurs. 918 * This hook is only registered to hold up boot processing while initial 919 * eclosure processing occurs. 920 * 921 * \param arg The enclosure softc, but currently unused in this callback. 922 */ 923 static void 924 enc_nop_confighook_cb(void *arg __unused) 925 { 926 } 927 928 static cam_status 929 enc_ctor(struct cam_periph *periph, void *arg) 930 { 931 cam_status status = CAM_REQ_CMP_ERR; 932 int err; 933 enc_softc_t *enc; 934 struct ccb_getdev *cgd; 935 char *tname; 936 937 cgd = (struct ccb_getdev *)arg; 938 if (cgd == NULL) { 939 printf("enc_ctor: no getdev CCB, can't register device\n"); 940 goto out; 941 } 942 943 enc = ENC_MALLOCZ(sizeof(*enc)); 944 if (enc == NULL) { 945 printf("enc_ctor: Unable to probe new device. " 946 "Unable to allocate enc\n"); 947 goto out; 948 } 949 enc->periph = periph; 950 enc->current_action = ENC_UPDATE_INVALID; 951 952 enc->enc_type = enc_type(cgd); 953 sx_init(&enc->enc_cache_lock, "enccache"); 954 955 switch (enc->enc_type) { 956 case ENC_SES: 957 case ENC_SES_SCSI2: 958 case ENC_SES_PASSTHROUGH: 959 case ENC_SEMB_SES: 960 err = ses_softc_init(enc); 961 break; 962 case ENC_SAFT: 963 case ENC_SEMB_SAFT: 964 err = safte_softc_init(enc); 965 break; 966 case ENC_NONE: 967 default: 968 ENC_FREE(enc); 969 return (CAM_REQ_CMP_ERR); 970 } 971 972 if (err) { 973 xpt_print(periph->path, "error %d initializing\n", err); 974 goto out; 975 } 976 977 /* 978 * Hold off userland until we have made at least one pass 979 * through our state machine so that physical path data is 980 * present. 981 */ 982 if (enc->enc_vec.poll_status != NULL) { 983 enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb; 984 enc->enc_boot_hold_ch.ich_arg = enc; 985 config_intrhook_establish(&enc->enc_boot_hold_ch); 986 } 987 988 /* 989 * The softc field is set only once the enc is fully initialized 990 * so that we can rely on this field to detect partially 991 * initialized periph objects in the AC_FOUND_DEVICE handler. 992 */ 993 periph->softc = enc; 994 995 cam_periph_unlock(periph); 996 if (enc->enc_vec.poll_status != NULL) { 997 err = enc_kproc_init(enc); 998 if (err) { 999 xpt_print(periph->path, 1000 "error %d starting enc_daemon\n", err); 1001 goto out; 1002 } 1003 } 1004 1005 /* 1006 * Acquire a reference to the periph before we create the devfs 1007 * instance for it. We'll release this reference once the devfs 1008 * instance has been freed. 1009 */ 1010 if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 1011 xpt_print(periph->path, "%s: lost periph during " 1012 "registration!\n", __func__); 1013 cam_periph_lock(periph); 1014 1015 return (CAM_REQ_CMP_ERR); 1016 } 1017 1018 enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number, 1019 UID_ROOT, GID_OPERATOR, 0600, "%s%d", 1020 periph->periph_name, periph->unit_number); 1021 1022 cam_periph_lock(periph); 1023 enc->enc_dev->si_drv1 = periph; 1024 1025 enc->enc_flags |= ENC_FLAG_INITIALIZED; 1026 1027 /* 1028 * Add an async callback so that we get notified if this 1029 * device goes away. 1030 */ 1031 xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path); 1032 1033 switch (enc->enc_type) { 1034 default: 1035 case ENC_NONE: 1036 tname = "No ENC device"; 1037 break; 1038 case ENC_SES_SCSI2: 1039 tname = "SCSI-2 ENC Device"; 1040 break; 1041 case ENC_SES: 1042 tname = "SCSI-3 ENC Device"; 1043 break; 1044 case ENC_SES_PASSTHROUGH: 1045 tname = "ENC Passthrough Device"; 1046 break; 1047 case ENC_SAFT: 1048 tname = "SAF-TE Compliant Device"; 1049 break; 1050 case ENC_SEMB_SES: 1051 tname = "SEMB SES Device"; 1052 break; 1053 case ENC_SEMB_SAFT: 1054 tname = "SEMB SAF-TE Device"; 1055 break; 1056 } 1057 xpt_announce_periph(periph, tname); 1058 status = CAM_REQ_CMP; 1059 1060 out: 1061 if (status != CAM_REQ_CMP) 1062 enc_dtor(periph); 1063 return (status); 1064 } 1065 1066