1 /*- 2 * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 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. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 32 #ifdef _KERNEL 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/bio.h> 36 #include <sys/sysctl.h> 37 #include <sys/taskqueue.h> 38 #include <sys/lock.h> 39 #include <sys/mutex.h> 40 #include <sys/conf.h> 41 #include <sys/devicestat.h> 42 #include <sys/eventhandler.h> 43 #include <sys/malloc.h> 44 #include <sys/cons.h> 45 #include <geom/geom_disk.h> 46 #endif /* _KERNEL */ 47 48 #ifndef _KERNEL 49 #include <stdio.h> 50 #include <string.h> 51 #endif /* _KERNEL */ 52 53 #include <cam/cam.h> 54 #include <cam/cam_ccb.h> 55 #include <cam/cam_periph.h> 56 #include <cam/cam_xpt_periph.h> 57 #include <cam/cam_xpt_internal.h> 58 #include <cam/cam_sim.h> 59 60 #include <cam/ata/ata_all.h> 61 62 #ifdef _KERNEL 63 64 typedef enum { 65 PMP_STATE_NORMAL, 66 PMP_STATE_PORTS, 67 PMP_STATE_PRECONFIG, 68 PMP_STATE_RESET, 69 PMP_STATE_CONNECT, 70 PMP_STATE_CHECK, 71 PMP_STATE_CLEAR, 72 PMP_STATE_CONFIG, 73 PMP_STATE_SCAN 74 } pmp_state; 75 76 typedef enum { 77 PMP_FLAG_SCTX_INIT = 0x200 78 } pmp_flags; 79 80 typedef enum { 81 PMP_CCB_PROBE = 0x01, 82 } pmp_ccb_state; 83 84 /* Offsets into our private area for storing information */ 85 #define ccb_state ppriv_field0 86 #define ccb_bp ppriv_ptr1 87 88 struct pmp_softc { 89 SLIST_ENTRY(pmp_softc) links; 90 pmp_state state; 91 pmp_flags flags; 92 uint32_t pm_pid; 93 uint32_t pm_prv; 94 int pm_ports; 95 int pm_step; 96 int pm_try; 97 int found; 98 int reset; 99 int frozen; 100 int restart; 101 int events; 102 #define PMP_EV_RESET 1 103 #define PMP_EV_RESCAN 2 104 struct task sysctl_task; 105 struct sysctl_ctx_list sysctl_ctx; 106 struct sysctl_oid *sysctl_tree; 107 }; 108 109 static periph_init_t pmpinit; 110 static void pmpasync(void *callback_arg, u_int32_t code, 111 struct cam_path *path, void *arg); 112 static void pmpsysctlinit(void *context, int pending); 113 static periph_ctor_t pmpregister; 114 static periph_dtor_t pmpcleanup; 115 static periph_start_t pmpstart; 116 static periph_oninv_t pmponinvalidate; 117 static void pmpdone(struct cam_periph *periph, 118 union ccb *done_ccb); 119 120 #ifndef PMP_DEFAULT_TIMEOUT 121 #define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 122 #endif 123 124 #ifndef PMP_DEFAULT_RETRY 125 #define PMP_DEFAULT_RETRY 1 126 #endif 127 128 static int pmp_retry_count = PMP_DEFAULT_RETRY; 129 static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 130 131 SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 132 "CAM Direct Access Disk driver"); 133 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 134 &pmp_retry_count, 0, "Normal I/O retry count"); 135 TUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 136 SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 137 &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 138 TUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 139 140 static struct periph_driver pmpdriver = 141 { 142 pmpinit, "pmp", 143 TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 144 CAM_PERIPH_DRV_EARLY 145 }; 146 147 PERIPHDRIVER_DECLARE(pmp, pmpdriver); 148 149 MALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 150 151 static void 152 pmpinit(void) 153 { 154 cam_status status; 155 156 /* 157 * Install a global async callback. This callback will 158 * receive async callbacks like "new device found". 159 */ 160 status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 161 162 if (status != CAM_REQ_CMP) { 163 printf("pmp: Failed to attach master async callback " 164 "due to status 0x%x!\n", status); 165 } 166 } 167 168 static void 169 pmpfreeze(struct cam_periph *periph, int mask) 170 { 171 struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 172 struct cam_path *dpath; 173 int i; 174 175 mask &= ~softc->frozen; 176 for (i = 0; i < 15; i++) { 177 if ((mask & (1 << i)) == 0) 178 continue; 179 if (xpt_create_path(&dpath, periph, 180 xpt_path_path_id(periph->path), 181 i, 0) == CAM_REQ_CMP) { 182 softc->frozen |= (1 << i); 183 xpt_acquire_device(dpath->device); 184 cam_freeze_devq_arg(dpath, 185 RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1); 186 xpt_free_path(dpath); 187 } 188 } 189 } 190 191 static void 192 pmprelease(struct cam_periph *periph, int mask) 193 { 194 struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 195 struct cam_path *dpath; 196 int i; 197 198 mask &= softc->frozen; 199 for (i = 0; i < 15; i++) { 200 if ((mask & (1 << i)) == 0) 201 continue; 202 if (xpt_create_path(&dpath, periph, 203 xpt_path_path_id(periph->path), 204 i, 0) == CAM_REQ_CMP) { 205 softc->frozen &= ~(1 << i); 206 cam_release_devq(dpath, 207 RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE); 208 xpt_release_device(dpath->device); 209 xpt_free_path(dpath); 210 } 211 } 212 } 213 214 static void 215 pmponinvalidate(struct cam_periph *periph) 216 { 217 struct pmp_softc *softc; 218 struct cam_path *dpath; 219 int i; 220 221 softc = (struct pmp_softc *)periph->softc; 222 223 /* 224 * De-register any async callbacks. 225 */ 226 xpt_register_async(0, pmpasync, periph, periph->path); 227 228 for (i = 0; i < 15; i++) { 229 if (xpt_create_path(&dpath, periph, 230 xpt_path_path_id(periph->path), 231 i, 0) == CAM_REQ_CMP) { 232 xpt_async(AC_LOST_DEVICE, dpath, NULL); 233 xpt_free_path(dpath); 234 } 235 } 236 pmprelease(periph, -1); 237 xpt_print(periph->path, "lost device\n"); 238 } 239 240 static void 241 pmpcleanup(struct cam_periph *periph) 242 { 243 struct pmp_softc *softc; 244 245 softc = (struct pmp_softc *)periph->softc; 246 247 xpt_print(periph->path, "removing device entry\n"); 248 cam_periph_unlock(periph); 249 250 /* 251 * If we can't free the sysctl tree, oh well... 252 */ 253 if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 254 && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 255 xpt_print(periph->path, "can't remove sysctl context\n"); 256 } 257 258 free(softc, M_DEVBUF); 259 cam_periph_lock(periph); 260 } 261 262 static void 263 pmpasync(void *callback_arg, u_int32_t code, 264 struct cam_path *path, void *arg) 265 { 266 struct cam_periph *periph; 267 struct pmp_softc *softc; 268 269 periph = (struct cam_periph *)callback_arg; 270 switch (code) { 271 case AC_FOUND_DEVICE: 272 { 273 struct ccb_getdev *cgd; 274 cam_status status; 275 276 cgd = (struct ccb_getdev *)arg; 277 if (cgd == NULL) 278 break; 279 280 if (cgd->protocol != PROTO_SATAPM) 281 break; 282 283 /* 284 * Allocate a peripheral instance for 285 * this device and start the probe 286 * process. 287 */ 288 status = cam_periph_alloc(pmpregister, pmponinvalidate, 289 pmpcleanup, pmpstart, 290 "pmp", CAM_PERIPH_BIO, 291 cgd->ccb_h.path, pmpasync, 292 AC_FOUND_DEVICE, cgd); 293 294 if (status != CAM_REQ_CMP 295 && status != CAM_REQ_INPROG) 296 printf("pmpasync: Unable to attach to new device " 297 "due to status 0x%x\n", status); 298 break; 299 } 300 case AC_SCSI_AEN: 301 case AC_SENT_BDR: 302 case AC_BUS_RESET: 303 softc = (struct pmp_softc *)periph->softc; 304 cam_periph_async(periph, code, path, arg); 305 if (code == AC_SCSI_AEN) 306 softc->events |= PMP_EV_RESCAN; 307 else 308 softc->events |= PMP_EV_RESET; 309 if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL) 310 break; 311 xpt_hold_boot(); 312 pmpfreeze(periph, softc->found); 313 if (code == AC_SENT_BDR || code == AC_BUS_RESET) 314 softc->found = 0; /* We have to reset everything. */ 315 if (softc->state == PMP_STATE_NORMAL) { 316 softc->state = PMP_STATE_PRECONFIG; 317 cam_periph_acquire(periph); 318 xpt_schedule(periph, CAM_PRIORITY_DEV); 319 } else 320 softc->restart = 1; 321 break; 322 default: 323 cam_periph_async(periph, code, path, arg); 324 break; 325 } 326 } 327 328 static void 329 pmpsysctlinit(void *context, int pending) 330 { 331 struct cam_periph *periph; 332 struct pmp_softc *softc; 333 char tmpstr[80], tmpstr2[80]; 334 335 periph = (struct cam_periph *)context; 336 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 337 return; 338 339 softc = (struct pmp_softc *)periph->softc; 340 snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 341 snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 342 343 sysctl_ctx_init(&softc->sysctl_ctx); 344 softc->flags |= PMP_FLAG_SCTX_INIT; 345 softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 346 SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 347 CTLFLAG_RD, 0, tmpstr); 348 if (softc->sysctl_tree == NULL) { 349 printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 350 cam_periph_release(periph); 351 return; 352 } 353 354 cam_periph_release(periph); 355 } 356 357 static cam_status 358 pmpregister(struct cam_periph *periph, void *arg) 359 { 360 struct pmp_softc *softc; 361 struct ccb_getdev *cgd; 362 363 cgd = (struct ccb_getdev *)arg; 364 if (periph == NULL) { 365 printf("pmpregister: periph was NULL!!\n"); 366 return(CAM_REQ_CMP_ERR); 367 } 368 369 if (cgd == NULL) { 370 printf("pmpregister: no getdev CCB, can't register device\n"); 371 return(CAM_REQ_CMP_ERR); 372 } 373 374 softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 375 M_NOWAIT|M_ZERO); 376 377 if (softc == NULL) { 378 printf("pmpregister: Unable to probe new device. " 379 "Unable to allocate softc\n"); 380 return(CAM_REQ_CMP_ERR); 381 } 382 periph->softc = softc; 383 384 softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 385 softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 386 TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 387 388 xpt_announce_periph(periph, NULL); 389 390 /* 391 * Add async callbacks for bus reset and 392 * bus device reset calls. I don't bother 393 * checking if this fails as, in most cases, 394 * the system will function just fine without 395 * them and the only alternative would be to 396 * not attach the device on failure. 397 */ 398 xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 399 AC_SCSI_AEN, pmpasync, periph, periph->path); 400 401 /* 402 * Take an exclusive refcount on the periph while pmpstart is called 403 * to finish the probe. The reference will be dropped in pmpdone at 404 * the end of probe. 405 */ 406 (void)cam_periph_acquire(periph); 407 xpt_hold_boot(); 408 softc->state = PMP_STATE_PORTS; 409 softc->events = PMP_EV_RESCAN; 410 xpt_schedule(periph, CAM_PRIORITY_DEV); 411 412 return(CAM_REQ_CMP); 413 } 414 415 static void 416 pmpstart(struct cam_periph *periph, union ccb *start_ccb) 417 { 418 struct ccb_trans_settings cts; 419 struct ccb_ataio *ataio; 420 struct pmp_softc *softc; 421 struct cam_path *dpath; 422 int revision = 0; 423 424 softc = (struct pmp_softc *)periph->softc; 425 ataio = &start_ccb->ataio; 426 427 if (softc->restart) { 428 softc->restart = 0; 429 softc->state = min(softc->state, PMP_STATE_PRECONFIG); 430 } 431 /* Fetch user wanted device speed. */ 432 if (softc->state == PMP_STATE_RESET || 433 softc->state == PMP_STATE_CONNECT) { 434 if (xpt_create_path(&dpath, periph, 435 xpt_path_path_id(periph->path), 436 softc->pm_step, 0) == CAM_REQ_CMP) { 437 bzero(&cts, sizeof(cts)); 438 xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 439 cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 440 cts.type = CTS_TYPE_USER_SETTINGS; 441 xpt_action((union ccb *)&cts); 442 if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 443 revision = cts.xport_specific.sata.revision; 444 xpt_free_path(dpath); 445 } 446 } 447 switch (softc->state) { 448 case PMP_STATE_PORTS: 449 cam_fill_ataio(ataio, 450 pmp_retry_count, 451 pmpdone, 452 /*flags*/CAM_DIR_NONE, 453 0, 454 /*data_ptr*/NULL, 455 /*dxfer_len*/0, 456 pmp_default_timeout * 1000); 457 ata_pm_read_cmd(ataio, 2, 15); 458 break; 459 case PMP_STATE_PRECONFIG: 460 cam_fill_ataio(ataio, 461 pmp_retry_count, 462 pmpdone, 463 /*flags*/CAM_DIR_NONE, 464 0, 465 /*data_ptr*/NULL, 466 /*dxfer_len*/0, 467 pmp_default_timeout * 1000); 468 ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 469 break; 470 case PMP_STATE_RESET: 471 cam_fill_ataio(ataio, 472 pmp_retry_count, 473 pmpdone, 474 /*flags*/CAM_DIR_NONE, 475 0, 476 /*data_ptr*/NULL, 477 /*dxfer_len*/0, 478 pmp_default_timeout * 1000); 479 ata_pm_write_cmd(ataio, 2, softc->pm_step, 480 (revision << 4) | 481 ((softc->found & (1 << softc->pm_step)) ? 0 : 1)); 482 break; 483 case PMP_STATE_CONNECT: 484 cam_fill_ataio(ataio, 485 pmp_retry_count, 486 pmpdone, 487 /*flags*/CAM_DIR_NONE, 488 0, 489 /*data_ptr*/NULL, 490 /*dxfer_len*/0, 491 pmp_default_timeout * 1000); 492 ata_pm_write_cmd(ataio, 2, softc->pm_step, 493 (revision << 4)); 494 break; 495 case PMP_STATE_CHECK: 496 cam_fill_ataio(ataio, 497 pmp_retry_count, 498 pmpdone, 499 /*flags*/CAM_DIR_NONE, 500 0, 501 /*data_ptr*/NULL, 502 /*dxfer_len*/0, 503 pmp_default_timeout * 1000); 504 ata_pm_read_cmd(ataio, 0, softc->pm_step); 505 break; 506 case PMP_STATE_CLEAR: 507 softc->reset = 0; 508 cam_fill_ataio(ataio, 509 pmp_retry_count, 510 pmpdone, 511 /*flags*/CAM_DIR_NONE, 512 0, 513 /*data_ptr*/NULL, 514 /*dxfer_len*/0, 515 pmp_default_timeout * 1000); 516 ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 517 break; 518 case PMP_STATE_CONFIG: 519 cam_fill_ataio(ataio, 520 pmp_retry_count, 521 pmpdone, 522 /*flags*/CAM_DIR_NONE, 523 0, 524 /*data_ptr*/NULL, 525 /*dxfer_len*/0, 526 pmp_default_timeout * 1000); 527 ata_pm_write_cmd(ataio, 0x60, 15, 0xf); 528 break; 529 default: 530 break; 531 } 532 xpt_action(start_ccb); 533 } 534 535 static void 536 pmpdone(struct cam_periph *periph, union ccb *done_ccb) 537 { 538 struct ccb_trans_settings cts; 539 struct pmp_softc *softc; 540 struct ccb_ataio *ataio; 541 struct cam_path *path, *dpath; 542 u_int32_t priority, res; 543 int i; 544 545 softc = (struct pmp_softc *)periph->softc; 546 ataio = &done_ccb->ataio; 547 548 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n")); 549 550 path = done_ccb->ccb_h.path; 551 priority = done_ccb->ccb_h.pinfo.priority; 552 553 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 554 if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { 555 return; 556 } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 557 cam_release_devq(done_ccb->ccb_h.path, 558 /*relsim_flags*/0, 559 /*reduction*/0, 560 /*timeout*/0, 561 /*getcount_only*/0); 562 } 563 goto done; 564 } 565 566 if (softc->restart) { 567 softc->restart = 0; 568 xpt_release_ccb(done_ccb); 569 softc->state = min(softc->state, PMP_STATE_PRECONFIG); 570 xpt_schedule(periph, priority); 571 return; 572 } 573 574 switch (softc->state) { 575 case PMP_STATE_PORTS: 576 softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 577 (done_ccb->ataio.res.lba_mid << 16) + 578 (done_ccb->ataio.res.lba_low << 8) + 579 done_ccb->ataio.res.sector_count; 580 /* This PMP declares 6 ports, while only 5 of them are real. 581 * Port 5 is enclosure management bridge port, which has implementation 582 * problems, causing probe faults. Hide it for now. */ 583 if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 584 softc->pm_ports = 5; 585 /* This PMP declares 7 ports, while only 5 of them are real. 586 * Port 5 is some fake "Config Disk" with 640 sectors size, 587 * port 6 is enclosure management bridge port. 588 * Both fake ports has implementation problems, causing 589 * probe faults. Hide them for now. */ 590 if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 591 softc->pm_ports = 5; 592 /* These PMPs declare one more port then actually have, 593 * for configuration purposes. Hide it for now. */ 594 if (softc->pm_pid == 0x57231095 || softc->pm_pid == 0x57331095 || 595 softc->pm_pid == 0x57341095 || softc->pm_pid == 0x57441095) 596 softc->pm_ports--; 597 printf("%s%d: %d fan-out ports\n", 598 periph->periph_name, periph->unit_number, 599 softc->pm_ports); 600 softc->state = PMP_STATE_PRECONFIG; 601 xpt_release_ccb(done_ccb); 602 xpt_schedule(periph, priority); 603 return; 604 case PMP_STATE_PRECONFIG: 605 softc->pm_step = 0; 606 softc->state = PMP_STATE_RESET; 607 softc->reset |= ~softc->found; 608 xpt_release_ccb(done_ccb); 609 xpt_schedule(periph, priority); 610 return; 611 case PMP_STATE_RESET: 612 softc->pm_step++; 613 if (softc->pm_step >= softc->pm_ports) { 614 softc->pm_step = 0; 615 cam_freeze_devq(periph->path); 616 cam_release_devq(periph->path, 617 RELSIM_RELEASE_AFTER_TIMEOUT, 618 /*reduction*/0, 619 /*timeout*/5, 620 /*getcount_only*/0); 621 softc->state = PMP_STATE_CONNECT; 622 } 623 xpt_release_ccb(done_ccb); 624 xpt_schedule(periph, priority); 625 return; 626 case PMP_STATE_CONNECT: 627 softc->pm_step++; 628 if (softc->pm_step >= softc->pm_ports) { 629 softc->pm_step = 0; 630 softc->pm_try = 0; 631 cam_freeze_devq(periph->path); 632 cam_release_devq(periph->path, 633 RELSIM_RELEASE_AFTER_TIMEOUT, 634 /*reduction*/0, 635 /*timeout*/10, 636 /*getcount_only*/0); 637 softc->state = PMP_STATE_CHECK; 638 } 639 xpt_release_ccb(done_ccb); 640 xpt_schedule(periph, priority); 641 return; 642 case PMP_STATE_CHECK: 643 res = (done_ccb->ataio.res.lba_high << 24) + 644 (done_ccb->ataio.res.lba_mid << 16) + 645 (done_ccb->ataio.res.lba_low << 8) + 646 done_ccb->ataio.res.sector_count; 647 if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 648 if (bootverbose) { 649 printf("%s%d: port %d status: %08x\n", 650 periph->periph_name, periph->unit_number, 651 softc->pm_step, res); 652 } 653 /* Report device speed. */ 654 if (xpt_create_path(&dpath, periph, 655 xpt_path_path_id(periph->path), 656 softc->pm_step, 0) == CAM_REQ_CMP) { 657 bzero(&cts, sizeof(cts)); 658 xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 659 cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 660 cts.type = CTS_TYPE_CURRENT_SETTINGS; 661 cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 662 cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 663 xpt_action((union ccb *)&cts); 664 xpt_free_path(dpath); 665 } 666 softc->found |= (1 << softc->pm_step); 667 softc->pm_step++; 668 } else { 669 if (softc->pm_try < 10) { 670 cam_freeze_devq(periph->path); 671 cam_release_devq(periph->path, 672 RELSIM_RELEASE_AFTER_TIMEOUT, 673 /*reduction*/0, 674 /*timeout*/10, 675 /*getcount_only*/0); 676 softc->pm_try++; 677 } else { 678 if (bootverbose) { 679 printf("%s%d: port %d status: %08x\n", 680 periph->periph_name, periph->unit_number, 681 softc->pm_step, res); 682 } 683 softc->found &= ~(1 << softc->pm_step); 684 if (xpt_create_path(&dpath, periph, 685 done_ccb->ccb_h.path_id, 686 softc->pm_step, 0) == CAM_REQ_CMP) { 687 xpt_async(AC_LOST_DEVICE, dpath, NULL); 688 xpt_free_path(dpath); 689 } 690 softc->pm_step++; 691 } 692 } 693 if (softc->pm_step >= softc->pm_ports) { 694 if (softc->reset & softc->found) { 695 cam_freeze_devq(periph->path); 696 cam_release_devq(periph->path, 697 RELSIM_RELEASE_AFTER_TIMEOUT, 698 /*reduction*/0, 699 /*timeout*/1000, 700 /*getcount_only*/0); 701 } 702 softc->state = PMP_STATE_CLEAR; 703 softc->pm_step = 0; 704 } 705 xpt_release_ccb(done_ccb); 706 xpt_schedule(periph, priority); 707 return; 708 case PMP_STATE_CLEAR: 709 softc->pm_step++; 710 if (softc->pm_step >= softc->pm_ports) { 711 softc->state = PMP_STATE_CONFIG; 712 softc->pm_step = 0; 713 } 714 xpt_release_ccb(done_ccb); 715 xpt_schedule(periph, priority); 716 return; 717 case PMP_STATE_CONFIG: 718 for (i = 0; i < softc->pm_ports; i++) { 719 union ccb *ccb; 720 721 if ((softc->found & (1 << i)) == 0) 722 continue; 723 if (xpt_create_path(&dpath, periph, 724 xpt_path_path_id(periph->path), 725 i, 0) != CAM_REQ_CMP) { 726 printf("pmpdone: xpt_create_path failed" 727 ", bus scan halted\n"); 728 xpt_free_ccb(done_ccb); 729 goto done; 730 } 731 /* If we did hard reset to this device, inform XPT. */ 732 if ((softc->reset & softc->found & (1 << i)) != 0) 733 xpt_async(AC_SENT_BDR, dpath, NULL); 734 /* If rescan requested, scan this device. */ 735 if (softc->events & PMP_EV_RESCAN) { 736 ccb = xpt_alloc_ccb_nowait(); 737 if (ccb == NULL) { 738 xpt_free_path(dpath); 739 goto done; 740 } 741 xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT); 742 xpt_rescan(ccb); 743 } else 744 xpt_free_path(dpath); 745 } 746 break; 747 default: 748 break; 749 } 750 done: 751 xpt_release_ccb(done_ccb); 752 softc->state = PMP_STATE_NORMAL; 753 softc->events = 0; 754 xpt_release_boot(); 755 pmprelease(periph, -1); 756 cam_periph_release_locked(periph); 757 } 758 759 #endif /* _KERNEL */ 760