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