⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi_target.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* @(#)scsi_target.c 1.10 *//* * SCSI Target Mode "stub" driver for Linux. * * Copyright (c) 2000, 2001 by Matthew Jacob * 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. * * Alternatively, this software may be distributed under the terms of the * the GNU Public License ("GPL"). * * 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. *  * Matthew Jacob * Feral Software * PMB #825 * 5214-F Diamond Hts Blvd * San Francisco, CA, 94131 * mjacob@feral.com */#ifdef	MODULE#define	EXPORT_SYMTAB#endif#include <linux/version.h>#ifndef	KERNEL_VERSION#define KERNEL_VERSION(v,p,s)		(((v)<<16)+(p<<8)+s)#endif#include <linux/autoconf.h>#ifdef	CONFIG_SMP#define	__SMP__	1#endif#define	_KVC	LINUX_VERSION_CODE#if _KVC <= KERNEL_VERSION(2,2,0)#error	"Linux 2.0 and 2.1 kernels are not supported anymore"#endif#if _KVC >= KERNEL_VERSION(2,3,0) && _KVC < KERNEL_VERSION(2,4,0)#error	"Linux 2.3 kernels are not supported"#endif#include <linux/module.h>#include <linux/config.h>#include <linux/init.h>#include <linux/types.h>#include <linux/blk.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/pci.h>#include <linux/malloc.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/irq.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)#include <linux/smp.h>#include <linux/spinlock.h>#else#include <asm/spinlock.h>#endif#include <asm/scatterlist.h>#include <asm/system.h>#include <linux/miscdevice.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && defined(CONFIG_PROC_FS)#include <linux/proc_fs.h>#endif#ifdef	min#undef	min#endif#define min(a,b) (((a)<(b))?(a):(b))#ifndef	roundup#define	roundup(x, y)	((((x)+((y)-1))/(y))*(y))#endif#include "scsi_target.h"#include "isp_tpublic.h"#include "linux/smp_lock.h"#define	DEFAULT_DEVICE_TYPE	3	/* PROCESSOR */#define	MAX_BUS			8#define	MAX_LUN			64#define	N_SENSE_BUFS		64typedef struct sdata {    struct sdata *next;    u_int8_t sdata[QLTM_SENSELEN];} sdata_t;struct bus;typedef struct initiator {    struct initiator *	ini_next;    struct bus *	ini_bus;	/* backpointer to containing bus */    struct sdata *	ini_sdata;	/* pending sense data list */    u_int64_t 		ini_iid;	/* initiator identifier */} ini_t;#define	HASH_WIDTH	16#define	INI_HASH_LISTP(busp, ini_id)	busp->list[ini_id & (HASH_WIDTH - 1)]typedef struct {    hba_register_t h;		/* must be first */    ini_t *list[HASH_WIDTH];	/* hash list of known initiators */    u_int8_t luns[2][MAX_LUN];} bus_t;#define	SDprintk		if (scsi_tdebug) printk#define	SDprintk2		if (scsi_tdebug > 1) printkstatic int scsi_tdebug = 0;static int scsi_target_open(struct inode *, struct file *);static int scsi_target_close(struct inode *, struct file *);static intscsi_target_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static void scsi_target_handler(qact_e, void *);static inline bus_t *bus_from_tmd(tmd_cmd_t *, int);static inline bus_t *bus_from_name(char *);static inline ini_t *ini_from_tmd(bus_t *, tmd_cmd_t *);static void add_sdata(ini_t *, void *);static void rem_sdata(ini_t *);static void scsi_target_start_cmd(tmd_cmd_t *, bus_t *);static int scsi_target_thread(void *);static int scsi_target_endis(char *, int, int, int, int);/* * Local Declarations */static u_int8_t inqdata[36] = {    DEFAULT_DEVICE_TYPE, 0x0, 0x2, 0x2, 32, 0, 0, 0x32,    'L', 'I', 'N', 'U', 'X', ' ', ' ', ' ',    'S', 'C', 'S', 'I', ' ', 'B', 'L', 'A',    'C', 'K', 'H', 'O', 'L', 'E', ' ', ' ',    '0', '0', '0', '1'};static u_int8_t illfld[QLTM_SENSELEN] = {    0xf0, 0, 0x5, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x24};static u_int8_t nolun[QLTM_SENSELEN] = {    0xf0, 0, 0x5, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x25};#if	0static u_int8_t notrdy[QLTM_SENSELEN] = {    0xf0, 0, 0x2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x04};#endifstatic u_int8_t ifailure[QLTM_SENSELEN] = {    0xf0, 0, 0x4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x44};static u_int8_t ua[QLTM_SENSELEN] = {    0xf0, 0, 0x0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0x29};static u_int8_t nosense[QLTM_SENSELEN] = {    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};static bus_t busses[MAX_BUS];static sdata_t *sdp;DECLARE_MUTEX_LOCKED(scsi_thread_sleep_semaphore);DECLARE_MUTEX_LOCKED(scsi_thread_entry_exit_semaphore);static tmd_cmd_t *p_front = NULL, *p_last = NULL;static spinlock_t scsi_target_lock = SPIN_LOCK_UNLOCKED;static int scsi_target_thread_exit = 0;static int scsi_target_thread_notified = 0;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && defined(CONFIG_PROC_FS)static struct proc_dir_entry *st = NULL;extern struct proc_dir_entry *proc_scsi;static int stp(char *, char **, off_t, int);#endifstatic struct file_operations scsi_target_fops = {ioctl:		scsi_target_ioctl,open:		scsi_target_open,	/* open */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)release:	scsi_target_close	/* close */#elserelease:	(void (*)(struct inode *, struct file *)) scsi_target_close#endif};static struct miscdevice scsi_target_dev = {    MISC_DYNAMIC_MINOR, "scsi_target", &scsi_target_fops};static intscsi_target_open(struct inode * inode, struct file * file){    return (0);}static intscsi_target_close(struct inode * inode, struct file * file){    return (0);}static intscsi_target_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,	unsigned long arg){    sc_enable_t *sc;    switch(cmd) {    case SC_ENABLE_LUN:    case SC_DISABLE_LUN:	sc = (sc_enable_t *) arg;	SDprintk("scsi_target_ioctl: %sable %s, chan %d, target %d, lun %d\n",	    (cmd == SC_ENABLE_LUN)? "en" : "dis", sc->hba_name_unit,	    sc->channel, sc->target, sc->lun);	return (scsi_target_endis(sc->hba_name_unit, sc->channel,	    sc->target, sc->lun, (cmd == SC_ENABLE_LUN)? 1 : 0));    default:	break;    }    return (-EINVAL);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && defined(CONFIG_PROC_FS)static intstp(char *buf, char **start, off_t offset, int length){    int len;    len = sprintf(buf, "%d\n", scsi_target_dev.minor);    *start = buf + offset;    len -= offset;    if (len > length)	len = length;    if (len < 0)	len = 0;    return (len);}#endifstatic intscsi_target_init(void){    int r = misc_register(&scsi_target_dev);    if (r == 0) {	printk("scsi_target: allocated misc minor number %d (0x%x)\n",	    scsi_target_dev.minor, scsi_target_dev.minor);	spin_lock_init(&scsi_target_lock);	kernel_thread(scsi_target_thread, NULL, 0);	down(&scsi_thread_entry_exit_semaphore);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && defined(CONFIG_PROC_FS)	st = create_proc_info_entry("scsi/scsi_target_minor", 0, 0, stp);#endif	    } else {	printk("scsi_target: unable to register with misc driver (%d)\n", r);    }    return (r);}static inline bus_t *bus_from_tmd(tmd_cmd_t *tmd, int doset){    bus_t *bp;    if (tmd->cd_private)	return (tmd->cd_private);    for (bp = busses; bp < &busses[MAX_BUS]; bp++) {    	if (bp->h.r_action == NULL)	    continue; 	if (bp->h.r_identity == tmd->cd_hba) {	    if (doset)		tmd->cd_private = bp;	    return (bp);	}    }    return (NULL);}static inline bus_t *bus_from_name(char *name){    bus_t *bp;    for (bp = busses; bp < &busses[MAX_BUS]; bp++) {	char localbuf[32];    	if (bp->h.r_action == NULL)	    continue;	sprintf(localbuf, "%s%d", bp->h.r_name, bp->h.r_inst); 	if (strncmp(name, localbuf, 32) == 0) {	    return (bp);	}    }    return (NULL);}static inline ini_t *ini_from_tmd(bus_t *bp, tmd_cmd_t *tmd){   ini_t *ptr = INI_HASH_LISTP(bp, tmd->cd_iid);   if (ptr) {	do {	    if (ptr->ini_iid == tmd->cd_iid)		return (ptr);	} while ((ptr = ptr->ini_next) != NULL);   }   return (ptr);}/* * Make an initiator structure */static intmake_ini(bus_t *bp, u_int64_t iid){   ini_t *nptr, **ptrlptr = &INI_HASH_LISTP(bp, iid);   nptr = kmalloc(sizeof (ini_t), GFP_KERNEL);   if (nptr == NULL) {       printk("no mem to create initiator structure\n");       return (-ENOMEM);   }   memset(nptr, 0, sizeof (ini_t));   nptr->ini_iid = iid;   nptr->ini_bus = (struct bus *) bp;   nptr->ini_next = *ptrlptr;   /*    * Start off with a Unit Attention condition.    */   add_sdata(nptr, ua);   *ptrlptr = nptr;   return (0);}/* * Add this sense data from the list of * sense data structures for this initiator. * We always add to the front of the list. */static voidadd_sdata(ini_t *ini, void *sd){   sdata_t *t = sdp;   if (t == NULL) {	printk("outta sense data structures\n");	t = kmalloc(sizeof (sdata_t), GFP_KERNEL);	if (t == NULL) {	    printk("REALLY outta sense data structures\n");	    return;	}	t->next = NULL;   }   memcpy(t->sdata, sd, sizeof (t->sdata));   t->next = ini->ini_sdata;   ini->ini_sdata = t;}/* * Remove one sense data item from the list of * sense data structures for this initiator. */static voidrem_sdata(ini_t *ini){    sdata_t *t = ini->ini_sdata;    if (t) {	ini->ini_sdata = t->next;	t->next = sdp;	sdp = t;    }}/* XXXX: NOT READY YET FOR NON-FC DEVICES - CONTINGENT ALLEGIANCE HANDLING */#ifndef	INQUIRY#define	INQUIRY 0x12#endif#ifndef	REQUEST_SENSE#define	REQUEST_SENSE	0x3#endif#ifndef	TEST_UNIT_READY#define	TEST_UNIT_READY	0#endif#define	_SGS0	 roundup(sizeof (struct scatterlist), sizeof (void *))#define	SGS_SIZE(x)		(roundup((x), sizeof (void *)) + _SGS0)#define	SGS_PAYLOAD(x, ptr)	(ptr) ((char *)x + _SGS0)static voidscsi_target_start_cmd(tmd_cmd_t *tmd, bus_t *bp){    unsigned long flags;    ini_t *ini;    spin_lock_irqsave(&scsi_target_lock, flags);    ini = ini_from_tmd(bp, tmd);    tmd->cd_hflags = 0;    tmd->cd_scsi_status = SCSI_GOOD;    tmd->cd_data = NULL;    tmd->cd_resid =  tmd->cd_totlen;    if (ini == NULL) {	if (make_ini(bp, tmd->cd_iid)) {	    tmd->cd_xfrlen = 0;	    tmd->cd_scsi_status = SCSI_BUSY;	    tmd->cd_hflags |= CDFH_STSVALID;            spin_unlock_irqrestore(&scsi_target_lock, flags);	    (*bp->h.r_action)(QIN_TMD_CONT, tmd);	    return;	}	ini = ini_from_tmd(bp, tmd);    }    spin_unlock_irqrestore(&scsi_target_lock, flags);    /*     * Commands get lumped into 4 rough groups:     *     *   + Commands which don't ever really return CHECK CONDITIONS and     *     always work. These are typically INQUIRY (future: Reserve/Release)     *     *   + Commands that we accept, but also report CHECK CONDITIONS against if     *     we have pending contingent allegiance (e..g, TEST UNIT READY).     *     *   + Commands that retrieve Sense Data (REQUEST SENSE)     *     *   + All others (which we bounce with either ILLEGAL COMMAND or BAD LUN).     */    if (tmd->cd_cdb[0] == INQUIRY) {	if (tmd->cd_totlen == 0)	    tmd->cd_totlen = tmd->cd_cdb[4];	if (tmd->cd_totlen == 0) {	    tmd->cd_hflags |= CDFH_STSVALID;	} else if ((tmd->cd_cdb[1] & 0x1f) == 0 && tmd->cd_cdb[2] == 0) {	    struct scatterlist *dp = NULL;	    dp = (struct scatterlist *)

⌨️ 快捷键说明

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