scsi_targ_bh.c revision 60041
1139826Simp/*
253541Sshin * Implementation of the Target Mode 'Black Hole device' for CAM.
353541Sshin *
453541Sshin * Copyright (c) 1999 Justin T. Gibbs.
553541Sshin * All rights reserved.
653541Sshin *
753541Sshin * Redistribution and use in source and binary forms, with or without
853541Sshin * modification, are permitted provided that the following conditions
953541Sshin * are met:
1053541Sshin * 1. Redistributions of source code must retain the above copyright
1153541Sshin *    notice, this list of conditions, and the following disclaimer,
1253541Sshin *    without modification, immediately at the beginning of the file.
1353541Sshin * 2. The name of the author may not be used to endorse or promote products
1453541Sshin *    derived from this software without specific prior written permission.
1553541Sshin *
1653541Sshin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1753541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1853541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1953541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2053541Sshin * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2153541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2253541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2353541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2453541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2553541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2653541Sshin * SUCH DAMAGE.
2753541Sshin *
28174510Sobrien * $FreeBSD: head/sys/cam/scsi/scsi_targ_bh.c 60041 2000-05-05 09:59:14Z phk $
29174510Sobrien */
3053541Sshin#include <stddef.h>	/* For offsetof */
3153541Sshin
32139826Simp#include <sys/param.h>
3353541Sshin#include <sys/queue.h>
3453541Sshin#include <sys/systm.h>
3553541Sshin#include <sys/kernel.h>
3653541Sshin#include <sys/types.h>
3753541Sshin#include <sys/bio.h>
3853541Sshin#include <sys/conf.h>
3953541Sshin#include <sys/devicestat.h>
4053541Sshin#include <sys/malloc.h>
4153541Sshin#include <sys/uio.h>
4253541Sshin
4353541Sshin#include <cam/cam.h>
4453541Sshin#include <cam/cam_ccb.h>
4553541Sshin#include <cam/cam_extend.h>
4653541Sshin#include <cam/cam_periph.h>
4753541Sshin#include <cam/cam_queue.h>
4853541Sshin#include <cam/cam_xpt_periph.h>
4953541Sshin#include <cam/cam_debug.h>
5053541Sshin
5153541Sshin#include <cam/scsi/scsi_all.h>
5253541Sshin#include <cam/scsi/scsi_message.h>
5353541Sshin
5453541Sshintypedef enum {
5553541Sshin	TARGBH_STATE_NORMAL,
5653541Sshin	TARGBH_STATE_EXCEPTION,
5753541Sshin	TARGBH_STATE_TEARDOWN
5853541Sshin} targbh_state;
5953541Sshin
6053541Sshintypedef enum {
6153541Sshin	TARGBH_FLAG_NONE	 = 0x00,
6253541Sshin	TARGBH_FLAG_LUN_ENABLED	 = 0x01
63174510Sobrien} targbh_flags;
64174510Sobrien
65174510Sobrientypedef enum {
6662587Sitojun	TARGBH_CCB_WORKQ,
6762587Sitojun	TARGBH_CCB_WAITING
6855009Sshin} targbh_ccb_types;
6953541Sshin
7053541Sshin#define MAX_ACCEPT	8
7195759Stanimura#define MAX_IMMEDIATE	16
72193066Sjamie#define MAX_BUF_SIZE	256	/* Max inquiry/sense/mode page transfer */
7395759Stanimura
7495759Stanimura#define MIN(a, b) ((a > b) ? b : a)
7578064Sume
7653541Sshin/* Offsets into our private CCB area for storing accept information */
77196019Srwatson#define ccb_type	ppriv_field0
7853541Sshin#define ccb_descr	ppriv_ptr1
7995759Stanimura
8053541Sshin/* We stick a pointer to the originating accept TIO in each continue I/O CCB */
8153541Sshin#define ccb_atio	ppriv_ptr1
8295759Stanimura
8395759StanimuraTAILQ_HEAD(ccb_queue, ccb_hdr);
8495759Stanimura
8553541Sshinstruct targbh_softc {
8653541Sshin	struct		ccb_queue pending_queue;
8753541Sshin	struct		ccb_queue work_queue;
8853541Sshin	struct		ccb_queue unknown_atio_queue;
89186119Sqingli	struct		devstat device_stats;
9053541Sshin	targbh_state	state;
9195759Stanimura	targbh_flags	flags;
92185571Sbz	u_int		init_level;
9353541Sshin	u_int		inq_data_len;
9453541Sshin	struct		ccb_accept_tio *accept_tio_list;
9595759Stanimura	struct		ccb_hdr_slist immed_notify_slist;
9653541Sshin};
9762587Sitojun
9895759Stanimurastruct targbh_cmd_desc {
99122922Sandre	struct	  ccb_accept_tio* atio_link;
100185571Sbz	u_int	  data_resid;	/* How much left to transfer */
10195759Stanimura	u_int	  data_increment;/* Amount to send before next disconnect */
10295759Stanimura	void*	  data;		/* The data. Can be from backing_store or not */
10395759Stanimura	void*	  backing_store;/* Backing store allocated for this descriptor*/
10453541Sshin	u_int	  max_size;	/* Size of backing_store */
105148385Sume	u_int32_t timeout;
10653541Sshin	u_int8_t  status;	/* Status to return to initiator */
10753541Sshin};
10853541Sshin
109171167Sgnnstatic struct scsi_inquiry_data no_lun_inq_data =
110105199Ssam{
111105199Ssam	T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
112105199Ssam	/* version */2, /* format version */2
113105199Ssam};
11462587Sitojun
115185348Szecstatic struct scsi_sense_data no_lun_sense_data =
116195699Srwatson{
117195699Srwatson	SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
118195699Srwatson	0,
119195699Srwatson	SSD_KEY_NOT_READY,
12053541Sshin	{ 0, 0, 0, 0 },
121195727Srwatson	/*extra_len*/offsetof(struct scsi_sense_data, fru)
122195727Srwatson                   - offsetof(struct scsi_sense_data, extra_len),
123195727Srwatson	{ 0, 0, 0, 0 },
124195727Srwatson	/* Logical Unit Not Supported */
125185088Szec	/*ASC*/0x25, /*ASCQ*/0
126195699Srwatson};
127195699Srwatson
128195699Srwatsonstatic const int request_sense_size = offsetof(struct scsi_sense_data, fru);
129195699Srwatson
130195727Srwatsonstatic periph_init_t	targbhinit;
131195727Srwatsonstatic void		targbhasync(void *callback_arg, u_int32_t code,
132195699Srwatson				    struct cam_path *path, void *arg);
133175162Sobrienstatic cam_status	targbhenlun(struct cam_periph *periph);
134175162Sobrienstatic cam_status	targbhdislun(struct cam_periph *periph);
135175162Sobrienstatic periph_ctor_t	targbhctor;
13662587Sitojunstatic periph_dtor_t	targbhdtor;
13762587Sitojunstatic periph_start_t	targbhstart;
138175162Sobrienstatic void		targbhdone(struct cam_periph *periph,
139175162Sobrien				   union ccb *done_ccb);
140175162Sobrien#ifdef NOTYET
14162587Sitojunstatic  int		targbherror(union ccb *ccb, u_int32_t cam_flags,
142148892Sume				    u_int32_t sense_flags);
14362587Sitojun#endif
14462587Sitojunstatic struct targbh_cmd_desc*	targbhallocdescr(void);
145175162Sobrienstatic void		targbhfreedescr(struct targbh_cmd_desc *buf);
14653541Sshin
14753541Sshinstatic struct periph_driver targbhdriver =
14853541Sshin{
149171259Sdelphij	targbhinit, "targbh",
15053541Sshin	TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
151171259Sdelphij};
152185088Szec
15353541SshinDATA_SET(periphdriver_set, targbhdriver);
15453541Sshin
155196039Srwatsonstatic void
156196039Srwatsontargbhinit(void)
157196039Srwatson{
158196039Srwatson	cam_status status;
159196039Srwatson	struct cam_path *path;
160196039Srwatson
161196039Srwatson	/*
162196039Srwatson	 * Install a global async callback.  This callback will
163196039Srwatson	 * receive async callbacks like "new path registered".
164196039Srwatson	 */
165196039Srwatson	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
166196039Srwatson				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
167196039Srwatson
168196039Srwatson	if (status == CAM_REQ_CMP) {
16962587Sitojun		struct ccb_setasync csa;
170171259Sdelphij
17162587Sitojun		xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
17278064Sume		csa.ccb_h.func_code = XPT_SASYNC_CB;
17362587Sitojun		csa.event_enable = AC_PATH_REGISTERED;
17462587Sitojun		csa.callback = targbhasync;
17562587Sitojun		csa.callback_arg = NULL;
17662587Sitojun		xpt_action((union ccb *)&csa);
17762587Sitojun		status = csa.ccb_h.status;
17862587Sitojun		xpt_free_path(path);
17962587Sitojun        }
18062587Sitojun
18162587Sitojun	if (status != CAM_REQ_CMP) {
18262587Sitojun		printf("targbh: Failed to attach master async callback "
18362587Sitojun		       "due to status 0x%x!\n", status);
18462587Sitojun	}
18562587Sitojun}
18662587Sitojun
18762587Sitojunstatic void
18862587Sitojuntargbhasync(void *callback_arg, u_int32_t code,
18962587Sitojun	    struct cam_path *path, void *arg)
19062587Sitojun{
19162587Sitojun	struct cam_periph *periph;
19262587Sitojun
19362587Sitojun	periph = (struct cam_periph *)callback_arg;
19462587Sitojun	switch (code) {
19562587Sitojun	case AC_PATH_REGISTERED:
19678064Sume	{
19762587Sitojun		struct ccb_pathinq *cpi;
19862587Sitojun		struct cam_path *new_path;
19962587Sitojun		cam_status status;
20062587Sitojun
20162587Sitojun		cpi = (struct ccb_pathinq *)arg;
20262587Sitojun
20362587Sitojun		/* Only attach to controllers that support target mode */
20462587Sitojun		if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
20562587Sitojun			break;
20678064Sume
20762587Sitojun		/*
20862587Sitojun		 * Allocate a peripheral instance for
20962587Sitojun		 * this target instance.
21062587Sitojun		 */
21162587Sitojun		status = xpt_create_path(&new_path, NULL,
21262587Sitojun					 xpt_path_path_id(path),
21362587Sitojun					 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
21462587Sitojun		if (status != CAM_REQ_CMP) {
21562587Sitojun			printf("targbhasync: Unable to create path "
21662587Sitojun				"due to status 0x%x\n", status);
21762587Sitojun			break;
21862587Sitojun		}
21962587Sitojun		status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
22062587Sitojun					  targbhstart,
22162587Sitojun					  "targbh", CAM_PERIPH_BIO,
22262587Sitojun					  new_path, targbhasync,
22362587Sitojun					  AC_PATH_REGISTERED,
22462587Sitojun					  cpi);
22553541Sshin		xpt_free_path(new_path);
226148385Sume		if (status != CAM_REQ_CMP
227148385Sume		 && status != CAM_REQ_INPROG)
228148385Sume			printf("targbhasync: Unable to allocate new periph "
229148385Sume			       "due to status 0x%x\n", status);
230171259Sdelphij		break;
231171259Sdelphij	}
232148385Sume	case AC_PATH_DEREGISTERED:
233148385Sume	{
234148385Sume		targbhdislun(periph);
235148385Sume		break;
236148385Sume	}
237148385Sume	default:
238148385Sume		break;
239148385Sume	}
240148385Sume}
241148385Sume
242148385Sume/* Attempt to enable our lun */
243148385Sumestatic cam_status
244148385Sumetargbhenlun(struct cam_periph *periph)
245148385Sume{
246148385Sume	union ccb immed_ccb;
247148385Sume	struct targbh_softc *softc;
248148385Sume	cam_status status;
249148385Sume	int i;
250148385Sume
251148385Sume	softc = (struct targbh_softc *)periph->softc;
252148385Sume
253148385Sume	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
254148385Sume		return (CAM_REQ_CMP);
255148385Sume
256148385Sume	xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
257148385Sume	immed_ccb.ccb_h.func_code = XPT_EN_LUN;
258148385Sume
25953541Sshin	/* Don't need support for any vendor specific commands */
26053541Sshin	immed_ccb.cel.grp6_len = 0;
26153541Sshin	immed_ccb.cel.grp7_len = 0;
262171259Sdelphij	immed_ccb.cel.enable = 1;
26353541Sshin	xpt_action(&immed_ccb);
26453541Sshin	status = immed_ccb.ccb_h.status;
26553541Sshin	if (status != CAM_REQ_CMP) {
26662587Sitojun		xpt_print_path(periph->path);
26753541Sshin		printf("targbhenlun - Enable Lun Rejected for status 0x%x\n",
26862587Sitojun		       status);
26953541Sshin		return (status);
270190964Srwatson	}
27153541Sshin
27262587Sitojun	softc->flags |= TARGBH_FLAG_LUN_ENABLED;
273181803Sbz
27462587Sitojun	/*
27562587Sitojun	 * Build up a buffer of accept target I/O
27662587Sitojun	 * operations for incoming selections.
277190964Srwatson	 */
27853541Sshin	for (i = 0; i < MAX_ACCEPT; i++) {
27962587Sitojun		struct ccb_accept_tio *atio;
28062587Sitojun
28153541Sshin		atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF,
28262587Sitojun						      M_NOWAIT);
28362587Sitojun		if (atio == NULL) {
28462587Sitojun			status = CAM_RESRC_UNAVAIL;
28562587Sitojun			break;
28662587Sitojun		}
28762587Sitojun
28862587Sitojun		atio->ccb_h.ccb_descr = targbhallocdescr();
28962587Sitojun
29062587Sitojun		if (atio->ccb_h.ccb_descr == NULL) {
29153541Sshin			free(atio, M_DEVBUF);
29253541Sshin			status = CAM_RESRC_UNAVAIL;
29353541Sshin			break;
294121472Sume		}
295121472Sume
296121472Sume		xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
297121472Sume		atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
298121472Sume		atio->ccb_h.cbfcnp = targbhdone;
299201688Sbz		xpt_action((union ccb *)atio);
300121472Sume		status = atio->ccb_h.status;
301121472Sume		if (status != CAM_REQ_INPROG) {
302121472Sume			targbhfreedescr(atio->ccb_h.ccb_descr);
30353541Sshin			free(atio, M_DEVBUF);
30453541Sshin			break;
30553541Sshin		}
30653541Sshin		((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
30753541Sshin		    softc->accept_tio_list;
30853541Sshin		softc->accept_tio_list = atio;
30953541Sshin	}
31053541Sshin
311121472Sume	if (i == 0) {
312121472Sume		xpt_print_path(periph->path);
313121472Sume		printf("targbhenlun - Could not allocate accept tio CCBs: "
314121472Sume		       "status = 0x%x\n", status);
31553541Sshin		targbhdislun(periph);
31653541Sshin		return (CAM_REQ_CMP_ERR);
31753541Sshin	}
31853541Sshin
31953541Sshin	/*
32062587Sitojun	 * Build up a buffer of immediate notify CCBs
32162587Sitojun	 * so the SIM can tell us of asynchronous target mode events.
32253541Sshin	 */
32362587Sitojun	for (i = 0; i < MAX_ACCEPT; i++) {
32462587Sitojun		struct ccb_immed_notify *inot;
32562587Sitojun
32653541Sshin		inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF,
32753541Sshin						        M_NOWAIT);
32862587Sitojun
32962587Sitojun		if (inot == NULL) {
33062587Sitojun			status = CAM_RESRC_UNAVAIL;
33162587Sitojun			break;
33262587Sitojun		}
33362587Sitojun
33462587Sitojun		xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
335190964Srwatson		inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
33662587Sitojun		inot->ccb_h.cbfcnp = targbhdone;
33762587Sitojun		xpt_action((union ccb *)inot);
33862587Sitojun		status = inot->ccb_h.status;
33962587Sitojun		if (status != CAM_REQ_INPROG) {
34062587Sitojun			free(inot, M_DEVBUF);
34153541Sshin			break;
34262587Sitojun		}
34362587Sitojun		SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
34462587Sitojun				  periph_links.sle);
34553541Sshin	}
346190964Srwatson
34762587Sitojun	if (i == 0) {
34862587Sitojun		xpt_print_path(periph->path);
34962587Sitojun		printf("targbhenlun - Could not allocate immediate notify "
35053541Sshin		       "CCBs: status = 0x%x\n", status);
35162587Sitojun		targbhdislun(periph);
35262587Sitojun		return (CAM_REQ_CMP_ERR);
35353541Sshin	}
35453541Sshin
35553541Sshin	return (CAM_REQ_CMP);
35653541Sshin}
35753541Sshin
35853541Sshinstatic cam_status
359190964Srwatsontargbhdislun(struct cam_periph *periph)
36053541Sshin{
36153541Sshin	union ccb ccb;
36253541Sshin	struct targbh_softc *softc;
36353541Sshin	struct ccb_accept_tio* atio;
36453541Sshin	struct ccb_hdr *ccb_h;
36553541Sshin
36653541Sshin	softc = (struct targbh_softc *)periph->softc;
36753541Sshin	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
36853541Sshin		return CAM_REQ_CMP;
36953541Sshin
37062587Sitojun	/* XXX Block for Continue I/O completion */
371111119Simp
37262587Sitojun	/* Kill off all ACCECPT and IMMEDIATE CCBs */
37362587Sitojun	while ((atio = softc->accept_tio_list) != NULL) {
37453541Sshin
37578064Sume		softc->accept_tio_list =
37653541Sshin		    ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
37753541Sshin		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
37853541Sshin		ccb.cab.ccb_h.func_code = XPT_ABORT;
37953541Sshin		ccb.cab.abort_ccb = (union ccb *)atio;
38053541Sshin		xpt_action(&ccb);
38153541Sshin	}
38253541Sshin
383121315Sume	while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
384121315Sume		SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
38553541Sshin		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
38653541Sshin		ccb.cab.ccb_h.func_code = XPT_ABORT;
38753541Sshin		ccb.cab.abort_ccb = (union ccb *)ccb_h;
38853541Sshin		xpt_action(&ccb);
38953541Sshin	}
39053541Sshin
39178064Sume	/*
39278064Sume	 * Dissable this lun.
393148987Sume	 */
39478064Sume	xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
39578064Sume	ccb.cel.ccb_h.func_code = XPT_EN_LUN;
39678064Sume	ccb.cel.enable = 0;
39778064Sume	xpt_action(&ccb);
39878064Sume
39978064Sume	if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
400190964Srwatson		printf("targbhdislun - Disabling lun on controller failed "
40195023Ssuz		       "with status 0x%x\n", ccb.cel.ccb_h.status);
40262587Sitojun	else
40362587Sitojun		softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
40462587Sitojun	return (ccb.cel.ccb_h.status);
40562587Sitojun}
40662587Sitojun
407148987Sumestatic cam_status
40862587Sitojuntargbhctor(struct cam_periph *periph, void *arg)
40962587Sitojun{
41053541Sshin	struct ccb_pathinq *cpi;
41153541Sshin	struct targbh_softc *softc;
41253541Sshin
41353541Sshin	cpi = (struct ccb_pathinq *)arg;
41453541Sshin
41553541Sshin	/* Allocate our per-instance private storage */
416171259Sdelphij	softc = (struct targbh_softc *)malloc(sizeof(*softc),
41753541Sshin					      M_DEVBUF, M_NOWAIT);
41853541Sshin	if (softc == NULL) {
419192923Sbms		printf("targctor: unable to malloc softc\n");
42053541Sshin		return (CAM_REQ_CMP_ERR);
42153541Sshin	}
42253541Sshin
42353541Sshin	bzero(softc, sizeof(softc));
42453541Sshin	TAILQ_INIT(&softc->pending_queue);
425165118Sbz	TAILQ_INIT(&softc->work_queue);
42653541Sshin	softc->accept_tio_list = NULL;
427192923Sbms	SLIST_INIT(&softc->immed_notify_slist);
428192923Sbms	softc->state = TARGBH_STATE_NORMAL;
42962587Sitojun	periph->softc = softc;
43053541Sshin	softc->init_level++;
43195023Ssuz
43262587Sitojun	return (targbhenlun(periph));
43353541Sshin}
43453541Sshin
43553541Sshinstatic void
43653541Sshintargbhdtor(struct cam_periph *periph)
43753541Sshin{
43853541Sshin	struct targbh_softc *softc;
43953541Sshin
44053541Sshin	softc = (struct targbh_softc *)periph->softc;
441190964Srwatson
44253541Sshin	softc->state = TARGBH_STATE_TEARDOWN;
44353541Sshin
44453541Sshin	targbhdislun(periph);
44553541Sshin
446191672Sbms	switch (softc->init_level) {
447191672Sbms	default:
448191672Sbms		/* FALLTHROUGH */
449191672Sbms	case 1:
450192923Sbms		free(softc, M_DEVBUF);
451191672Sbms		break;
452191672Sbms	case 0:
453191672Sbms		panic("targdtor - impossible init level");;
454191672Sbms	}
455191672Sbms}
456191672Sbms
457191672Sbmsstatic void
458191672Sbmstargbhstart(struct cam_periph *periph, union ccb *start_ccb)
459191672Sbms{
460191672Sbms	struct targbh_softc *softc;
46153541Sshin	struct ccb_hdr *ccbh;
46253541Sshin	struct ccb_accept_tio *atio;
46362587Sitojun	struct targbh_cmd_desc *desc;
46453541Sshin	struct ccb_scsiio *csio;
46562587Sitojun	ccb_flags flags;
46662587Sitojun	int    s;
46762587Sitojun
468190964Srwatson	softc = (struct targbh_softc *)periph->softc;
46962587Sitojun
47062587Sitojun	s = splbio();
47162587Sitojun	ccbh = TAILQ_FIRST(&softc->work_queue);
47253541Sshin	if (periph->immediate_priority <= periph->pinfo.priority) {
47353541Sshin		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;
47453541Sshin		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
47578064Sume				  periph_links.sle);
47653541Sshin		periph->immediate_priority = CAM_PRIORITY_NONE;
477165118Sbz		splx(s);
478165118Sbz		wakeup(&periph->ccb_list);
479190964Srwatson	} else if (ccbh == NULL) {
48053541Sshin		splx(s);
48153541Sshin		xpt_release_ccb(start_ccb);
48253541Sshin	} else {
48383934Sbrooks		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
48453541Sshin		TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
48553541Sshin				  periph_links.tqe);
486148987Sume		splx(s);
48753541Sshin		atio = (struct ccb_accept_tio*)ccbh;
48853541Sshin		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
48953541Sshin
49053541Sshin		/* Is this a tagged request? */
49153541Sshin		flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
49253541Sshin
49353541Sshin		csio = &start_ccb->csio;
49453541Sshin		/*
49553541Sshin		 * If we are done with the transaction, tell the
49653541Sshin		 * controller to send status and perform a CMD_CMPLT.
49753541Sshin		 * If we have associated sense data, see if we can
49853541Sshin		 * send that too.
499190964Srwatson		 */
500192923Sbms		if (desc->data_resid == desc->data_increment) {
50153541Sshin			flags |= CAM_SEND_STATUS;
502192923Sbms			if (atio->sense_len) {
50353541Sshin				csio->sense_len = atio->sense_len;
50453541Sshin				csio->sense_data = atio->sense_data;
50553541Sshin				flags |= CAM_SEND_SENSE;
506192923Sbms			}
50753541Sshin
50853541Sshin		}
50953541Sshin
51053541Sshin		cam_fill_ctio(csio,
51153541Sshin			      /*retries*/2,
512192923Sbms			      targbhdone,
51362587Sitojun			      flags,
51462587Sitojun			      /*tag_action*/MSG_SIMPLE_Q_TAG,
51553541Sshin			      atio->tag_id,
51662587Sitojun			      atio->init_id,
51753541Sshin			      desc->status,
51862587Sitojun			      /*data_ptr*/desc->data_increment == 0
51962587Sitojun					  ? NULL : desc->data,
52062587Sitojun			      /*dxfer_len*/desc->data_increment,
52162587Sitojun			      /*timeout*/desc->timeout);
52253541Sshin
52353541Sshin		/* Override our wildcard attachment */
52453541Sshin		start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
52553541Sshin		start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
52653541Sshin
52753541Sshin		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
52853541Sshin		start_ccb->ccb_h.ccb_atio = atio;
52953541Sshin		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
53053541Sshin			  ("Sending a CTIO\n"));
53153541Sshin		xpt_action(start_ccb);
532192923Sbms		s = splbio();
53353541Sshin		ccbh = TAILQ_FIRST(&softc->work_queue);
534126194Sume		splx(s);
535126194Sume	}
53653541Sshin	if (ccbh != NULL)
53753541Sshin		xpt_schedule(periph, /*priority*/1);
53862587Sitojun}
53962587Sitojun
54062587Sitojunstatic void
54162587Sitojuntargbhdone(struct cam_periph *periph, union ccb *done_ccb)
54253541Sshin{
54353541Sshin	struct targbh_softc *softc;
54453541Sshin
54553541Sshin	softc = (struct targbh_softc *)periph->softc;
546192923Sbms
54753541Sshin	if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) {
54853541Sshin		/* Caller will release the CCB */
549151465Ssuz		wakeup(&done_ccb->ccb_h.cbfcnp);
550151465Ssuz		return;
55153541Sshin	}
552151465Ssuz
55353541Sshin	switch (done_ccb->ccb_h.func_code) {
55453541Sshin	case XPT_ACCEPT_TARGET_IO:
55553541Sshin	{
55653541Sshin		struct ccb_accept_tio *atio;
55753541Sshin		struct targbh_cmd_desc *descr;
55853541Sshin		u_int8_t *cdb;
55953541Sshin
56053541Sshin		atio = &done_ccb->atio;
561192923Sbms		descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
56253541Sshin		cdb = atio->cdb_io.cdb_bytes;
56353541Sshin		if (softc->state == TARGBH_STATE_TEARDOWN
56453541Sshin		 || atio->ccb_h.status == CAM_REQ_ABORTED) {
56553541Sshin			targbhfreedescr(descr);
56653541Sshin			free(done_ccb, M_DEVBUF);
56753541Sshin			return;
56853541Sshin		}
56953541Sshin
57053541Sshin		/*
57153541Sshin		 * Determine the type of incoming command and
57253541Sshin		 * setup our buffer for a response.
57353541Sshin		 */
57453541Sshin		switch (cdb[0]) {
57553541Sshin		case INQUIRY:
57653541Sshin		{
577192923Sbms			struct scsi_inquiry *inq;
57853541Sshin
57953541Sshin			inq = (struct scsi_inquiry *)cdb;
58053541Sshin			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
58153541Sshin				  ("Saw an inquiry!\n"));
58253541Sshin			/*
58353541Sshin			 * Validate the command.  We don't
58462587Sitojun			 * support any VPD pages, so complain
58562587Sitojun			 * if EVPD is set.
58653541Sshin			 */
58762587Sitojun			if ((inq->byte2 & SI_EVPD) != 0
588108741Ssam			 || inq->page_code != 0) {
58953541Sshin				atio->ccb_h.flags &= ~CAM_DIR_MASK;
590111119Simp				atio->ccb_h.flags |= CAM_DIR_NONE;
591111070Ssam				/*
592111070Ssam				 * This needs to have other than a
593111070Ssam				 * no_lun_sense_data response.
59462587Sitojun				 */
595111119Simp				atio->sense_data = no_lun_sense_data;
59662587Sitojun				atio->sense_len = sizeof (no_lun_sense_data);
59762587Sitojun				descr->data_resid = 0;
59862587Sitojun				descr->data_increment = 0;
59962587Sitojun				descr->status = SCSI_STATUS_CHECK_COND;
60062587Sitojun				break;
60153541Sshin			}
60253541Sshin			/*
60353541Sshin			 * Direction is always relative
60453541Sshin			 * to the initator.
60553541Sshin			 */
60653541Sshin			atio->ccb_h.flags &= ~CAM_DIR_MASK;
60753541Sshin			atio->ccb_h.flags |= CAM_DIR_IN;
60853541Sshin			descr->data = &no_lun_inq_data;
60953541Sshin			descr->data_resid = MIN(sizeof(no_lun_inq_data),
61053541Sshin						inq->length);
61153541Sshin			descr->data_increment = descr->data_resid;
61253541Sshin			descr->timeout = 5 * 1000;
61362587Sitojun			descr->status = SCSI_STATUS_OK;
614108741Ssam			break;
615108741Ssam		}
61653541Sshin		case REQUEST_SENSE:
617120891Sume		{
61862587Sitojun			struct scsi_request_sense *rsense;
61953541Sshin
62062587Sitojun			rsense = (struct scsi_request_sense *)cdb;
621108741Ssam			/* Refer to static sense data */
622108741Ssam			atio->ccb_h.flags &= ~CAM_DIR_MASK;
62362587Sitojun			atio->ccb_h.flags |= CAM_DIR_IN;
62453541Sshin			descr->data = &no_lun_sense_data;
62553541Sshin			descr->data_resid = request_sense_size;
626166046Sume			descr->data_resid = MIN(descr->data_resid,
627166046Sume						rsense->length);
62853541Sshin			descr->data_increment = descr->data_resid;
62953541Sshin			descr->timeout = 5 * 1000;
63053541Sshin			descr->status = SCSI_STATUS_OK;
63153541Sshin			break;
63253541Sshin		}
633190964Srwatson		default:
634190964Srwatson			/* Constant CA, tell initiator */
63553541Sshin			/* Direction is always relative to the initator */
63653541Sshin			atio->ccb_h.flags &= ~CAM_DIR_MASK;
63753541Sshin			atio->ccb_h.flags |= CAM_DIR_NONE;
63853541Sshin			atio->sense_data = no_lun_sense_data;
63953541Sshin			atio->sense_len = sizeof (no_lun_sense_data);
640192923Sbms			descr->data_resid = 0;
64153541Sshin			descr->data_increment = 0;
64253541Sshin			descr->timeout = 5 * 1000;
64353541Sshin			descr->status = SCSI_STATUS_CHECK_COND;
64453541Sshin			break;
64596116Sume		}
64696116Sume
647191672Sbms		/* Queue us up to receive a Continue Target I/O ccb. */
648191672Sbms		TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
649191672Sbms				  periph_links.tqe);
650192923Sbms		xpt_schedule(periph, /*priority*/1);
651192923Sbms		break;
652192923Sbms	}
653192923Sbms	case XPT_CONT_TARGET_IO:
654192923Sbms	{
655191672Sbms		struct ccb_accept_tio *atio;
656191672Sbms		struct targbh_cmd_desc *desc;
657191672Sbms
658192923Sbms		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
65962587Sitojun			  ("Received completed CTIO\n"));
660191672Sbms		atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
661191672Sbms		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
66253541Sshin
66353541Sshin		TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
66453541Sshin			     periph_links.tqe);
66553541Sshin
66653541Sshin		/*
66753541Sshin		 * We could check for CAM_SENT_SENSE bein set here,
66853541Sshin		 * but since we're not maintaining any CA/UA state,
669181803Sbz		 * there's no point.
67062587Sitojun		 */
67162587Sitojun		atio->sense_len = 0;
67253541Sshin		done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
67353541Sshin		done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
67462587Sitojun
67553541Sshin		/* XXX Check for errors */
67653541Sshin		desc->data_resid -= desc->data_increment;
67753541Sshin		xpt_release_ccb(done_ccb);
67853541Sshin		if (softc->state != TARGBH_STATE_TEARDOWN) {
67953541Sshin
68062587Sitojun			/*
68153541Sshin			 * Send the original accept TIO back to the
682120891Sume			 * controller to handle more work.
68362587Sitojun			 */
68462587Sitojun			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
68562587Sitojun				  ("Returning ATIO to target\n"));
68662587Sitojun			/* Restore wildcards */
68762587Sitojun			atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
68853541Sshin			atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
68953541Sshin			xpt_action((union ccb *)atio);
690193066Sjamie			break;
69153541Sshin		} else {
692193066Sjamie			targbhfreedescr(desc);
69353541Sshin			free(atio, M_DEVBUF);
694169664Sjinmei		}
695169664Sjinmei		break;
696169664Sjinmei	}
697169664Sjinmei	case XPT_IMMED_NOTIFY:
698181803Sbz	{
69978064Sume		if (softc->state == TARGBH_STATE_TEARDOWN
70078064Sume		 || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
70162587Sitojun			printf("Freed an immediate notify\n");
70262587Sitojun			free(done_ccb, M_DEVBUF);
70362587Sitojun		}
70462587Sitojun		break;
70562587Sitojun	}
70662587Sitojun	default:
70762587Sitojun		panic("targbhdone: Unexpected ccb opcode");
708111119Simp		break;
70962587Sitojun	}
710111119Simp}
71162587Sitojun
71262587Sitojun#ifdef NOTYET
71362587Sitojunstatic int
71462587Sitojuntargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
71562587Sitojun{
716166619Sbms	return 0;
717108466Ssam}
718108466Ssam#endif
719108466Ssam
720108466Ssamstatic struct targbh_cmd_desc*
721108466Ssamtargbhallocdescr()
722108466Ssam{
723108466Ssam	struct targbh_cmd_desc* descr;
724108466Ssam
725108466Ssam	/* Allocate the targbh_descr structure */
726108466Ssam	descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
72753541Sshin					       M_DEVBUF, M_NOWAIT);
72853541Sshin	if (descr == NULL)
72953541Sshin		return (NULL);
73053541Sshin
73178064Sume	bzero(descr, sizeof(*descr));
73262587Sitojun
73362587Sitojun	/* Allocate buffer backing store */
734193066Sjamie	descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT);
735193066Sjamie	if (descr->backing_store == NULL) {
736194118Sjamie		free(descr, M_DEVBUF);
737193066Sjamie		return (NULL);
738193066Sjamie	}
73953541Sshin	descr->max_size = MAX_BUF_SIZE;
74053541Sshin	return (descr);
74153541Sshin}
74253541Sshin
74353541Sshinstatic void
74453541Sshintargbhfreedescr(struct targbh_cmd_desc *descr)
74553541Sshin{
74653541Sshin	free(descr->backing_store, M_DEVBUF);
74753541Sshin	free(descr, M_DEVBUF);
748194118Sjamie}
749194118Sjamie