1 /* 2 * Implementation of the Target Mode 'Black Hole device' for CAM. 3 * 4 * Copyright (c) 1999 Justin T. Gibbs. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer, 12 * without modification, immediately at the beginning of the file. 13 * 2. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/cam/scsi/scsi_targ_bh.c,v 1.4.2.5 2001/07/30 00:15:22 mjacob Exp $ 29 * $DragonFly: src/sys/bus/cam/scsi/scsi_targ_bh.c,v 1.4 2003/08/07 21:16:45 dillon Exp $ 30 */ 31 #include <sys/param.h> 32 #include <sys/queue.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/types.h> 36 #include <sys/buf.h> 37 #include <sys/conf.h> 38 #include <sys/devicestat.h> 39 #include <sys/malloc.h> 40 #include <sys/uio.h> 41 42 #include "../cam.h" 43 #include "../cam_ccb.h" 44 #include "../cam_extend.h" 45 #include "../cam_periph.h" 46 #include "../cam_queue.h" 47 #include "../cam_xpt_periph.h" 48 #include "../cam_debug.h" 49 50 #include "scsi_all.h" 51 #include "scsi_message.h" 52 53 typedef enum { 54 TARGBH_STATE_NORMAL, 55 TARGBH_STATE_EXCEPTION, 56 TARGBH_STATE_TEARDOWN 57 } targbh_state; 58 59 typedef enum { 60 TARGBH_FLAG_NONE = 0x00, 61 TARGBH_FLAG_LUN_ENABLED = 0x01 62 } targbh_flags; 63 64 typedef enum { 65 TARGBH_CCB_WORKQ, 66 TARGBH_CCB_WAITING 67 } targbh_ccb_types; 68 69 #define MAX_ACCEPT 8 70 #define MAX_IMMEDIATE 16 71 #define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */ 72 73 /* Offsets into our private CCB area for storing accept information */ 74 #define ccb_type ppriv_field0 75 #define ccb_descr ppriv_ptr1 76 77 /* We stick a pointer to the originating accept TIO in each continue I/O CCB */ 78 #define ccb_atio ppriv_ptr1 79 80 TAILQ_HEAD(ccb_queue, ccb_hdr); 81 82 struct targbh_softc { 83 struct ccb_queue pending_queue; 84 struct ccb_queue work_queue; 85 struct ccb_queue unknown_atio_queue; 86 struct devstat device_stats; 87 targbh_state state; 88 targbh_flags flags; 89 u_int init_level; 90 u_int inq_data_len; 91 struct ccb_accept_tio *accept_tio_list; 92 struct ccb_hdr_slist immed_notify_slist; 93 }; 94 95 struct targbh_cmd_desc { 96 struct ccb_accept_tio* atio_link; 97 u_int data_resid; /* How much left to transfer */ 98 u_int data_increment;/* Amount to send before next disconnect */ 99 void* data; /* The data. Can be from backing_store or not */ 100 void* backing_store;/* Backing store allocated for this descriptor*/ 101 u_int max_size; /* Size of backing_store */ 102 u_int32_t timeout; 103 u_int8_t status; /* Status to return to initiator */ 104 }; 105 106 static struct scsi_inquiry_data no_lun_inq_data = 107 { 108 T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0, 109 /* version */2, /* format version */2 110 }; 111 112 static struct scsi_sense_data no_lun_sense_data = 113 { 114 SSD_CURRENT_ERROR|SSD_ERRCODE_VALID, 115 0, 116 SSD_KEY_NOT_READY, 117 { 0, 0, 0, 0 }, 118 /*extra_len*/offsetof(struct scsi_sense_data, fru) 119 - offsetof(struct scsi_sense_data, extra_len), 120 { 0, 0, 0, 0 }, 121 /* Logical Unit Not Supported */ 122 /*ASC*/0x25, /*ASCQ*/0 123 }; 124 125 static const int request_sense_size = offsetof(struct scsi_sense_data, fru); 126 127 static periph_init_t targbhinit; 128 static void targbhasync(void *callback_arg, u_int32_t code, 129 struct cam_path *path, void *arg); 130 static cam_status targbhenlun(struct cam_periph *periph); 131 static cam_status targbhdislun(struct cam_periph *periph); 132 static periph_ctor_t targbhctor; 133 static periph_dtor_t targbhdtor; 134 static periph_start_t targbhstart; 135 static void targbhdone(struct cam_periph *periph, 136 union ccb *done_ccb); 137 #ifdef NOTYET 138 static int targbherror(union ccb *ccb, u_int32_t cam_flags, 139 u_int32_t sense_flags); 140 #endif 141 static struct targbh_cmd_desc* targbhallocdescr(void); 142 static void targbhfreedescr(struct targbh_cmd_desc *buf); 143 144 static struct periph_driver targbhdriver = 145 { 146 targbhinit, "targbh", 147 TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0 148 }; 149 150 DATA_SET(periphdriver_set, targbhdriver); 151 152 static void 153 targbhinit(void) 154 { 155 cam_status status; 156 struct cam_path *path; 157 158 /* 159 * Install a global async callback. This callback will 160 * receive async callbacks like "new path registered". 161 */ 162 status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID, 163 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 164 165 if (status == CAM_REQ_CMP) { 166 struct ccb_setasync csa; 167 168 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); 169 csa.ccb_h.func_code = XPT_SASYNC_CB; 170 csa.event_enable = AC_PATH_REGISTERED; 171 csa.callback = targbhasync; 172 csa.callback_arg = NULL; 173 xpt_action((union ccb *)&csa); 174 status = csa.ccb_h.status; 175 xpt_free_path(path); 176 } 177 178 if (status != CAM_REQ_CMP) { 179 printf("targbh: Failed to attach master async callback " 180 "due to status 0x%x!\n", status); 181 } 182 } 183 184 static void 185 targbhasync(void *callback_arg, u_int32_t code, 186 struct cam_path *path, void *arg) 187 { 188 struct cam_periph *periph; 189 190 periph = (struct cam_periph *)callback_arg; 191 switch (code) { 192 case AC_PATH_REGISTERED: 193 { 194 struct ccb_pathinq *cpi; 195 struct cam_path *new_path; 196 cam_status status; 197 198 cpi = (struct ccb_pathinq *)arg; 199 200 /* Only attach to controllers that support target mode */ 201 if ((cpi->target_sprt & PIT_PROCESSOR) == 0) 202 break; 203 204 /* 205 * Allocate a peripheral instance for 206 * this target instance. 207 */ 208 status = xpt_create_path(&new_path, NULL, 209 xpt_path_path_id(path), 210 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD); 211 if (status != CAM_REQ_CMP) { 212 printf("targbhasync: Unable to create path " 213 "due to status 0x%x\n", status); 214 break; 215 } 216 status = cam_periph_alloc(targbhctor, NULL, targbhdtor, 217 targbhstart, 218 "targbh", CAM_PERIPH_BIO, 219 new_path, targbhasync, 220 AC_PATH_REGISTERED, 221 cpi); 222 xpt_free_path(new_path); 223 if (status != CAM_REQ_CMP 224 && status != CAM_REQ_INPROG) 225 printf("targbhasync: Unable to allocate new periph " 226 "due to status 0x%x\n", status); 227 break; 228 } 229 case AC_PATH_DEREGISTERED: 230 { 231 targbhdislun(periph); 232 break; 233 } 234 default: 235 break; 236 } 237 } 238 239 /* Attempt to enable our lun */ 240 static cam_status 241 targbhenlun(struct cam_periph *periph) 242 { 243 union ccb immed_ccb; 244 struct targbh_softc *softc; 245 cam_status status; 246 int i; 247 248 softc = (struct targbh_softc *)periph->softc; 249 250 if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0) 251 return (CAM_REQ_CMP); 252 253 xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1); 254 immed_ccb.ccb_h.func_code = XPT_EN_LUN; 255 256 /* Don't need support for any vendor specific commands */ 257 immed_ccb.cel.grp6_len = 0; 258 immed_ccb.cel.grp7_len = 0; 259 immed_ccb.cel.enable = 1; 260 xpt_action(&immed_ccb); 261 status = immed_ccb.ccb_h.status; 262 if (status != CAM_REQ_CMP) { 263 xpt_print_path(periph->path); 264 printf("targbhenlun - Enable Lun Rejected with status 0x%x\n", 265 status); 266 return (status); 267 } 268 269 softc->flags |= TARGBH_FLAG_LUN_ENABLED; 270 271 /* 272 * Build up a buffer of accept target I/O 273 * operations for incoming selections. 274 */ 275 for (i = 0; i < MAX_ACCEPT; i++) { 276 struct ccb_accept_tio *atio; 277 278 atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF, 279 M_NOWAIT); 280 if (atio == NULL) { 281 status = CAM_RESRC_UNAVAIL; 282 break; 283 } 284 285 atio->ccb_h.ccb_descr = targbhallocdescr(); 286 287 if (atio->ccb_h.ccb_descr == NULL) { 288 free(atio, M_DEVBUF); 289 status = CAM_RESRC_UNAVAIL; 290 break; 291 } 292 293 xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1); 294 atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; 295 atio->ccb_h.cbfcnp = targbhdone; 296 xpt_action((union ccb *)atio); 297 status = atio->ccb_h.status; 298 if (status != CAM_REQ_INPROG) { 299 targbhfreedescr(atio->ccb_h.ccb_descr); 300 free(atio, M_DEVBUF); 301 break; 302 } 303 ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link = 304 softc->accept_tio_list; 305 softc->accept_tio_list = atio; 306 } 307 308 if (i == 0) { 309 xpt_print_path(periph->path); 310 printf("targbhenlun - Could not allocate accept tio CCBs: " 311 "status = 0x%x\n", status); 312 targbhdislun(periph); 313 return (CAM_REQ_CMP_ERR); 314 } 315 316 /* 317 * Build up a buffer of immediate notify CCBs 318 * so the SIM can tell us of asynchronous target mode events. 319 */ 320 for (i = 0; i < MAX_ACCEPT; i++) { 321 struct ccb_immed_notify *inot; 322 323 inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF, 324 M_NOWAIT); 325 326 if (inot == NULL) { 327 status = CAM_RESRC_UNAVAIL; 328 break; 329 } 330 331 xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1); 332 inot->ccb_h.func_code = XPT_IMMED_NOTIFY; 333 inot->ccb_h.cbfcnp = targbhdone; 334 xpt_action((union ccb *)inot); 335 status = inot->ccb_h.status; 336 if (status != CAM_REQ_INPROG) { 337 free(inot, M_DEVBUF); 338 break; 339 } 340 SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h, 341 periph_links.sle); 342 } 343 344 if (i == 0) { 345 xpt_print_path(periph->path); 346 printf("targbhenlun - Could not allocate immediate notify " 347 "CCBs: status = 0x%x\n", status); 348 targbhdislun(periph); 349 return (CAM_REQ_CMP_ERR); 350 } 351 352 return (CAM_REQ_CMP); 353 } 354 355 static cam_status 356 targbhdislun(struct cam_periph *periph) 357 { 358 union ccb ccb; 359 struct targbh_softc *softc; 360 struct ccb_accept_tio* atio; 361 struct ccb_hdr *ccb_h; 362 363 softc = (struct targbh_softc *)periph->softc; 364 if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0) 365 return CAM_REQ_CMP; 366 367 /* XXX Block for Continue I/O completion */ 368 369 /* Kill off all ACCECPT and IMMEDIATE CCBs */ 370 while ((atio = softc->accept_tio_list) != NULL) { 371 372 softc->accept_tio_list = 373 ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link; 374 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 375 ccb.cab.ccb_h.func_code = XPT_ABORT; 376 ccb.cab.abort_ccb = (union ccb *)atio; 377 xpt_action(&ccb); 378 } 379 380 while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) { 381 SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle); 382 xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1); 383 ccb.cab.ccb_h.func_code = XPT_ABORT; 384 ccb.cab.abort_ccb = (union ccb *)ccb_h; 385 xpt_action(&ccb); 386 } 387 388 /* 389 * Dissable this lun. 390 */ 391 xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1); 392 ccb.cel.ccb_h.func_code = XPT_EN_LUN; 393 ccb.cel.enable = 0; 394 xpt_action(&ccb); 395 396 if (ccb.cel.ccb_h.status != CAM_REQ_CMP) 397 printf("targbhdislun - Disabling lun on controller failed " 398 "with status 0x%x\n", ccb.cel.ccb_h.status); 399 else 400 softc->flags &= ~TARGBH_FLAG_LUN_ENABLED; 401 return (ccb.cel.ccb_h.status); 402 } 403 404 static cam_status 405 targbhctor(struct cam_periph *periph, void *arg) 406 { 407 struct ccb_pathinq *cpi; 408 struct targbh_softc *softc; 409 410 cpi = (struct ccb_pathinq *)arg; 411 412 /* Allocate our per-instance private storage */ 413 softc = (struct targbh_softc *)malloc(sizeof(*softc), 414 M_DEVBUF, M_NOWAIT); 415 if (softc == NULL) { 416 printf("targctor: unable to malloc softc\n"); 417 return (CAM_REQ_CMP_ERR); 418 } 419 420 bzero(softc, sizeof(*softc)); 421 TAILQ_INIT(&softc->pending_queue); 422 TAILQ_INIT(&softc->work_queue); 423 softc->accept_tio_list = NULL; 424 SLIST_INIT(&softc->immed_notify_slist); 425 softc->state = TARGBH_STATE_NORMAL; 426 periph->softc = softc; 427 softc->init_level++; 428 429 return (targbhenlun(periph)); 430 } 431 432 static void 433 targbhdtor(struct cam_periph *periph) 434 { 435 struct targbh_softc *softc; 436 437 softc = (struct targbh_softc *)periph->softc; 438 439 softc->state = TARGBH_STATE_TEARDOWN; 440 441 targbhdislun(periph); 442 443 switch (softc->init_level) { 444 default: 445 /* FALLTHROUGH */ 446 case 1: 447 free(softc, M_DEVBUF); 448 break; 449 case 0: 450 panic("targdtor - impossible init level");; 451 } 452 } 453 454 static void 455 targbhstart(struct cam_periph *periph, union ccb *start_ccb) 456 { 457 struct targbh_softc *softc; 458 struct ccb_hdr *ccbh; 459 struct ccb_accept_tio *atio; 460 struct targbh_cmd_desc *desc; 461 struct ccb_scsiio *csio; 462 ccb_flags flags; 463 int s; 464 465 softc = (struct targbh_softc *)periph->softc; 466 467 s = splbio(); 468 ccbh = TAILQ_FIRST(&softc->work_queue); 469 if (periph->immediate_priority <= periph->pinfo.priority) { 470 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING; 471 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h, 472 periph_links.sle); 473 periph->immediate_priority = CAM_PRIORITY_NONE; 474 splx(s); 475 wakeup(&periph->ccb_list); 476 } else if (ccbh == NULL) { 477 splx(s); 478 xpt_release_ccb(start_ccb); 479 } else { 480 TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe); 481 TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh, 482 periph_links.tqe); 483 splx(s); 484 atio = (struct ccb_accept_tio*)ccbh; 485 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 486 487 /* Is this a tagged request? */ 488 flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK); 489 490 csio = &start_ccb->csio; 491 /* 492 * If we are done with the transaction, tell the 493 * controller to send status and perform a CMD_CMPLT. 494 * If we have associated sense data, see if we can 495 * send that too. 496 */ 497 if (desc->data_resid == desc->data_increment) { 498 flags |= CAM_SEND_STATUS; 499 if (atio->sense_len) { 500 csio->sense_len = atio->sense_len; 501 csio->sense_data = atio->sense_data; 502 flags |= CAM_SEND_SENSE; 503 } 504 505 } 506 507 cam_fill_ctio(csio, 508 /*retries*/2, 509 targbhdone, 510 flags, 511 (flags & CAM_TAG_ACTION_VALID)? 512 MSG_SIMPLE_Q_TAG : 0, 513 atio->tag_id, 514 atio->init_id, 515 desc->status, 516 /*data_ptr*/desc->data_increment == 0 517 ? NULL : desc->data, 518 /*dxfer_len*/desc->data_increment, 519 /*timeout*/desc->timeout); 520 521 /* Override our wildcard attachment */ 522 start_ccb->ccb_h.target_id = atio->ccb_h.target_id; 523 start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun; 524 525 start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ; 526 start_ccb->ccb_h.ccb_atio = atio; 527 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 528 ("Sending a CTIO\n")); 529 xpt_action(start_ccb); 530 s = splbio(); 531 ccbh = TAILQ_FIRST(&softc->work_queue); 532 splx(s); 533 } 534 if (ccbh != NULL) 535 xpt_schedule(periph, /*priority*/1); 536 } 537 538 static void 539 targbhdone(struct cam_periph *periph, union ccb *done_ccb) 540 { 541 struct targbh_softc *softc; 542 543 softc = (struct targbh_softc *)periph->softc; 544 545 if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) { 546 /* Caller will release the CCB */ 547 wakeup(&done_ccb->ccb_h.cbfcnp); 548 return; 549 } 550 551 switch (done_ccb->ccb_h.func_code) { 552 case XPT_ACCEPT_TARGET_IO: 553 { 554 struct ccb_accept_tio *atio; 555 struct targbh_cmd_desc *descr; 556 u_int8_t *cdb; 557 558 atio = &done_ccb->atio; 559 descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr; 560 cdb = atio->cdb_io.cdb_bytes; 561 if (softc->state == TARGBH_STATE_TEARDOWN 562 || atio->ccb_h.status == CAM_REQ_ABORTED) { 563 targbhfreedescr(descr); 564 free(done_ccb, M_DEVBUF); 565 return; 566 } 567 568 /* 569 * Determine the type of incoming command and 570 * setup our buffer for a response. 571 */ 572 switch (cdb[0]) { 573 case INQUIRY: 574 { 575 struct scsi_inquiry *inq; 576 577 inq = (struct scsi_inquiry *)cdb; 578 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 579 ("Saw an inquiry!\n")); 580 /* 581 * Validate the command. We don't 582 * support any VPD pages, so complain 583 * if EVPD is set. 584 */ 585 if ((inq->byte2 & SI_EVPD) != 0 586 || inq->page_code != 0) { 587 atio->ccb_h.flags &= ~CAM_DIR_MASK; 588 atio->ccb_h.flags |= CAM_DIR_NONE; 589 /* 590 * This needs to have other than a 591 * no_lun_sense_data response. 592 */ 593 atio->sense_data = no_lun_sense_data; 594 atio->sense_len = sizeof(no_lun_sense_data); 595 descr->data_resid = 0; 596 descr->data_increment = 0; 597 descr->status = SCSI_STATUS_CHECK_COND; 598 break; 599 } 600 /* 601 * Direction is always relative 602 * to the initator. 603 */ 604 atio->ccb_h.flags &= ~CAM_DIR_MASK; 605 atio->ccb_h.flags |= CAM_DIR_IN; 606 descr->data = &no_lun_inq_data; 607 descr->data_resid = MIN(sizeof(no_lun_inq_data), 608 SCSI_CDB6_LEN(inq->length)); 609 descr->data_increment = descr->data_resid; 610 descr->timeout = 5 * 1000; 611 descr->status = SCSI_STATUS_OK; 612 break; 613 } 614 case REQUEST_SENSE: 615 { 616 struct scsi_request_sense *rsense; 617 618 rsense = (struct scsi_request_sense *)cdb; 619 /* Refer to static sense data */ 620 atio->ccb_h.flags &= ~CAM_DIR_MASK; 621 atio->ccb_h.flags |= CAM_DIR_IN; 622 descr->data = &no_lun_sense_data; 623 descr->data_resid = request_sense_size; 624 descr->data_resid = MIN(descr->data_resid, 625 SCSI_CDB6_LEN(rsense->length)); 626 descr->data_increment = descr->data_resid; 627 descr->timeout = 5 * 1000; 628 descr->status = SCSI_STATUS_OK; 629 break; 630 } 631 default: 632 /* Constant CA, tell initiator */ 633 /* Direction is always relative to the initator */ 634 atio->ccb_h.flags &= ~CAM_DIR_MASK; 635 atio->ccb_h.flags |= CAM_DIR_NONE; 636 atio->sense_data = no_lun_sense_data; 637 atio->sense_len = sizeof (no_lun_sense_data); 638 descr->data_resid = 0; 639 descr->data_increment = 0; 640 descr->timeout = 5 * 1000; 641 descr->status = SCSI_STATUS_CHECK_COND; 642 break; 643 } 644 645 /* Queue us up to receive a Continue Target I/O ccb. */ 646 TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h, 647 periph_links.tqe); 648 xpt_schedule(periph, /*priority*/1); 649 break; 650 } 651 case XPT_CONT_TARGET_IO: 652 { 653 struct ccb_accept_tio *atio; 654 struct targbh_cmd_desc *desc; 655 656 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 657 ("Received completed CTIO\n")); 658 atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio; 659 desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr; 660 661 TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h, 662 periph_links.tqe); 663 664 /* 665 * We could check for CAM_SENT_SENSE bein set here, 666 * but since we're not maintaining any CA/UA state, 667 * there's no point. 668 */ 669 atio->sense_len = 0; 670 done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE; 671 done_ccb->ccb_h.status &= ~CAM_SENT_SENSE; 672 673 /* XXX Check for errors */ 674 desc->data_resid -= desc->data_increment; 675 xpt_release_ccb(done_ccb); 676 if (softc->state != TARGBH_STATE_TEARDOWN) { 677 678 /* 679 * Send the original accept TIO back to the 680 * controller to handle more work. 681 */ 682 CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 683 ("Returning ATIO to target\n")); 684 /* Restore wildcards */ 685 atio->ccb_h.target_id = CAM_TARGET_WILDCARD; 686 atio->ccb_h.target_lun = CAM_LUN_WILDCARD; 687 xpt_action((union ccb *)atio); 688 break; 689 } else { 690 targbhfreedescr(desc); 691 free(atio, M_DEVBUF); 692 } 693 break; 694 } 695 case XPT_IMMED_NOTIFY: 696 { 697 if (softc->state == TARGBH_STATE_TEARDOWN 698 || done_ccb->ccb_h.status == CAM_REQ_ABORTED) { 699 printf("Freed an immediate notify\n"); 700 free(done_ccb, M_DEVBUF); 701 } 702 break; 703 } 704 default: 705 panic("targbhdone: Unexpected ccb opcode"); 706 break; 707 } 708 } 709 710 #ifdef NOTYET 711 static int 712 targbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags) 713 { 714 return 0; 715 } 716 #endif 717 718 static struct targbh_cmd_desc* 719 targbhallocdescr() 720 { 721 struct targbh_cmd_desc* descr; 722 723 /* Allocate the targbh_descr structure */ 724 descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr), 725 M_DEVBUF, M_NOWAIT); 726 if (descr == NULL) 727 return (NULL); 728 729 bzero(descr, sizeof(*descr)); 730 731 /* Allocate buffer backing store */ 732 descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT); 733 if (descr->backing_store == NULL) { 734 free(descr, M_DEVBUF); 735 return (NULL); 736 } 737 descr->max_size = MAX_BUF_SIZE; 738 return (descr); 739 } 740 741 static void 742 targbhfreedescr(struct targbh_cmd_desc *descr) 743 { 744 free(descr->backing_store, M_DEVBUF); 745 free(descr, M_DEVBUF); 746 } 747