📄 sg.c
字号:
/* * 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 + -