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_enc.h> 60 61 MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers"); 62 63 /* Enclosure type independent driver */ 64 65 #define SEN_ID "UNISYS SUN_SEN" 66 #define SEN_ID_LEN 24 67 68 static d_open_t enc_open; 69 static d_close_t enc_close; 70 static d_ioctl_t enc_ioctl; 71 static periph_init_t enc_init; 72 static periph_ctor_t enc_ctor; 73 static periph_oninv_t enc_oninvalidate; 74 static periph_dtor_t enc_dtor; 75 static periph_start_t enc_start; 76 77 static void enc_async(void *, uint32_t, struct cam_path *, void *); 78 static enctyp enc_type(struct ccb_getdev *); 79 80 SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0, 81 "CAM Enclosure Services driver"); 82 83 static struct periph_driver encdriver = { 84 enc_init, "ses", 85 TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0 86 }; 87 88 PERIPHDRIVER_DECLARE(enc, encdriver); 89 90 static struct cdevsw enc_cdevsw = { 91 .d_version = D_VERSION, 92 .d_open = enc_open, 93 .d_close = enc_close, 94 .d_ioctl = enc_ioctl, 95 .d_name = "ses", 96 .d_flags = D_TRACKCLOSE, 97 }; 98 99 static void 100 enc_init(void) 101 { 102 cam_status status; 103 104 /* 105 * Install a global async callback. This callback will 106 * receive async callbacks like "new device found". 107 */ 108 status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL); 109 110 if (status != CAM_REQ_CMP) { 111 printf("enc: Failed to attach master async callback " 112 "due to status 0x%x!\n", status); 113 } 114 } 115 116 static void 117 enc_oninvalidate(struct cam_periph *periph) 118 { 119 struct enc_softc *enc; 120 121 enc = periph->softc; 122 123 enc->enc_flags |= ENC_FLAG_INVALID; 124 125 /* If the sub-driver has an invalidate routine, call it */ 126 if (enc->enc_vec.softc_invalidate != NULL) 127 enc->enc_vec.softc_invalidate(enc); 128 129 /* 130 * Unregister any async callbacks. 131 */ 132 xpt_register_async(0, enc_async, periph, periph->path); 133 134 /* 135 * Shutdown our daemon. 136 */ 137 enc->enc_flags |= ENC_FLAG_SHUTDOWN; 138 if (enc->enc_daemon != NULL) { 139 /* Signal the ses daemon to terminate. */ 140 wakeup(enc->enc_daemon); 141 } 142 callout_drain(&enc->status_updater); 143 144 xpt_print(periph->path, "lost device\n"); 145 } 146 147 static void 148 enc_dtor(struct cam_periph *periph) 149 { 150 struct enc_softc *enc; 151 152 enc = periph->softc; 153 154 xpt_print(periph->path, "removing device entry\n"); 155 cam_periph_unlock(periph); 156 destroy_dev(enc->enc_dev); 157 cam_periph_lock(periph); 158 159 /* If the sub-driver has a cleanup routine, call it */ 160 if (enc->enc_vec.softc_cleanup != NULL) 161 enc->enc_vec.softc_cleanup(enc); 162 163 if (enc->enc_boot_hold_ch.ich_func != NULL) { 164 config_intrhook_disestablish(&enc->enc_boot_hold_ch); 165 enc->enc_boot_hold_ch.ich_func = NULL; 166 } 167 168 ENC_FREE(enc); 169 } 170 171 static void 172 enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg) 173 { 174 struct cam_periph *periph; 175 176 periph = (struct cam_periph *)callback_arg; 177 178 switch(code) { 179 case AC_FOUND_DEVICE: 180 { 181 struct ccb_getdev *cgd; 182 cam_status status; 183 path_id_t path_id; 184 185 cgd = (struct ccb_getdev *)arg; 186 if (arg == NULL) { 187 break; 188 } 189 190 if (enc_type(cgd) == ENC_NONE) { 191 /* 192 * Schedule announcement of the ENC bindings for 193 * this device if it is managed by a SEP. 194 */ 195 path_id = xpt_path_path_id(path); 196 xpt_lock_buses(); 197 TAILQ_FOREACH(periph, &encdriver.units, unit_links) { 198 struct enc_softc *softc; 199 200 softc = (struct enc_softc *)periph->softc; 201 if (xpt_path_path_id(periph->path) != path_id 202 || softc == NULL 203 || (softc->enc_flags & ENC_FLAG_INITIALIZED) 204 == 0 205 || softc->enc_vec.device_found == NULL) 206 continue; 207 208 softc->enc_vec.device_found(softc); 209 } 210 xpt_unlock_buses(); 211 return; 212 } 213 214 status = cam_periph_alloc(enc_ctor, enc_oninvalidate, 215 enc_dtor, enc_start, "ses", CAM_PERIPH_BIO, 216 cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd); 217 218 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) { 219 printf("enc_async: Unable to probe new device due to " 220 "status 0x%x\n", status); 221 } 222 break; 223 } 224 default: 225 cam_periph_async(periph, code, path, arg); 226 break; 227 } 228 } 229 230 static int 231 enc_open(struct cdev *dev, int flags, int fmt, struct thread *td) 232 { 233 struct cam_periph *periph; 234 struct enc_softc *softc; 235 int error = 0; 236 237 periph = (struct cam_periph *)dev->si_drv1; 238 if (periph == NULL) { 239 return (ENXIO); 240 } 241 242 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 243 return (ENXIO); 244 245 cam_periph_lock(periph); 246 247 softc = (struct enc_softc *)periph->softc; 248 249 if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { 250 error = ENXIO; 251 goto out; 252 } 253 if (softc->enc_flags & ENC_FLAG_INVALID) { 254 error = ENXIO; 255 goto out; 256 } 257 out: 258 if (error != 0) 259 cam_periph_release_locked(periph); 260 261 cam_periph_unlock(periph); 262 263 return (error); 264 } 265 266 static int 267 enc_close(struct cdev *dev, int flag, int fmt, struct thread *td) 268 { 269 struct cam_periph *periph; 270 271 periph = (struct cam_periph *)dev->si_drv1; 272 if (periph == NULL) 273 return (ENXIO); 274 275 cam_periph_release(periph); 276 277 return (0); 278 } 279 280 static void 281 enc_start(struct cam_periph *p, union ccb *sccb) 282 { 283 struct enc_softc *enc; 284 285 enc = p->softc; 286 ENC_DLOG(enc, "%s enter imm=%d prio=%d\n", 287 __func__, p->immediate_priority, p->pinfo.priority); 288 if (p->immediate_priority <= p->pinfo.priority) { 289 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle); 290 p->immediate_priority = CAM_PRIORITY_NONE; 291 wakeup(&p->ccb_list); 292 } else 293 xpt_release_ccb(sccb); 294 ENC_DLOG(enc, "%s exit\n", __func__); 295 } 296 297 void 298 enc_done(struct cam_periph *periph, union ccb *dccb) 299 { 300 wakeup(&dccb->ccb_h.cbfcnp); 301 } 302 303 int 304 enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags) 305 { 306 struct enc_softc *softc; 307 struct cam_periph *periph; 308 309 periph = xpt_path_periph(ccb->ccb_h.path); 310 softc = (struct enc_softc *)periph->softc; 311 312 return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb)); 313 } 314 315 static int 316 enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag, 317 struct thread *td) 318 { 319 struct cam_periph *periph; 320 encioc_enc_status_t tmp; 321 encioc_string_t sstr; 322 encioc_elm_status_t elms; 323 encioc_elm_desc_t elmd; 324 encioc_elm_devnames_t elmdn; 325 encioc_element_t *uelm; 326 enc_softc_t *enc; 327 enc_cache_t *cache; 328 void *addr; 329 int error, i; 330 331 332 if (arg_addr) 333 addr = *((caddr_t *) arg_addr); 334 else 335 addr = NULL; 336 337 periph = (struct cam_periph *)dev->si_drv1; 338 if (periph == NULL) 339 return (ENXIO); 340 341 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n")); 342 343 cam_periph_lock(periph); 344 enc = (struct enc_softc *)periph->softc; 345 cache = &enc->enc_cache; 346 347 /* 348 * Now check to see whether we're initialized or not. 349 * This actually should never fail as we're not supposed 350 * to get past enc_open w/o successfully initializing 351 * things. 352 */ 353 if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) { 354 cam_periph_unlock(periph); 355 return (ENXIO); 356 } 357 cam_periph_unlock(periph); 358 359 error = 0; 360 361 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 362 ("trying to do ioctl %#lx\n", cmd)); 363 364 /* 365 * If this command can change the device's state, 366 * we must have the device open for writing. 367 * 368 * For commands that get information about the 369 * device- we don't need to lock the peripheral 370 * if we aren't running a command. The periph 371 * also can't go away while a user process has 372 * it open. 373 */ 374 switch (cmd) { 375 case ENCIOC_GETNELM: 376 case ENCIOC_GETELMMAP: 377 case ENCIOC_GETENCSTAT: 378 case ENCIOC_GETELMSTAT: 379 case ENCIOC_GETELMDESC: 380 case ENCIOC_GETELMDEVNAMES: 381 break; 382 default: 383 if ((flag & FWRITE) == 0) { 384 return (EBADF); 385 } 386 } 387 388 /* 389 * XXX The values read here are only valid for the current 390 * configuration generation. We need these ioctls 391 * to also pass in/out a generation number. 392 */ 393 sx_slock(&enc->enc_cache_lock); 394 switch (cmd) { 395 case ENCIOC_GETNELM: 396 error = copyout(&cache->nelms, addr, sizeof (cache->nelms)); 397 break; 398 399 case ENCIOC_GETELMMAP: 400 for (uelm = addr, i = 0; i != cache->nelms; i++) { 401 encioc_element_t kelm; 402 kelm.elm_idx = i; 403 kelm.elm_subenc_id = cache->elm_map[i].subenclosure; 404 kelm.elm_type = cache->elm_map[i].enctype; 405 error = copyout(&kelm, &uelm[i], sizeof(kelm)); 406 if (error) 407 break; 408 } 409 break; 410 411 case ENCIOC_GETENCSTAT: 412 cam_periph_lock(periph); 413 error = enc->enc_vec.get_enc_status(enc, 1); 414 if (error) { 415 cam_periph_unlock(periph); 416 break; 417 } 418 tmp = cache->enc_status; 419 cam_periph_unlock(periph); 420 error = copyout(&tmp, addr, sizeof(tmp)); 421 cache->enc_status = tmp; 422 break; 423 424 case ENCIOC_SETENCSTAT: 425 error = copyin(addr, &tmp, sizeof(tmp)); 426 if (error) 427 break; 428 cam_periph_lock(periph); 429 error = enc->enc_vec.set_enc_status(enc, tmp, 1); 430 cam_periph_unlock(periph); 431 break; 432 433 case ENCIOC_GETSTRING: 434 case ENCIOC_SETSTRING: 435 if (enc->enc_vec.handle_string == NULL) { 436 error = EINVAL; 437 break; 438 } 439 error = copyin(addr, &sstr, sizeof(sstr)); 440 if (error) 441 break; 442 cam_periph_lock(periph); 443 error = enc->enc_vec.handle_string(enc, &sstr, cmd); 444 cam_periph_unlock(periph); 445 break; 446 447 case ENCIOC_GETELMSTAT: 448 error = copyin(addr, &elms, sizeof(elms)); 449 if (error) 450 break; 451 if (elms.elm_idx >= cache->nelms) { 452 error = EINVAL; 453 break; 454 } 455 cam_periph_lock(periph); 456 error = enc->enc_vec.get_elm_status(enc, &elms, 1); 457 cam_periph_unlock(periph); 458 if (error) 459 break; 460 error = copyout(&elms, addr, sizeof(elms)); 461 break; 462 463 case ENCIOC_GETELMDESC: 464 error = copyin(addr, &elmd, sizeof(elmd)); 465 if (error) 466 break; 467 if (elmd.elm_idx >= cache->nelms) { 468 error = EINVAL; 469 break; 470 } 471 if (enc->enc_vec.get_elm_desc != NULL) { 472 error = enc->enc_vec.get_elm_desc(enc, &elmd); 473 if (error) 474 break; 475 } else 476 elmd.elm_desc_len = 0; 477 error = copyout(&elmd, addr, sizeof(elmd)); 478 break; 479 480 case ENCIOC_GETELMDEVNAMES: 481 if (enc->enc_vec.get_elm_devnames == NULL) { 482 error = EINVAL; 483 break; 484 } 485 error = copyin(addr, &elmdn, sizeof(elmdn)); 486 if (error) 487 break; 488 if (elmdn.elm_idx >= cache->nelms) { 489 error = EINVAL; 490 break; 491 } 492 cam_periph_lock(periph); 493 error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn); 494 cam_periph_unlock(periph); 495 if (error) 496 break; 497 error = copyout(&elmdn, addr, sizeof(elmdn)); 498 break; 499 500 case ENCIOC_SETELMSTAT: 501 error = copyin(addr, &elms, sizeof(elms)); 502 if (error) 503 break; 504 505 if (elms.elm_idx >= cache->nelms) { 506 error = EINVAL; 507 break; 508 } 509 cam_periph_lock(periph); 510 error = enc->enc_vec.set_elm_status(enc, &elms, 1); 511 cam_periph_unlock(periph); 512 513 break; 514 515 case ENCIOC_INIT: 516 517 cam_periph_lock(periph); 518 error = enc->enc_vec.init_enc(enc); 519 cam_periph_unlock(periph); 520 break; 521 522 default: 523 cam_periph_lock(periph); 524 error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error); 525 cam_periph_unlock(periph); 526 break; 527 } 528 sx_sunlock(&enc->enc_cache_lock); 529 return (error); 530 } 531 532 int 533 enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp) 534 { 535 int error, dlen, tdlen; 536 ccb_flags ddf; 537 union ccb *ccb; 538 539 CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE, 540 ("entering enc_runcmd\n")); 541 if (dptr) { 542 if ((dlen = *dlenp) < 0) { 543 dlen = -dlen; 544 ddf = CAM_DIR_OUT; 545 } else { 546 ddf = CAM_DIR_IN; 547 } 548 } else { 549 dlen = 0; 550 ddf = CAM_DIR_NONE; 551 } 552 553 if (cdbl > IOCDBLEN) { 554 cdbl = IOCDBLEN; 555 } 556 557 ccb = cam_periph_getccb(enc->periph, 1); 558 if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) { 559 tdlen = min(dlen, 1020); 560 tdlen = (tdlen + 3) & ~3; 561 cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen, 562 30 * 1000); 563 if (cdb[0] == RECEIVE_DIAGNOSTIC) 564 ata_28bit_cmd(&ccb->ataio, 565 ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4); 566 else if (cdb[0] == SEND_DIAGNOSTIC) 567 ata_28bit_cmd(&ccb->ataio, 568 ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, 569 0x82, tdlen / 4); 570 else if (cdb[0] == READ_BUFFER) 571 ata_28bit_cmd(&ccb->ataio, 572 ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4); 573 else 574 ata_28bit_cmd(&ccb->ataio, 575 ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0, 576 0x80, tdlen / 4); 577 } else { 578 tdlen = dlen; 579 cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG, 580 dptr, dlen, sizeof (struct scsi_sense_data), cdbl, 581 60 * 1000); 582 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl); 583 } 584 585 error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL); 586 if (error) { 587 if (dptr) { 588 *dlenp = dlen; 589 } 590 } else { 591 if (dptr) { 592 if (ccb->ccb_h.func_code == XPT_ATA_IO) 593 *dlenp = ccb->ataio.resid; 594 else 595 *dlenp = ccb->csio.resid; 596 *dlenp += tdlen - dlen; 597 } 598 } 599 xpt_release_ccb(ccb); 600 CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE, 601 ("exiting enc_runcmd: *dlenp = %d\n", *dlenp)); 602 return (error); 603 } 604 605 void 606 enc_log(struct enc_softc *enc, const char *fmt, ...) 607 { 608 va_list ap; 609 610 printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number); 611 va_start(ap, fmt); 612 vprintf(fmt, ap); 613 va_end(ap); 614 } 615 616 /* 617 * The code after this point runs on many platforms, 618 * so forgive the slightly awkward and nonconforming 619 * appearance. 620 */ 621 622 /* 623 * Is this a device that supports enclosure services? 624 * 625 * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's 626 * an ENC device. If it happens to be an old UNISYS SEN device, we can 627 * handle that too. 628 */ 629 630 #define SAFTE_START 44 631 #define SAFTE_END 50 632 #define SAFTE_LEN SAFTE_END-SAFTE_START 633 634 static enctyp 635 enc_type(struct ccb_getdev *cgd) 636 { 637 int buflen; 638 unsigned char *iqd; 639 640 if (cgd->protocol == PROTO_SEMB) { 641 iqd = (unsigned char *)&cgd->ident_data; 642 if (STRNCMP(iqd + 43, "S-E-S", 5) == 0) 643 return (ENC_SEMB_SES); 644 else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0) 645 return (ENC_SEMB_SAFT); 646 return (ENC_NONE); 647 648 } else if (cgd->protocol != PROTO_SCSI) 649 return (ENC_NONE); 650 651 iqd = (unsigned char *)&cgd->inq_data; 652 buflen = min(sizeof(cgd->inq_data), 653 SID_ADDITIONAL_LENGTH(&cgd->inq_data)); 654 if (buflen < 8+SEN_ID_LEN) 655 return (ENC_NONE); 656 657 if ((iqd[0] & 0x1f) == T_ENCLOSURE) { 658 if (STRNCMP(&iqd[8], SEN_ID, SEN_ID_LEN) == 0) { 659 return (ENC_SEN); 660 } else 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 (periph == NULL) { 883 printf("enc_ctor: periph was NULL!!\n"); 884 goto out; 885 } 886 887 if (cgd == NULL) { 888 printf("enc_ctor: no getdev CCB, can't register device\n"); 889 goto out; 890 } 891 892 enc = ENC_MALLOCZ(sizeof(*enc)); 893 if (enc == NULL) { 894 printf("enc_ctor: Unable to probe new device. " 895 "Unable to allocate enc\n"); 896 goto out; 897 } 898 enc->periph = periph; 899 enc->current_action = ENC_UPDATE_INVALID; 900 901 enc->enc_type = enc_type(cgd); 902 sx_init(&enc->enc_cache_lock, "enccache"); 903 904 switch (enc->enc_type) { 905 case ENC_SES: 906 case ENC_SES_SCSI2: 907 case ENC_SES_PASSTHROUGH: 908 case ENC_SEMB_SES: 909 err = ses_softc_init(enc); 910 break; 911 case ENC_SAFT: 912 case ENC_SEMB_SAFT: 913 err = safte_softc_init(enc); 914 break; 915 case ENC_SEN: 916 case ENC_NONE: 917 default: 918 ENC_FREE(enc); 919 return (CAM_REQ_CMP_ERR); 920 } 921 922 if (err) { 923 xpt_print(periph->path, "error %d initializing\n", err); 924 goto out; 925 } 926 927 /* 928 * Hold off userland until we have made at least one pass 929 * through our state machine so that physical path data is 930 * present. 931 */ 932 if (enc->enc_vec.poll_status != NULL) { 933 enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb; 934 enc->enc_boot_hold_ch.ich_arg = enc; 935 config_intrhook_establish(&enc->enc_boot_hold_ch); 936 } 937 938 /* 939 * The softc field is set only once the enc is fully initialized 940 * so that we can rely on this field to detect partially 941 * initialized periph objects in the AC_FOUND_DEVICE handler. 942 */ 943 periph->softc = enc; 944 945 cam_periph_unlock(periph); 946 if (enc->enc_vec.poll_status != NULL) { 947 err = enc_kproc_init(enc); 948 if (err) { 949 xpt_print(periph->path, 950 "error %d starting enc_daemon\n", err); 951 goto out; 952 } 953 } 954 enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number, 955 UID_ROOT, GID_OPERATOR, 0600, "%s%d", 956 periph->periph_name, periph->unit_number); 957 cam_periph_lock(periph); 958 enc->enc_dev->si_drv1 = periph; 959 960 enc->enc_flags |= ENC_FLAG_INITIALIZED; 961 962 /* 963 * Add an async callback so that we get notified if this 964 * device goes away. 965 */ 966 xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path); 967 968 switch (enc->enc_type) { 969 default: 970 case ENC_NONE: 971 tname = "No ENC device"; 972 break; 973 case ENC_SES_SCSI2: 974 tname = "SCSI-2 ENC Device"; 975 break; 976 case ENC_SES: 977 tname = "SCSI-3 ENC Device"; 978 break; 979 case ENC_SES_PASSTHROUGH: 980 tname = "ENC Passthrough Device"; 981 break; 982 case ENC_SEN: 983 tname = "UNISYS SEN Device (NOT HANDLED YET)"; 984 break; 985 case ENC_SAFT: 986 tname = "SAF-TE Compliant Device"; 987 break; 988 case ENC_SEMB_SES: 989 tname = "SEMB SES Device"; 990 break; 991 case ENC_SEMB_SAFT: 992 tname = "SEMB SAF-TE Device"; 993 break; 994 } 995 xpt_announce_periph(periph, tname); 996 status = CAM_REQ_CMP; 997 998 out: 999 if (status != CAM_REQ_CMP) 1000 enc_dtor(periph); 1001 return (status); 1002 } 1003 1004