scsi_targ_bh.c revision 63172
142650Sgibbs/*
242650Sgibbs * Implementation of the Target Mode 'Black Hole device' for CAM.
342650Sgibbs *
442650Sgibbs * Copyright (c) 1999 Justin T. Gibbs.
542650Sgibbs * All rights reserved.
642650Sgibbs *
742650Sgibbs * Redistribution and use in source and binary forms, with or without
842650Sgibbs * modification, are permitted provided that the following conditions
942650Sgibbs * are met:
1042650Sgibbs * 1. Redistributions of source code must retain the above copyright
1142650Sgibbs *    notice, this list of conditions, and the following disclaimer,
1242650Sgibbs *    without modification, immediately at the beginning of the file.
1342650Sgibbs * 2. The name of the author may not be used to endorse or promote products
1442650Sgibbs *    derived from this software without specific prior written permission.
1542650Sgibbs *
1642650Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1742650Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1842650Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1942650Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2042650Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2142650Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2242650Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2342650Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2442650Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2542650Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2642650Sgibbs * SUCH DAMAGE.
2742650Sgibbs *
2850477Speter * $FreeBSD: head/sys/cam/scsi/scsi_targ_bh.c 63172 2000-07-14 19:41:43Z mjacob $
2942650Sgibbs */
3042650Sgibbs#include <stddef.h>	/* For offsetof */
3142650Sgibbs
3242650Sgibbs#include <sys/param.h>
3342650Sgibbs#include <sys/queue.h>
3442650Sgibbs#include <sys/systm.h>
3542650Sgibbs#include <sys/kernel.h>
3642650Sgibbs#include <sys/types.h>
3760041Sphk#include <sys/bio.h>
3842650Sgibbs#include <sys/conf.h>
3942650Sgibbs#include <sys/devicestat.h>
4042650Sgibbs#include <sys/malloc.h>
4142650Sgibbs#include <sys/uio.h>
4242650Sgibbs
4342650Sgibbs#include <cam/cam.h>
4442650Sgibbs#include <cam/cam_ccb.h>
4542650Sgibbs#include <cam/cam_extend.h>
4642650Sgibbs#include <cam/cam_periph.h>
4742650Sgibbs#include <cam/cam_queue.h>
4842650Sgibbs#include <cam/cam_xpt_periph.h>
4942650Sgibbs#include <cam/cam_debug.h>
5042650Sgibbs
5142650Sgibbs#include <cam/scsi/scsi_all.h>
5242650Sgibbs#include <cam/scsi/scsi_message.h>
5342650Sgibbs
5442650Sgibbstypedef enum {
5542650Sgibbs	TARGBH_STATE_NORMAL,
5642650Sgibbs	TARGBH_STATE_EXCEPTION,
5742650Sgibbs	TARGBH_STATE_TEARDOWN
5842650Sgibbs} targbh_state;
5942650Sgibbs
6042650Sgibbstypedef enum {
6142650Sgibbs	TARGBH_FLAG_NONE	 = 0x00,
6242650Sgibbs	TARGBH_FLAG_LUN_ENABLED	 = 0x01
6342650Sgibbs} targbh_flags;
6442650Sgibbs
6542650Sgibbstypedef enum {
6642650Sgibbs	TARGBH_CCB_WORKQ,
6742650Sgibbs	TARGBH_CCB_WAITING
6842650Sgibbs} targbh_ccb_types;
6942650Sgibbs
7044503Sgibbs#define MAX_ACCEPT	8
7142650Sgibbs#define MAX_IMMEDIATE	16
7242650Sgibbs#define MAX_BUF_SIZE	256	/* Max inquiry/sense/mode page transfer */
7342650Sgibbs
7442650Sgibbs#define MIN(a, b) ((a > b) ? b : a)
7542650Sgibbs
7642650Sgibbs/* Offsets into our private CCB area for storing accept information */
7742650Sgibbs#define ccb_type	ppriv_field0
7842650Sgibbs#define ccb_descr	ppriv_ptr1
7942650Sgibbs
8042650Sgibbs/* We stick a pointer to the originating accept TIO in each continue I/O CCB */
8142650Sgibbs#define ccb_atio	ppriv_ptr1
8242650Sgibbs
8360938SjakeTAILQ_HEAD(ccb_queue, ccb_hdr);
8442650Sgibbs
8542650Sgibbsstruct targbh_softc {
8642650Sgibbs	struct		ccb_queue pending_queue;
8742650Sgibbs	struct		ccb_queue work_queue;
8842650Sgibbs	struct		ccb_queue unknown_atio_queue;
8942650Sgibbs	struct		devstat device_stats;
9042650Sgibbs	targbh_state	state;
9142650Sgibbs	targbh_flags	flags;
9242650Sgibbs	u_int		init_level;
9342650Sgibbs	u_int		inq_data_len;
9442650Sgibbs	struct		ccb_accept_tio *accept_tio_list;
9542650Sgibbs	struct		ccb_hdr_slist immed_notify_slist;
9642650Sgibbs};
9742650Sgibbs
9842650Sgibbsstruct targbh_cmd_desc {
9942650Sgibbs	struct	  ccb_accept_tio* atio_link;
10042650Sgibbs	u_int	  data_resid;	/* How much left to transfer */
10142650Sgibbs	u_int	  data_increment;/* Amount to send before next disconnect */
10242650Sgibbs	void*	  data;		/* The data. Can be from backing_store or not */
10342650Sgibbs	void*	  backing_store;/* Backing store allocated for this descriptor*/
10442650Sgibbs	u_int	  max_size;	/* Size of backing_store */
10542650Sgibbs	u_int32_t timeout;
10642650Sgibbs	u_int8_t  status;	/* Status to return to initiator */
10742650Sgibbs};
10842650Sgibbs
10942650Sgibbsstatic struct scsi_inquiry_data no_lun_inq_data =
11042650Sgibbs{
11142650Sgibbs	T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
11242650Sgibbs	/* version */2, /* format version */2
11342650Sgibbs};
11442650Sgibbs
11542650Sgibbsstatic struct scsi_sense_data no_lun_sense_data =
11642650Sgibbs{
11742650Sgibbs	SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
11842650Sgibbs	0,
11942650Sgibbs	SSD_KEY_NOT_READY,
12044503Sgibbs	{ 0, 0, 0, 0 },
12142650Sgibbs	/*extra_len*/offsetof(struct scsi_sense_data, fru)
12242650Sgibbs                   - offsetof(struct scsi_sense_data, extra_len),
12344503Sgibbs	{ 0, 0, 0, 0 },
12442650Sgibbs	/* Logical Unit Not Supported */
12542650Sgibbs	/*ASC*/0x25, /*ASCQ*/0
12642650Sgibbs};
12742650Sgibbs
12842650Sgibbsstatic const int request_sense_size = offsetof(struct scsi_sense_data, fru);
12942650Sgibbs
13042650Sgibbsstatic periph_init_t	targbhinit;
13142650Sgibbsstatic void		targbhasync(void *callback_arg, u_int32_t code,
13242650Sgibbs				    struct cam_path *path, void *arg);
13342650Sgibbsstatic cam_status	targbhenlun(struct cam_periph *periph);
13442650Sgibbsstatic cam_status	targbhdislun(struct cam_periph *periph);
13542650Sgibbsstatic periph_ctor_t	targbhctor;
13642650Sgibbsstatic periph_dtor_t	targbhdtor;
13742650Sgibbsstatic periph_start_t	targbhstart;
13842650Sgibbsstatic void		targbhdone(struct cam_periph *periph,
13942650Sgibbs				   union ccb *done_ccb);
14044503Sgibbs#ifdef NOTYET
14142650Sgibbsstatic  int		targbherror(union ccb *ccb, u_int32_t cam_flags,
14242650Sgibbs				    u_int32_t sense_flags);
14344503Sgibbs#endif
14442650Sgibbsstatic struct targbh_cmd_desc*	targbhallocdescr(void);
14542650Sgibbsstatic void		targbhfreedescr(struct targbh_cmd_desc *buf);
14642650Sgibbs
14742650Sgibbsstatic struct periph_driver targbhdriver =
14842650Sgibbs{
14942650Sgibbs	targbhinit, "targbh",
15042650Sgibbs	TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
15142650Sgibbs};
15242650Sgibbs
15342650SgibbsDATA_SET(periphdriver_set, targbhdriver);
15442650Sgibbs
15542650Sgibbsstatic void
15642650Sgibbstargbhinit(void)
15742650Sgibbs{
15842650Sgibbs	cam_status status;
15942650Sgibbs	struct cam_path *path;
16042650Sgibbs
16142650Sgibbs	/*
16242650Sgibbs	 * Install a global async callback.  This callback will
16342650Sgibbs	 * receive async callbacks like "new path registered".
16442650Sgibbs	 */
16542650Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
16642650Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
16742650Sgibbs
16842650Sgibbs	if (status == CAM_REQ_CMP) {
16942650Sgibbs		struct ccb_setasync csa;
17042650Sgibbs
17142650Sgibbs		xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
17242650Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
17342650Sgibbs		csa.event_enable = AC_PATH_REGISTERED;
17442650Sgibbs		csa.callback = targbhasync;
17542650Sgibbs		csa.callback_arg = NULL;
17642650Sgibbs		xpt_action((union ccb *)&csa);
17742650Sgibbs		status = csa.ccb_h.status;
17842650Sgibbs		xpt_free_path(path);
17942650Sgibbs        }
18042650Sgibbs
18142650Sgibbs	if (status != CAM_REQ_CMP) {
18242650Sgibbs		printf("targbh: Failed to attach master async callback "
18342650Sgibbs		       "due to status 0x%x!\n", status);
18442650Sgibbs	}
18542650Sgibbs}
18642650Sgibbs
18742650Sgibbsstatic void
18842650Sgibbstargbhasync(void *callback_arg, u_int32_t code,
18942650Sgibbs	    struct cam_path *path, void *arg)
19042650Sgibbs{
19142650Sgibbs	struct cam_periph *periph;
19242650Sgibbs
19342650Sgibbs	periph = (struct cam_periph *)callback_arg;
19442650Sgibbs	switch (code) {
19542650Sgibbs	case AC_PATH_REGISTERED:
19642650Sgibbs	{
19742650Sgibbs		struct ccb_pathinq *cpi;
19842650Sgibbs		struct cam_path *new_path;
19942650Sgibbs		cam_status status;
20042650Sgibbs
20142650Sgibbs		cpi = (struct ccb_pathinq *)arg;
20242650Sgibbs
20342650Sgibbs		/* Only attach to controllers that support target mode */
20442650Sgibbs		if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
20542650Sgibbs			break;
20642650Sgibbs
20742650Sgibbs		/*
20842650Sgibbs		 * Allocate a peripheral instance for
20942650Sgibbs		 * this target instance.
21042650Sgibbs		 */
21142650Sgibbs		status = xpt_create_path(&new_path, NULL,
21242650Sgibbs					 xpt_path_path_id(path),
21342650Sgibbs					 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
21442650Sgibbs		if (status != CAM_REQ_CMP) {
21542650Sgibbs			printf("targbhasync: Unable to create path "
21642650Sgibbs				"due to status 0x%x\n", status);
21742650Sgibbs			break;
21842650Sgibbs		}
21942650Sgibbs		status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
22042650Sgibbs					  targbhstart,
22142650Sgibbs					  "targbh", CAM_PERIPH_BIO,
22242650Sgibbs					  new_path, targbhasync,
22342650Sgibbs					  AC_PATH_REGISTERED,
22442650Sgibbs					  cpi);
22542650Sgibbs		xpt_free_path(new_path);
22642650Sgibbs		if (status != CAM_REQ_CMP
22742650Sgibbs		 && status != CAM_REQ_INPROG)
22842650Sgibbs			printf("targbhasync: Unable to allocate new periph "
22942650Sgibbs			       "due to status 0x%x\n", status);
23042650Sgibbs		break;
23142650Sgibbs	}
23242650Sgibbs	case AC_PATH_DEREGISTERED:
23342650Sgibbs	{
23442650Sgibbs		targbhdislun(periph);
23542650Sgibbs		break;
23642650Sgibbs	}
23742650Sgibbs	default:
23842650Sgibbs		break;
23942650Sgibbs	}
24042650Sgibbs}
24142650Sgibbs
24242650Sgibbs/* Attempt to enable our lun */
24342650Sgibbsstatic cam_status
24442650Sgibbstargbhenlun(struct cam_periph *periph)
24542650Sgibbs{
24642650Sgibbs	union ccb immed_ccb;
24742650Sgibbs	struct targbh_softc *softc;
24842650Sgibbs	cam_status status;
24942650Sgibbs	int i;
25042650Sgibbs
25142650Sgibbs	softc = (struct targbh_softc *)periph->softc;
25242650Sgibbs
25342650Sgibbs	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
25442650Sgibbs		return (CAM_REQ_CMP);
25542650Sgibbs
25642650Sgibbs	xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
25742650Sgibbs	immed_ccb.ccb_h.func_code = XPT_EN_LUN;
25842650Sgibbs
25942650Sgibbs	/* Don't need support for any vendor specific commands */
26042650Sgibbs	immed_ccb.cel.grp6_len = 0;
26142650Sgibbs	immed_ccb.cel.grp7_len = 0;
26242650Sgibbs	immed_ccb.cel.enable = 1;
26342650Sgibbs	xpt_action(&immed_ccb);
26442650Sgibbs	status = immed_ccb.ccb_h.status;
26542650Sgibbs	if (status != CAM_REQ_CMP) {
26642650Sgibbs		xpt_print_path(periph->path);
26742650Sgibbs		printf("targbhenlun - Enable Lun Rejected for status 0x%x\n",
26842650Sgibbs		       status);
26942650Sgibbs		return (status);
27042650Sgibbs	}
27142650Sgibbs
27242650Sgibbs	softc->flags |= TARGBH_FLAG_LUN_ENABLED;
27342650Sgibbs
27442650Sgibbs	/*
27542650Sgibbs	 * Build up a buffer of accept target I/O
27642650Sgibbs	 * operations for incoming selections.
27742650Sgibbs	 */
27842650Sgibbs	for (i = 0; i < MAX_ACCEPT; i++) {
27942650Sgibbs		struct ccb_accept_tio *atio;
28042650Sgibbs
28142650Sgibbs		atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF,
28242650Sgibbs						      M_NOWAIT);
28342650Sgibbs		if (atio == NULL) {
28442650Sgibbs			status = CAM_RESRC_UNAVAIL;
28542650Sgibbs			break;
28642650Sgibbs		}
28742650Sgibbs
28842650Sgibbs		atio->ccb_h.ccb_descr = targbhallocdescr();
28942650Sgibbs
29042650Sgibbs		if (atio->ccb_h.ccb_descr == NULL) {
29142650Sgibbs			free(atio, M_DEVBUF);
29242650Sgibbs			status = CAM_RESRC_UNAVAIL;
29342650Sgibbs			break;
29442650Sgibbs		}
29542650Sgibbs
29642650Sgibbs		xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
29742650Sgibbs		atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
29842650Sgibbs		atio->ccb_h.cbfcnp = targbhdone;
29942650Sgibbs		xpt_action((union ccb *)atio);
30042650Sgibbs		status = atio->ccb_h.status;
30142650Sgibbs		if (status != CAM_REQ_INPROG) {
30242650Sgibbs			targbhfreedescr(atio->ccb_h.ccb_descr);
30342650Sgibbs			free(atio, M_DEVBUF);
30442650Sgibbs			break;
30542650Sgibbs		}
30642650Sgibbs		((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
30742650Sgibbs		    softc->accept_tio_list;
30842650Sgibbs		softc->accept_tio_list = atio;
30942650Sgibbs	}
31042650Sgibbs
31142650Sgibbs	if (i == 0) {
31242650Sgibbs		xpt_print_path(periph->path);
31342650Sgibbs		printf("targbhenlun - Could not allocate accept tio CCBs: "
31442650Sgibbs		       "status = 0x%x\n", status);
31542650Sgibbs		targbhdislun(periph);
31642650Sgibbs		return (CAM_REQ_CMP_ERR);
31742650Sgibbs	}
31842650Sgibbs
31942650Sgibbs	/*
32042650Sgibbs	 * Build up a buffer of immediate notify CCBs
32142650Sgibbs	 * so the SIM can tell us of asynchronous target mode events.
32242650Sgibbs	 */
32342650Sgibbs	for (i = 0; i < MAX_ACCEPT; i++) {
32442650Sgibbs		struct ccb_immed_notify *inot;
32542650Sgibbs
32642650Sgibbs		inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF,
32742650Sgibbs						        M_NOWAIT);
32842650Sgibbs
32942650Sgibbs		if (inot == NULL) {
33042650Sgibbs			status = CAM_RESRC_UNAVAIL;
33142650Sgibbs			break;
33242650Sgibbs		}
33342650Sgibbs
33442650Sgibbs		xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
33542650Sgibbs		inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
33642650Sgibbs		inot->ccb_h.cbfcnp = targbhdone;
33742650Sgibbs		xpt_action((union ccb *)inot);
33842650Sgibbs		status = inot->ccb_h.status;
33942650Sgibbs		if (status != CAM_REQ_INPROG) {
34042650Sgibbs			free(inot, M_DEVBUF);
34142650Sgibbs			break;
34242650Sgibbs		}
34342650Sgibbs		SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
34442650Sgibbs				  periph_links.sle);
34542650Sgibbs	}
34642650Sgibbs
34742650Sgibbs	if (i == 0) {
34842650Sgibbs		xpt_print_path(periph->path);
34942650Sgibbs		printf("targbhenlun - Could not allocate immediate notify "
35042650Sgibbs		       "CCBs: status = 0x%x\n", status);
35142650Sgibbs		targbhdislun(periph);
35242650Sgibbs		return (CAM_REQ_CMP_ERR);
35342650Sgibbs	}
35442650Sgibbs
35542650Sgibbs	return (CAM_REQ_CMP);
35642650Sgibbs}
35742650Sgibbs
35842650Sgibbsstatic cam_status
35942650Sgibbstargbhdislun(struct cam_periph *periph)
36042650Sgibbs{
36142650Sgibbs	union ccb ccb;
36242650Sgibbs	struct targbh_softc *softc;
36342650Sgibbs	struct ccb_accept_tio* atio;
36442650Sgibbs	struct ccb_hdr *ccb_h;
36542650Sgibbs
36642650Sgibbs	softc = (struct targbh_softc *)periph->softc;
36742650Sgibbs	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
36842650Sgibbs		return CAM_REQ_CMP;
36942650Sgibbs
37042650Sgibbs	/* XXX Block for Continue I/O completion */
37142650Sgibbs
37242650Sgibbs	/* Kill off all ACCECPT and IMMEDIATE CCBs */
37342650Sgibbs	while ((atio = softc->accept_tio_list) != NULL) {
37442650Sgibbs
37542650Sgibbs		softc->accept_tio_list =
37642650Sgibbs		    ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
37742650Sgibbs		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
37842650Sgibbs		ccb.cab.ccb_h.func_code = XPT_ABORT;
37942650Sgibbs		ccb.cab.abort_ccb = (union ccb *)atio;
38042650Sgibbs		xpt_action(&ccb);
38142650Sgibbs	}
38242650Sgibbs
38342650Sgibbs	while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
38442650Sgibbs		SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
38542650Sgibbs		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
38642650Sgibbs		ccb.cab.ccb_h.func_code = XPT_ABORT;
38742650Sgibbs		ccb.cab.abort_ccb = (union ccb *)ccb_h;
38842650Sgibbs		xpt_action(&ccb);
38942650Sgibbs	}
39042650Sgibbs
39142650Sgibbs	/*
39242650Sgibbs	 * Dissable this lun.
39342650Sgibbs	 */
39442650Sgibbs	xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
39542650Sgibbs	ccb.cel.ccb_h.func_code = XPT_EN_LUN;
39642650Sgibbs	ccb.cel.enable = 0;
39742650Sgibbs	xpt_action(&ccb);
39842650Sgibbs
39942650Sgibbs	if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
40042650Sgibbs		printf("targbhdislun - Disabling lun on controller failed "
40142650Sgibbs		       "with status 0x%x\n", ccb.cel.ccb_h.status);
40242650Sgibbs	else
40342650Sgibbs		softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
40442650Sgibbs	return (ccb.cel.ccb_h.status);
40542650Sgibbs}
40642650Sgibbs
40742650Sgibbsstatic cam_status
40842650Sgibbstargbhctor(struct cam_periph *periph, void *arg)
40942650Sgibbs{
41042650Sgibbs	struct ccb_pathinq *cpi;
41142650Sgibbs	struct targbh_softc *softc;
41242650Sgibbs
41342650Sgibbs	cpi = (struct ccb_pathinq *)arg;
41442650Sgibbs
41542650Sgibbs	/* Allocate our per-instance private storage */
41642650Sgibbs	softc = (struct targbh_softc *)malloc(sizeof(*softc),
41742650Sgibbs					      M_DEVBUF, M_NOWAIT);
41842650Sgibbs	if (softc == NULL) {
41942650Sgibbs		printf("targctor: unable to malloc softc\n");
42042650Sgibbs		return (CAM_REQ_CMP_ERR);
42142650Sgibbs	}
42242650Sgibbs
42363172Smjacob	bzero(softc, sizeof(*softc));
42442650Sgibbs	TAILQ_INIT(&softc->pending_queue);
42542650Sgibbs	TAILQ_INIT(&softc->work_queue);
42642650Sgibbs	softc->accept_tio_list = NULL;
42742650Sgibbs	SLIST_INIT(&softc->immed_notify_slist);
42842650Sgibbs	softc->state = TARGBH_STATE_NORMAL;
42942650Sgibbs	periph->softc = softc;
43042650Sgibbs	softc->init_level++;
43142650Sgibbs
43242650Sgibbs	return (targbhenlun(periph));
43342650Sgibbs}
43442650Sgibbs
43542650Sgibbsstatic void
43642650Sgibbstargbhdtor(struct cam_periph *periph)
43742650Sgibbs{
43842650Sgibbs	struct targbh_softc *softc;
43942650Sgibbs
44042650Sgibbs	softc = (struct targbh_softc *)periph->softc;
44142650Sgibbs
44242650Sgibbs	softc->state = TARGBH_STATE_TEARDOWN;
44342650Sgibbs
44442650Sgibbs	targbhdislun(periph);
44542650Sgibbs
44642650Sgibbs	switch (softc->init_level) {
44742650Sgibbs	default:
44842650Sgibbs		/* FALLTHROUGH */
44942650Sgibbs	case 1:
45042650Sgibbs		free(softc, M_DEVBUF);
45142650Sgibbs		break;
45242650Sgibbs	case 0:
45342650Sgibbs		panic("targdtor - impossible init level");;
45442650Sgibbs	}
45542650Sgibbs}
45642650Sgibbs
45742650Sgibbsstatic void
45842650Sgibbstargbhstart(struct cam_periph *periph, union ccb *start_ccb)
45942650Sgibbs{
46042650Sgibbs	struct targbh_softc *softc;
46142650Sgibbs	struct ccb_hdr *ccbh;
46242650Sgibbs	struct ccb_accept_tio *atio;
46342650Sgibbs	struct targbh_cmd_desc *desc;
46442650Sgibbs	struct ccb_scsiio *csio;
46542650Sgibbs	ccb_flags flags;
46642650Sgibbs	int    s;
46742650Sgibbs
46842650Sgibbs	softc = (struct targbh_softc *)periph->softc;
46942650Sgibbs
47042650Sgibbs	s = splbio();
47142650Sgibbs	ccbh = TAILQ_FIRST(&softc->work_queue);
47242650Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
47342650Sgibbs		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;
47442650Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
47542650Sgibbs				  periph_links.sle);
47642650Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
47742650Sgibbs		splx(s);
47842650Sgibbs		wakeup(&periph->ccb_list);
47942650Sgibbs	} else if (ccbh == NULL) {
48042650Sgibbs		splx(s);
48142650Sgibbs		xpt_release_ccb(start_ccb);
48242650Sgibbs	} else {
48342650Sgibbs		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
48442650Sgibbs		TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
48542650Sgibbs				  periph_links.tqe);
48642650Sgibbs		splx(s);
48742650Sgibbs		atio = (struct ccb_accept_tio*)ccbh;
48842650Sgibbs		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
48942650Sgibbs
49042650Sgibbs		/* Is this a tagged request? */
49142650Sgibbs		flags = atio->ccb_h.flags & (CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
49242650Sgibbs
49356594Smjacob		csio = &start_ccb->csio;
49442650Sgibbs		/*
49542650Sgibbs		 * If we are done with the transaction, tell the
49642650Sgibbs		 * controller to send status and perform a CMD_CMPLT.
49756594Smjacob		 * If we have associated sense data, see if we can
49856594Smjacob		 * send that too.
49942650Sgibbs		 */
50056594Smjacob		if (desc->data_resid == desc->data_increment) {
50142650Sgibbs			flags |= CAM_SEND_STATUS;
50256594Smjacob			if (atio->sense_len) {
50356594Smjacob				csio->sense_len = atio->sense_len;
50456594Smjacob				csio->sense_data = atio->sense_data;
50556594Smjacob				flags |= CAM_SEND_SENSE;
50656594Smjacob			}
50742650Sgibbs
50856594Smjacob		}
50956594Smjacob
51042650Sgibbs		cam_fill_ctio(csio,
51142650Sgibbs			      /*retries*/2,
51242650Sgibbs			      targbhdone,
51342650Sgibbs			      flags,
51442650Sgibbs			      /*tag_action*/MSG_SIMPLE_Q_TAG,
51542650Sgibbs			      atio->tag_id,
51642650Sgibbs			      atio->init_id,
51742650Sgibbs			      desc->status,
51842650Sgibbs			      /*data_ptr*/desc->data_increment == 0
51942650Sgibbs					  ? NULL : desc->data,
52042650Sgibbs			      /*dxfer_len*/desc->data_increment,
52142650Sgibbs			      /*timeout*/desc->timeout);
52242650Sgibbs
52342650Sgibbs		/* Override our wildcard attachment */
52442650Sgibbs		start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
52542650Sgibbs		start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
52642650Sgibbs
52742650Sgibbs		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
52842650Sgibbs		start_ccb->ccb_h.ccb_atio = atio;
52942650Sgibbs		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
53042650Sgibbs			  ("Sending a CTIO\n"));
53142650Sgibbs		xpt_action(start_ccb);
53242650Sgibbs		s = splbio();
53342650Sgibbs		ccbh = TAILQ_FIRST(&softc->work_queue);
53442650Sgibbs		splx(s);
53542650Sgibbs	}
53642650Sgibbs	if (ccbh != NULL)
53742650Sgibbs		xpt_schedule(periph, /*priority*/1);
53842650Sgibbs}
53942650Sgibbs
54042650Sgibbsstatic void
54142650Sgibbstargbhdone(struct cam_periph *periph, union ccb *done_ccb)
54242650Sgibbs{
54342650Sgibbs	struct targbh_softc *softc;
54442650Sgibbs
54542650Sgibbs	softc = (struct targbh_softc *)periph->softc;
54642650Sgibbs
54742650Sgibbs	if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) {
54842650Sgibbs		/* Caller will release the CCB */
54942650Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
55042650Sgibbs		return;
55142650Sgibbs	}
55242650Sgibbs
55342650Sgibbs	switch (done_ccb->ccb_h.func_code) {
55442650Sgibbs	case XPT_ACCEPT_TARGET_IO:
55542650Sgibbs	{
55642650Sgibbs		struct ccb_accept_tio *atio;
55742650Sgibbs		struct targbh_cmd_desc *descr;
55842650Sgibbs		u_int8_t *cdb;
55942650Sgibbs
56042650Sgibbs		atio = &done_ccb->atio;
56142650Sgibbs		descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
56242650Sgibbs		cdb = atio->cdb_io.cdb_bytes;
56342650Sgibbs		if (softc->state == TARGBH_STATE_TEARDOWN
56442650Sgibbs		 || atio->ccb_h.status == CAM_REQ_ABORTED) {
56542650Sgibbs			targbhfreedescr(descr);
56642650Sgibbs			free(done_ccb, M_DEVBUF);
56742650Sgibbs			return;
56842650Sgibbs		}
56942650Sgibbs
57042650Sgibbs		/*
57142650Sgibbs		 * Determine the type of incoming command and
57242650Sgibbs		 * setup our buffer for a response.
57342650Sgibbs		 */
57442650Sgibbs		switch (cdb[0]) {
57542650Sgibbs		case INQUIRY:
57642650Sgibbs		{
57742650Sgibbs			struct scsi_inquiry *inq;
57842650Sgibbs
57942650Sgibbs			inq = (struct scsi_inquiry *)cdb;
58042650Sgibbs			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
58142650Sgibbs				  ("Saw an inquiry!\n"));
58242650Sgibbs			/*
58342650Sgibbs			 * Validate the command.  We don't
58442650Sgibbs			 * support any VPD pages, so complain
58542650Sgibbs			 * if EVPD is set.
58642650Sgibbs			 */
58742650Sgibbs			if ((inq->byte2 & SI_EVPD) != 0
58842650Sgibbs			 || inq->page_code != 0) {
58942650Sgibbs				atio->ccb_h.flags &= ~CAM_DIR_MASK;
59042650Sgibbs				atio->ccb_h.flags |= CAM_DIR_NONE;
59156594Smjacob				/*
59256594Smjacob				 * This needs to have other than a
59356594Smjacob				 * no_lun_sense_data response.
59456594Smjacob				 */
59556594Smjacob				atio->sense_data = no_lun_sense_data;
59663172Smjacob				atio->sense_len = sizeof(no_lun_sense_data);
59742650Sgibbs				descr->data_resid = 0;
59842650Sgibbs				descr->data_increment = 0;
59942650Sgibbs				descr->status = SCSI_STATUS_CHECK_COND;
60042650Sgibbs				break;
60142650Sgibbs			}
60242650Sgibbs			/*
60342650Sgibbs			 * Direction is always relative
60442650Sgibbs			 * to the initator.
60542650Sgibbs			 */
60642650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
60742650Sgibbs			atio->ccb_h.flags |= CAM_DIR_IN;
60842650Sgibbs			descr->data = &no_lun_inq_data;
60942650Sgibbs			descr->data_resid = MIN(sizeof(no_lun_inq_data),
61063172Smjacob						SCSI_CDB6_LEN(inq->length));
61142650Sgibbs			descr->data_increment = descr->data_resid;
61242650Sgibbs			descr->timeout = 5 * 1000;
61342650Sgibbs			descr->status = SCSI_STATUS_OK;
61442650Sgibbs			break;
61542650Sgibbs		}
61642650Sgibbs		case REQUEST_SENSE:
61742650Sgibbs		{
61842650Sgibbs			struct scsi_request_sense *rsense;
61942650Sgibbs
62042650Sgibbs			rsense = (struct scsi_request_sense *)cdb;
62142650Sgibbs			/* Refer to static sense data */
62242650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
62342650Sgibbs			atio->ccb_h.flags |= CAM_DIR_IN;
62442650Sgibbs			descr->data = &no_lun_sense_data;
62542650Sgibbs			descr->data_resid = request_sense_size;
62642650Sgibbs			descr->data_resid = MIN(descr->data_resid,
62763172Smjacob						SCSI_CDB6_LEN(rsense->length));
62842650Sgibbs			descr->data_increment = descr->data_resid;
62942650Sgibbs			descr->timeout = 5 * 1000;
63042650Sgibbs			descr->status = SCSI_STATUS_OK;
63142650Sgibbs			break;
63242650Sgibbs		}
63342650Sgibbs		default:
63442650Sgibbs			/* Constant CA, tell initiator */
63542650Sgibbs			/* Direction is always relative to the initator */
63642650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
63742650Sgibbs			atio->ccb_h.flags |= CAM_DIR_NONE;
63856594Smjacob			atio->sense_data = no_lun_sense_data;
63956594Smjacob			atio->sense_len = sizeof (no_lun_sense_data);
64042650Sgibbs			descr->data_resid = 0;
64142650Sgibbs			descr->data_increment = 0;
64242650Sgibbs			descr->timeout = 5 * 1000;
64342650Sgibbs			descr->status = SCSI_STATUS_CHECK_COND;
64442650Sgibbs			break;
64542650Sgibbs		}
64642650Sgibbs
64742650Sgibbs		/* Queue us up to receive a Continue Target I/O ccb. */
64842650Sgibbs		TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
64942650Sgibbs				  periph_links.tqe);
65042650Sgibbs		xpt_schedule(periph, /*priority*/1);
65142650Sgibbs		break;
65242650Sgibbs	}
65342650Sgibbs	case XPT_CONT_TARGET_IO:
65442650Sgibbs	{
65542650Sgibbs		struct ccb_accept_tio *atio;
65642650Sgibbs		struct targbh_cmd_desc *desc;
65742650Sgibbs
65842650Sgibbs		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
65942650Sgibbs			  ("Received completed CTIO\n"));
66042650Sgibbs		atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
66142650Sgibbs		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
66242650Sgibbs
66342650Sgibbs		TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
66442650Sgibbs			     periph_links.tqe);
66542650Sgibbs
66656594Smjacob		/*
66756594Smjacob		 * We could check for CAM_SENT_SENSE bein set here,
66856594Smjacob		 * but since we're not maintaining any CA/UA state,
66956594Smjacob		 * there's no point.
67056594Smjacob		 */
67156594Smjacob		atio->sense_len = 0;
67256594Smjacob		done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
67356594Smjacob		done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
67456594Smjacob
67542650Sgibbs		/* XXX Check for errors */
67642650Sgibbs		desc->data_resid -= desc->data_increment;
67742650Sgibbs		xpt_release_ccb(done_ccb);
67842650Sgibbs		if (softc->state != TARGBH_STATE_TEARDOWN) {
67942650Sgibbs
68042650Sgibbs			/*
68142650Sgibbs			 * Send the original accept TIO back to the
68242650Sgibbs			 * controller to handle more work.
68342650Sgibbs			 */
68442650Sgibbs			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
68542650Sgibbs				  ("Returning ATIO to target\n"));
68642650Sgibbs			/* Restore wildcards */
68742650Sgibbs			atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
68842650Sgibbs			atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
68942650Sgibbs			xpt_action((union ccb *)atio);
69042650Sgibbs			break;
69142650Sgibbs		} else {
69242650Sgibbs			targbhfreedescr(desc);
69342650Sgibbs			free(atio, M_DEVBUF);
69442650Sgibbs		}
69542650Sgibbs		break;
69642650Sgibbs	}
69742650Sgibbs	case XPT_IMMED_NOTIFY:
69842650Sgibbs	{
69942650Sgibbs		if (softc->state == TARGBH_STATE_TEARDOWN
70042650Sgibbs		 || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
70142650Sgibbs			printf("Freed an immediate notify\n");
70242650Sgibbs			free(done_ccb, M_DEVBUF);
70342650Sgibbs		}
70442650Sgibbs		break;
70542650Sgibbs	}
70644503Sgibbs	default:
70744503Sgibbs		panic("targbhdone: Unexpected ccb opcode");
70844503Sgibbs		break;
70942650Sgibbs	}
71042650Sgibbs}
71142650Sgibbs
71244503Sgibbs#ifdef NOTYET
71342650Sgibbsstatic int
71442650Sgibbstargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
71542650Sgibbs{
71642650Sgibbs	return 0;
71742650Sgibbs}
71844503Sgibbs#endif
71942650Sgibbs
72042650Sgibbsstatic struct targbh_cmd_desc*
72142650Sgibbstargbhallocdescr()
72242650Sgibbs{
72342650Sgibbs	struct targbh_cmd_desc* descr;
72442650Sgibbs
72542650Sgibbs	/* Allocate the targbh_descr structure */
72642650Sgibbs	descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
72742650Sgibbs					       M_DEVBUF, M_NOWAIT);
72842650Sgibbs	if (descr == NULL)
72942650Sgibbs		return (NULL);
73042650Sgibbs
73142650Sgibbs	bzero(descr, sizeof(*descr));
73242650Sgibbs
73342650Sgibbs	/* Allocate buffer backing store */
73442650Sgibbs	descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT);
73542650Sgibbs	if (descr->backing_store == NULL) {
73642650Sgibbs		free(descr, M_DEVBUF);
73742650Sgibbs		return (NULL);
73842650Sgibbs	}
73942650Sgibbs	descr->max_size = MAX_BUF_SIZE;
74042650Sgibbs	return (descr);
74142650Sgibbs}
74242650Sgibbs
74342650Sgibbsstatic void
74442650Sgibbstargbhfreedescr(struct targbh_cmd_desc *descr)
74542650Sgibbs{
74642650Sgibbs	free(descr->backing_store, M_DEVBUF);
74742650Sgibbs	free(descr, M_DEVBUF);
74842650Sgibbs}
749