nsp32.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页
C
2,409 行
/* * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver * Copyright (C) 2001, 2002, 2003 * YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> * GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org> * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * Revision History: * 1.0: Initial Release. * 1.1: Add /proc SDTR status. * Remove obsolete error handler nsp32_reset. * Some clean up. * 1.2: PowerPC (big endian) support. */#include <linux/version.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/major.h>#include <linux/blkdev.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ctype.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include "scsi.h"#include <scsi/scsi_host.h>#include <scsi/scsi_ioctl.h>#include <scsi/scsi.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))# include <linux/blk.h>#endif#include "nsp32.h"/*********************************************************************** * Module parameters */static int trans_mode = 0; /* default: BIOS */MODULE_PARM (trans_mode, "i");MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");#define ASYNC_MODE 1#define ULTRA20M_MODE 2static int auto_param = 0; /* default: ON */MODULE_PARM (auto_param, "i");MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");static int disc_priv = 1; /* default: OFF */MODULE_PARM (disc_priv, "i");MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))");MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");MODULE_LICENSE("GPL");static const char *nsp32_release_version = "1.2";/**************************************************************************** * Supported hardware */static struct pci_device_id nsp32_pci_table[] __devinitdata = { { .vendor = PCI_VENDOR_ID_IODATA, .device = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_IODATA, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32BI_KME, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_KME, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32BI_WBT, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_WORKBIT, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_WORKBIT_STANDARD, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_PCI_WORKBIT, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_LOGITEC, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_PCI_LOGITEC, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_PCI_MELCO, }, { .vendor = PCI_VENDOR_ID_WORKBIT, .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .driver_data = MODEL_PCI_MELCO, }, {0,0,},};MODULE_DEVICE_TABLE(pci, nsp32_pci_table);static nsp32_hw_data nsp32_data_base; /* probe <-> detect glue *//* * Period/AckWidth speed conversion table * * Note: This period/ackwidth speed table must be in descending order. */static nsp32_sync_table nsp32_sync_table_40M[] = { /* {PNo, AW, SP, EP, SREQ smpl} Speed(MB/s) Period AckWidth */ {0x1, 0, 0x0c, 0x0c, SMPL_40M}, /* 20.0 : 50ns, 25ns */ {0x2, 0, 0x0d, 0x18, SMPL_40M}, /* 13.3 : 75ns, 25ns */ {0x3, 1, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ {0x4, 1, 0x1a, 0x1f, SMPL_20M}, /* 8.0 : 125ns, 50ns */ {0x5, 2, 0x20, 0x25, SMPL_20M}, /* 6.7 : 150ns, 75ns */ {0x6, 2, 0x26, 0x31, SMPL_20M}, /* 5.7 : 175ns, 75ns */ {0x7, 3, 0x32, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ {0x8, 3, 0x33, 0x38, SMPL_10M}, /* 4.4 : 225ns, 100ns */ {0x9, 3, 0x39, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */};static nsp32_sync_table nsp32_sync_table_20M[] = { {0x1, 0, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ {0x2, 0, 0x1a, 0x25, SMPL_20M}, /* 6.7 : 150ns, 50ns */ {0x3, 1, 0x26, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ {0x4, 1, 0x33, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */ {0x5, 2, 0x3f, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 150ns */ {0x6, 2, 0x4c, 0x57, SMPL_10M}, /* 2.8 : 350ns, 150ns */ {0x7, 3, 0x58, 0x64, SMPL_10M}, /* 2.5 : 400ns, 200ns */ {0x8, 3, 0x65, 0x70, SMPL_10M}, /* 2.2 : 450ns, 200ns */ {0x9, 3, 0x71, 0x7d, SMPL_10M}, /* 2.0 : 500ns, 200ns */};static nsp32_sync_table nsp32_sync_table_pci[] = { {0x1, 0, 0x0c, 0x0f, SMPL_40M}, /* 16.6 : 60ns, 30ns */ {0x2, 0, 0x10, 0x16, SMPL_40M}, /* 11.1 : 90ns, 30ns */ {0x3, 1, 0x17, 0x1e, SMPL_20M}, /* 8.3 : 120ns, 60ns */ {0x4, 1, 0x1f, 0x25, SMPL_20M}, /* 6.7 : 150ns, 60ns */ {0x5, 2, 0x26, 0x2d, SMPL_20M}, /* 5.6 : 180ns, 90ns */ {0x6, 2, 0x2e, 0x34, SMPL_10M}, /* 4.8 : 210ns, 90ns */ {0x7, 3, 0x35, 0x3c, SMPL_10M}, /* 4.2 : 240ns, 120ns */ {0x8, 3, 0x3d, 0x43, SMPL_10M}, /* 3.7 : 270ns, 120ns */ {0x9, 3, 0x44, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 120ns */};/* * function declaration *//* module entry point */static int __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *);static void __devexit nsp32_remove(struct pci_dev *);static int __init init_nsp32 (void);static void __exit exit_nsp32 (void);/* struct Scsi_Host_Template */#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);#elsestatic int nsp32_proc_info (char *, char **, off_t, int, int, int);#endif#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))static int nsp32_detect (struct pci_dev *pdev);#elsestatic int nsp32_detect (Scsi_Host_Template *);#endifstatic int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));static const char *nsp32_info (struct Scsi_Host *);static int nsp32_release (struct Scsi_Host *);/* SCSI error handler */static int nsp32_eh_abort (Scsi_Cmnd *);static int nsp32_eh_bus_reset (Scsi_Cmnd *);static int nsp32_eh_host_reset(Scsi_Cmnd *);/* generate SCSI message */static void nsp32_build_identify(Scsi_Cmnd *);static void nsp32_build_nop (Scsi_Cmnd *);static void nsp32_build_reject (Scsi_Cmnd *);static void nsp32_build_sdtr (Scsi_Cmnd *, unsigned char, unsigned char);/* SCSI message handler */static int nsp32_busfree_occur(Scsi_Cmnd *, unsigned short);static void nsp32_msgout_occur (Scsi_Cmnd *);static void nsp32_msgin_occur (Scsi_Cmnd *, unsigned long, unsigned short);static int nsp32_setup_sg_table (Scsi_Cmnd *);static int nsp32_selection_autopara(Scsi_Cmnd *);static int nsp32_selection_autoscsi(Scsi_Cmnd *);static void nsp32_scsi_done (Scsi_Cmnd *);static int nsp32_arbitration (Scsi_Cmnd *, unsigned int);static int nsp32_reselection (Scsi_Cmnd *, unsigned char);static void nsp32_adjust_busfree (Scsi_Cmnd *, unsigned int);static void nsp32_restart_autoscsi (Scsi_Cmnd *, unsigned short);/* SCSI SDTR */static void nsp32_analyze_sdtr (Scsi_Cmnd *);static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);static void nsp32_set_async (nsp32_hw_data *, nsp32_target *);static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *, int, unsigned char);/* SCSI bus status handler */static void nsp32_wait_req (nsp32_hw_data *, int);static void nsp32_wait_sack (nsp32_hw_data *, int);static void nsp32_sack_assert (nsp32_hw_data *);static void nsp32_sack_negate (nsp32_hw_data *);static void nsp32_do_bus_reset(nsp32_hw_data *);/* hardware interrupt handler */static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);/* initialize hardware */static int nsp32hw_init(nsp32_hw_data *);/* EEPROM handler */static int nsp32_getprom_param (nsp32_hw_data *);static int nsp32_getprom_at24 (nsp32_hw_data *);static int nsp32_getprom_c16 (nsp32_hw_data *);static void nsp32_prom_start (nsp32_hw_data *);static void nsp32_prom_stop (nsp32_hw_data *);static int nsp32_prom_read (nsp32_hw_data *, int);static int nsp32_prom_read_bit (nsp32_hw_data *);static void nsp32_prom_write_bit(nsp32_hw_data *, int);static void nsp32_prom_set (nsp32_hw_data *, int, int);static int nsp32_prom_get (nsp32_hw_data *, int);/* debug/warning/info message */static void nsp32_message (const char *, int, char *, char *, ...);#ifdef NSP32_DEBUGstatic void nsp32_dmessage(const char *, int, int, char *, ...);#endif/* * max_sectors is currently limited up to 128. */static Scsi_Host_Template nsp32_template = { .proc_name = "nsp32", .name = "Workbit NinjaSCSI-32Bi/UDE", .proc_info = nsp32_proc_info, .info = nsp32_info, .queuecommand = nsp32_queuecommand, .can_queue = 1, .sg_tablesize = NSP32_SG_SIZE, .max_sectors = 128, .cmd_per_lun = 1, .this_id = NSP32_HOST_SCSIID, .use_clustering = DISABLE_CLUSTERING, .eh_abort_handler = nsp32_eh_abort,/* .eh_device_reset_handler = NULL, */ .eh_bus_reset_handler = nsp32_eh_bus_reset, .eh_host_reset_handler = nsp32_eh_host_reset,#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)) .detect = nsp32_detect, .release = nsp32_release,#endif#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) .use_new_eh_code = 1,#else/* .highmem_io = 1, */#endif};#include "nsp32_io.h"/*********************************************************************** * debug, error print */#ifndef NSP32_DEBUG# define NSP32_DEBUG_MASK 0x000000# define nsp32_msg(type, args...) nsp32_message ("", 0, (type), args)# define nsp32_dbg(mask, args...) /* */#else# define NSP32_DEBUG_MASK 0xffffff# define nsp32_msg(type, args...) \ nsp32_message (__FUNCTION__, __LINE__, (type), args)# define nsp32_dbg(mask, args...) \ nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)#endif#define NSP32_DEBUG_QUEUECOMMAND BIT(0)#define NSP32_DEBUG_REGISTER BIT(1)#define NSP32_DEBUG_AUTOSCSI BIT(2)#define NSP32_DEBUG_INTR BIT(3)#define NSP32_DEBUG_SGLIST BIT(4)#define NSP32_DEBUG_BUSFREE BIT(5)#define NSP32_DEBUG_CDB_CONTENTS BIT(6)#define NSP32_DEBUG_RESELECTION BIT(7)#define NSP32_DEBUG_MSGINOCCUR BIT(8)#define NSP32_DEBUG_EEPROM BIT(9)#define NSP32_DEBUG_MSGOUTOCCUR BIT(10)#define NSP32_DEBUG_BUSRESET BIT(11)#define NSP32_DEBUG_RESTART BIT(12)#define NSP32_DEBUG_SYNC BIT(13)#define NSP32_DEBUG_WAIT BIT(14)#define NSP32_DEBUG_TARGETFLAG BIT(15)#define NSP32_DEBUG_PROC BIT(16)#define NSP32_DEBUG_INIT BIT(17)#define NSP32_SPECIAL_PRINT_REGISTER BIT(20)#define NSP32_DEBUG_BUF_LEN 100static void nsp32_message(const char *func, int line, char *type, char *fmt, ...){ va_list args; char buf[NSP32_DEBUG_BUF_LEN]; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args);#ifndef NSP32_DEBUG printk("%snsp32: %s\n", type, buf);#else printk("%snsp32: %s (%d): %s\n", type, func, line, buf);#endif}#ifdef NSP32_DEBUGstatic void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...){ va_list args; char buf[NSP32_DEBUG_BUF_LEN]; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); if (mask & NSP32_DEBUG_MASK) { printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); }}#endif#ifdef NSP32_DEBUG# include "nsp32_debug.c"#else# define show_command(arg) /* */# define show_busphase(arg) /* */# define show_autophase(arg) /* */#endif/* * IDENTIFY Message */static void nsp32_build_identify(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int pos = data->msgout_len; int mode = FALSE; /* XXX: Auto DiscPriv detection is progressing... */ if (disc_priv == 0) { /* mode = TRUE; */ } data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++; data->msgout_len = pos;}/* * SDTR Message Routine */static void nsp32_build_sdtr(Scsi_Cmnd *SCpnt, unsigned char period, unsigned char offset){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int pos = data->msgout_len; data->msgoutbuf[pos] = EXTENDED_MESSAGE; pos++; data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++; data->msgoutbuf[pos] = EXTENDED_SDTR; pos++; data->msgoutbuf[pos] = period; pos++; data->msgoutbuf[pos] = offset; pos++; data->msgout_len = pos;}/* * No Operation Message */static void nsp32_build_nop(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int pos = data->msgout_len; if (pos != 0) { nsp32_msg(KERN_WARNING, "Some messages are already contained!"); return; } data->msgoutbuf[pos] = NOP; pos++; data->msgout_len = pos;}/* * Reject Message */static void nsp32_build_reject(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int pos = data->msgout_len; data->msgoutbuf[pos] = MESSAGE_REJECT; pos++; data->msgout_len = pos;} /* * timer */#if 0static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time){ unsigned int base = SCpnt->host->io_port; nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time); if (time & (~TIMER_CNT_MASK)) { nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow"); } nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);}#endif/* * set SCSI command and other parameter to asic, and start selection phase */static int nsp32_selection_autopara(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; unsigned int host_id = SCpnt->device->host->this_id;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?