scsi_targ_bh.c revision 139743
1139743Simp/*-
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 */
2842650Sgibbs
29116162Sobrien#include <sys/cdefs.h>
30116162Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/scsi_targ_bh.c 139743 2005-01-05 22:34:37Z imp $");
31116162Sobrien
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_periph.h>
4642650Sgibbs#include <cam/cam_queue.h>
4742650Sgibbs#include <cam/cam_xpt_periph.h>
4842650Sgibbs#include <cam/cam_debug.h>
4942650Sgibbs
5042650Sgibbs#include <cam/scsi/scsi_all.h>
5142650Sgibbs#include <cam/scsi/scsi_message.h>
5242650Sgibbs
5342650Sgibbstypedef enum {
5442650Sgibbs	TARGBH_STATE_NORMAL,
5542650Sgibbs	TARGBH_STATE_EXCEPTION,
5642650Sgibbs	TARGBH_STATE_TEARDOWN
5742650Sgibbs} targbh_state;
5842650Sgibbs
5942650Sgibbstypedef enum {
6042650Sgibbs	TARGBH_FLAG_NONE	 = 0x00,
6142650Sgibbs	TARGBH_FLAG_LUN_ENABLED	 = 0x01
6242650Sgibbs} targbh_flags;
6342650Sgibbs
6442650Sgibbstypedef enum {
6542650Sgibbs	TARGBH_CCB_WORKQ,
6642650Sgibbs	TARGBH_CCB_WAITING
6742650Sgibbs} targbh_ccb_types;
6842650Sgibbs
6944503Sgibbs#define MAX_ACCEPT	8
7042650Sgibbs#define MAX_IMMEDIATE	16
7142650Sgibbs#define MAX_BUF_SIZE	256	/* Max inquiry/sense/mode page transfer */
7242650Sgibbs
7342650Sgibbs/* Offsets into our private CCB area for storing accept information */
7442650Sgibbs#define ccb_type	ppriv_field0
7542650Sgibbs#define ccb_descr	ppriv_ptr1
7642650Sgibbs
7742650Sgibbs/* We stick a pointer to the originating accept TIO in each continue I/O CCB */
7842650Sgibbs#define ccb_atio	ppriv_ptr1
7942650Sgibbs
8060938SjakeTAILQ_HEAD(ccb_queue, ccb_hdr);
8142650Sgibbs
8242650Sgibbsstruct targbh_softc {
8342650Sgibbs	struct		ccb_queue pending_queue;
8442650Sgibbs	struct		ccb_queue work_queue;
8542650Sgibbs	struct		ccb_queue unknown_atio_queue;
8642650Sgibbs	struct		devstat device_stats;
8742650Sgibbs	targbh_state	state;
8842650Sgibbs	targbh_flags	flags;
8942650Sgibbs	u_int		init_level;
9042650Sgibbs	u_int		inq_data_len;
9142650Sgibbs	struct		ccb_accept_tio *accept_tio_list;
9242650Sgibbs	struct		ccb_hdr_slist immed_notify_slist;
9342650Sgibbs};
9442650Sgibbs
9542650Sgibbsstruct targbh_cmd_desc {
9642650Sgibbs	struct	  ccb_accept_tio* atio_link;
9742650Sgibbs	u_int	  data_resid;	/* How much left to transfer */
9842650Sgibbs	u_int	  data_increment;/* Amount to send before next disconnect */
9942650Sgibbs	void*	  data;		/* The data. Can be from backing_store or not */
10042650Sgibbs	void*	  backing_store;/* Backing store allocated for this descriptor*/
10142650Sgibbs	u_int	  max_size;	/* Size of backing_store */
10242650Sgibbs	u_int32_t timeout;
10342650Sgibbs	u_int8_t  status;	/* Status to return to initiator */
10442650Sgibbs};
10542650Sgibbs
10642650Sgibbsstatic struct scsi_inquiry_data no_lun_inq_data =
10742650Sgibbs{
10842650Sgibbs	T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
10942650Sgibbs	/* version */2, /* format version */2
11042650Sgibbs};
11142650Sgibbs
11242650Sgibbsstatic struct scsi_sense_data no_lun_sense_data =
11342650Sgibbs{
11442650Sgibbs	SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
11542650Sgibbs	0,
11642650Sgibbs	SSD_KEY_NOT_READY,
11744503Sgibbs	{ 0, 0, 0, 0 },
11842650Sgibbs	/*extra_len*/offsetof(struct scsi_sense_data, fru)
11942650Sgibbs                   - offsetof(struct scsi_sense_data, extra_len),
12044503Sgibbs	{ 0, 0, 0, 0 },
12142650Sgibbs	/* Logical Unit Not Supported */
12242650Sgibbs	/*ASC*/0x25, /*ASCQ*/0
12342650Sgibbs};
12442650Sgibbs
12542650Sgibbsstatic const int request_sense_size = offsetof(struct scsi_sense_data, fru);
12642650Sgibbs
12742650Sgibbsstatic periph_init_t	targbhinit;
12842650Sgibbsstatic void		targbhasync(void *callback_arg, u_int32_t code,
12942650Sgibbs				    struct cam_path *path, void *arg);
13042650Sgibbsstatic cam_status	targbhenlun(struct cam_periph *periph);
13142650Sgibbsstatic cam_status	targbhdislun(struct cam_periph *periph);
13242650Sgibbsstatic periph_ctor_t	targbhctor;
13342650Sgibbsstatic periph_dtor_t	targbhdtor;
13442650Sgibbsstatic periph_start_t	targbhstart;
13542650Sgibbsstatic void		targbhdone(struct cam_periph *periph,
13642650Sgibbs				   union ccb *done_ccb);
13744503Sgibbs#ifdef NOTYET
13842650Sgibbsstatic  int		targbherror(union ccb *ccb, u_int32_t cam_flags,
13942650Sgibbs				    u_int32_t sense_flags);
14044503Sgibbs#endif
14142650Sgibbsstatic struct targbh_cmd_desc*	targbhallocdescr(void);
14242650Sgibbsstatic void		targbhfreedescr(struct targbh_cmd_desc *buf);
14342650Sgibbs
14442650Sgibbsstatic struct periph_driver targbhdriver =
14542650Sgibbs{
14642650Sgibbs	targbhinit, "targbh",
14742650Sgibbs	TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
14842650Sgibbs};
14942650Sgibbs
15072119SpeterPERIPHDRIVER_DECLARE(targbh, targbhdriver);
15142650Sgibbs
15242650Sgibbsstatic void
15342650Sgibbstargbhinit(void)
15442650Sgibbs{
15542650Sgibbs	cam_status status;
15642650Sgibbs	struct cam_path *path;
15742650Sgibbs
15842650Sgibbs	/*
15942650Sgibbs	 * Install a global async callback.  This callback will
16042650Sgibbs	 * receive async callbacks like "new path registered".
16142650Sgibbs	 */
16242650Sgibbs	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
16342650Sgibbs				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
16442650Sgibbs
16542650Sgibbs	if (status == CAM_REQ_CMP) {
16642650Sgibbs		struct ccb_setasync csa;
16742650Sgibbs
16842650Sgibbs		xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
16942650Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
170120426Ssimokawa		csa.event_enable = AC_PATH_REGISTERED | AC_PATH_DEREGISTERED;
17142650Sgibbs		csa.callback = targbhasync;
17242650Sgibbs		csa.callback_arg = NULL;
17342650Sgibbs		xpt_action((union ccb *)&csa);
17442650Sgibbs		status = csa.ccb_h.status;
17542650Sgibbs		xpt_free_path(path);
17642650Sgibbs        }
17742650Sgibbs
17842650Sgibbs	if (status != CAM_REQ_CMP) {
17942650Sgibbs		printf("targbh: Failed to attach master async callback "
18042650Sgibbs		       "due to status 0x%x!\n", status);
18142650Sgibbs	}
18242650Sgibbs}
18342650Sgibbs
18442650Sgibbsstatic void
18542650Sgibbstargbhasync(void *callback_arg, u_int32_t code,
18642650Sgibbs	    struct cam_path *path, void *arg)
18742650Sgibbs{
188120426Ssimokawa	struct cam_path *new_path;
189120601Ssimokawa	struct ccb_pathinq *cpi;
190120601Ssimokawa	path_id_t bus_path_id;
191120426Ssimokawa	cam_status status;
19242650Sgibbs
193120601Ssimokawa	cpi = (struct ccb_pathinq *)arg;
194120601Ssimokawa	if (code == AC_PATH_REGISTERED)
195120601Ssimokawa		bus_path_id = cpi->ccb_h.path_id;
196120601Ssimokawa	else
197120601Ssimokawa		bus_path_id = xpt_path_path_id(path);
198120426Ssimokawa	/*
199120426Ssimokawa	 * Allocate a peripheral instance for
200120426Ssimokawa	 * this target instance.
201120426Ssimokawa	 */
202120426Ssimokawa	status = xpt_create_path(&new_path, NULL,
203120601Ssimokawa				 bus_path_id,
204120426Ssimokawa				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
205120426Ssimokawa	if (status != CAM_REQ_CMP) {
206120426Ssimokawa		printf("targbhasync: Unable to create path "
207120426Ssimokawa			"due to status 0x%x\n", status);
208120426Ssimokawa		return;
209120426Ssimokawa	}
210120426Ssimokawa
21142650Sgibbs	switch (code) {
21242650Sgibbs	case AC_PATH_REGISTERED:
21342650Sgibbs	{
21442650Sgibbs		/* Only attach to controllers that support target mode */
21542650Sgibbs		if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
21642650Sgibbs			break;
21742650Sgibbs
21842650Sgibbs		status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
21942650Sgibbs					  targbhstart,
22042650Sgibbs					  "targbh", CAM_PERIPH_BIO,
22142650Sgibbs					  new_path, targbhasync,
22242650Sgibbs					  AC_PATH_REGISTERED,
22342650Sgibbs					  cpi);
22442650Sgibbs		break;
22542650Sgibbs	}
22642650Sgibbs	case AC_PATH_DEREGISTERED:
22742650Sgibbs	{
228120601Ssimokawa		struct cam_periph *periph;
229120601Ssimokawa
230120601Ssimokawa		if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
231120601Ssimokawa			cam_periph_invalidate(periph);
23242650Sgibbs		break;
23342650Sgibbs	}
23442650Sgibbs	default:
23542650Sgibbs		break;
23642650Sgibbs	}
237120426Ssimokawa	xpt_free_path(new_path);
23842650Sgibbs}
23942650Sgibbs
24042650Sgibbs/* Attempt to enable our lun */
24142650Sgibbsstatic cam_status
24242650Sgibbstargbhenlun(struct cam_periph *periph)
24342650Sgibbs{
24442650Sgibbs	union ccb immed_ccb;
24542650Sgibbs	struct targbh_softc *softc;
24642650Sgibbs	cam_status status;
24742650Sgibbs	int i;
24842650Sgibbs
24942650Sgibbs	softc = (struct targbh_softc *)periph->softc;
25042650Sgibbs
25142650Sgibbs	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
25242650Sgibbs		return (CAM_REQ_CMP);
25342650Sgibbs
25442650Sgibbs	xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);
25542650Sgibbs	immed_ccb.ccb_h.func_code = XPT_EN_LUN;
25642650Sgibbs
25742650Sgibbs	/* Don't need support for any vendor specific commands */
25842650Sgibbs	immed_ccb.cel.grp6_len = 0;
25942650Sgibbs	immed_ccb.cel.grp7_len = 0;
26042650Sgibbs	immed_ccb.cel.enable = 1;
26142650Sgibbs	xpt_action(&immed_ccb);
26242650Sgibbs	status = immed_ccb.ccb_h.status;
26342650Sgibbs	if (status != CAM_REQ_CMP) {
26442650Sgibbs		xpt_print_path(periph->path);
26571493Smjacob		printf("targbhenlun - Enable Lun Rejected with status 0x%x\n",
26642650Sgibbs		       status);
26742650Sgibbs		return (status);
26842650Sgibbs	}
26942650Sgibbs
27042650Sgibbs	softc->flags |= TARGBH_FLAG_LUN_ENABLED;
27142650Sgibbs
27242650Sgibbs	/*
27342650Sgibbs	 * Build up a buffer of accept target I/O
27442650Sgibbs	 * operations for incoming selections.
27542650Sgibbs	 */
27642650Sgibbs	for (i = 0; i < MAX_ACCEPT; i++) {
27742650Sgibbs		struct ccb_accept_tio *atio;
27842650Sgibbs
27942650Sgibbs		atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF,
28042650Sgibbs						      M_NOWAIT);
28142650Sgibbs		if (atio == NULL) {
28242650Sgibbs			status = CAM_RESRC_UNAVAIL;
28342650Sgibbs			break;
28442650Sgibbs		}
28542650Sgibbs
28642650Sgibbs		atio->ccb_h.ccb_descr = targbhallocdescr();
28742650Sgibbs
28842650Sgibbs		if (atio->ccb_h.ccb_descr == NULL) {
28942650Sgibbs			free(atio, M_DEVBUF);
29042650Sgibbs			status = CAM_RESRC_UNAVAIL;
29142650Sgibbs			break;
29242650Sgibbs		}
29342650Sgibbs
29442650Sgibbs		xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);
29542650Sgibbs		atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
29642650Sgibbs		atio->ccb_h.cbfcnp = targbhdone;
29742650Sgibbs		xpt_action((union ccb *)atio);
29842650Sgibbs		status = atio->ccb_h.status;
29942650Sgibbs		if (status != CAM_REQ_INPROG) {
30042650Sgibbs			targbhfreedescr(atio->ccb_h.ccb_descr);
30142650Sgibbs			free(atio, M_DEVBUF);
30242650Sgibbs			break;
30342650Sgibbs		}
30442650Sgibbs		((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
30542650Sgibbs		    softc->accept_tio_list;
30642650Sgibbs		softc->accept_tio_list = atio;
30742650Sgibbs	}
30842650Sgibbs
30942650Sgibbs	if (i == 0) {
31042650Sgibbs		xpt_print_path(periph->path);
31142650Sgibbs		printf("targbhenlun - Could not allocate accept tio CCBs: "
31242650Sgibbs		       "status = 0x%x\n", status);
31342650Sgibbs		targbhdislun(periph);
31442650Sgibbs		return (CAM_REQ_CMP_ERR);
31542650Sgibbs	}
31642650Sgibbs
31742650Sgibbs	/*
31842650Sgibbs	 * Build up a buffer of immediate notify CCBs
31942650Sgibbs	 * so the SIM can tell us of asynchronous target mode events.
32042650Sgibbs	 */
32142650Sgibbs	for (i = 0; i < MAX_ACCEPT; i++) {
32242650Sgibbs		struct ccb_immed_notify *inot;
32342650Sgibbs
32442650Sgibbs		inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF,
32542650Sgibbs						        M_NOWAIT);
32642650Sgibbs
32742650Sgibbs		if (inot == NULL) {
32842650Sgibbs			status = CAM_RESRC_UNAVAIL;
32942650Sgibbs			break;
33042650Sgibbs		}
33142650Sgibbs
33242650Sgibbs		xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);
33342650Sgibbs		inot->ccb_h.func_code = XPT_IMMED_NOTIFY;
33442650Sgibbs		inot->ccb_h.cbfcnp = targbhdone;
33542650Sgibbs		xpt_action((union ccb *)inot);
33642650Sgibbs		status = inot->ccb_h.status;
33742650Sgibbs		if (status != CAM_REQ_INPROG) {
33842650Sgibbs			free(inot, M_DEVBUF);
33942650Sgibbs			break;
34042650Sgibbs		}
34142650Sgibbs		SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
34242650Sgibbs				  periph_links.sle);
34342650Sgibbs	}
34442650Sgibbs
34542650Sgibbs	if (i == 0) {
34642650Sgibbs		xpt_print_path(periph->path);
34742650Sgibbs		printf("targbhenlun - Could not allocate immediate notify "
34842650Sgibbs		       "CCBs: status = 0x%x\n", status);
34942650Sgibbs		targbhdislun(periph);
35042650Sgibbs		return (CAM_REQ_CMP_ERR);
35142650Sgibbs	}
35242650Sgibbs
35342650Sgibbs	return (CAM_REQ_CMP);
35442650Sgibbs}
35542650Sgibbs
35642650Sgibbsstatic cam_status
35742650Sgibbstargbhdislun(struct cam_periph *periph)
35842650Sgibbs{
35942650Sgibbs	union ccb ccb;
36042650Sgibbs	struct targbh_softc *softc;
36142650Sgibbs	struct ccb_accept_tio* atio;
36242650Sgibbs	struct ccb_hdr *ccb_h;
36342650Sgibbs
36442650Sgibbs	softc = (struct targbh_softc *)periph->softc;
36542650Sgibbs	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
36642650Sgibbs		return CAM_REQ_CMP;
36742650Sgibbs
36842650Sgibbs	/* XXX Block for Continue I/O completion */
36942650Sgibbs
37042650Sgibbs	/* Kill off all ACCECPT and IMMEDIATE CCBs */
37142650Sgibbs	while ((atio = softc->accept_tio_list) != NULL) {
37242650Sgibbs
37342650Sgibbs		softc->accept_tio_list =
37442650Sgibbs		    ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
37542650Sgibbs		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
37642650Sgibbs		ccb.cab.ccb_h.func_code = XPT_ABORT;
37742650Sgibbs		ccb.cab.abort_ccb = (union ccb *)atio;
37842650Sgibbs		xpt_action(&ccb);
37942650Sgibbs	}
38042650Sgibbs
38142650Sgibbs	while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
38242650Sgibbs		SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
38342650Sgibbs		xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, /*priority*/1);
38442650Sgibbs		ccb.cab.ccb_h.func_code = XPT_ABORT;
38542650Sgibbs		ccb.cab.abort_ccb = (union ccb *)ccb_h;
38642650Sgibbs		xpt_action(&ccb);
38742650Sgibbs	}
38842650Sgibbs
38942650Sgibbs	/*
39042650Sgibbs	 * Dissable this lun.
39142650Sgibbs	 */
39242650Sgibbs	xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, /*priority*/1);
39342650Sgibbs	ccb.cel.ccb_h.func_code = XPT_EN_LUN;
39442650Sgibbs	ccb.cel.enable = 0;
39542650Sgibbs	xpt_action(&ccb);
39642650Sgibbs
39742650Sgibbs	if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
39842650Sgibbs		printf("targbhdislun - Disabling lun on controller failed "
39942650Sgibbs		       "with status 0x%x\n", ccb.cel.ccb_h.status);
40042650Sgibbs	else
40142650Sgibbs		softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
40242650Sgibbs	return (ccb.cel.ccb_h.status);
40342650Sgibbs}
40442650Sgibbs
40542650Sgibbsstatic cam_status
40642650Sgibbstargbhctor(struct cam_periph *periph, void *arg)
40742650Sgibbs{
40842650Sgibbs	struct targbh_softc *softc;
40942650Sgibbs
41042650Sgibbs	/* Allocate our per-instance private storage */
41142650Sgibbs	softc = (struct targbh_softc *)malloc(sizeof(*softc),
41242650Sgibbs					      M_DEVBUF, M_NOWAIT);
41342650Sgibbs	if (softc == NULL) {
41442650Sgibbs		printf("targctor: unable to malloc softc\n");
41542650Sgibbs		return (CAM_REQ_CMP_ERR);
41642650Sgibbs	}
41742650Sgibbs
41863172Smjacob	bzero(softc, sizeof(*softc));
41942650Sgibbs	TAILQ_INIT(&softc->pending_queue);
42042650Sgibbs	TAILQ_INIT(&softc->work_queue);
42142650Sgibbs	softc->accept_tio_list = NULL;
42242650Sgibbs	SLIST_INIT(&softc->immed_notify_slist);
42342650Sgibbs	softc->state = TARGBH_STATE_NORMAL;
42442650Sgibbs	periph->softc = softc;
42542650Sgibbs	softc->init_level++;
42642650Sgibbs
42742650Sgibbs	return (targbhenlun(periph));
42842650Sgibbs}
42942650Sgibbs
43042650Sgibbsstatic void
43142650Sgibbstargbhdtor(struct cam_periph *periph)
43242650Sgibbs{
43342650Sgibbs	struct targbh_softc *softc;
43442650Sgibbs
43542650Sgibbs	softc = (struct targbh_softc *)periph->softc;
43642650Sgibbs
43742650Sgibbs	softc->state = TARGBH_STATE_TEARDOWN;
43842650Sgibbs
43942650Sgibbs	targbhdislun(periph);
44042650Sgibbs
44142650Sgibbs	switch (softc->init_level) {
442115561Sphk	case 0:
443115561Sphk		panic("targdtor - impossible init level");;
444115561Sphk	case 1:
445115561Sphk		/* FALLTHROUGH */
44642650Sgibbs	default:
447120426Ssimokawa		/* XXX Wait for callback of targbhdislun() */
448120426Ssimokawa		tsleep(softc, PRIBIO, "targbh", hz/2);
44942650Sgibbs		free(softc, M_DEVBUF);
45042650Sgibbs		break;
45142650Sgibbs	}
45242650Sgibbs}
45342650Sgibbs
45442650Sgibbsstatic void
45542650Sgibbstargbhstart(struct cam_periph *periph, union ccb *start_ccb)
45642650Sgibbs{
45742650Sgibbs	struct targbh_softc *softc;
45842650Sgibbs	struct ccb_hdr *ccbh;
45942650Sgibbs	struct ccb_accept_tio *atio;
46042650Sgibbs	struct targbh_cmd_desc *desc;
46142650Sgibbs	struct ccb_scsiio *csio;
46242650Sgibbs	ccb_flags flags;
46342650Sgibbs	int    s;
46442650Sgibbs
46542650Sgibbs	softc = (struct targbh_softc *)periph->softc;
46642650Sgibbs
46742650Sgibbs	s = splbio();
46842650Sgibbs	ccbh = TAILQ_FIRST(&softc->work_queue);
46942650Sgibbs	if (periph->immediate_priority <= periph->pinfo.priority) {
47042650Sgibbs		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WAITING;
47142650Sgibbs		SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
47242650Sgibbs				  periph_links.sle);
47342650Sgibbs		periph->immediate_priority = CAM_PRIORITY_NONE;
47442650Sgibbs		splx(s);
47542650Sgibbs		wakeup(&periph->ccb_list);
47642650Sgibbs	} else if (ccbh == NULL) {
47742650Sgibbs		splx(s);
47842650Sgibbs		xpt_release_ccb(start_ccb);
47942650Sgibbs	} else {
48042650Sgibbs		TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
48142650Sgibbs		TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
48242650Sgibbs				  periph_links.tqe);
48342650Sgibbs		splx(s);
48442650Sgibbs		atio = (struct ccb_accept_tio*)ccbh;
48542650Sgibbs		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
48642650Sgibbs
48742650Sgibbs		/* Is this a tagged request? */
48880573Smjacob		flags = atio->ccb_h.flags &
48980573Smjacob		    (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
49042650Sgibbs
49156594Smjacob		csio = &start_ccb->csio;
49242650Sgibbs		/*
49342650Sgibbs		 * If we are done with the transaction, tell the
49442650Sgibbs		 * controller to send status and perform a CMD_CMPLT.
49556594Smjacob		 * If we have associated sense data, see if we can
49656594Smjacob		 * send that too.
49742650Sgibbs		 */
49856594Smjacob		if (desc->data_resid == desc->data_increment) {
49942650Sgibbs			flags |= CAM_SEND_STATUS;
50056594Smjacob			if (atio->sense_len) {
50156594Smjacob				csio->sense_len = atio->sense_len;
50256594Smjacob				csio->sense_data = atio->sense_data;
50356594Smjacob				flags |= CAM_SEND_SENSE;
50456594Smjacob			}
50542650Sgibbs
50656594Smjacob		}
50756594Smjacob
50842650Sgibbs		cam_fill_ctio(csio,
50942650Sgibbs			      /*retries*/2,
51042650Sgibbs			      targbhdone,
51142650Sgibbs			      flags,
51263190Smjacob			      (flags & CAM_TAG_ACTION_VALID)?
51363190Smjacob				MSG_SIMPLE_Q_TAG : 0,
51442650Sgibbs			      atio->tag_id,
51542650Sgibbs			      atio->init_id,
51642650Sgibbs			      desc->status,
51742650Sgibbs			      /*data_ptr*/desc->data_increment == 0
51842650Sgibbs					  ? NULL : desc->data,
51942650Sgibbs			      /*dxfer_len*/desc->data_increment,
52042650Sgibbs			      /*timeout*/desc->timeout);
52142650Sgibbs
52242650Sgibbs		/* Override our wildcard attachment */
52342650Sgibbs		start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
52442650Sgibbs		start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
52542650Sgibbs
52642650Sgibbs		start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
52742650Sgibbs		start_ccb->ccb_h.ccb_atio = atio;
52842650Sgibbs		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
52942650Sgibbs			  ("Sending a CTIO\n"));
53042650Sgibbs		xpt_action(start_ccb);
53180573Smjacob		/*
53280573Smjacob		 * If the queue was frozen waiting for the response
53380573Smjacob		 * to this ATIO (for instance disconnection was disallowed),
53480573Smjacob		 * then release it now that our response has been queued.
53580573Smjacob		 */
53680573Smjacob		if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
53780573Smjacob			cam_release_devq(periph->path,
53880573Smjacob					 /*relsim_flags*/0,
53980573Smjacob					 /*reduction*/0,
54080573Smjacob					 /*timeout*/0,
54180573Smjacob					 /*getcount_only*/0);
54280573Smjacob			atio->ccb_h.status &= ~CAM_DEV_QFRZN;
54380573Smjacob		}
54442650Sgibbs		s = splbio();
54542650Sgibbs		ccbh = TAILQ_FIRST(&softc->work_queue);
54642650Sgibbs		splx(s);
54742650Sgibbs	}
54842650Sgibbs	if (ccbh != NULL)
54942650Sgibbs		xpt_schedule(periph, /*priority*/1);
55042650Sgibbs}
55142650Sgibbs
55242650Sgibbsstatic void
55342650Sgibbstargbhdone(struct cam_periph *periph, union ccb *done_ccb)
55442650Sgibbs{
55542650Sgibbs	struct targbh_softc *softc;
55642650Sgibbs
55742650Sgibbs	softc = (struct targbh_softc *)periph->softc;
55842650Sgibbs
55942650Sgibbs	if (done_ccb->ccb_h.ccb_type == TARGBH_CCB_WAITING) {
56042650Sgibbs		/* Caller will release the CCB */
56142650Sgibbs		wakeup(&done_ccb->ccb_h.cbfcnp);
56242650Sgibbs		return;
56342650Sgibbs	}
56442650Sgibbs
56542650Sgibbs	switch (done_ccb->ccb_h.func_code) {
56642650Sgibbs	case XPT_ACCEPT_TARGET_IO:
56742650Sgibbs	{
56842650Sgibbs		struct ccb_accept_tio *atio;
56942650Sgibbs		struct targbh_cmd_desc *descr;
57042650Sgibbs		u_int8_t *cdb;
57180573Smjacob		int priority;
57242650Sgibbs
57342650Sgibbs		atio = &done_ccb->atio;
57442650Sgibbs		descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
57542650Sgibbs		cdb = atio->cdb_io.cdb_bytes;
57642650Sgibbs		if (softc->state == TARGBH_STATE_TEARDOWN
57742650Sgibbs		 || atio->ccb_h.status == CAM_REQ_ABORTED) {
57842650Sgibbs			targbhfreedescr(descr);
57942650Sgibbs			free(done_ccb, M_DEVBUF);
58042650Sgibbs			return;
58142650Sgibbs		}
58242650Sgibbs
58342650Sgibbs		/*
58442650Sgibbs		 * Determine the type of incoming command and
58542650Sgibbs		 * setup our buffer for a response.
58642650Sgibbs		 */
58742650Sgibbs		switch (cdb[0]) {
58842650Sgibbs		case INQUIRY:
58942650Sgibbs		{
59042650Sgibbs			struct scsi_inquiry *inq;
59142650Sgibbs
59242650Sgibbs			inq = (struct scsi_inquiry *)cdb;
59342650Sgibbs			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
59442650Sgibbs				  ("Saw an inquiry!\n"));
59542650Sgibbs			/*
59642650Sgibbs			 * Validate the command.  We don't
59742650Sgibbs			 * support any VPD pages, so complain
59842650Sgibbs			 * if EVPD is set.
59942650Sgibbs			 */
60042650Sgibbs			if ((inq->byte2 & SI_EVPD) != 0
60142650Sgibbs			 || inq->page_code != 0) {
60242650Sgibbs				atio->ccb_h.flags &= ~CAM_DIR_MASK;
60342650Sgibbs				atio->ccb_h.flags |= CAM_DIR_NONE;
60456594Smjacob				/*
60556594Smjacob				 * This needs to have other than a
60656594Smjacob				 * no_lun_sense_data response.
60756594Smjacob				 */
60856594Smjacob				atio->sense_data = no_lun_sense_data;
60963172Smjacob				atio->sense_len = sizeof(no_lun_sense_data);
61042650Sgibbs				descr->data_resid = 0;
61142650Sgibbs				descr->data_increment = 0;
61242650Sgibbs				descr->status = SCSI_STATUS_CHECK_COND;
61342650Sgibbs				break;
61442650Sgibbs			}
61542650Sgibbs			/*
61642650Sgibbs			 * Direction is always relative
61742650Sgibbs			 * to the initator.
61842650Sgibbs			 */
61942650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
62042650Sgibbs			atio->ccb_h.flags |= CAM_DIR_IN;
62142650Sgibbs			descr->data = &no_lun_inq_data;
62242650Sgibbs			descr->data_resid = MIN(sizeof(no_lun_inq_data),
62363172Smjacob						SCSI_CDB6_LEN(inq->length));
62442650Sgibbs			descr->data_increment = descr->data_resid;
62542650Sgibbs			descr->timeout = 5 * 1000;
62642650Sgibbs			descr->status = SCSI_STATUS_OK;
62742650Sgibbs			break;
62842650Sgibbs		}
62942650Sgibbs		case REQUEST_SENSE:
63042650Sgibbs		{
63142650Sgibbs			struct scsi_request_sense *rsense;
63242650Sgibbs
63342650Sgibbs			rsense = (struct scsi_request_sense *)cdb;
63442650Sgibbs			/* Refer to static sense data */
63542650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
63642650Sgibbs			atio->ccb_h.flags |= CAM_DIR_IN;
63742650Sgibbs			descr->data = &no_lun_sense_data;
63842650Sgibbs			descr->data_resid = request_sense_size;
63942650Sgibbs			descr->data_resid = MIN(descr->data_resid,
64063172Smjacob						SCSI_CDB6_LEN(rsense->length));
64142650Sgibbs			descr->data_increment = descr->data_resid;
64242650Sgibbs			descr->timeout = 5 * 1000;
64342650Sgibbs			descr->status = SCSI_STATUS_OK;
64442650Sgibbs			break;
64542650Sgibbs		}
64642650Sgibbs		default:
64742650Sgibbs			/* Constant CA, tell initiator */
64842650Sgibbs			/* Direction is always relative to the initator */
64942650Sgibbs			atio->ccb_h.flags &= ~CAM_DIR_MASK;
65042650Sgibbs			atio->ccb_h.flags |= CAM_DIR_NONE;
65156594Smjacob			atio->sense_data = no_lun_sense_data;
65256594Smjacob			atio->sense_len = sizeof (no_lun_sense_data);
65342650Sgibbs			descr->data_resid = 0;
65442650Sgibbs			descr->data_increment = 0;
65542650Sgibbs			descr->timeout = 5 * 1000;
65642650Sgibbs			descr->status = SCSI_STATUS_CHECK_COND;
65742650Sgibbs			break;
65842650Sgibbs		}
65942650Sgibbs
66042650Sgibbs		/* Queue us up to receive a Continue Target I/O ccb. */
66180573Smjacob		if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
66280573Smjacob			TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
66380573Smjacob					  periph_links.tqe);
66480573Smjacob			priority = 0;
66580573Smjacob		} else {
66680573Smjacob			TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
66780573Smjacob					  periph_links.tqe);
66880573Smjacob			priority = 1;
66980573Smjacob		}
67080573Smjacob		xpt_schedule(periph, priority);
67142650Sgibbs		break;
67242650Sgibbs	}
67342650Sgibbs	case XPT_CONT_TARGET_IO:
67442650Sgibbs	{
67542650Sgibbs		struct ccb_accept_tio *atio;
67642650Sgibbs		struct targbh_cmd_desc *desc;
67742650Sgibbs
67842650Sgibbs		CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
67942650Sgibbs			  ("Received completed CTIO\n"));
68042650Sgibbs		atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
68142650Sgibbs		desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
68242650Sgibbs
68342650Sgibbs		TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
68442650Sgibbs			     periph_links.tqe);
68542650Sgibbs
68656594Smjacob		/*
68756594Smjacob		 * We could check for CAM_SENT_SENSE bein set here,
68856594Smjacob		 * but since we're not maintaining any CA/UA state,
68956594Smjacob		 * there's no point.
69056594Smjacob		 */
69156594Smjacob		atio->sense_len = 0;
69256594Smjacob		done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
69356594Smjacob		done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
69456594Smjacob
69580573Smjacob		/*
69680573Smjacob		 * Any errors will not change the data we return,
69780573Smjacob		 * so make sure the queue is not left frozen.
69880573Smjacob		 * XXX - At some point there may be errors that
69980573Smjacob		 *       leave us in a connected state with the
70080573Smjacob		 *       initiator...
70180573Smjacob		 */
70280573Smjacob		if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
70380573Smjacob			printf("Releasing Queue\n");
70480573Smjacob			cam_release_devq(done_ccb->ccb_h.path,
70580573Smjacob					 /*relsim_flags*/0,
70680573Smjacob					 /*reduction*/0,
70780573Smjacob					 /*timeout*/0,
70880573Smjacob					 /*getcount_only*/0);
70980573Smjacob			done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
71080573Smjacob		}
71142650Sgibbs		desc->data_resid -= desc->data_increment;
71242650Sgibbs		xpt_release_ccb(done_ccb);
71342650Sgibbs		if (softc->state != TARGBH_STATE_TEARDOWN) {
71442650Sgibbs
71542650Sgibbs			/*
71642650Sgibbs			 * Send the original accept TIO back to the
71742650Sgibbs			 * controller to handle more work.
71842650Sgibbs			 */
71942650Sgibbs			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
72042650Sgibbs				  ("Returning ATIO to target\n"));
72142650Sgibbs			/* Restore wildcards */
72242650Sgibbs			atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
72342650Sgibbs			atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
72442650Sgibbs			xpt_action((union ccb *)atio);
72542650Sgibbs			break;
72642650Sgibbs		} else {
72742650Sgibbs			targbhfreedescr(desc);
72842650Sgibbs			free(atio, M_DEVBUF);
72942650Sgibbs		}
73042650Sgibbs		break;
73142650Sgibbs	}
73242650Sgibbs	case XPT_IMMED_NOTIFY:
73342650Sgibbs	{
73480573Smjacob		int frozen;
73580573Smjacob
73680573Smjacob		frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
73742650Sgibbs		if (softc->state == TARGBH_STATE_TEARDOWN
73842650Sgibbs		 || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
73942650Sgibbs			printf("Freed an immediate notify\n");
74042650Sgibbs			free(done_ccb, M_DEVBUF);
74180573Smjacob		} else {
74280573Smjacob			/* Requeue for another immediate event */
74380573Smjacob			xpt_action(done_ccb);
74442650Sgibbs		}
74580573Smjacob		if (frozen != 0)
74680573Smjacob			cam_release_devq(periph->path,
74780573Smjacob					 /*relsim_flags*/0,
74880573Smjacob					 /*opening reduction*/0,
74980573Smjacob					 /*timeout*/0,
75080573Smjacob					 /*getcount_only*/0);
75142650Sgibbs		break;
75242650Sgibbs	}
75344503Sgibbs	default:
75444503Sgibbs		panic("targbhdone: Unexpected ccb opcode");
75544503Sgibbs		break;
75642650Sgibbs	}
75742650Sgibbs}
75842650Sgibbs
75944503Sgibbs#ifdef NOTYET
76042650Sgibbsstatic int
76142650Sgibbstargbherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
76242650Sgibbs{
76342650Sgibbs	return 0;
76442650Sgibbs}
76544503Sgibbs#endif
76642650Sgibbs
76742650Sgibbsstatic struct targbh_cmd_desc*
76842650Sgibbstargbhallocdescr()
76942650Sgibbs{
77042650Sgibbs	struct targbh_cmd_desc* descr;
77142650Sgibbs
77242650Sgibbs	/* Allocate the targbh_descr structure */
77342650Sgibbs	descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
77442650Sgibbs					       M_DEVBUF, M_NOWAIT);
77542650Sgibbs	if (descr == NULL)
77642650Sgibbs		return (NULL);
77742650Sgibbs
77842650Sgibbs	bzero(descr, sizeof(*descr));
77942650Sgibbs
78042650Sgibbs	/* Allocate buffer backing store */
78142650Sgibbs	descr->backing_store = malloc(MAX_BUF_SIZE, M_DEVBUF, M_NOWAIT);
78242650Sgibbs	if (descr->backing_store == NULL) {
78342650Sgibbs		free(descr, M_DEVBUF);
78442650Sgibbs		return (NULL);
78542650Sgibbs	}
78642650Sgibbs	descr->max_size = MAX_BUF_SIZE;
78742650Sgibbs	return (descr);
78842650Sgibbs}
78942650Sgibbs
79042650Sgibbsstatic void
79142650Sgibbstargbhfreedescr(struct targbh_cmd_desc *descr)
79242650Sgibbs{
79342650Sgibbs	free(descr->backing_store, M_DEVBUF);
79442650Sgibbs	free(descr, M_DEVBUF);
79542650Sgibbs}
796