ata_pmp.c revision 198708
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: head/sys/cam/ata/ata_pmp.c 198708 2009-10-31 10:43:38Z mav $"); 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_sim.h> 58 59#include <cam/ata/ata_all.h> 60 61#ifdef _KERNEL 62 63typedef enum { 64 PMP_STATE_NORMAL, 65 PMP_STATE_PORTS, 66 PMP_STATE_CONFIG, 67 PMP_STATE_RESET, 68 PMP_STATE_CONNECT, 69 PMP_STATE_CHECK, 70 PMP_STATE_CLEAR, 71 PMP_STATE_SCAN 72} pmp_state; 73 74typedef enum { 75 PMP_FLAG_SCTX_INIT = 0x200 76} pmp_flags; 77 78typedef enum { 79 PMP_CCB_PROBE = 0x01, 80} pmp_ccb_state; 81 82/* Offsets into our private area for storing information */ 83#define ccb_state ppriv_field0 84#define ccb_bp ppriv_ptr1 85 86struct pmp_softc { 87 SLIST_ENTRY(pmp_softc) links; 88 pmp_state state; 89 pmp_flags flags; 90 uint32_t pm_pid; 91 uint32_t pm_prv; 92 int pm_ports; 93 int pm_step; 94 int pm_try; 95 int found; 96 int reset; 97 int frozen; 98 int restart; 99 union ccb saved_ccb; 100 struct task sysctl_task; 101 struct sysctl_ctx_list sysctl_ctx; 102 struct sysctl_oid *sysctl_tree; 103}; 104 105static periph_init_t pmpinit; 106static void pmpasync(void *callback_arg, u_int32_t code, 107 struct cam_path *path, void *arg); 108static void pmpsysctlinit(void *context, int pending); 109static periph_ctor_t pmpregister; 110static periph_dtor_t pmpcleanup; 111static periph_start_t pmpstart; 112static periph_oninv_t pmponinvalidate; 113static void pmpdone(struct cam_periph *periph, 114 union ccb *done_ccb); 115 116#ifndef PMP_DEFAULT_TIMEOUT 117#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 118#endif 119 120#ifndef PMP_DEFAULT_RETRY 121#define PMP_DEFAULT_RETRY 1 122#endif 123 124static int pmp_retry_count = PMP_DEFAULT_RETRY; 125static int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 126 127SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 128 "CAM Direct Access Disk driver"); 129SYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 130 &pmp_retry_count, 0, "Normal I/O retry count"); 131TUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 132SYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 133 &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 134TUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 135 136static struct periph_driver pmpdriver = 137{ 138 pmpinit, "pmp", 139 TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 140 CAM_PERIPH_DRV_EARLY 141}; 142 143PERIPHDRIVER_DECLARE(pmp, pmpdriver); 144 145MALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 146 147static void 148pmpinit(void) 149{ 150 cam_status status; 151 152 /* 153 * Install a global async callback. This callback will 154 * receive async callbacks like "new device found". 155 */ 156 status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 157 158 if (status != CAM_REQ_CMP) { 159 printf("pmp: Failed to attach master async callback " 160 "due to status 0x%x!\n", status); 161 } 162} 163 164static void 165pmpfreeze(struct cam_periph *periph, int mask) 166{ 167 struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 168 struct cam_path *dpath; 169 int i; 170 171 mask &= ~softc->frozen; 172 for (i = 0; i < 15; i++) { 173 if ((mask & (1 << i)) == 0) 174 continue; 175 if (xpt_create_path(&dpath, periph, 176 xpt_path_path_id(periph->path), 177 i, 0) == CAM_REQ_CMP) { 178printf("PMP freeze: %d\n", i); 179 softc->frozen |= (1 << i); 180 cam_freeze_devq(dpath); 181 xpt_free_path(dpath); 182 } 183 } 184} 185 186static void 187pmprelease(struct cam_periph *periph, int mask) 188{ 189 struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 190 struct cam_path *dpath; 191 int i; 192 193 mask &= softc->frozen; 194 for (i = 0; i < 15; i++) { 195 if ((mask & (1 << i)) == 0) 196 continue; 197 if (xpt_create_path(&dpath, periph, 198 xpt_path_path_id(periph->path), 199 i, 0) == CAM_REQ_CMP) { 200printf("PMP release: %d\n", i); 201 softc->frozen &= ~(1 << i); 202 cam_release_devq(dpath, 0, 0, 0, FALSE); 203 xpt_free_path(dpath); 204 } 205 } 206} 207 208static void 209pmponinvalidate(struct cam_periph *periph) 210{ 211 struct pmp_softc *softc; 212 struct cam_path *dpath; 213 int i; 214 215 softc = (struct pmp_softc *)periph->softc; 216 217 /* 218 * De-register any async callbacks. 219 */ 220 xpt_register_async(0, pmpasync, periph, periph->path); 221 222 for (i = 0; i < 15; i++) { 223 if (xpt_create_path(&dpath, periph, 224 xpt_path_path_id(periph->path), 225 i, 0) == CAM_REQ_CMP) { 226 xpt_async(AC_LOST_DEVICE, dpath, NULL); 227 xpt_free_path(dpath); 228 } 229 } 230 xpt_print(periph->path, "lost device\n"); 231} 232 233static void 234pmpcleanup(struct cam_periph *periph) 235{ 236 struct pmp_softc *softc; 237 238 softc = (struct pmp_softc *)periph->softc; 239 240 xpt_print(periph->path, "removing device entry\n"); 241 cam_periph_unlock(periph); 242 243 /* 244 * If we can't free the sysctl tree, oh well... 245 */ 246 if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 247 && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 248 xpt_print(periph->path, "can't remove sysctl context\n"); 249 } 250 251 free(softc, M_DEVBUF); 252 cam_periph_lock(periph); 253} 254 255static void 256pmpasync(void *callback_arg, u_int32_t code, 257 struct cam_path *path, void *arg) 258{ 259 struct cam_periph *periph; 260 struct pmp_softc *softc; 261 262 periph = (struct cam_periph *)callback_arg; 263 switch (code) { 264 case AC_FOUND_DEVICE: 265 { 266 struct ccb_getdev *cgd; 267 cam_status status; 268 269 cgd = (struct ccb_getdev *)arg; 270 if (cgd == NULL) 271 break; 272 273 if (cgd->protocol != PROTO_SATAPM) 274 break; 275 276 /* 277 * Allocate a peripheral instance for 278 * this device and start the probe 279 * process. 280 */ 281 status = cam_periph_alloc(pmpregister, pmponinvalidate, 282 pmpcleanup, pmpstart, 283 "pmp", CAM_PERIPH_BIO, 284 cgd->ccb_h.path, pmpasync, 285 AC_FOUND_DEVICE, cgd); 286 287 if (status != CAM_REQ_CMP 288 && status != CAM_REQ_INPROG) 289 printf("pmpasync: Unable to attach to new device " 290 "due to status 0x%x\n", status); 291 break; 292 } 293 case AC_SCSI_AEN: 294 case AC_SENT_BDR: 295 case AC_BUS_RESET: 296 softc = (struct pmp_softc *)periph->softc; 297 cam_periph_async(periph, code, path, arg); 298 if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL && 299 softc->state != PMP_STATE_SCAN) 300 break; 301 if (softc->state != PMP_STATE_SCAN) 302 pmpfreeze(periph, softc->found); 303 else 304 pmpfreeze(periph, softc->found & ~(1 << softc->pm_step)); 305 if (code == AC_SENT_BDR || code == AC_BUS_RESET) 306 softc->found = 0; /* We have to reset everything. */ 307 if (softc->state == PMP_STATE_NORMAL) { 308 softc->state = PMP_STATE_PORTS; 309 cam_periph_acquire(periph); 310 xpt_schedule(periph, CAM_PRIORITY_BUS); 311 } else 312 softc->restart = 1; 313 break; 314 default: 315 cam_periph_async(periph, code, path, arg); 316 break; 317 } 318} 319 320static void 321pmpsysctlinit(void *context, int pending) 322{ 323 struct cam_periph *periph; 324 struct pmp_softc *softc; 325 char tmpstr[80], tmpstr2[80]; 326 327 periph = (struct cam_periph *)context; 328 if (cam_periph_acquire(periph) != CAM_REQ_CMP) 329 return; 330 331 softc = (struct pmp_softc *)periph->softc; 332 snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 333 snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 334 335 sysctl_ctx_init(&softc->sysctl_ctx); 336 softc->flags |= PMP_FLAG_SCTX_INIT; 337 softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 338 SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 339 CTLFLAG_RD, 0, tmpstr); 340 if (softc->sysctl_tree == NULL) { 341 printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 342 cam_periph_release(periph); 343 return; 344 } 345 346 cam_periph_release(periph); 347} 348 349static cam_status 350pmpregister(struct cam_periph *periph, void *arg) 351{ 352 struct pmp_softc *softc; 353 struct ccb_pathinq cpi; 354 struct ccb_getdev *cgd; 355 356 cgd = (struct ccb_getdev *)arg; 357 if (periph == NULL) { 358 printf("pmpregister: periph was NULL!!\n"); 359 return(CAM_REQ_CMP_ERR); 360 } 361 362 if (cgd == NULL) { 363 printf("pmpregister: no getdev CCB, can't register device\n"); 364 return(CAM_REQ_CMP_ERR); 365 } 366 367 softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 368 M_NOWAIT|M_ZERO); 369 370 if (softc == NULL) { 371 printf("pmpregister: Unable to probe new device. " 372 "Unable to allocate softc\n"); 373 return(CAM_REQ_CMP_ERR); 374 } 375 periph->softc = softc; 376 377 softc->state = PMP_STATE_PORTS; 378 softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 379 softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 380 381 /* Check if the SIM does not want queued commands */ 382 bzero(&cpi, sizeof(cpi)); 383 xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL); 384 cpi.ccb_h.func_code = XPT_PATH_INQ; 385 xpt_action((union ccb *)&cpi); 386 387 TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 388 389 xpt_announce_periph(periph, NULL); 390 391 /* 392 * Add async callbacks for bus reset and 393 * bus device reset calls. I don't bother 394 * checking if this fails as, in most cases, 395 * the system will function just fine without 396 * them and the only alternative would be to 397 * not attach the device on failure. 398 */ 399 xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 400 AC_SCSI_AEN, pmpasync, periph, periph->path); 401 402 /* 403 * Take an exclusive refcount on the periph while pmpstart is called 404 * to finish the probe. The reference will be dropped in pmpdone at 405 * the end of probe. 406 */ 407 (void)cam_periph_acquire(periph); 408 xpt_schedule(periph, CAM_PRIORITY_BUS); 409 410 return(CAM_REQ_CMP); 411} 412 413static void 414pmpstart(struct cam_periph *periph, union ccb *start_ccb) 415{ 416 struct ccb_ataio *ataio; 417 struct pmp_softc *softc; 418 419 softc = (struct pmp_softc *)periph->softc; 420 ataio = &start_ccb->ataio; 421 422 if (softc->restart) { 423 softc->restart = 0; 424 softc->state = PMP_STATE_PORTS; 425 } 426 427 switch (softc->state) { 428 case PMP_STATE_PORTS: 429 cam_fill_ataio(ataio, 430 pmp_retry_count, 431 pmpdone, 432 /*flags*/CAM_DIR_NONE, 433 0, 434 /*data_ptr*/NULL, 435 /*dxfer_len*/0, 436 pmp_default_timeout * 1000); 437 ata_pm_read_cmd(ataio, 2, 15); 438 break; 439 case PMP_STATE_CONFIG: 440 cam_fill_ataio(ataio, 441 pmp_retry_count, 442 pmpdone, 443 /*flags*/CAM_DIR_NONE, 444 0, 445 /*data_ptr*/NULL, 446 /*dxfer_len*/0, 447 pmp_default_timeout * 1000); 448 ata_pm_write_cmd(ataio, 0x60, 15, 0xf); 449 break; 450 case PMP_STATE_RESET: 451 cam_fill_ataio(ataio, 452 pmp_retry_count, 453 pmpdone, 454 /*flags*/CAM_DIR_NONE, 455 0, 456 /*data_ptr*/NULL, 457 /*dxfer_len*/0, 458 pmp_default_timeout * 1000); 459 ata_pm_write_cmd(ataio, 2, softc->pm_step, 460 (softc->found & (1 << softc->pm_step)) ? 0 : 1); 461printf("PM RESET %d%s\n", softc->pm_step, 462 (softc->found & (1 << softc->pm_step)) ? " skipping" : ""); 463 break; 464 case PMP_STATE_CONNECT: 465 cam_fill_ataio(ataio, 466 pmp_retry_count, 467 pmpdone, 468 /*flags*/CAM_DIR_NONE, 469 0, 470 /*data_ptr*/NULL, 471 /*dxfer_len*/0, 472 pmp_default_timeout * 1000); 473 ata_pm_write_cmd(ataio, 2, softc->pm_step, 0); 474 break; 475 case PMP_STATE_CHECK: 476 cam_fill_ataio(ataio, 477 pmp_retry_count, 478 pmpdone, 479 /*flags*/CAM_DIR_NONE, 480 0, 481 /*data_ptr*/NULL, 482 /*dxfer_len*/0, 483 pmp_default_timeout * 1000); 484 ata_pm_read_cmd(ataio, 0, softc->pm_step); 485 break; 486 case PMP_STATE_CLEAR: 487 softc->reset = 0; 488 cam_fill_ataio(ataio, 489 pmp_retry_count, 490 pmpdone, 491 /*flags*/CAM_DIR_NONE, 492 0, 493 /*data_ptr*/NULL, 494 /*dxfer_len*/0, 495 pmp_default_timeout * 1000); 496 ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 497 break; 498 default: 499 break; 500 } 501 xpt_action(start_ccb); 502} 503 504static void 505pmpdone(struct cam_periph *periph, union ccb *done_ccb) 506{ 507 struct pmp_softc *softc; 508 struct ccb_ataio *ataio; 509 union ccb *work_ccb; 510 struct cam_path *path, *dpath; 511 u_int32_t priority, res; 512 513 softc = (struct pmp_softc *)periph->softc; 514 ataio = &done_ccb->ataio; 515 516 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n")); 517 518 path = done_ccb->ccb_h.path; 519 priority = done_ccb->ccb_h.pinfo.priority; 520 521 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 522 if (cam_periph_error(done_ccb, 0, 0, 523 &softc->saved_ccb) == ERESTART) { 524 return; 525 } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 526 cam_release_devq(done_ccb->ccb_h.path, 527 /*relsim_flags*/0, 528 /*reduction*/0, 529 /*timeout*/0, 530 /*getcount_only*/0); 531 } 532 goto done; 533 } 534 535 if (softc->restart) { 536 softc->restart = 0; 537 if (softc->state == PMP_STATE_SCAN) { 538 pmpfreeze(periph, 1 << softc->pm_step); 539 work_ccb = done_ccb; 540 done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0; 541 /* Free the current request path- we're done with it. */ 542 xpt_free_path(work_ccb->ccb_h.path); 543 xpt_free_ccb(work_ccb); 544 } 545 xpt_release_ccb(done_ccb); 546 softc->state = PMP_STATE_PORTS; 547 xpt_schedule(periph, priority); 548 return; 549 } 550 551 switch (softc->state) { 552 case PMP_STATE_PORTS: 553 softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 554 (done_ccb->ataio.res.lba_mid << 16) + 555 (done_ccb->ataio.res.lba_low << 8) + 556 done_ccb->ataio.res.sector_count; 557 /* This PM declares 6 ports, while only 5 of them are real. 558 * Port 5 is enclosure management bridge port, which has implementation 559 * problems, causing probe faults. Hide it for now. */ 560 if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 561 softc->pm_ports = 5; 562 /* This PM declares 7 ports, while only 5 of them are real. 563 * Port 5 is some fake "Config Disk" with 640 sectors size, 564 * port 6 is enclosure management bridge port. 565 * Both fake ports has implementation problems, causing 566 * probe faults. Hide them for now. */ 567 if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 568 softc->pm_ports = 5; 569 printf("PM ports: %d\n", softc->pm_ports); 570 softc->state = PMP_STATE_CONFIG; 571 xpt_release_ccb(done_ccb); 572 xpt_schedule(periph, priority); 573 return; 574 case PMP_STATE_CONFIG: 575 softc->pm_step = 0; 576 softc->state = PMP_STATE_RESET; 577 softc->reset |= ~softc->found; 578 xpt_release_ccb(done_ccb); 579 xpt_schedule(periph, priority); 580 return; 581 case PMP_STATE_RESET: 582 softc->pm_step++; 583 if (softc->pm_step >= softc->pm_ports) { 584 softc->pm_step = 0; 585 cam_freeze_devq(periph->path); 586 cam_release_devq(periph->path, 587 RELSIM_RELEASE_AFTER_TIMEOUT, 588 /*reduction*/0, 589 /*timeout*/5, 590 /*getcount_only*/0); 591 printf("PM reset done\n"); 592 softc->state = PMP_STATE_CONNECT; 593 } 594 xpt_release_ccb(done_ccb); 595 xpt_schedule(periph, priority); 596 return; 597 case PMP_STATE_CONNECT: 598 softc->pm_step++; 599 if (softc->pm_step >= softc->pm_ports) { 600 softc->pm_step = 0; 601 softc->pm_try = 0; 602 cam_freeze_devq(periph->path); 603 cam_release_devq(periph->path, 604 RELSIM_RELEASE_AFTER_TIMEOUT, 605 /*reduction*/0, 606 /*timeout*/10, 607 /*getcount_only*/0); 608 printf("PM connect done\n"); 609 softc->state = PMP_STATE_CHECK; 610 } 611 xpt_release_ccb(done_ccb); 612 xpt_schedule(periph, priority); 613 return; 614 case PMP_STATE_CHECK: 615 res = (done_ccb->ataio.res.lba_high << 24) + 616 (done_ccb->ataio.res.lba_mid << 16) + 617 (done_ccb->ataio.res.lba_low << 8) + 618 done_ccb->ataio.res.sector_count; 619 if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 620 printf("PM status: %d - %08x\n", softc->pm_step, res); 621 softc->found |= (1 << softc->pm_step); 622 softc->pm_step++; 623 } else { 624 if (softc->pm_try < 10) { 625 cam_freeze_devq(periph->path); 626 cam_release_devq(periph->path, 627 RELSIM_RELEASE_AFTER_TIMEOUT, 628 /*reduction*/0, 629 /*timeout*/10, 630 /*getcount_only*/0); 631 softc->pm_try++; 632 } else { 633 printf("PM status: %d - %08x\n", softc->pm_step, res); 634 softc->found &= ~(1 << softc->pm_step); 635 if (xpt_create_path(&dpath, periph, 636 done_ccb->ccb_h.path_id, 637 softc->pm_step, 0) == CAM_REQ_CMP) { 638 xpt_async(AC_LOST_DEVICE, dpath, NULL); 639 xpt_free_path(dpath); 640 } 641 softc->pm_step++; 642 } 643 } 644 if (softc->pm_step >= softc->pm_ports) { 645 if (softc->reset & softc->found) { 646 cam_freeze_devq(periph->path); 647 cam_release_devq(periph->path, 648 RELSIM_RELEASE_AFTER_TIMEOUT, 649 /*reduction*/0, 650 /*timeout*/1000, 651 /*getcount_only*/0); 652 } 653 softc->state = PMP_STATE_CLEAR; 654 softc->pm_step = 0; 655 } 656 xpt_release_ccb(done_ccb); 657 xpt_schedule(periph, priority); 658 return; 659 case PMP_STATE_CLEAR: 660 softc->pm_step++; 661 if (softc->pm_step < softc->pm_ports) { 662 xpt_release_ccb(done_ccb); 663 xpt_schedule(periph, priority); 664 return; 665 } else if (softc->found) { 666 softc->pm_step = 0; 667 softc->state = PMP_STATE_SCAN; 668 work_ccb = xpt_alloc_ccb_nowait(); 669 if (work_ccb != NULL) 670 goto do_scan; 671 xpt_release_ccb(done_ccb); 672 } 673 break; 674 case PMP_STATE_SCAN: 675 work_ccb = done_ccb; 676 done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0; 677 /* Free the current request path- we're done with it. */ 678 xpt_free_path(work_ccb->ccb_h.path); 679 softc->pm_step++; 680do_scan: 681 while (softc->pm_step < softc->pm_ports && 682 (softc->found & (1 << softc->pm_step)) == 0) { 683 softc->pm_step++; 684 } 685 if (softc->pm_step >= softc->pm_ports) { 686 xpt_free_ccb(work_ccb); 687 break; 688 } 689 if (xpt_create_path(&dpath, periph, 690 done_ccb->ccb_h.path_id, 691 softc->pm_step, 0) != CAM_REQ_CMP) { 692 printf("pmpdone: xpt_create_path failed" 693 ", bus scan halted\n"); 694 xpt_free_ccb(work_ccb); 695 break; 696 } 697 xpt_setup_ccb(&work_ccb->ccb_h, dpath, 698 done_ccb->ccb_h.pinfo.priority); 699 work_ccb->ccb_h.func_code = XPT_SCAN_LUN; 700 work_ccb->ccb_h.cbfcnp = pmpdone; 701 work_ccb->ccb_h.ppriv_ptr0 = done_ccb; 702 work_ccb->crcn.flags = done_ccb->crcn.flags; 703 xpt_action(work_ccb); 704 pmprelease(periph, 1 << softc->pm_step); 705 return; 706 default: 707 break; 708 } 709done: 710 xpt_release_ccb(done_ccb); 711 softc->state = PMP_STATE_NORMAL; 712 pmprelease(periph, -1); 713 cam_periph_release_locked(periph); 714} 715 716#endif /* _KERNEL */ 717