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