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

📄 sg.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  History: *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com), *           to allow user process control of SCSI devices. *  Development Sponsored by Killy Corp. NY NY * * Original driver (sg.c): *        Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: *        Copyright (C) 1998 - 2000 Douglas Gilbert * *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * */#include <linux/config.h>#ifdef CONFIG_PROC_FS static char * sg_version_str = "Version: 3.1.17 (20001002)";#endif static int sg_version_num = 30117; /* 2 digits for each component *//* *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING *        (otherwise the macros compile to empty statements). *        Then before running the program to be debugged enter: *          # echo "scsi log timeout 7" > /proc/scsi/scsi *        This will send copious output to the console and the log which *        is usually /var/log/messages. To turn off debugging enter: *          # echo "scsi log timeout 0" > /proc/scsi/scsi *        The 'timeout' token was chosen because it is relatively unused. *        The token 'hlcomplete' should be used but that triggers too *        much output from the sd device driver. To dump the current *        state of the SCSI mid level data structures enter: *          # echo "scsi dump 1" > /proc/scsi/scsi *        To dump the state of sg's data structures use: *          # cat /proc/scsi/sg/debug * */#include <linux/module.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/errno.h>#include <linux/mtio.h>#include <linux/ioctl.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/smp_lock.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/blk.h>#include "scsi.h"#include "hosts.h"#include <scsi/scsi_ioctl.h>#include <scsi/sg.h>#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>static int sg_proc_init(void);static void sg_proc_cleanup(void);#endif#ifndef LINUX_VERSION_CODE#include <linux/version.h>#endif /* LINUX_VERSION_CODE *//* #define SG_ALLOW_DIO */#ifdef SG_ALLOW_DIO#include <linux/iobuf.h>#endifint sg_big_buff = SG_DEF_RESERVED_SIZE;/* N.B. This variable is readable and writeable via   /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer   of this size (or less if there is not enough memory) will be reserved   for use by this file descriptor. [Deprecated usage: this variable is also   readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into   the kernel (i.e. it is not a module).] */static int def_reserved_size = -1;      /* picks up init parameter */#define SG_SECTOR_SZ 512#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)#define SG_LOW_POOL_THRESHHOLD 30#define SG_MAX_POOL_SECTORS 320  /* Max. number of pool sectors to take */static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;#define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */#define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */#define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */#define SG_USER_MEM 4   /* memory belongs to user space */#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */static int sg_init(void);static int sg_attach(Scsi_Device *);static void sg_finish(void);static int sg_detect(Scsi_Device *);static void sg_detach(Scsi_Device *);static Scsi_Request * dummy_cmdp = 0;    /* only used for sizeof */static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;  /* Also used to lock			file descriptor list for device */static struct Scsi_Device_Template sg_template ={      tag:"sg",      scsi_type:0xff,      major:SCSI_GENERIC_MAJOR,      detect:sg_detect,      init:sg_init,      finish:sg_finish,      attach:sg_attach,      detach:sg_detach};typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */{    unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */    unsigned bufflen;           /* Size of (aggregate) data buffer */    unsigned b_malloc_len;      /* actual len malloc'ed in buffer */    void * buffer;              /* Data buffer or scatter list,12 bytes each*/    struct kiobuf * kiobp;      /* for direct IO information */    char mapped;                /* indicates kiobp has locked pages */    char buffer_mem_src;        /* heap whereabouts of 'buffer' */    unsigned char cmd_opcode;   /* first byte of command */} Sg_scatter_hold;    /* 24 bytes long on i386 */struct sg_device;               /* forward declarations */struct sg_fd;typedef struct sg_request  /* SG_MAX_QUEUE requests outstanding per file */{    Scsi_Request * my_cmdp;     /* != 0  when request with lower levels */    struct sg_request * nextrp; /* NULL -> tail request (slist) */    struct sg_fd * parentfp;    /* NULL -> not in use */    Sg_scatter_hold data;       /* hold buffer, perhaps scatter list */    sg_io_hdr_t header;         /* scsi command+info, see <scsi/sg.h> */    unsigned char sense_b[sizeof(dummy_cmdp->sr_sense_buffer)];    char res_used;              /* 1 -> using reserve buffer, 0 -> not ... */    char orphan;                /* 1 -> drop on sight, 0 -> normal */    char sg_io_owned;           /* 1 -> packet belongs to SG_IO */    char done;                  /* 0->before bh, 1->before read, 2->read */} Sg_request; /* 168 bytes long on i386 */typedef struct sg_fd /* holds the state of a file descriptor */{    struct sg_fd * nextfp; /* NULL when last opened fd on this device */    struct sg_device * parentdp;     /* owning device */    wait_queue_head_t read_wait;     /* queue read until command done */    rwlock_t rq_list_lock;	     /* protect access to list in req_arr */    int timeout;                     /* defaults to SG_DEFAULT_TIMEOUT */    Sg_scatter_hold reserve;  /* buffer held for this file descriptor */    unsigned save_scat_len;   /* original length of trunc. scat. element */    Sg_request * headrp;      /* head of request slist, NULL->empty */    struct fasync_struct * async_qp; /* used by asynchronous notification */    Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */    char low_dma;       /* as in parent but possibly overridden to 1 */    char force_packid;  /* 1 -> pack_id input to read(), 0 -> ignored */    char closed;        /* 1 -> fd closed but request(s) outstanding */    char fd_mem_src;    /* heap whereabouts of this Sg_fd object */    char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */    char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */    char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */} Sg_fd; /* 2768 bytes long on i386 */typedef struct sg_device /* holds the state of each scsi generic device */{    Scsi_Device * device;    wait_queue_head_t o_excl_wait;   /* queue open() when O_EXCL in use */    int sg_tablesize;   /* adapter's max scatter-gather table size */    Sg_fd * headfp;     /* first open fd belonging to this device */    devfs_handle_t de;    kdev_t i_rdev;      /* holds device major+minor number */    char exclude;       /* opened for exclusive access */    char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */    char detached;      /* 0->attached, 1->detached pending removal */} Sg_device; /* 44 bytes long on i386 */static int sg_fasync(int fd, struct file * filp, int mode);static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt);static int sg_start_req(Sg_request * srp);static void sg_finish_rem_req(Sg_request * srp);static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,			   Sg_request * srp);static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,			int blocking, int read_only, Sg_request ** o_srp);static int sg_common_write(Sg_fd * sfp, Sg_request * srp,			   unsigned char * cmnd, int timeout, int blocking);static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,		      int wr_xf, int * countp, unsigned char ** up);static int sg_write_xfer(Sg_request * srp);static int sg_read_xfer(Sg_request * srp);static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer);static void sg_remove_scat(Sg_scatter_hold * schp);static char * sg_get_sgat_msa(Sg_scatter_hold * schp);static void sg_build_reserve(Sg_fd * sfp, int req_size);static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,                        int * mem_srcp);static void sg_free(char * buff, int size, int mem_src);static char * sg_low_malloc(int rqSz, int lowDma, int mem_src,                            int * retSzp);static void sg_low_free(char * buff, int size, int mem_src);static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);static Sg_request * sg_add_request(Sg_fd * sfp);static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);static int sg_res_in_use(Sg_fd * sfp);static int sg_dio_in_use(Sg_fd * sfp);static void sg_clr_srpnt(Scsi_Request * SRpnt);static void sg_shorten_timeout(Scsi_Request * srpnt);static int sg_ms_to_jif(unsigned int msecs);static unsigned sg_jif_to_ms(int jifs);static int sg_allow_access(unsigned char opcode, char dev_type);static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);static Sg_device * sg_get_dev(int dev);#ifdef CONFIG_PROC_FSstatic int sg_last_dev(void);#endifstatic Sg_device ** sg_dev_arr = NULL;static const int size_sg_header = sizeof(struct sg_header);static const int size_sg_io_hdr = sizeof(sg_io_hdr_t);static const int size_sg_iovec = sizeof(sg_iovec_t);static const int size_sg_req_info = sizeof(sg_req_info_t);static int sg_open(struct inode * inode, struct file * filp){    int dev = MINOR(inode->i_rdev);    int flags = filp->f_flags;    Sg_device * sdp;    Sg_fd * sfp;    int res;    sdp = sg_get_dev(dev);    if ((! sdp) || (! sdp->device) || (! sdp->device->host))        return -ENXIO;    if (sdp->i_rdev != inode->i_rdev)        printk("sg_open: inode maj=%d, min=%d   sdp maj=%d, min=%d\n",               MAJOR(inode->i_rdev), MINOR(inode->i_rdev),               MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));    /* If we are in the middle of error recovery, don't let anyone     * else try and use this device.  Also, if error recovery fails, it     * may try and take the device offline, in which case all further     * access to the device is prohibited.  */    if (! ((flags & O_NONBLOCK) || 	   scsi_block_when_processing_errors(sdp->device)))        return -ENXIO;    SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));    if (flags & O_EXCL) {        if (O_RDONLY == (flags & O_ACCMODE))            return -EACCES;   /* Can't lock it with read only access */        if (sdp->headfp && (flags & O_NONBLOCK))            return -EBUSY;        res = 0;  /* following is a macro that beats race condition */	__wait_event_interruptible(sdp->o_excl_wait,	       ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),                                   res);        if (res)            return res; /* -ERESTARTSYS because signal hit process */    }    else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */        if (flags & O_NONBLOCK)            return -EBUSY;        res = 0;  /* following is a macro that beats race condition */        __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);        if (res)            return res; /* -ERESTARTSYS because signal hit process */    }    if (! sdp->headfp) { /* no existing opens on this device */        sdp->sgdebug = 0;        sdp->sg_tablesize = sdp->device->host->sg_tablesize;    }    if ((sfp = sg_add_sfp(sdp, dev)))        filp->private_data = sfp;    else {        if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */        return -ENOMEM;    }    if (sdp->device->host->hostt->module)        __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);    return 0;}/* Following function was formerly called 'sg_close' */static int sg_release(struct inode * inode, struct file * filp){    Sg_device * sdp;    Sg_fd * sfp;    lock_kernel();    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {	unlock_kernel();        return -ENXIO;    }    SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev)));    sg_fasync(-1, filp, 0);   /* remove filp from async notification list */    sg_remove_sfp(sdp, sfp);    if (! sdp->headfp)        filp->private_data = NULL;    if (sdp->device->host->hostt->module)        __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);    sdp->exclude = 0;    wake_up_interruptible(&sdp->o_excl_wait);    unlock_kernel();    return 0;}static ssize_t sg_read(struct file * filp, char * buf,                       size_t count, loff_t *ppos){    int k, res;    Sg_device * sdp;    Sg_fd * sfp;    Sg_request * srp;    int req_pack_id = -1;    struct sg_header old_hdr;    sg_io_hdr_t new_hdr;    sg_io_hdr_t * hp;    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))        return -ENXIO;    SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",                               MINOR(sdp->i_rdev), (int)count));    if (ppos != &filp->f_pos)        ; /* FIXME: Hmm.  Seek to the right place, or fail?  */    if ((k = verify_area(VERIFY_WRITE, buf, count)))        return k;    if (sfp->force_packid && (count >= size_sg_header)) {	__copy_from_user(&old_hdr, buf, size_sg_header);	if (old_hdr.reply_len < 0) {	    if (count >= size_sg_io_hdr) {		__copy_from_user(&new_hdr, buf, size_sg_io_hdr);		req_pack_id = new_hdr.pack_id;	    }	}	else	    req_pack_id = old_hdr.pack_id;    }    srp = sg_get_rq_mark(sfp, req_pack_id);    if (! srp) { /* now wait on packet to arrive */        if (filp->f_flags & O_NONBLOCK)            return -EAGAIN;	while (1) {	    int dio = sg_dio_in_use(sfp);	    res = 0;  /* following is a macro that beats race condition */	    __wait_event_interruptible(sfp->read_wait,                                   (srp = sg_get_rq_mark(sfp, req_pack_id)),                                   res);	    if (0 == res)		break;	    else if (! dio)     /* only let signal out if no dio */		return res; /* -ERESTARTSYS because signal hit process */	}    }    if (srp->header.interface_id != '\0')	return sg_new_read(sfp, buf, count, srp);    hp = &srp->header;    memset(&old_hdr, 0, size_sg_header);    old_hdr.reply_len = (int)hp->timeout;    old_hdr.pack_len = old_hdr.reply_len;   /* very old, strange behaviour */

⌨️ 快捷键说明

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