File:  [DragonFly] / src / sys / bus / cam / scsi / scsi_targ_bh.c
Revision 1.6: download - view: text, annotated - select for diffs
Tue Mar 2 20:55:10 2004 UTC (10 years, 7 months ago) by drhodus
Branches: MAIN
CVS tags: HEAD
*    Remove instances of PRIBIO because DragonFly no longer
     uses sleep priorities.

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