scsi_targ_bh.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 723 行 · 第 1/2 页

C
723
字号
/* * Implementation of the Target Mode 'Black Hole device' for CAM. * * Copyright (c) 1999 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *      $Id: scsi_targ_bh.c,v 1.1.2.1 1999/03/07 00:40:31 gibbs Exp $ */#include <stddef.h>	/* For offsetof */#include <sys/param.h>#include <sys/queue.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/types.h>#include <sys/buf.h>#include <sys/conf.h>#include <sys/devicestat.h>#include <sys/malloc.h>#include <sys/uio.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/cam_extend.h>#include <cam/cam_periph.h>#include <cam/cam_queue.h>#include <cam/cam_xpt_periph.h>#include <cam/cam_debug.h>#include <cam/scsi/scsi_all.h>#include <cam/scsi/scsi_message.h>typedef enum {	TARGBH_STATE_NORMAL,	TARGBH_STATE_EXCEPTION,	TARGBH_STATE_TEARDOWN} targbh_state;typedef enum {	TARGBH_FLAG_NONE	 = 0x00,	TARGBH_FLAG_LUN_ENABLED	 = 0x01} targbh_flags;typedef enum {	TARGBH_CCB_WORKQ,	TARGBH_CCB_WAITING} targbh_ccb_types;#define MAX_ACCEPT	8#define MAX_IMMEDIATE	16#define MAX_BUF_SIZE	256	/* Max inquiry/sense/mode page transfer */#define MIN(a, b) ((a > b) ? b : a)/* Offsets into our private CCB area for storing accept information */#define ccb_type	ppriv_field0#define ccb_descr	ppriv_ptr1/* We stick a pointer to the originating accept TIO in each continue I/O CCB */#define ccb_atio	ppriv_ptr1TAILQ_HEAD(ccb_queue, ccb_hdr);struct targbh_softc {	struct		ccb_queue pending_queue;	struct		ccb_queue work_queue;	struct		ccb_queue unknown_atio_queue;	struct		devstat device_stats;	targbh_state	state;	targbh_flags	flags;		u_int		init_level;	u_int		inq_data_len;	struct		ccb_accept_tio *accept_tio_list;	struct		ccb_hdr_slist immed_notify_slist;};struct targbh_cmd_desc {	struct	  ccb_accept_tio* atio_link;	u_int	  data_resid;	/* How much left to transfer */	u_int	  data_increment;/* Amount to send before next disconnect */	void*	  data;		/* The data. Can be from backing_store or not */	void*	  backing_store;/* Backing store allocated for this descriptor*/	u_int	  max_size;	/* Size of backing_store */	u_int32_t timeout;		u_int8_t  status;	/* Status to return to initiator */};static struct scsi_inquiry_data no_lun_inq_data ={	T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,	/* version */2, /* format version */2};static struct scsi_sense_data no_lun_sense_data ={	SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,	0,	SSD_KEY_NOT_READY, 	{ 0, 0, 0, 0 },	/*extra_len*/offsetof(struct scsi_sense_data, fru)                   - offsetof(struct scsi_sense_data, extra_len),	{ 0, 0, 0, 0 },	/* Logical Unit Not Supported */	/*ASC*/0x25, /*ASCQ*/0};static const int request_sense_size = offsetof(struct scsi_sense_data, fru);static periph_init_t	targbhinit;static void		targbhasync(void *callback_arg, u_int32_t code,				    struct cam_path *path, void *arg);static cam_status	targbhenlun(struct cam_periph *periph);static cam_status	targbhdislun(struct cam_periph *periph);static periph_ctor_t	targbhctor;static periph_dtor_t	targbhdtor;static periph_start_t	targbhstart;static void		targbhdone(struct cam_periph *periph,				   union ccb *done_ccb);#ifdef NOTYETstatic  int		targbherror(union ccb *ccb, u_int32_t cam_flags,				    u_int32_t sense_flags);#endifstatic struct targbh_cmd_desc*	targbhallocdescr(void);static void		targbhfreedescr(struct targbh_cmd_desc *buf);					static struct periph_driver targbhdriver ={	targbhinit, "targbh",	TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0};DATA_SET(periphdriver_set, targbhdriver);static voidtargbhinit(void){	cam_status status;	struct cam_path *path;	/*	 * Install a global async callback.  This callback will	 * receive async callbacks like "new path registered".	 */	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);	if (status == CAM_REQ_CMP) {		struct ccb_setasync csa;		xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);		csa.ccb_h.func_code = XPT_SASYNC_CB;		csa.event_enable = AC_PATH_REGISTERED;		csa.callback = targbhasync;		csa.callback_arg = NULL;		xpt_action((union ccb *)&csa);		status = csa.ccb_h.status;		xpt_free_path(path);        }	if (status != CAM_REQ_CMP) {		printf("targbh: Failed to attach master async callback "		       "due to status 0x%x!\n", status);	}}static voidtargbhasync(void *callback_arg, u_int32_t code,	    struct cam_path *path, void *arg){	struct cam_periph *periph;	periph = (struct cam_periph *)callback_arg;	switch (code) {	case AC_PATH_REGISTERED:	{		struct ccb_pathinq *cpi;		struct cam_path *new_path;		cam_status status; 		cpi = (struct ccb_pathinq *)arg;		/* Only attach to controllers that support target mode */		if ((cpi->target_sprt & PIT_PROCESSOR) == 0)			break;		/*		 * Allocate a peripheral instance for		 * this target instance.		 */		status = xpt_create_path(&new_path, NULL,					 xpt_path_path_id(path),					 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);		if (status != CAM_REQ_CMP) {			printf("targbhasync: Unable to create path "				"due to status 0x%x\n", status);			break;		}		status = cam_periph_alloc(targbhctor, NULL, targbhdtor,					  targbhstart,					  "targbh", CAM_PERIPH_BIO,					  new_path, targbhasync,					  AC_PATH_REGISTERED,					  cpi);		xpt_free_path(new_path);		if (status != CAM_REQ_CMP		 && status != CAM_REQ_INPROG)			printf("targbhasync: Unable to allocate new periph "			       "due to status 0x%x\n", status);		break;	}	case AC_PATH_DEREGISTERED:	{		targbhdislun(periph);		break;	}	default:		break;	}}/* Attempt to enable our lun */static cam_statustargbhenlun(struct cam_periph *periph){	union ccb immed_ccb;	struct targbh_softc *softc;	cam_status status;	int i;	softc = (struct targbh_softc *)periph->softc;	if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)		return (CAM_REQ_CMP);	xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, /*priority*/1);	immed_ccb.ccb_h.func_code = XPT_EN_LUN;	/* Don't need support for any vendor specific commands */	immed_ccb.cel.grp6_len = 0;	immed_ccb.cel.grp7_len = 0;	immed_ccb.cel.enable = 1;	xpt_action(&immed_ccb);	status = immed_ccb.ccb_h.status;	if (status != CAM_REQ_CMP) {		xpt_print_path(periph->path);		printf("targbhenlun - Enable Lun Rejected for status 0x%x\n",		       status);		return (status);	}		softc->flags |= TARGBH_FLAG_LUN_ENABLED;	/*	 * Build up a buffer of accept target I/O	 * operations for incoming selections.	 */	for (i = 0; i < MAX_ACCEPT; i++) {		struct ccb_accept_tio *atio;		atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_DEVBUF,						      M_NOWAIT);		if (atio == NULL) {			status = CAM_RESRC_UNAVAIL;			break;		}		atio->ccb_h.ccb_descr = targbhallocdescr();		if (atio->ccb_h.ccb_descr == NULL) {			free(atio, M_DEVBUF);			status = CAM_RESRC_UNAVAIL;			break;		}		xpt_setup_ccb(&atio->ccb_h, periph->path, /*priority*/1);		atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;		atio->ccb_h.cbfcnp = targbhdone;		xpt_action((union ccb *)atio);		status = atio->ccb_h.status;		if (status != CAM_REQ_INPROG) {			targbhfreedescr(atio->ccb_h.ccb_descr);			free(atio, M_DEVBUF);			break;		}		((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =		    softc->accept_tio_list;		softc->accept_tio_list = atio;	}	if (i == 0) {		xpt_print_path(periph->path);		printf("targbhenlun - Could not allocate accept tio CCBs: "		       "status = 0x%x\n", status);		targbhdislun(periph);		return (CAM_REQ_CMP_ERR);	}	/*	 * Build up a buffer of immediate notify CCBs	 * so the SIM can tell us of asynchronous target mode events.	 */	for (i = 0; i < MAX_ACCEPT; i++) {		struct ccb_immed_notify *inot;		inot = (struct ccb_immed_notify*)malloc(sizeof(*inot), M_DEVBUF,						        M_NOWAIT);		if (inot == NULL) {			status = CAM_RESRC_UNAVAIL;			break;		}		xpt_setup_ccb(&inot->ccb_h, periph->path, /*priority*/1);		inot->ccb_h.func_code = XPT_IMMED_NOTIFY;		inot->ccb_h.cbfcnp = targbhdone;		xpt_action((union ccb *)inot);		status = inot->ccb_h.status;		if (status != CAM_REQ_INPROG) {			free(inot, M_DEVBUF);			break;		}		SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,				  periph_links.sle);	}	if (i == 0) {		xpt_print_path(periph->path);		printf("targbhenlun - Could not allocate immediate notify "		       "CCBs: status = 0x%x\n", status);		targbhdislun(periph);		return (CAM_REQ_CMP_ERR);	}	return (CAM_REQ_CMP);}static cam_statustargbhdislun(struct cam_periph *periph){	union ccb ccb;	struct targbh_softc *softc;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?