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

📄 ub.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * The low performance USB storage driver (ub). * * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) * * This work is a part of Linux kernel, is derived from it, * and is not licensed separately. See file COPYING for details. * * TODO (sorted by decreasing priority) *  -- Kill first_open (Al Viro fixed the block layer now) *  -- Do resets with usb_device_reset (needs a thread context, use khubd) *  -- set readonly flag for CDs, set removable flag for CF readers *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries *  -- verify the 13 conditions and do bulk resets *  -- kill last_pipe and simply do two-state clearing on both pipes *  -- verify protocol (bulk) from USB descriptors (maybe...) *  -- highmem *  -- move top_sense and work_bcs into separate allocations (if they survive) *     for cache purists and esoteric architectures. *  -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ? *  -- prune comments, they are too volumnous *  -- Exterminate P3 printks *  -- Resove XXX's *  -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=? *  -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. */#include <linux/kernel.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/blkdev.h>#include <linux/devfs_fs_kernel.h>#include <linux/timer.h>#include <scsi/scsi.h>#define DRV_NAME "ub"#define DEVFS_NAME DRV_NAME#define UB_MAJOR 180/* * The command state machine is the key model for understanding of this driver. * * The general rule is that all transitions are done towards the bottom * of the diagram, thus preventing any loops. * * An exception to that is how the STAT state is handled. A counter allows it * to be re-entered along the path marked with [C]. * *       +--------+ *       ! INIT   ! *       +--------+ *           ! *        ub_scsi_cmd_start fails ->--------------------------------------\ *           !                                                            ! *           V                                                            ! *       +--------+                                                       ! *       ! CMD    !                                                       ! *       +--------+                                                       ! *           !                                            +--------+      ! *         was -EPIPE -->-------------------------------->! CLEAR  !      ! *           !                                            +--------+      ! *           !                                                !           ! *         was error -->------------------------------------- ! --------->\ *           !                                                !           ! *  /--<-- cmd->dir == NONE ?                                 !           ! *  !        !                                                !           ! *  !        V                                                !           ! *  !    +--------+                                           !           ! *  !    ! DATA   !                                           !           ! *  !    +--------+                                           !           ! *  !        !                           +---------+          !           ! *  !      was -EPIPE -->--------------->! CLR2STS !          !           ! *  !        !                           +---------+          !           ! *  !        !                                !               !           ! *  !        !                              was error -->---- ! --------->\ *  !      was error -->--------------------- ! ------------- ! --------->\ *  !        !                                !               !           ! *  !        V                                !               !           ! *  \--->+--------+                           !               !           ! *       ! STAT   !<--------------------------/               !           ! *  /--->+--------+                                           !           ! *  !        !                                                !           ! * [C]     was -EPIPE -->-----------\                         !           ! *  !        !                      !                         !           ! *  +<---- len == 0                 !                         !           ! *  !        !                      !                         !           ! *  !      was error -->--------------------------------------!---------->\ *  !        !                      !                         !           ! *  +<---- bad CSW                  !                         !           ! *  +<---- bad tag                  !                         !           ! *  !        !                      V                         !           ! *  !        !                 +--------+                     !           ! *  !        !                 ! CLRRS  !                     !           ! *  !        !                 +--------+                     !           ! *  !        !                      !                         !           ! *  \------- ! --------------------[C]--------\               !           ! *           !                                !               !           ! *         cmd->error---\                +--------+           !           ! *           !          +--------------->! SENSE  !<----------/           ! *         STAT_FAIL----/                +--------+                       ! *           !                                !                           V *           !                                V                      +--------+ *           \--------------------------------\--------------------->! DONE   ! *                                                                   +--------+ *//* * Definitions which have to be scattered once we understand the layout better. *//* Transport (despite PR in the name) */#define US_PR_BULK	0x50		/* bulk only *//* Protocol */#define US_SC_SCSI	0x06		/* Transparent *//* * This many LUNs per USB device. * Every one of them takes a host, see UB_MAX_HOSTS. */#define UB_MAX_LUNS   9/* */#define UB_MINORS_PER_MAJOR	8#define UB_MAX_CDB_SIZE      16		/* Corresponds to Bulk */#define UB_SENSE_SIZE  18/* *//* command block wrapper */struct bulk_cb_wrap {	__le32	Signature;		/* contains 'USBC' */	u32	Tag;			/* unique per command id */	__le32	DataTransferLength;	/* size of data */	u8	Flags;			/* direction in bit 0 */	u8	Lun;			/* LUN */	u8	Length;			/* of of the CDB */	u8	CDB[UB_MAX_CDB_SIZE];	/* max command */};#define US_BULK_CB_WRAP_LEN	31#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */#define US_BULK_FLAG_IN		1#define US_BULK_FLAG_OUT	0/* command status wrapper */struct bulk_cs_wrap {	__le32	Signature;		/* should = 'USBS' */	u32	Tag;			/* same as original command */	__le32	Residue;		/* amount not transferred */	u8	Status;			/* see below */};#define US_BULK_CS_WRAP_LEN	13#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */#define US_BULK_STAT_OK		0#define US_BULK_STAT_FAIL	1#define US_BULK_STAT_PHASE	2/* bulk-only class specific requests */#define US_BULK_RESET_REQUEST	0xff#define US_BULK_GET_MAX_LUN	0xfe/* */struct ub_dev;#define UB_MAX_REQ_SG	9	/* cdrecord requires 32KB and maybe a header */#define UB_MAX_SECTORS 64/* * A second is more than enough for a 32K transfer (UB_MAX_SECTORS) * even if a webcam hogs the bus, but some devices need time to spin up. */#define UB_URB_TIMEOUT	(HZ*2)#define UB_DATA_TIMEOUT	(HZ*5)	/* ZIP does spin-ups in the data phase */#define UB_STAT_TIMEOUT	(HZ*5)	/* Same spinups and eject for a dataless cmd. */#define UB_CTRL_TIMEOUT	(HZ/2)	/* 500ms ought to be enough to clear a stall *//* * An instance of a SCSI command in transit. */#define UB_DIR_NONE	0#define UB_DIR_READ	1#define UB_DIR_ILLEGAL2	2#define UB_DIR_WRITE	3#define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \			 (((c)==UB_DIR_READ)? 'r': 'n'))enum ub_scsi_cmd_state {	UB_CMDST_INIT,			/* Initial state */	UB_CMDST_CMD,			/* Command submitted */	UB_CMDST_DATA,			/* Data phase */	UB_CMDST_CLR2STS,		/* Clearing before requesting status */	UB_CMDST_STAT,			/* Status phase */	UB_CMDST_CLEAR,			/* Clearing a stall (halt, actually) */	UB_CMDST_CLRRS,			/* Clearing before retrying status */	UB_CMDST_SENSE,			/* Sending Request Sense */	UB_CMDST_DONE			/* Final state */};static char *ub_scsi_cmd_stname[] = {	".  ",	"Cmd",	"dat",	"c2s",	"sts",	"clr",	"crs",	"Sen",	"fin"};struct ub_scsi_cmd {	unsigned char cdb[UB_MAX_CDB_SIZE];	unsigned char cdb_len;	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */	unsigned char trace_index;	enum ub_scsi_cmd_state state;	unsigned int tag;	struct ub_scsi_cmd *next;	int error;			/* Return code - valid upon done */	unsigned int act_len;		/* Return size */	unsigned char key, asc, ascq;	/* May be valid if error==-EIO */	int stat_count;			/* Retries getting status. */	unsigned int len;		/* Requested length */	unsigned int current_sg;	unsigned int nsg;		/* sgv[nsg] */	struct scatterlist sgv[UB_MAX_REQ_SG];	struct ub_lun *lun;	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);	void *back;};/* */struct ub_capacity {	unsigned long nsec;		/* Linux size - 512 byte sectors */	unsigned int bsize;		/* Linux hardsect_size */	unsigned int bshift;		/* Shift between 512 and hard sects */};/* * The SCSI command tracing structure. */#define SCMD_ST_HIST_SZ   8#define SCMD_TRACE_SZ    63		/* Less than 4KB of 61-byte lines */struct ub_scsi_cmd_trace {	int hcur;	unsigned int tag;	unsigned int req_size, act_size;	unsigned char op;	unsigned char dir;	unsigned char key, asc, ascq;	char st_hst[SCMD_ST_HIST_SZ];	};struct ub_scsi_trace {	int cur;	struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];};/* * This is a direct take-off from linux/include/completion.h * The difference is that I do not wait on this thing, just poll. * When I want to wait (ub_probe), I just use the stock completion. * * Note that INIT_COMPLETION takes no lock. It is correct. But why * in the bloody hell that thing takes struct instead of pointer to struct * is quite beyond me. I just copied it from the stock completion. */struct ub_completion {	unsigned int done;	spinlock_t lock;};static inline void ub_init_completion(struct ub_completion *x){	x->done = 0;	spin_lock_init(&x->lock);}#define UB_INIT_COMPLETION(x)	((x).done = 0)static void ub_complete(struct ub_completion *x){	unsigned long flags;	spin_lock_irqsave(&x->lock, flags);	x->done++;	spin_unlock_irqrestore(&x->lock, flags);}static int ub_is_completed(struct ub_completion *x){	unsigned long flags;	int ret;	spin_lock_irqsave(&x->lock, flags);	ret = x->done;	spin_unlock_irqrestore(&x->lock, flags);	return ret;}/* */struct ub_scsi_cmd_queue {	int qlen, qmax;	struct ub_scsi_cmd *head, *tail;};/* * The block device instance (one per LUN). */struct ub_lun {	struct ub_dev *udev;	struct list_head link;	struct gendisk *disk;	int id;				/* Host index */	int num;			/* LUN number */	char name[16];	int changed;			/* Media was changed */	int removable;	int readonly;	int first_open;			/* Kludge. See ub_bd_open. */	/* Use Ingo's mempool if or when we have more than one command. */	/*	 * Currently we never need more than one command for the whole device.	 * However, giving every LUN a command is a cheap and automatic way	 * to enforce fairness between them.	 */	int cmda[1];	struct ub_scsi_cmd cmdv[1];	struct ub_capacity capacity; };/* * The USB device instance. */struct ub_dev {	spinlock_t lock;	atomic_t poison;		/* The USB device is disconnected */	int openc;			/* protected by ub_lock! */					/* kref is too implicit for our taste */	unsigned int tagcnt;	char name[12];	struct usb_device *dev;	struct usb_interface *intf;	struct list_head luns;	unsigned int send_bulk_pipe;	/* cached pipe values */	unsigned int recv_bulk_pipe;	unsigned int send_ctrl_pipe;	unsigned int recv_ctrl_pipe;	struct tasklet_struct tasklet;	struct ub_scsi_cmd_queue cmd_queue;	struct ub_scsi_cmd top_rqs_cmd;	/* REQUEST SENSE */	unsigned char top_sense[UB_SENSE_SIZE];	struct ub_completion work_done;	struct urb work_urb;	struct timer_list work_timer;	int last_pipe;			/* What might need clearing */	__le32 signature;		/* Learned signature */	struct bulk_cb_wrap work_bcb;	struct bulk_cs_wrap work_bcs;	struct usb_ctrlrequest work_cr;	int sg_stat[6];	struct ub_scsi_trace tr;};/* */static void ub_cleanup(struct ub_dev *sc);static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,    struct ub_scsi_cmd *cmd, struct request *rq);static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,    struct ub_scsi_cmd *cmd, struct request *rq);static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_end_rq(struct request *rq, int uptodate);static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);static void ub_scsi_action(unsigned long _dev);static void ub_scsi_dispatch(struct ub_dev *sc);static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,    int stalled_pipe);static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,    struct ub_capacity *ret);static int ub_probe_lun(struct ub_dev *sc, int lnum);/* */static struct usb_device_id ub_usb_ids[] = {	// { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) },	/* SDDR-31 */	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },	{ }};MODULE_DEVICE_TABLE(usb, ub_usb_ids);/* * Find me a way to identify "next free minor" for add_disk(), * and the array disappears the next day. However, the number of * hosts has something to do with the naming and /proc/partitions. * This has to be thought out in detail before changing. * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. */#define UB_MAX_HOSTS  26static char ub_hostv[UB_MAX_HOSTS];static DEFINE_SPINLOCK(ub_lock);	/* Locks globals and ->openc *//* * The SCSI command tracing procedures. */static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	int n;	struct ub_scsi_cmd_trace *t;	if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;	t = &sc->tr.vec[n];	memset(t, 0, sizeof(struct ub_scsi_cmd_trace));	t->tag = cmd->tag;	t->op = cmd->cdb[0];	t->dir = cmd->dir;	t->req_size = cmd->len;	t->st_hst[0] = cmd->state;	sc->tr.cur = n;	cmd->trace_index = n;}static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	int n;	struct ub_scsi_cmd_trace *t;	t = &sc->tr.vec[cmd->trace_index];	if (t->tag == cmd->tag) {		if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;		t->st_hst[n] = cmd->state;		t->hcur = n;	}}static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct ub_scsi_cmd_trace *t;	t = &sc->tr.vec[cmd->trace_index];	if (t->tag == cmd->tag)		t->act_size = cmd->act_len;}static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd,    unsigned char *sense){	struct ub_scsi_cmd_trace *t;	t = &sc->tr.vec[cmd->trace_index];	if (t->tag == cmd->tag) {		t->key = sense[2] & 0x0F;		t->asc = sense[12];		t->ascq = sense[13];	}}

⌨️ 快捷键说明

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