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