u14-34f.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,874 行 · 第 1/5 页

C
1,874
字号
 *  cmds/lun) and Q > 2, whenever there is already an active command to the *  device all other commands to the same device  (up to Q-1) are kept waiting *  in the elevator sorting queue. When the active command completes, the *  commands in this queue are sorted by sector address. The sort is chosen *  between increasing or decreasing by minimizing the seek distance between *  the sector of the commands just completed and the sector of the first *  command in the list to be sorted. *  Trivial math assures that the unsorted average seek distance when doing *  random seeks over S sectors is S/3. *  When (Q-1) requests are uniformly distributed over S sectors, the average *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted *  average seek distance for (Q-1) random requests over S sectors is S/Q. *  The elevator sorting hence divides the seek distance by a factor Q/3. *  The above pure geometric remarks are valid in all cases and the *  driver effectively reduces the seek distance by the predicted factor *  when there are Q concurrent read i/o operations on the device, but this *  does not necessarily results in a noticeable performance improvement: *  your mileage may vary.... * *  Note: command reordering inside a batch of queued commands could cause *        wrong results only if there is at least one write request and the *        intersection (sector-wise) of all requests is not empty. *        When the driver detects a batch including overlapping requests *        (a really rare event) strict serial (pid) order is enforced. *  ---------------------------------------------------------------------------- * *  The boards are named Ux4F0, Ux4F1,... according to the detection order. * *  In order to support multiple ISA boards in a reliable way, *  the driver sets host->wish_block = TRUE for all ISA boards. */#include <linux/config.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/system.h>#include <asm/byteorder.h>#include <linux/proc_fs.h>#include <linux/blkdev.h>#include <linux/interrupt.h>#include <linux/stat.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/ctype.h>#include <linux/spinlock.h>#include <scsi/scsicam.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <asm/dma.h>#include <asm/irq.h>static int u14_34f_detect(Scsi_Host_Template *);static int u14_34f_release(struct Scsi_Host *);static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));static int u14_34f_eh_abort(Scsi_Cmnd *);static int u14_34f_eh_host_reset(Scsi_Cmnd *);static int u14_34f_bios_param(struct scsi_device *, struct block_device *,                              sector_t, int *);static int u14_34f_slave_configure(Scsi_Device *);static Scsi_Host_Template driver_template = {                .name                    = "UltraStor 14F/34F rev. 8.10.00 ",                .detect                  = u14_34f_detect,                .release                 = u14_34f_release,                .queuecommand            = u14_34f_queuecommand,                .eh_abort_handler        = u14_34f_eh_abort,                .eh_device_reset_handler = NULL,                .eh_bus_reset_handler    = NULL,                .eh_host_reset_handler   = u14_34f_eh_host_reset,                .bios_param              = u14_34f_bios_param,                .slave_configure         = u14_34f_slave_configure,                .this_id                 = 7,                .unchecked_isa_dma       = 1,                .use_clustering          = ENABLE_CLUSTERING                };#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)#error "Adjust your <asm/byteorder.h> defines"#endif/* Values for the PRODUCT_ID ports for the 14/34F */#define PRODUCT_ID1  0x56#define PRODUCT_ID2  0x40        /* NOTE: Only upper nibble is used *//* Subversion values */#define ISA  0#define ESA 1#define OP_HOST_ADAPTER   0x1#define OP_SCSI           0x2#define OP_RESET          0x4#define DTD_SCSI          0x0#define DTD_IN            0x1#define DTD_OUT           0x2#define DTD_NONE          0x3#define HA_CMD_INQUIRY    0x1#define HA_CMD_SELF_DIAG  0x2#define HA_CMD_READ_BUFF  0x3#define HA_CMD_WRITE_BUFF 0x4#undef  DEBUG_LINKED_COMMANDS#undef  DEBUG_DETECT#undef  DEBUG_INTERRUPT#undef  DEBUG_RESET#undef  DEBUG_GENERATE_ERRORS#undef  DEBUG_GENERATE_ABORTS#undef  DEBUG_GEOMETRY#define MAX_ISA 3#define MAX_VESA 1#define MAX_EISA 0#define MAX_PCI 0#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)#define MAX_CHANNEL 1#define MAX_LUN 8#define MAX_TARGET 8#define MAX_MAILBOXES 16#define MAX_SGLIST 32#define MAX_SAFE_SGLIST 16#define MAX_INTERNAL_RETRIES 64#define MAX_CMD_PER_LUN 2#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)#define SKIP ULONG_MAX#define FALSE 0#define TRUE 1#define FREE 0#define IN_USE   1#define LOCKED   2#define IN_RESET 3#define IGNORE   4#define READY    5#define ABORTING 6#define NO_DMA  0xff#define MAXLOOP  10000#define TAG_DISABLED 0#define TAG_SIMPLE   1#define TAG_ORDERED  2#define REG_LCL_MASK      0#define REG_LCL_INTR      1#define REG_SYS_MASK      2#define REG_SYS_INTR      3#define REG_PRODUCT_ID1   4#define REG_PRODUCT_ID2   5#define REG_CONFIG1       6#define REG_CONFIG2       7#define REG_OGM           8#define REG_ICM           12#define REGION_SIZE       13UL#define BSY_ASSERTED      0x01#define IRQ_ASSERTED      0x01#define CMD_RESET         0xc0#define CMD_OGM_INTR      0x01#define CMD_CLR_INTR      0x01#define CMD_ENA_INTR      0x81#define ASOK              0x00#define ASST              0x91#define YESNO(a) ((a) ? 'y' : 'n')#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)#define PACKED          __attribute__((packed))struct sg_list {   unsigned int address;                /* Segment Address */   unsigned int num_bytes;              /* Segment Length */   };/* MailBox SCSI Command Packet */struct mscp {#if defined(__BIG_ENDIAN_BITFIELD)   unsigned char sg:1, ca:1, dcn:1, xdir:2, opcode:3;   unsigned char lun: 3, channel:2, target:3;#else   unsigned char opcode: 3,             /* type of command */                 xdir: 2,               /* data transfer direction */                 dcn: 1,                /* disable disconnect */                 ca: 1,                 /* use cache (if available) */                 sg: 1;                 /* scatter/gather operation */   unsigned char target: 3,             /* SCSI target id */                 channel: 2,            /* SCSI channel number */                 lun: 3;                /* SCSI logical unit number */#endif   unsigned int data_address PACKED;    /* transfer data pointer */   unsigned int data_len PACKED;        /* length in bytes */   unsigned int link_address PACKED;    /* for linking command chains */   unsigned char clink_id;              /* identifies command in chain */   unsigned char use_sg;                /* (if sg is set) 8 bytes per list */   unsigned char sense_len;   unsigned char cdb_len;               /* 6, 10, or 12 */   unsigned char cdb[12];               /* SCSI Command Descriptor Block */   unsigned char adapter_status;        /* non-zero indicates HA error */   unsigned char target_status;         /* non-zero indicates target error */   unsigned int sense_addr PACKED;   /* Additional fields begin here. */   Scsi_Cmnd *SCpnt;   unsigned int cpp_index;              /* cp index */   /* All the cp structure is zero filled by queuecommand except the      following CP_TAIL_SIZE bytes, initialized by detect */   dma_addr_t cp_dma_addr; /* dma handle for this cp structure */   struct sg_list *sglist; /* pointer to the allocated SG list */   };#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))struct hostdata {   struct mscp cp[MAX_MAILBOXES];       /* Mailboxes for this board */   unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */   unsigned int last_cp_used;           /* Index of last mailbox used */   unsigned int iocount;                /* Total i/o done for this board */   int board_number;                    /* Number of this board */   char board_name[16];                 /* Name of this board */   int in_reset;                        /* True if board is doing a reset */   int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */   int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */   unsigned int retries;                /* Number of internal retries */   unsigned long last_retried_pid;      /* Pid of last retried command */   unsigned char subversion;            /* Bus type, either ISA or ESA */   struct pci_dev *pdev;                /* Always NULL */   unsigned char heads;   unsigned char sectors;   char board_id[256];                  /* data from INQUIRY on this board */   };static struct Scsi_Host *sh[MAX_BOARDS + 1];static const char *driver_name = "Ux4F";static char sha[MAX_BOARDS];static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;/* Initialize num_boards so that ihdlr can work while detect is in progress */static unsigned int num_boards = MAX_BOARDS;static unsigned long io_port[] = {   /* Space for MAX_INT_PARAM ports usable while loading as a module */   SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,    SKIP,   /* Possible ISA/VESA ports */   0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,   /* End of list */   0x0   };#define HD(board) ((struct hostdata *) &sh[board]->hostdata)#define BN(board) (HD(board)->board_name)/* Device is Little Endian */#define H2DEV(x) cpu_to_le32(x)#define DEV2H(x) le32_to_cpu(x)static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int);static int do_trace = FALSE;static int setup_done = FALSE;static int link_statistics;static int ext_tran = FALSE;#if defined(HAVE_OLD_UX4F_FIRMWARE)static int have_old_firmware = TRUE;#elsestatic int have_old_firmware = FALSE;#endif#if defined(CONFIG_SCSI_U14_34F_TAGGED_QUEUE)static int tag_mode = TAG_SIMPLE;#elsestatic int tag_mode = TAG_DISABLED;#endif#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)static int linked_comm = TRUE;#elsestatic int linked_comm = FALSE;#endif#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;#elsestatic int max_queue_depth = MAX_CMD_PER_LUN;#endif#define MAX_INT_PARAM 10#define MAX_BOOT_OPTIONS_SIZE 256static char boot_options[MAX_BOOT_OPTIONS_SIZE];#if defined(MODULE)#include <linux/module.h>#include <linux/moduleparam.h>module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0);MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \"option." \"      Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\"");MODULE_AUTHOR("Dario Ballabio");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver");#endifstatic int u14_34f_slave_configure(Scsi_Device *dev) {   int j, tqd, utqd;   char *tag_suffix, *link_suffix;   struct Scsi_Host *host = dev->host;   j = ((struct hostdata *) host->hostdata)->board_number;   utqd = MAX_CMD_PER_LUN;   tqd = max_queue_depth;   if (TLDEV(dev->type) && dev->tagged_supported)      if (tag_mode == TAG_SIMPLE) {         scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);         tag_suffix = ", simple tags";         }      else if (tag_mode == TAG_ORDERED) {         scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);         tag_suffix = ", ordered tags";         }      else {         scsi_adjust_queue_depth(dev, 0, tqd);         tag_suffix = ", no tags";         }   else if (TLDEV(dev->type) && linked_comm) {      scsi_adjust_queue_depth(dev, 0, tqd);      tag_suffix = ", untagged";      }   else {      scsi_adjust_queue_depth(dev, 0, utqd);      tag_suffix = "";      }   if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2)      link_suffix = ", sorted";   else if (TLDEV(dev->type))      link_suffix = ", unsorted";   else      link_suffix = "";   printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",          BN(j), host->host_no, dev->channel, dev->id, dev->lun,          dev->queue_depth, link_suffix, tag_suffix);   return FALSE;}static int wait_on_busy(unsigned long iobase, unsigned int loop) {   while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {      udelay(1L);      if (--loop == 0) return TRUE;      }   return FALSE;}static int board_inquiry(unsigned int j) {   struct mscp *cpp;   dma_addr_t id_dma_addr;   unsigned int time, limit = 0;   id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,                    sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);

⌨️ 快捷键说明

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