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