patch-2.4.23 linux-2.4.23/drivers/scsi/pcmcia/nsp_cs.c
Next file: linux-2.4.23/drivers/scsi/pcmcia/nsp_cs.h
Previous file: linux-2.4.23/drivers/scsi/pas16.c
Back to the patch index
Back to the overall index
- Lines: 2695
- Date:
2003-11-28 10:26:20.000000000 -0800
- Orig file:
linux-2.4.22/drivers/scsi/pcmcia/nsp_cs.c
- Orig date:
2003-08-25 04:44:42.000000000 -0700
diff -urN linux-2.4.22/drivers/scsi/pcmcia/nsp_cs.c linux-2.4.23/drivers/scsi/pcmcia/nsp_cs.c
@@ -1,8 +1,10 @@
/*======================================================================
- NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI hostadapter card driver
+ NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ Ver.2.8 Support 32bit MMIO mode
+ Support Synchronous Data Transfer Request (SDTR) mode
Ver.2.0 Support 32bit PIO mode
Ver.1.1.2 Fix for scatter list buffer exceeds
Ver.1.1 Support scatter list
@@ -23,34 +25,32 @@
***********************************************************************/
-/* $Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $ */
-
-#ifdef NSP_KERNEL_2_2
-#include <pcmcia/config.h>
-#include <pcmcia/k_compat.h>
-#endif
+/* $Id: nsp_cs.c,v 1.25 2003/09/24 10:38:18 elca Exp $ */
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/major.h>
-#include <linux/blk.h>
+#include <linux/blkdev.h>
#include <linux/stat.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+# include <linux/blk.h>
+#endif
#include <asm/io.h>
#include <asm/irq.h>
#include <../drivers/scsi/scsi.h>
#include <../drivers/scsi/hosts.h>
-#include <../drivers/scsi/sd.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
@@ -59,138 +59,192 @@
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "nsp_cs.h"
MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
-MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.25 $");
MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
MODULE_LICENSE("GPL");
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-MODULE_PARM_DESC(pc_debug, "set debug level");
-static char *version = "$Id: nsp_cs.c,v 1.42 2001/09/10 10:30:58 elca Exp $";
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-#else
-#define DEBUG(n, args...) /* */
-#endif
-
#include "nsp_io.h"
/*====================================================================*/
+/* Parameters that can be set with 'insmod' */
-typedef struct scsi_info_t {
- dev_link_t link;
- struct Scsi_Host *host;
- int ndev;
- dev_node_t node[8];
- int stop;
- struct bus_operations *bus;
-} scsi_info_t;
+static unsigned int irq_mask = 0xffff;
+MODULE_PARM (irq_mask, "i");
+MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xffff)");
+static int irq_list[4] = { -1 };
+MODULE_PARM (irq_list, "1-4i");
+MODULE_PARM_DESC(irq_list, "Use specified IRQ number. (default: auto select)");
+
+static int nsp_burst_mode = BURST_MEM32;
+MODULE_PARM (nsp_burst_mode, "i");
+MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
+
+/* Release IO ports after configuration? */
+static int free_ports = 0;
+MODULE_PARM (free_ports, "i");
+MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
-/*----------------------------------------------------------------*/
-
-#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)
-#define PROC_SCSI_NSP PROC_SCSI_IBMMCA /* bad hack... */
-static struct proc_dir_entry proc_scsi_nsp = {
- PROC_SCSI_NSP, 6, "nsp_cs",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
+/* /usr/src/linux/drivers/scsi/hosts.h */
+static Scsi_Host_Template nsp_driver_template = {
+ .proc_name = "nsp_cs",
+ .proc_info = nsp_proc_info,
+ .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+ .detect = nsp_detect_old,
+ .release = nsp_release_old,
+#endif
+ .info = nsp_info,
+ .queuecommand = nsp_queuecommand,
+/* .eh_strategy_handler = nsp_eh_strategy,*/
+/* .eh_abort_handler = nsp_eh_abort,*/
+/* .eh_device_reset_handler = nsp_eh_device_reset,*/
+ .eh_bus_reset_handler = nsp_eh_bus_reset,
+ .eh_host_reset_handler = nsp_eh_host_reset,
+ .can_queue = 1,
+ .this_id = NSP_INITIATOR_ID,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = DISABLE_CLUSTERING,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+ .use_new_eh_code = 1,
#endif
+};
-/*====================================================================*/
-/* Parameters that can be set with 'insmod' */
+static dev_link_t *dev_list = NULL;
+static dev_info_t dev_info = "nsp_cs";
-static unsigned int irq_mask = 0xffff;
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM_DESC(irq_mask, "IRQ mask bits");
+static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
-static int irq_list[4] = { -1 };
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM_DESC(irq_list, "IRQ number list");
-/*----------------------------------------------------------------*/
-/* driver state info, local to driver */
-static char nspinfo[100]; /* description */
-/* /usr/src/linux/drivers/scsi/hosts.h */
-static Scsi_Host_Template driver_template = {
-/* next: NULL,*/
-#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
- proc_dir: &proc_scsi_nsp, /* kernel 2.2 */
+/******************************************************************
+ * debug, error print
+ */
+#ifdef NSP_DEBUG
+# include "nsp_debug.c"
+#endif /* NSP_DEBUG */
+
+#ifndef NSP_DEBUG
+# define NSP_DEBUG_MASK 0x000000
+# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
+# define nsp_dbg(mask, args...) /* */
#else
- proc_name: "nsp_cs", /* kernel 2.4 */
+# define NSP_DEBUG_MASK 0xffffff
+# define nsp_msg(type, args...) \
+ nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
+# define nsp_dbg(mask, args...) \
+ nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
#endif
-/* proc_info: NULL,*/
- name: "WorkBit NinjaSCSI-3/32Bi",
- detect: nsp_detect,
- release: nsp_release,
- info: nsp_info,
-/* command: NULL,*/
- queuecommand: nsp_queuecommand,
-/* eh_strategy_handler: nsp_eh_strategy,*/
- eh_abort_handler: nsp_eh_abort,
- eh_device_reset_handler: nsp_eh_device_reset,
- eh_bus_reset_handler: nsp_eh_bus_reset,
- eh_host_reset_handler: nsp_eh_host_reset,
- abort: nsp_abort,
- reset: nsp_reset,
-/* slave_attach: NULL,*/
-/* bios_param: NULL,*/
- can_queue: 1,
- this_id: SCSI_INITIATOR_ID,
- sg_tablesize: SG_ALL,
- cmd_per_lun: 1,
-/* present: 0,*/
-/* unchecked_isa_dma: 0,*/
- use_clustering: DISABLE_CLUSTERING,
- use_new_eh_code: 0,
-/* emulated: 0,*/
-};
-static dev_link_t *dev_list = NULL;
-static dev_info_t dev_info = {"nsp_cs"};
+#define NSP_DEBUG_QUEUECOMMAND BIT(0)
+#define NSP_DEBUG_REGISTER BIT(1)
+#define NSP_DEBUG_AUTOSCSI BIT(2)
+#define NSP_DEBUG_INTR BIT(3)
+#define NSP_DEBUG_SGLIST BIT(4)
+#define NSP_DEBUG_BUSFREE BIT(5)
+#define NSP_DEBUG_CDB_CONTENTS BIT(6)
+#define NSP_DEBUG_RESELECTION BIT(7)
+#define NSP_DEBUG_MSGINOCCUR BIT(8)
+#define NSP_DEBUG_EEPROM BIT(9)
+#define NSP_DEBUG_MSGOUTOCCUR BIT(10)
+#define NSP_DEBUG_BUSRESET BIT(11)
+#define NSP_DEBUG_RESTART BIT(12)
+#define NSP_DEBUG_SYNC BIT(13)
+#define NSP_DEBUG_WAIT BIT(14)
+#define NSP_DEBUG_TARGETFLAG BIT(15)
+#define NSP_DEBUG_PROC BIT(16)
+#define NSP_DEBUG_INIT BIT(17)
+#define NSP_DEBUG_DATA_IO BIT(18)
+#define NSP_SPECIAL_PRINT_REGISTER BIT(20)
+
+#define NSP_DEBUG_BUF_LEN 150
+
+static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
+{
+ va_list args;
+ char buf[NSP_DEBUG_BUF_LEN];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
-static nsp_hw_data nsp_data;
+#ifndef NSP_DEBUG
+ printk("%snsp_cs: %s\n", type, buf);
+#else
+ printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+#ifdef NSP_DEBUG
+static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
+{
+ va_list args;
+ char buf[NSP_DEBUG_BUF_LEN];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ if (mask & NSP_DEBUG_MASK) {
+ printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
+ }
+}
+#endif
/***********************************************************/
+/*====================================================
+ * Clenaup parameters and call done() functions.
+ * You must be set SCpnt->result before call this function.
+ */
+static void nsp_scsi_done(Scsi_Cmnd *SCpnt)
+{
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+ data->CurrentSC = NULL;
+
+ SCpnt->scsi_done(SCpnt);
+}
+
static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
-#ifdef PCMCIA_DEBUG
- //unsigned int host_id = SCpnt->host->this_id;
- //unsigned int base = SCpnt->host->io_port;
- unsigned char target = SCpnt->target;
-#endif
- nsp_hw_data *data = &nsp_data;
-
- DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
- SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
- //DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC);
-
- if(data->CurrentSC != NULL) {
- printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n");
- data->CurrentSC = NULL;
+#ifdef NSP_DEBUG
+ /*unsigned int host_id = SCpnt->device->host->this_id;*/
+ /*unsigned int base = SCpnt->device->host->io_port;*/
+ unsigned char target = SCpnt->device->id;
+#endif
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+ nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
+ SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+ //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
+
+ SCpnt->scsi_done = done;
+
+ if (data->CurrentSC != NULL) {
+ nsp_msg(KERN_WARNING, "CurrentSC!=NULL this can't be happen");
SCpnt->result = DID_BAD_TARGET << 16;
- done(SCpnt);
- return -1;
+ nsp_scsi_done(SCpnt);
+ return SCSI_MLQUEUE_HOST_BUSY;
}
show_command(SCpnt);
- SCpnt->scsi_done = done;
data->CurrentSC = SCpnt;
- RESID = SCpnt->request_bufflen;
- SCpnt->SCp.Status = -1;
- SCpnt->SCp.Message = -1;
+ SCpnt->SCp.Status = CHECK_CONDITION;
+ SCpnt->SCp.Message = 0;
SCpnt->SCp.have_data_in = IO_UNKNOWN;
SCpnt->SCp.sent_command = 0;
SCpnt->SCp.phase = PH_UNDETERMINED;
+ SCpnt->resid = SCpnt->request_bufflen;
/* setup scratch area
SCp.ptr : buffer pointer
@@ -200,7 +254,7 @@
SCp.phase : current state of the command */
if (SCpnt->use_sg) {
SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
+ SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
} else {
@@ -210,16 +264,18 @@
SCpnt->SCp.buffers_residual = 0;
}
- if(nsphw_start_selection(SCpnt, data) == FALSE) {
- DEBUG(0, " selection fail\n");
- data->CurrentSC = NULL;
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- return -1;
+ if (nsphw_start_selection(SCpnt) == FALSE) {
+ nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
+ SCpnt->result = DID_BUS_BUSY << 16;
+ nsp_scsi_done(SCpnt);
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
- //DEBUG(0, __FUNCTION__ "() out\n");
+ //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
+#ifdef NSP_DEBUG
+ data->CmdId++;
+#endif
return 0;
}
@@ -231,7 +287,7 @@
unsigned int base = data->BaseAddress;
unsigned char transfer_mode_reg;
- //DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
if (enabled != FALSE) {
transfer_mode_reg = TRANSFER_GO | BRAIND;
@@ -244,37 +300,45 @@
nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
}
+static void nsphw_init_sync(nsp_hw_data *data)
+{
+ sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
+ .SyncPeriod = 0,
+ .SyncOffset = 0
+ };
+ int i;
+
+ /* setup sync data */
+ for ( i = 0; i < NUMBER(data->Sync); i++ ) {
+ data->Sync[i] = tmp_sync;
+ }
+}
+
/*
* Initialize Ninja hardware
*/
static int nsphw_init(nsp_hw_data *data)
{
unsigned int base = data->BaseAddress;
- int i, j;
- sync_data tmp_sync = { SyncNegotiation: SYNC_NOT_YET,
- SyncPeriod: 0,
- SyncOffset: 0
- };
- DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base);
+ nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
- data->ScsiClockDiv = CLOCK_40M;
+ data->ScsiClockDiv = CLOCK_40M | FAST_20;
data->CurrentSC = NULL;
data->FifoCount = 0;
data->TransferMode = MODE_IO8;
- /* setup sync data */
- for ( i = 0; i < N_TARGET; i++ ) {
- for ( j = 0; j < N_LUN; j++ ) {
- data->Sync[i][j] = tmp_sync;
- }
- }
+ nsphw_init_sync(data);
+
/* block all interrupts */
- nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR_AND_MASK);
+
+ nsp_write(base, IFSELECT, 0);
+ data->ChipRev = nsp_read(base, FIFOSTATUS);
/* setup SCSI interface */
- nsp_write(base, IFSELECT, IF_IFSEL);
+ nsp_write(base, IFSELECT, IF_REGSEL);
nsp_index_write(base, SCSIIRQMODE, 0);
@@ -291,7 +355,7 @@
nsp_write(base, IFSELECT, IF_REGSEL);
nsp_index_write(base, TERMPWRCTRL, 0);
if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
- printk(KERN_INFO "nsp_cs: terminator power on\n");
+ nsp_msg(KERN_INFO, "terminator power on");
nsp_index_write(base, TERMPWRCTRL, POWER_ON);
}
@@ -305,7 +369,7 @@
nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
RESELECT_EI |
SCSI_RESET_IRQ_EI );
- nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR);
nsp_setup_fifo(data, FALSE);
@@ -315,110 +379,147 @@
/*
* Start selection phase
*/
-static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt,
- nsp_hw_data *data)
+static int nsphw_start_selection(Scsi_Cmnd *SCpnt)
{
- unsigned int host_id = SCpnt->host->this_id;
- unsigned int base = SCpnt->host->io_port;
- unsigned char target = SCpnt->target;
- int wait_count;
+ unsigned int host_id = SCpnt->device->host->this_id;
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned char target = SCpnt->device->id;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ int time_out;
unsigned char phase, arbit;
- //DEBUG(0, __FUNCTION__ "()in\n");
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
phase = nsp_index_read(base, SCSIBUSMON);
if(phase != BUSMON_BUS_FREE) {
- //DEBUG(0, " bus busy\n");
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
return FALSE;
}
/* start arbitration */
- //DEBUG(0, " start arbit\n");
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
SCpnt->SCp.phase = PH_ARBSTART;
nsp_index_write(base, SETARBIT, ARBIT_GO);
- wait_count = jiffies + 10 * HZ;
+ time_out = 1000;
do {
/* XXX: what a stupid chip! */
arbit = nsp_index_read(base, ARBITSTATUS);
- //DEBUG(0, " arbit=%d, wait_count=%d\n", arbit, wait_count);
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
udelay(1); /* hold 1.2us */
} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
- time_before(jiffies, wait_count));
+ (time_out-- != 0));
- if((arbit & ARBIT_WIN) == 0) {
- //DEBUG(0, " arbit fail\n");
+ if (!(arbit & ARBIT_WIN)) {
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
return FALSE;
}
/* assert select line */
- //DEBUG(0, " assert SEL line\n");
+ //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
SCpnt->SCp.phase = PH_SELSTART;
- udelay(3);
- nsp_index_write(base, SCSIDATALATCH, (1 << host_id) | (1 << target));
- nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
- udelay(3);
+ udelay(3); /* wait 2.4us */
+ nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
+ nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
+ udelay(2); /* wait >1.2us */
nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
- udelay(3);
- nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
+ /*udelay(1);*/ /* wait >90ns */
+ nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
/* check selection timeout */
- nsp_start_timer(SCpnt, data, 1000/51);
+ nsp_start_timer(SCpnt, 1000/51);
data->SelectionTimeOut = 1;
return TRUE;
}
+/***********************************************************************
+ * Period/AckWidth speed conversion table
+ *
+ * Note: This period/ackwidth speed table must be in descending order.
+ ***********************************************************************/
struct nsp_sync_table {
- unsigned int min_period;
- unsigned int max_period;
unsigned int chip_period;
unsigned int ack_width;
+ unsigned int min_period;
+ unsigned int max_period;
};
static struct nsp_sync_table nsp_sync_table_40M[] = {
- {0x0c,0x0c,0x1,0}, /* 20MB 50ns*/
- {0x19,0x19,0x3,1}, /* 10MB 100ns*/
- {0x1a,0x25,0x5,2}, /* 7.5MB 150ns*/
- {0x26,0x32,0x7,3}, /* 5MB 200ns*/
- {0x0, 0, 0, 0}
+ /* {PNo, AW, SP, EP} Speed(MB/s) Period AckWidth */
+ {0x1, 0, 0x0c, 0x0c}, /* 20.0 : 50ns, 25ns */
+ {0x2, 0, 0x0d, 0x18}, /* 13.3 : 75ns, 25ns */
+ {0x3, 1, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */
+ {0x4, 1, 0x1a, 0x1f}, /* 8.0 : 125ns, 50ns */
+ {0x5, 2, 0x20, 0x25}, /* 7.5 : 150ns, 75ns */
+ {0x6, 2, 0x26, 0x31}, /* 5.71: 175ns, 75ns */
+ {0x7, 3, 0x32, 0x32}, /* 5.0 : 200ns, 100ns */
+ {0x8, 3, 0x33, 0x38}, /* 4.44: 225ns, 100ns */
+ {0x9, 3, 0x39, 0x3e}, /* 4.0 : 250ns, 100ns */
+ {0xa, 3, 0x3f, 0x44}, /* 3.64: 275ns, 100ns */
+ {0xb, 3, 0x45, 0x4b}, /* 3.33: 300ns, 100ns */
+ {0xc, 3, 0x4c, 0x53}, /* 3.01: 325ns, 100ns */
+ {0xd, 3, 0x54, 0x57}, /* 2.86: 350ns, 100ns */
+ {0xe, 3, 0x58, 0x5d}, /* 2.67: 375ns, 100ns */
+ {0xf, 3, 0x5e, 0x64}, /* 2.5 : 400ns, 100ns */
+ {0,0,0,0},
};
static struct nsp_sync_table nsp_sync_table_20M[] = {
- {0x19,0x19,0x1,0}, /* 10MB 100ns*/
- {0x1a,0x25,0x2,0}, /* 7.5MB 150ns*/
- {0x26,0x32,0x3,1}, /* 5MB 200ns*/
- {0x0, 0, 0, 0}
+ {0x1, 0, 0x19, 0x19}, /* 10.0 : 100ns, 50ns */
+ {0x2, 0, 0x1a, 0x25}, /* 6.7 : 150ns, 50ns */
+ {0x3, 1, 0x26, 0x32}, /* 5.0 : 200ns, 100ns */
+ {0x4, 1, 0x33, 0x3e}, /* 4.0 : 250ns, 100ns */
+ {0x5, 2, 0x3f, 0x4b}, /* 3.3 : 300ns, 150ns */
+ {0x6, 2, 0x4c, 0x57}, /* 2.8 : 350ns, 150ns */
+ {0x7, 3, 0x58, 0x64}, /* 2.5 : 400ns, 200ns */
+ {0x8, 3, 0x65, 0x70}, /* 2.2 : 450ns, 200ns */
+ {0x9, 3, 0x71, 0x7d}, /* 2.0 : 500ns, 200ns */
+ {0xa, 3, 0x7e, 0x89}, /* 1.82: 550ns, 200ns */
+ {0xb, 3, 0x8a, 0x95}, /* 1.67: 550ns, 200ns */
+ {0xc, 3, 0x96, 0xa2}, /* 1.54: 550ns, 200ns */
+ {0xd, 3, 0xa3, 0xae}, /* 1.43: 550ns, 200ns */
+ {0xe, 3, 0xaf, 0xbb}, /* 1.33: 550ns, 200ns */
+ {0xf, 3, 0xbc, 0xc8}, /* 1.25: 550ns, 200ns */
+ {0,0,0,0},
};
/*
* setup synchronous data transfer mode
*/
-static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt)
{
- unsigned char target = SCpnt->target;
- unsigned char lun = SCpnt->lun;
- sync_data *sync = &(data->Sync[target][lun]);
+ unsigned char target = SCpnt->device->id;
+// unsigned char lun = SCpnt->device->lun;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ sync_data *sync = &(data->Sync[target]);
struct nsp_sync_table *sync_table;
unsigned int period, offset;
int i;
- DEBUG(0, __FUNCTION__ "()\n");
-
-/**!**/
+ nsp_dbg(NSP_DEBUG_SYNC, "in");
period = sync->SyncPeriod;
offset = sync->SyncOffset;
- DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset);
+ nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
- if (data->ScsiClockDiv == CLOCK_20M) {
- sync_table = &nsp_sync_table_20M[0];
- } else {
- sync_table = &nsp_sync_table_40M[0];
+ switch (data->ScsiClockDiv) {
+ case CLOCK_20M:
+ case CLOCK_40M:
+ sync_table = nsp_sync_table_20M;
+ break;
+ case CLOCK_40M | FAST_20:
+ sync_table = nsp_sync_table_40M;
+ break;
+ default:
+ nsp_msg(KERN_WARNING,
+ "Invalid clock div is selected, set 20M.");
+ sync_table = nsp_sync_table_20M;
+ break;
}
for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
@@ -432,13 +533,12 @@
/*
* No proper period/offset found
*/
- DEBUG(0, " no proper period/offset\n");
+ nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
sync->SyncPeriod = 0;
sync->SyncOffset = 0;
sync->SyncRegister = 0;
sync->AckWidth = 0;
- sync->SyncNegotiation = SYNC_OK;
return FALSE;
}
@@ -446,9 +546,8 @@
sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
(offset & SYNCREG_OFFSET_MASK);
sync->AckWidth = sync_table->ack_width;
- sync->SyncNegotiation = SYNC_OK;
- DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth);
+ nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
return TRUE;
}
@@ -457,11 +556,12 @@
/*
* start ninja hardware timer
*/
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time)
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
{
- unsigned int base = SCpnt->host->io_port;
+ unsigned int base = SCpnt->device->host->io_port;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
- //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);
+ //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
data->TimerCount = time;
nsp_index_write(base, TIMERCOUNT, time);
}
@@ -471,23 +571,23 @@
*/
static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
{
- unsigned int base = SCpnt->host->io_port;
+ unsigned int base = SCpnt->device->host->io_port;
unsigned char reg;
- int count, i = TRUE;
+ int time_out;
- //DEBUG(0, __FUNCTION__ "()\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "in");
- count = jiffies + HZ;
+ time_out = 100;
do {
reg = nsp_index_read(base, SCSIBUSMON);
if (reg == 0xff) {
break;
}
- } while ((i = time_before(jiffies, count)) && (reg & mask) != 0);
+ } while ((time_out-- != 0) && (reg & mask) != 0);
- if (!i) {
- printk(KERN_DEBUG __FUNCTION__ " %s signal off timeut\n", str);
+ if (time_out == 0) {
+ nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
}
return 0;
@@ -500,51 +600,52 @@
unsigned char current_phase,
unsigned char mask)
{
- unsigned int base = SCpnt->host->io_port;
- int wait_count;
+ unsigned int base = SCpnt->device->host->io_port;
+ int time_out;
unsigned char phase, i_src;
- //DEBUG(0, __FUNCTION__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask);
+ //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
- wait_count = jiffies + HZ;
+ time_out = 100;
do {
phase = nsp_index_read(base, SCSIBUSMON);
if (phase == 0xff) {
- //DEBUG(0, " ret -1\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
return -1;
}
i_src = nsp_read(base, IRQSTATUS);
if (i_src & IRQSTATUS_SCSI) {
- //DEBUG(0, " ret 0 found scsi signal\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
return 0;
}
if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
- //DEBUG(0, " ret 1 phase=0x%x\n", phase);
+ //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
return 1;
}
- } while(time_before(jiffies, wait_count));
+ } while(time_out-- != 0);
- //DEBUG(0, __FUNCTION__ " : " __FUNCTION__ " timeout\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "timeout");
return -1;
}
/*
* transfer SCSI message
*/
-static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase)
+static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
{
- unsigned int base = SCpnt->host->io_port;
+ unsigned int base = SCpnt->device->host->io_port;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
char *buf = data->MsgBuffer;
int len = MIN(MSGBUF_SIZE, data->MsgLen);
int ptr;
int ret;
- //DEBUG(0, __FUNCTION__ "()\n");
- for (ptr = 0; len > 0; len --, ptr ++) {
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
+ for (ptr = 0; len > 0; len--, ptr++) {
ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
if (ret <= 0) {
- DEBUG(0, " xfer quit\n");
+ nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
return 0;
}
@@ -555,10 +656,10 @@
/* read & write message */
if (phase & BUSMON_IO) {
- DEBUG(0, " read msg\n");
+ nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
} else {
- DEBUG(0, " write msg\n");
+ nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
}
nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
@@ -570,11 +671,12 @@
/*
* get extra SCSI data from fifo
*/
-static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
{
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
unsigned int count;
- //DEBUG(0, __FUNCTION__ "()\n");
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
if (SCpnt->SCp.have_data_in != IO_IN) {
return 0;
@@ -582,7 +684,7 @@
count = nsp_fifo_count(SCpnt);
if (data->FifoCount == count) {
- //DEBUG(0, " not use bypass quirk\n");
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
return 0;
}
@@ -590,30 +692,49 @@
* XXX: NSP_QUIRK
* data phase skip only occures in case of SCSI_LOW_READ
*/
+ nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
SCpnt->SCp.phase = PH_DATA;
- nsp_pio_read(SCpnt, data);
+ nsp_pio_read(SCpnt);
nsp_setup_fifo(data, FALSE);
- DEBUG(0, " use bypass quirk\n");
return 0;
}
/*
* accept reselection
*/
-static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static int nsp_reselected(Scsi_Cmnd *SCpnt)
{
- unsigned int base = SCpnt->host->io_port;
- unsigned char reg;
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned int host_id = SCpnt->device->host->this_id;
+ //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ unsigned char bus_reg;
+ unsigned char id_reg, tmp;
+ int target;
+
+ nsp_dbg(NSP_DEBUG_RESELECTION, "in");
+
+ id_reg = nsp_index_read(base, RESELECTID);
+ tmp = id_reg & (~BIT(host_id));
+ target = 0;
+ while(tmp != 0) {
+ if (tmp & BIT(0)) {
+ break;
+ }
+ tmp >>= 1;
+ target++;
+ }
- //DEBUG(0, __FUNCTION__ "()\n");
+ if (SCpnt->device->id != target) {
+ nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
+ }
nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
- nsp_nexus(SCpnt, data);
- reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
- nsp_index_write(base, SCSIBUSCTRL, reg);
- nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB);
+ nsp_nexus(SCpnt);
+ bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
+ nsp_index_write(base, SCSIBUSCTRL, bus_reg);
+ nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
return TRUE;
}
@@ -623,19 +744,20 @@
*/
static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
{
- unsigned int base = SCpnt->host->io_port;
+ unsigned int base = SCpnt->device->host->io_port;
unsigned int count;
- unsigned int l, m, h;
+ unsigned int l, m, h, dummy;
- nsp_index_write(base, POINTERCLR, POINTER_CLEAR);
+ nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
- l = (unsigned int)nsp_read(base, DATAREG);
- m = (unsigned int)nsp_read(base, DATAREG);
- h = (unsigned int)nsp_read(base, DATAREG);
+ l = nsp_index_read(base, TRANSFERCOUNT);
+ m = nsp_index_read(base, TRANSFERCOUNT);
+ h = nsp_index_read(base, TRANSFERCOUNT);
+ dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
count = (h << 16) | (m << 8) | (l << 0);
- //DEBUG(0, __FUNCTION__ "() =0x%x\n", count);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
return count;
}
@@ -647,34 +769,37 @@
/*
* read data in DATA IN phase
*/
-static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static void nsp_pio_read(Scsi_Cmnd *SCpnt)
{
- unsigned int base = SCpnt->host->io_port;
- int time_out, i;
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned long mmio_base = SCpnt->device->host->base;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ long time_out;
int ocount, res;
unsigned char stat, fifo_stat;
ocount = data->FifoCount;
- DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
+ SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
- time_out = jiffies + 10 * HZ;
+ time_out = 1000;
- while ((i = time_before(jiffies,time_out)) &&
+ while ((time_out-- != 0) &&
(SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
stat = nsp_index_read(base, SCSIBUSMON);
stat &= BUSMON_PHASE_MASK;
- res = nsp_fifo_count(SCpnt) - ocount;
- //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);
+ res = nsp_fifo_count(SCpnt) - ocount;
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);
if (res == 0) { /* if some data avilable ? */
if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
- //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
continue;
} else {
- DEBUG(0, " phase changed stat=0x%x\n", stat);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
break;
}
}
@@ -695,72 +820,93 @@
case MODE_IO8:
nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
break;
- default:
- DEBUG(0, "unknown read mode\n");
+
+ case MODE_MEM32:
+ res &= ~(BIT(1)|BIT(0)); /* align 4 */
+ nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
break;
+
+ default:
+ nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
+ return;
}
- RESID -= res;
+ SCpnt->resid -= res;
SCpnt->SCp.ptr += res;
SCpnt->SCp.this_residual -= res;
ocount += res;
- //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
/* go to next scatter list if available */
if (SCpnt->SCp.this_residual == 0 &&
SCpnt->SCp.buffers_residual != 0 ) {
- //DEBUG(0, " scatterlist next timeout=%d\n", time_out);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
SCpnt->SCp.buffers_residual--;
SCpnt->SCp.buffer++;
- SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
+ SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
- }
+ time_out = 1000;
- time_out = jiffies + 10 * HZ;
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
+ }
}
data->FifoCount = ocount;
- if (!i) {
- printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+ if (time_out == 0) {
+ nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
+ SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
}
- DEBUG(0, " read ocount=0x%x\n", ocount);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
}
/*
* write data in DATA OUT phase
*/
-static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static void nsp_pio_write(Scsi_Cmnd *SCpnt)
{
- unsigned int base = SCpnt->host->io_port;
- int time_out, i;
- unsigned int ocount, res;
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned long mmio_base = SCpnt->device->host->base;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ int time_out;
+ int ocount, res;
unsigned char stat;
ocount = data->FifoCount;
- DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
+ data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
- time_out = jiffies + 10 * HZ;
+ time_out = 1000;
- while ((i = time_before(jiffies, time_out)) &&
+ while ((time_out-- != 0) &&
(SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
stat = nsp_index_read(base, SCSIBUSMON);
stat &= BUSMON_PHASE_MASK;
+
if (stat != BUSPHASE_DATA_OUT) {
- DEBUG(0, " phase changed stat=0x%x\n", stat);
+ res = ocount - nsp_fifo_count(SCpnt);
+
+ nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
+ /* Put back pointer */
+ SCpnt->resid += res;
+ SCpnt->SCp.ptr -= res;
+ SCpnt->SCp.this_residual += res;
+ ocount -= res;
+
break;
}
res = ocount - nsp_fifo_count(SCpnt);
if (res > 0) { /* write all data? */
- DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
continue;
}
res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT);
- //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
switch (data->TransferMode) {
case MODE_IO32:
res &= ~(BIT(1)|BIT(0)); /* align 4 */
@@ -769,12 +915,18 @@
case MODE_IO8:
nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
break;
+
+ case MODE_MEM32:
+ res &= ~(BIT(1)|BIT(0)); /* align 4 */
+ nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
+ break;
+
default:
- DEBUG(0, "unknown write mode\n");
+ nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
break;
}
- RESID -= res;
+ SCpnt->resid -= res;
SCpnt->SCp.ptr += res;
SCpnt->SCp.this_residual -= res;
ocount += res;
@@ -782,55 +934,60 @@
/* go to next scatter list if available */
if (SCpnt->SCp.this_residual == 0 &&
SCpnt->SCp.buffers_residual != 0 ) {
- //DEBUG(0, " scatterlist next\n");
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
SCpnt->SCp.buffers_residual--;
SCpnt->SCp.buffer++;
- SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
+ SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+ time_out = 1000;
}
-
- time_out = jiffies + 10 * HZ;
}
data->FifoCount = ocount;
- if (!i) {
- printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID);
+ if (time_out == 0) {
+ nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
}
- //DEBUG(0, " write ocount=%d\n", ocount);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
+ nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
}
-
#undef RFIFO_CRIT
#undef WFIFO_CRIT
/*
* setup synchronous/asynchronous data transfer mode
*/
-static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+static int nsp_nexus(Scsi_Cmnd *SCpnt)
{
- unsigned int base = SCpnt->host->io_port;
- unsigned char target = SCpnt->target;
- unsigned char lun = SCpnt->lun;
- sync_data *sync = &(data->Sync[target][lun]);
+ unsigned int base = SCpnt->device->host->io_port;
+ unsigned char target = SCpnt->device->id;
+// unsigned char lun = SCpnt->device->lun;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+ sync_data *sync = &(data->Sync[target]);
- //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt);
+ //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
/* setup synch transfer registers */
nsp_index_write(base, SYNCREG, sync->SyncRegister);
nsp_index_write(base, ACKWIDTH, sync->AckWidth);
- if (RESID % 4 != 0 ||
- RESID <= 256 ) {
+ if (SCpnt->use_sg == 0 ||
+ SCpnt->resid % 4 != 0 ||
+ SCpnt->resid <= PAGE_SIZE ) {
data->TransferMode = MODE_IO8;
- } else {
+ } else if (nsp_burst_mode == BURST_MEM32) {
+ data->TransferMode = MODE_MEM32;
+ } else if (nsp_burst_mode == BURST_IO32) {
data->TransferMode = MODE_IO32;
+ } else {
+ data->TransferMode = MODE_IO8;
}
/* setup pdma fifo */
nsp_setup_fifo(data, TRUE);
/* clear ack counter */
- data->FifoCount = 0;
+ data->FifoCount = 0;
nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
ACK_COUNTER_CLEAR |
REQ_COUNTER_CLEAR |
@@ -843,111 +1000,126 @@
/*
* interrupt handler
*/
-static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int base;
- unsigned char i_src, irq_phase, phase;
+ unsigned char irq_status, irq_phase, phase;
Scsi_Cmnd *tmpSC;
- int len;
unsigned char target, lun;
unsigned int *sync_neg;
int i, tmp;
+ unsigned long flags;
nsp_hw_data *data;
+ int handled = 0;
- //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id);
+ //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
+ //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
- /* sanity check */
- if (&nsp_data != dev_id) {
- DEBUG(0, " irq conflict? this can't happen\n");
- return;
- }
- data = dev_id;
- if (irq != data->IrqNumber) {
- return;
+ if ( dev_id != NULL &&
+ ((scsi_info_t *)dev_id)->host != NULL ) {
+ scsi_info_t *info = (scsi_info_t *)dev_id;
+
+ data = (nsp_hw_data *)(info->host->hostdata);
+ } else {
+ nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
+ return IRQ_NONE;
}
+ spin_lock_irqsave(HOST_LOCK, flags);
+
+ //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
+
base = data->BaseAddress;
- //DEBUG(0, " base=0x%x\n", base);
+ //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
/*
* interrupt check
*/
- nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
- i_src = nsp_read(base, IRQSTATUS);
- if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) {
- nsp_write(base, IRQCONTROL, 0);
- //DEBUG(0, " no irq\n");
- return;
+ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_MASK);
+ irq_status = nsp_read(base, IRQSTATUS);
+ //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
+ if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
+ //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
+ goto out;
}
-
- //DEBUG(0, " i_src=0x%x\n", i_src);
+ handled = 1;
/* XXX: IMPORTANT
* Do not read an irq_phase register if no scsi phase interrupt.
* Unless, you should lose a scsi phase interrupt.
*/
phase = nsp_index_read(base, SCSIBUSMON);
- if((i_src & IRQSTATUS_SCSI) != 0) {
+ if((irq_status & IRQSTATUS_SCSI) != 0) {
irq_phase = nsp_index_read(base, IRQPHASESENCE);
} else {
irq_phase = 0;
}
- //DEBUG(0, " irq_phase=0x%x\n", irq_phase);
+ //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
/*
* timer interrupt handler (scsi vs timer interrupts)
*/
- //DEBUG(0, " timercount=%d\n", data->TimerCount);
+ //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
if (data->TimerCount != 0) {
- //DEBUG(0, " stop timer\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
nsp_index_write(base, TIMERCOUNT, 0);
nsp_index_write(base, TIMERCOUNT, 0);
data->TimerCount = 0;
}
- if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
+ if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
data->SelectionTimeOut == 0) {
- //DEBUG(0, " timer start\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "timer start");
nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
- return;
+ goto out;
}
nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
+ if ((irq_status & IRQSTATUS_SCSI) &&
+ (irq_phase & SCSI_RESET_IRQ)) {
+ nsp_msg(KERN_ERR, "bus reset (power off?)");
+
+ nsphw_init(data);
+ nsp_bus_reset(data);
+
+ if(data->CurrentSC != NULL) {
+ tmpSC = data->CurrentSC;
+ tmpSC->result = (DID_RESET << 16) |
+ ((tmpSC->SCp.Message & 0xff) << 8) |
+ ((tmpSC->SCp.Status & 0xff) << 0);
+ nsp_scsi_done(tmpSC);
+ }
+ goto out;
+ }
+
if (data->CurrentSC == NULL) {
- printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase);
- return;
- } else {
- tmpSC = data->CurrentSC;
- target = tmpSC->target;
- lun = tmpSC->lun;
- sync_neg = &(data->Sync[target][lun].SyncNegotiation);
+ nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase);
+ nsphw_init(data);
+ nsp_bus_reset(data);
+ goto out;
}
+ tmpSC = data->CurrentSC;
+ target = tmpSC->device->id;
+ lun = tmpSC->device->lun;
+ sync_neg = &(data->Sync[target].SyncNegotiation);
+
/*
* parse hardware SCSI irq reasons register
*/
- if ((i_src & IRQSTATUS_SCSI) != 0) {
- if ((irq_phase & SCSI_RESET_IRQ) != 0) {
- printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n");
- *sync_neg = SYNC_NOT_YET;
- data->CurrentSC = NULL;
- tmpSC->result = DID_RESET << 16;
- tmpSC->scsi_done(tmpSC);
- return;
- }
-
- if ((irq_phase & RESELECT_IRQ) != 0) {
- DEBUG(0, " reselect\n");
+ if (irq_status & IRQSTATUS_SCSI) {
+ if (irq_phase & RESELECT_IRQ) {
+ nsp_dbg(NSP_DEBUG_INTR, "reselect");
nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
- if (nsp_reselected(tmpSC, data) != FALSE) {
- return;
+ if (nsp_reselected(tmpSC) != FALSE) {
+ goto out;
}
}
if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
- return;
+ goto out;
}
}
@@ -955,50 +1127,48 @@
switch(tmpSC->SCp.phase) {
case PH_SELSTART:
- *sync_neg = SYNC_NOT_YET;
+ // *sync_neg = SYNC_NOT_YET;
if ((phase & BUSMON_BSY) == 0) {
- //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut);
+ //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
- DEBUG(0, " selection time out\n");
+ nsp_dbg(NSP_DEBUG_INTR, "selection time out");
data->SelectionTimeOut = 0;
nsp_index_write(base, SCSIBUSCTRL, 0);
- data->CurrentSC = NULL;
- tmpSC->result = DID_NO_CONNECT << 16;
- tmpSC->scsi_done(tmpSC);
+ tmpSC->result = DID_TIME_OUT << 16;
+ nsp_scsi_done(tmpSC);
- return;
+ goto out;
}
data->SelectionTimeOut += 1;
- nsp_start_timer(tmpSC, data, 1000/51);
- return;
+ nsp_start_timer(tmpSC, 1000/51);
+ goto out;
}
/* attention assert */
- //DEBUG(0, " attention assert\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
data->SelectionTimeOut = 0;
tmpSC->SCp.phase = PH_SELECTED;
nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
udelay(1);
nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
- return;
+ goto out;
break;
case PH_RESELECT:
- //DEBUG(0, " phase reselect\n");
- *sync_neg = SYNC_NOT_YET;
+ //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
+ // *sync_neg = SYNC_NOT_YET;
if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
- data->CurrentSC = NULL;
tmpSC->result = DID_ABORT << 16;
- tmpSC->scsi_done(tmpSC);
- return;
+ nsp_scsi_done(tmpSC);
+ goto out;
}
/* fall thru */
default:
- if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
- return;
+ if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
+ goto out;
}
break;
}
@@ -1006,140 +1176,153 @@
/*
* SCSI sequencer
*/
- //DEBUG(0, " start scsi seq\n");
+ //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
/* normal disconnect */
- if ((irq_phase & LATCHED_BUS_FREE) != 0) {
- //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
+ if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
+ (irq_phase & LATCHED_BUS_FREE) != 0 ) {
+ nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
+
+ // *sync_neg = SYNC_NOT_YET;
+
if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
- *sync_neg = SYNC_NOT_YET;
- data->CurrentSC = NULL;
- tmpSC->result = (DID_OK << 16) |
- (tmpSC->SCp.Message << 8) |
- (tmpSC->SCp.Status << 0);
- DEBUG(0, " command complete result=0x%x\n", tmpSC->result);
- tmpSC->scsi_done(tmpSC);
- return;
+ tmpSC->result = (DID_OK << 16) |
+ ((tmpSC->SCp.Message & 0xff) << 8) |
+ ((tmpSC->SCp.Status & 0xff) << 0);
+ nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
+ nsp_scsi_done(tmpSC);
+
+ goto out;
}
- return;
+ goto out;
}
/* check unexpected bus free state */
if (phase == 0) {
- printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
+ nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
- *sync_neg = SYNC_NOT_YET;
- data->CurrentSC = NULL;
+ *sync_neg = SYNC_NG;
tmpSC->result = DID_ERROR << 16;
- tmpSC->scsi_done(tmpSC);
- return;
+ nsp_scsi_done(tmpSC);
+ goto out;
}
switch (phase & BUSMON_PHASE_MASK) {
case BUSPHASE_COMMAND:
- DEBUG(0, " BUSPHASE_COMMAND\n");
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
if ((phase & BUSMON_REQ) == 0) {
- DEBUG(0, " REQ == 0\n");
- return;
+ nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
+ goto out;
}
tmpSC->SCp.phase = PH_COMMAND;
- nsp_nexus(tmpSC, data);
+ nsp_nexus(tmpSC);
/* write scsi command */
+ nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
- for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) {
- nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]);
+ for (i = 0; i < tmpSC->cmd_len; i++) {
+ nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
}
nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
break;
case BUSPHASE_DATA_OUT:
- DEBUG(0, " BUSPHASE_DATA_OUT\n");
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
- tmpSC->SCp.phase = PH_DATA;
+ tmpSC->SCp.phase = PH_DATA;
tmpSC->SCp.have_data_in = IO_OUT;
- nsp_pio_write(tmpSC, data);
+ nsp_pio_write(tmpSC);
break;
case BUSPHASE_DATA_IN:
- DEBUG(0, " BUSPHASE_DATA_IN\n");
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
- tmpSC->SCp.phase = PH_DATA;
+ tmpSC->SCp.phase = PH_DATA;
tmpSC->SCp.have_data_in = IO_IN;
- nsp_pio_read(tmpSC, data);
+ nsp_pio_read(tmpSC);
break;
case BUSPHASE_STATUS:
- nsp_dataphase_bypass(tmpSC, data);
- DEBUG(0, " BUSPHASE_STATUS\n");
+ nsp_dataphase_bypass(tmpSC);
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
tmpSC->SCp.phase = PH_STATUS;
tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
- //DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status);
+ nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
break;
case BUSPHASE_MESSAGE_OUT:
- DEBUG(0, " BUSPHASE_MESSAGE_OUT\n");
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
if ((phase & BUSMON_REQ) == 0) {
goto timer_out;
}
tmpSC->SCp.phase = PH_MSG_OUT;
- data->MsgLen = len = 0;
+ // *sync_neg = SYNC_NOT_YET;
+
+ data->MsgLen = i = 0;
+ data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
+
if (*sync_neg == SYNC_NOT_YET) {
- data->Sync[target][lun].SyncPeriod = 0;
- data->Sync[target][lun].SyncOffset = 0;
- nsp_msg(tmpSC, data);
-
- data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++;
- /*
- data->MsgBuffer[len] = MSG_EXTENDED; len++;
- data->MsgBuffer[len] = 3; len++;
- data->MsgBuffer[len] = MSG_EXT_SDTR; len++;
- data->MsgBuffer[len] = 0x0c; len++;
- data->MsgBuffer[len] = 15; len++;
- */
- }
- if (len == 0) {
- data->MsgBuffer[len] = MSG_NO_OPERATION; len++;
+ data->Sync[target].SyncPeriod = 0;
+ data->Sync[target].SyncOffset = 0;
+
+ /**/
+ data->MsgBuffer[i] = MSG_EXTENDED; i++;
+ data->MsgBuffer[i] = 3; i++;
+ data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
+ data->MsgBuffer[i] = 0x0c; i++;
+ data->MsgBuffer[i] = 15; i++;
+ /**/
}
- data->MsgLen = len;
+ data->MsgLen = i;
+ nsp_analyze_sdtr(tmpSC);
show_message(data);
- nsp_message_out(tmpSC, data);
+ nsp_message_out(tmpSC);
break;
case BUSPHASE_MESSAGE_IN:
- nsp_dataphase_bypass(tmpSC, data);
- DEBUG(0, " BUSPHASE_MESSAGE_IN\n");
+ nsp_dataphase_bypass(tmpSC);
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
if ((phase & BUSMON_REQ) == 0) {
goto timer_out;
}
tmpSC->SCp.phase = PH_MSG_IN;
- nsp_message_in(tmpSC, data);
+ nsp_message_in(tmpSC);
- /*
- if (data->MsgLen >= 5 &&
- data->MsgBuffer[0] == MSG_EXTENDED &&
- data->MsgBuffer[1] == 3 &&
- data->MsgBuffer[2] == MSG_EXT_SDTR ) {
- data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3];
- data->Sync[target][lun].SyncOffset = data->MsgBuffer[4];
- nsp_msg(tmpSC, data);
+ /**/
+ if (*sync_neg == SYNC_NOT_YET) {
+ //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
+
+ if (data->MsgLen >= 5 &&
+ data->MsgBuffer[0] == MSG_EXTENDED &&
+ data->MsgBuffer[1] == 3 &&
+ data->MsgBuffer[2] == MSG_EXT_SDTR ) {
+ data->Sync[target].SyncPeriod = data->MsgBuffer[3];
+ data->Sync[target].SyncOffset = data->MsgBuffer[4];
+ //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
+ *sync_neg = SYNC_OK;
+ } else {
+ data->Sync[target].SyncPeriod = 0;
+ data->Sync[target].SyncOffset = 0;
+ *sync_neg = SYNC_NG;
+ }
+ nsp_analyze_sdtr(tmpSC);
}
- */
+ /**/
/* search last messeage byte */
tmp = -1;
@@ -1151,134 +1334,291 @@
}
tmpSC->SCp.Message = tmp;
- DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen);
+ nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
show_message(data);
break;
case BUSPHASE_SELECT:
default:
- DEBUG(0, " BUSPHASE other\n");
+ nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
break;
}
- //DEBUG(0, __FUNCTION__ "() out\n");
- return;
+ goto out;
+
timer_out:
- nsp_start_timer(tmpSC, data, 1000/102);
- return;
+ nsp_start_timer(tmpSC, 1000/102);
+ out:
+ nsp_write(base, IRQCONTROL, 0); /* clear IRQ mask */
+ spin_unlock_irqrestore(HOST_LOCK, flags);
+ //nsp_dbg(NSP_DEBUG_INTR, "out");
+ return IRQ_RETVAL(handled);
}
-#ifdef PCMCIA_DEBUG
-#include "nsp_debug.c"
-#endif /* DBG_SHOWCOMMAND */
/*----------------------------------------------------------------*/
/* look for ninja3 card and init if found */
/*----------------------------------------------------------------*/
-static int nsp_detect(Scsi_Host_Template *sht)
+static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht)
{
struct Scsi_Host *host; /* registered host structure */
- nsp_hw_data *data = &nsp_data;
+ nsp_hw_data *data;
- DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
+ nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+ host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
+#else
+ host = scsi_register(sht, sizeof(nsp_hw_data));
+#endif
+ if (host == NULL) {
+ nsp_dbg(NSP_DEBUG_INIT, "host failed");
+ return NULL;
+ }
- request_region(data->BaseAddress, data->NumAddress, "nsp_cs");
- host = scsi_register(sht, 0);
- host->io_port = data->BaseAddress;
- host->unique_id = data->BaseAddress;
- host->n_io_port = data->NumAddress;
- host->irq = data->IrqNumber;
- host->dma_channel = 0xff; /* not use dms */
+ /* Copy global variable to driver specific area */
+ data = (nsp_hw_data *)host->hostdata;
+ *data = nsp_data_base;
+
+ data->ScsiInfo->host = host;
+#ifdef NSP_DEBUG
+ data->CmdId = 0;
+#endif
- sprintf(nspinfo,
-/* Buffer size is 100 bytes */
-/* 0 1 2 3 4 5 6 7 8 9 0*/
-/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
- "NinjaSCSI-3/32Bi Driver $Revision: 1.42 $, I/O 0x%04lx-0x%04lx IRQ %2d",
- host->io_port, host->io_port + host->n_io_port,
- host->irq);
- sht->name = nspinfo;
+ nsp_dbg(NSP_DEBUG_INIT, "irq base=0x%p,%d data=0x%p,%d", &nsp_data_base, (&nsp_data_base)->IrqNumber, data, data->IrqNumber);
- DEBUG(0, __FUNCTION__ " end\n");
+ host->unique_id = data->BaseAddress;
+ host->io_port = data->BaseAddress;
+ host->n_io_port = data->NumAddress;
+ host->irq = data->IrqNumber;
+ host->base = data->MmioAddress;
- return 1; /* detect done. */
+ spin_lock_init(&(data->Lock));
+
+ snprintf(data->nspinfo,
+ sizeof(data->nspinfo),
+ "NinjaSCSI-3/32Bi Driver $Revision: 1.25 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
+ host->io_port, host->io_port + host->n_io_port - 1,
+ host->base,
+ host->irq);
+ sht->name = data->nspinfo;
+
+ nsp_dbg(NSP_DEBUG_INIT, "end");
+
+
+ return host; /* detect done. */
}
-/* nsp_cs requires own release handler because its uses dev_id (=data) */
-static int nsp_release(struct Scsi_Host *shpnt)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+/*----------------------------------------*/
+/* Compatibility functions for 2.4 kernel */
+/*----------------------------------------*/
+static int nsp_detect_old(Scsi_Host_Template *sht)
{
- nsp_hw_data *data = &nsp_data;
-
- if (shpnt->irq) {
- free_irq(shpnt->irq, data);
- }
- if (shpnt->io_port && shpnt->n_io_port) {
- release_region(shpnt->io_port, shpnt->n_io_port);
+ if (nsp_detect(sht) == NULL) {
+ return 0;
+ } else {
+ return 1; /* detects 1 Ninja host card */
}
+}
+
+static int nsp_release_old(struct Scsi_Host *shpnt)
+{
+ //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
+
+ /* PCMCIA Card Service dose same things below. */
+ /* So we do nothing. */
+ //if (shpnt->irq) {
+ // free_irq(shpnt->irq, data->ScsiInfo);
+ //}
+ //if (shpnt->io_port) {
+ // release_region(shpnt->io_port, shpnt->n_io_port);
+ //}
+
return 0;
}
+#endif
/*----------------------------------------------------------------*/
/* return info string */
/*----------------------------------------------------------------*/
static const char *nsp_info(struct Scsi_Host *shpnt)
{
- return nspinfo;
+ nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
+
+ return data->nspinfo;
}
-/*---------------------------------------------------------------*/
-/* error handler */
-/*---------------------------------------------------------------*/
-static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
+#undef SPRINTF
+#define SPRINTF(args...) \
+ do { \
+ if(length > (pos - buffer)) { \
+ pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
+ nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
+ } \
+ } while(0)
+
+/* Shows Ninja host card information for user. */
+static int
+nsp_proc_info(
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+ struct Scsi_Host *host,
+#endif
+ char *buffer,
+ char **start,
+ off_t offset,
+ int length,
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+ int hostno,
+#endif
+ int inout)
{
- DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why);
+ int id;
+ char *pos = buffer;
+ int thislength;
+ int speed;
+ unsigned long flags;
+ nsp_hw_data *data;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+ struct Scsi_Host *host;
+#else
+ int hostno;
+#endif
+ if (inout) {
+ return -EINVAL;
+ }
- nsp_eh_bus_reset(SCpnt);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+ hostno = host->host_no;
+#else
+ /* search this HBA host */
+ host = scsi_host_hn_get(hostno);
+ if (host == NULL) {
+ return -ESRCH;
+ }
+#endif
+ data = (nsp_hw_data *)host->hostdata;
- return SCSI_RESET_SUCCESS;
-}
-static int nsp_abort(Scsi_Cmnd *SCpnt)
-{
- DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+ SPRINTF("NinjaSCSI status\n\n");
+ SPRINTF("Driver version: $Revision: 1.25 $\n");
+ SPRINTF("SCSI host No.: %d\n", hostno);
+ SPRINTF("IRQ: %d\n", host->irq);
+ SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+ SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
+ SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
+
+ SPRINTF("burst transfer mode: ");
+ switch (nsp_burst_mode) {
+ case BURST_IO8:
+ SPRINTF("io8");
+ break;
+ case BURST_IO32:
+ SPRINTF("io32");
+ break;
+ case BURST_MEM32:
+ SPRINTF("mem32");
+ break;
+ default:
+ SPRINTF("???");
+ break;
+ }
+ SPRINTF("\n");
+ SPRINTF("Chip ID: %d\n", data->ChipRev >> 4);
+ SPRINTF("Chip revision: %d\n", data->ChipRev & 0x0f);
+
+
+ spin_lock_irqsave(&(data->Lock), flags);
+ SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
+ spin_unlock_irqrestore(&(data->Lock), flags);
+
+ SPRINTF("SDTR status\n");
+ for(id = 0; id < NUMBER(data->Sync); id++) {
+
+ SPRINTF("id %d: ", id);
+
+ if (id == host->this_id) {
+ SPRINTF("----- NinjaSCSI-3 host adapter\n");
+ continue;
+ }
- nsp_eh_bus_reset(SCpnt);
+ switch(data->Sync[id].SyncNegotiation) {
+ case SYNC_OK:
+ SPRINTF(" sync");
+ break;
+ case SYNC_NG:
+ SPRINTF("async");
+ break;
+ case SYNC_NOT_YET:
+ SPRINTF(" none");
+ break;
+ default:
+ SPRINTF("?????");
+ break;
+ }
+
+ if (data->Sync[id].SyncPeriod != 0) {
+ speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
+
+ SPRINTF(" transfer %d.%dMB/s, offset %d",
+ speed / 1000,
+ speed % 1000,
+ data->Sync[id].SyncOffset
+ );
+ }
+ SPRINTF("\n");
+ }
- return SCSI_ABORT_SUCCESS;
+ thislength = pos - (buffer + offset);
+
+ if(thislength < 0) {
+ *start = 0;
+ return 0;
+ }
+
+
+ thislength = MIN(thislength, length);
+ *start = buffer + offset;
+
+ return thislength;
}
+#undef SPRINTF
+
+/*---------------------------------------------------------------*/
+/* error handler */
+/*---------------------------------------------------------------*/
/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
{
return FAILED;
}*/
+/*
static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
{
- DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
-
- nsp_eh_bus_reset(SCpnt);
+ nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
- return SUCCESS;
-}
+ return nsp_eh_bus_reset(SCpnt);
+}*/
+/*
static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt)
{
- DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+ nsp_dbg(NSP_DEBUG_BUSRESET, "%s: SCpnt=0x%p", SCpnt);
return FAILED;
-}
+}*/
-static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+/* Do bus reset. This function uses in low-level initialize functions. */
+static int nsp_bus_reset(nsp_hw_data *data)
{
- unsigned int base = SCpnt->host->io_port;
+ unsigned int base = data->BaseAddress;
int i;
- DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base);
-
- nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+ nsp_msg(KERN_WARNING, "Bus reset");
+ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR_AND_MASK);
nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
mdelay(100); /* 100ms */
@@ -1287,33 +1627,46 @@
nsp_index_read(base, IRQPHASESENCE); /* dummy read */
}
- nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+ nsphw_init_sync(data);
+
+ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_CLEAR);
+
+ if (data->CurrentSC != NULL) {
+ nsp_msg(KERN_WARNING, "clean up current scsi command.");
+ data->CurrentSC->result = DID_ERROR << 16;
+ nsp_scsi_done(data->CurrentSC);
+ }
return SUCCESS;
}
+/* Do bus reset. This function uses in high-level SCSI driver. */
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+ nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
+
+ return nsp_bus_reset(data);
+}
+
+/* Initialise Ninja host adapter. */
static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
{
- nsp_hw_data *data = &nsp_data;
+ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
- DEBUG(0, __FUNCTION__ "\n");
+ nsp_dbg(NSP_DEBUG_BUSRESET, "in");
+ nsp_msg(KERN_DEBUG, "host reset");
nsphw_init(data);
- return nsp_eh_bus_reset(SCpnt);
+ return SUCCESS;
}
/**********************************************************************
PCMCIA functions
- *********************************************************************/
-
-/*====================================================================*/
-static void cs_error(client_handle_t handle, int func, int ret)
-{
- error_info_t err = { func, ret };
- CardServices(ReportError, handle, &err);
-}
+**********************************************************************/
/*======================================================================
nsp_cs_attach() creates an "instance" of the driver, allocating
@@ -1330,15 +1683,19 @@
client_reg_t client_reg;
dev_link_t *link;
int ret, i;
+ nsp_hw_data *data = &nsp_data_base;
- DEBUG(0, __FUNCTION__ "()\n");
+ nsp_dbg(NSP_DEBUG_INIT, "in");
/* Create new SCSI device */
info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info) { return NULL; }
+ if (info == NULL) { return NULL; }
memset(info, 0, sizeof(*info));
link = &info->link;
link->priv = info;
+ data->ScsiInfo = info;
+
+ nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
/* The io structure describes IO port mapping */
link->io.NumPorts1 = 0x10;
@@ -1352,11 +1709,14 @@
link->irq.IRQInfo2 = irq_mask;
} else {
for (i = 0; i < 4; i++) {
- link->irq.IRQInfo2 |= 1 << irq_list[i];
+ link->irq.IRQInfo2 |= BIT(irq_list[i]);
}
}
+
+ /* Interrupt handler */
link->irq.Handler = &nspintr;
- link->irq.Instance = &nsp_data;
+ link->irq.Instance = info;
+ link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM);
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
@@ -1384,6 +1744,8 @@
return NULL;
}
+
+ nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
return link;
} /* nsp_cs_attach */
@@ -1398,8 +1760,8 @@
{
dev_link_t **linkp;
- DEBUG(0, __FUNCTION__ "(0x%p)\n", link);
-
+ nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
+
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
if (*linkp == link) {
@@ -1411,11 +1773,7 @@
}
if (link->state & DEV_CONFIG) {
- nsp_cs_release((u_long)link);
- if (link->state & DEV_STALE_CONFIG) {
- link->state |= DEV_STALE_LINK;
- return;
- }
+ nsp_cs_release(link);
}
/* Break the link with Card Services */
@@ -1426,6 +1784,7 @@
/* Unlink device structure, free bits */
*linkp = link->next;
kfree(link->priv);
+ link->priv = NULL;
} /* nsp_cs_detach */
@@ -1440,22 +1799,26 @@
#define CFG_CHECK(fn, args...) \
if (CardServices(fn, args) != 0) goto next_entry
/*====================================================================*/
-
static void nsp_cs_config(dev_link_t *link)
{
client_handle_t handle = link->handle;
scsi_info_t *info = link->priv;
tuple_t tuple;
cisparse_t parse;
- int i, last_ret, last_fn;
- u_char tuple_data[64];
+ int last_ret, last_fn;
+ unsigned char tuple_data[64];
config_info_t conf;
+ win_req_t req;
+ memreq_t map;
+ cistpl_cftable_entry_t dflt = { 0 };
+ struct Scsi_Host *host;
+ nsp_hw_data *data = &nsp_data_base;
+#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
Scsi_Device *dev;
dev_node_t **tail, *node;
- struct Scsi_Host *host;
- nsp_hw_data *data = &nsp_data;
+#endif
- DEBUG(0, __FUNCTION__ "() in\n");
+ nsp_dbg(NSP_DEBUG_INIT, "in");
tuple.DesiredTuple = CISTPL_CONFIG;
tuple.Attributes = 0;
@@ -1469,7 +1832,6 @@
link->conf.Present = parse.config.rmask[0];
/* Configure card */
- driver_template.module = &__this_module;
link->state |= DEV_CONFIG;
/* Look up the current Vcc */
@@ -1479,81 +1841,195 @@
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
CS_CHECK(GetFirstTuple, handle, &tuple);
while (1) {
+ cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+
CFG_CHECK(GetTupleData, handle, &tuple);
CFG_CHECK(ParseTuple, handle, &tuple, &parse);
- link->conf.ConfigIndex = parse.cftable_entry.index;
- link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
- i = CardServices(RequestIO, handle, &link->io);
- if (i == CS_SUCCESS) {
- break;
+
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
+ if (cfg->index == 0) { goto next_entry; }
+ link->conf.ConfigIndex = cfg->index;
+
+ /* Does this card need audio output? */
+ if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+ link->conf.Attributes |= CONF_ENABLE_SPKR;
+ link->conf.Status = CCSR_AUDIO_ENA;
+ }
+
+ /* Use power settings for Vcc and Vpp if present */
+ /* Note that the CIS values need to be rescaled */
+ if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
+ goto next_entry;
+ }
+ } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+ if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
+ goto next_entry;
+ }
}
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ }
+
+ /* Do we need to allocate an interrupt? */
+ if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
+ link->conf.Attributes |= CONF_ENABLE_IRQ;
+ }
+
+ /* IO window settings */
+ link->io.NumPorts1 = link->io.NumPorts2 = 0;
+ if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(io->flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.NumPorts1 = io->win[0].len;
+ if (io->nwin > 1) {
+ link->io.Attributes2 = link->io.Attributes1;
+ link->io.BasePort2 = io->win[1].base;
+ link->io.NumPorts2 = io->win[1].len;
+ }
+ /* This reserves IO space but doesn't actually enable it */
+ CFG_CHECK(RequestIO, link->handle, &link->io);
+ }
+
+ if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+ cistpl_mem_t *mem =
+ (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+ req.Attributes |= WIN_ENABLE;
+ req.Base = mem->win[0].host_addr;
+ req.Size = mem->win[0].len;
+ if (req.Size < 0x1000) {
+ req.Size = 0x1000;
+ }
+ req.AccessSpeed = 0;
+ link->win = (window_handle_t)link->handle;
+ CFG_CHECK(RequestWindow, &link->win, &req);
+ map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+ CFG_CHECK(MapMemPage, link->win, &map);
+
+ data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
+ data->MmioLength = req.Size;
+ }
+ /* If we got this far, we're cool! */
+ break;
+
next_entry:
- DEBUG(0, __FUNCTION__ " next\n");
+ nsp_dbg(NSP_DEBUG_INIT, "next");
+
+ if (link->io.NumPorts1) {
+ CardServices(ReleaseIO, link->handle, &link->io);
+ }
CS_CHECK(GetNextTuple, handle, &tuple);
}
- CS_CHECK(RequestIRQ, handle, &link->irq);
+ if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+ CS_CHECK(RequestIRQ, link->handle, &link->irq);
+ }
CS_CHECK(RequestConfiguration, handle, &link->conf);
- /* A bad hack... */
- release_region(link->io.BasePort1, link->io.NumPorts1);
+ if (free_ports) {
+ if (link->io.BasePort1) {
+ release_region(link->io.BasePort1, link->io.NumPorts1);
+ }
+ if (link->io.BasePort2) {
+ release_region(link->io.BasePort2, link->io.NumPorts2);
+ }
+ }
/* Set port and IRQ */
data->BaseAddress = link->io.BasePort1;
data->NumAddress = link->io.NumPorts1;
data->IrqNumber = link->irq.AssignedIRQ;
- DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n",
- data->BaseAddress, data->NumAddress, data->IrqNumber);
+ nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
+ data->BaseAddress, data->NumAddress, data->IrqNumber);
if(nsphw_init(data) == FALSE) {
goto cs_failed;
}
- scsi_register_module(MODULE_SCSI_HA, &driver_template);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+ host = nsp_detect(&nsp_driver_template);
+#else
+ scsi_register_host(&nsp_driver_template);
+ for (host = scsi_host_get_next(NULL); host != NULL;
+ host = scsi_host_get_next(host)) {
+ if (host->hostt == &nsp_driver_template) {
+ break;
+ }
+ }
+#endif
- DEBUG(0, "GET_SCSI_INFO\n");
+ if (host == NULL) {
+ nsp_dbg(NSP_DEBUG_INIT, "detect failed");
+ goto cs_failed;
+ }
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
+ scsi_add_host (host, NULL);
+ scsi_scan_host(host);
+
+ snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
+ link->dev = &info->node;
+ info->host = host;
+
+#else
+ nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
tail = &link->dev;
info->ndev = 0;
- for (host = scsi_hostlist; host != NULL; host = host->next) {
- if (host->hostt == &driver_template) {
- for (dev = host->host_queue; dev != NULL; dev = dev->next) {
- u_long arg[2], id;
- kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
- id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
- ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
- node = &info->node[info->ndev];
- node->minor = 0;
- switch (dev->type) {
- case TYPE_TAPE:
- node->major = SCSI_TAPE_MAJOR;
- sprintf(node->dev_name, "st#%04lx", id);
- break;
- case TYPE_DISK:
- case TYPE_MOD:
- node->major = SCSI_DISK0_MAJOR;
- sprintf(node->dev_name, "sd#%04lx", id);
- break;
- case TYPE_ROM:
- case TYPE_WORM:
- node->major = SCSI_CDROM_MAJOR;
- sprintf(node->dev_name, "sr#%04lx", id);
- break;
- default:
- node->major = SCSI_GENERIC_MAJOR;
- sprintf(node->dev_name, "sg#%04lx", id);
- break;
- }
- *tail = node; tail = &node->next;
- info->ndev++;
- info->host = dev->host;
- }
+
+ nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
+
+ for (dev = host->host_queue; dev != NULL; dev = dev->next) {
+ unsigned long arg[2], id;
+ kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+ id = (arg[0] & 0x0f) + ((arg[0] >> 4) & 0xf0) +
+ ((arg[0] >> 8) & 0xf00) + ((arg[0] >> 12) & 0xf000);
+ node = &info->node[info->ndev];
+ node->minor = 0;
+ switch (dev->type) {
+ case TYPE_TAPE:
+ node->major = SCSI_TAPE_MAJOR;
+ snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
+ break;
+ case TYPE_DISK:
+ case TYPE_MOD:
+ node->major = SCSI_DISK0_MAJOR;
+ snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
+ break;
+ case TYPE_ROM:
+ case TYPE_WORM:
+ node->major = SCSI_CDROM_MAJOR;
+ snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
+ break;
+ default:
+ node->major = SCSI_GENERIC_MAJOR;
+ snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
+ break;
}
+ *tail = node; tail = &node->next;
+ info->ndev++;
+ info->host = dev->host;
}
+
*tail = NULL;
if (info->ndev == 0) {
- printk(KERN_INFO "nsp_cs: no SCSI devices found\n");
+ nsp_msg(KERN_INFO, "no SCSI devices found");
}
+ nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
+#endif
/* Finally, report what we've done */
printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d",
@@ -1569,47 +2045,60 @@
printk(", io 0x%04x-0x%04x", link->io.BasePort1,
link->io.BasePort1+link->io.NumPorts1-1);
}
+ if (link->io.NumPorts2)
+ printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+ link->io.BasePort2+link->io.NumPorts2-1);
+ if (link->win)
+ printk(", mem 0x%06lx-0x%06lx", req.Base,
+ req.Base+req.Size-1);
printk("\n");
link->state &= ~DEV_CONFIG_PENDING;
return;
-cs_failed:
+ cs_failed:
+ nsp_dbg(NSP_DEBUG_INIT, "config fail");
cs_error(link->handle, last_fn, last_ret);
- nsp_cs_release((u_long)link);
- return;
+ nsp_cs_release(link);
+ return;
} /* nsp_cs_config */
#undef CS_CHECK
#undef CFG_CHECK
+
/*======================================================================
After a card is removed, nsp_cs_release() will unregister the net
device, and release the PCMCIA configuration. If the device is
still open, this will be postponed until it is closed.
======================================================================*/
-static void nsp_cs_release(u_long arg)
+static void nsp_cs_release(dev_link_t *link)
{
- dev_link_t *link = (dev_link_t *)arg;
-
- DEBUG(0, __FUNCTION__ "(0x%p)\n", link);
+ scsi_info_t *info = link->priv;
+ nsp_hw_data *data = NULL;
- /*
- * If the device is currently in use, we won't release until it
- * is actually closed.
- */
- if (link->open) {
- DEBUG(1, "nsp_cs: release postponed, '%s' still open\n",
- link->dev->dev_name);
- link->state |= DEV_STALE_CONFIG;
- return;
+ if (info->host == NULL) {
+ nsp_msg(KERN_DEBUG, "unexpected card release call.");
+ } else {
+ data = (nsp_hw_data *)info->host->hostdata;
}
+ nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
+
/* Unlink the device chain */
- scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
+ if (info->host != NULL) {
+ scsi_remove_host(info->host);
+ }
+#else
+ scsi_unregister_host(&nsp_driver_template);
+#endif
link->dev = NULL;
if (link->win) {
+ if (data != NULL) {
+ iounmap((void *)(data->MmioAddress));
+ }
CardServices(ReleaseWindow, link->win);
}
CardServices(ReleaseConfiguration, link->handle);
@@ -1620,10 +2109,11 @@
CardServices(ReleaseIRQ, link->handle, &link->irq);
}
link->state &= ~DEV_CONFIG;
-
- if (link->state & DEV_STALE_LINK) {
- nsp_cs_detach(link);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
+ if (info->host != NULL) {
+ scsi_host_put(info->host);
}
+#endif
} /* nsp_cs_release */
/*======================================================================
@@ -1637,39 +2127,53 @@
to block future accesses to this device. All the functions that
actually access the device should check this flag to make sure
the card is still present.
-
+
======================================================================*/
-static int nsp_cs_event(event_t event,
- int priority,
- event_callback_args_t *args)
+static int nsp_cs_event(event_t event,
+ int priority,
+ event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
scsi_info_t *info = link->priv;
+ nsp_hw_data *data;
- DEBUG(1, __FUNCTION__ "(0x%06x)\n", event);
+ nsp_dbg(NSP_DEBUG_INIT, "in, event=0x%08x", event);
switch (event) {
case CS_EVENT_CARD_REMOVAL:
- DEBUG(0, " event: remove\n");
+ nsp_dbg(NSP_DEBUG_INIT, "event: remove");
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
((scsi_info_t *)link->priv)->stop = 1;
- nsp_cs_release((u_long)link);
+ nsp_cs_release(link);
}
break;
case CS_EVENT_CARD_INSERTION:
- DEBUG(0, " event: insert\n");
+ nsp_dbg(NSP_DEBUG_INIT, "event: insert");
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
info->bus = args->bus;
+#endif
nsp_cs_config(link);
break;
case CS_EVENT_PM_SUSPEND:
+ nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
link->state |= DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_RESET_PHYSICAL:
/* Mark the device as stopped, to block IO until later */
+ nsp_dbg(NSP_DEBUG_INIT, "event: reset physical");
+
+ if (info->host != NULL) {
+ nsp_msg(KERN_INFO, "clear SDTR status");
+
+ data = (nsp_hw_data *)info->host->hostdata;
+
+ nsphw_init_sync(data);
+ }
+
info->stop = 1;
if (link->state & DEV_CONFIG) {
CardServices(ReleaseConfiguration, link->handle);
@@ -1677,68 +2181,92 @@
break;
case CS_EVENT_PM_RESUME:
+ nsp_dbg(NSP_DEBUG_INIT, "event: resume");
link->state &= ~DEV_SUSPEND;
/* Fall through... */
case CS_EVENT_CARD_RESET:
- DEBUG(0, " event: reset\n");
+ nsp_dbg(NSP_DEBUG_INIT, "event: reset");
if (link->state & DEV_CONFIG) {
- Scsi_Cmnd tmp;
-
CardServices(RequestConfiguration, link->handle, &link->conf);
- tmp.host = info->host;
- nsp_eh_host_reset(&tmp);
}
info->stop = 0;
+
+ if (info->host != NULL) {
+ nsp_msg(KERN_INFO, "reset host and bus");
+
+ data = (nsp_hw_data *)info->host->hostdata;
+
+ nsphw_init (data);
+ nsp_bus_reset(data);
+ }
+
break;
default:
- DEBUG(0, " event: unknown\n");
+ nsp_dbg(NSP_DEBUG_INIT, "event: unknown");
break;
}
- DEBUG(0, __FUNCTION__ " end\n");
+ nsp_dbg(NSP_DEBUG_INIT, "end");
return 0;
} /* nsp_cs_event */
/*======================================================================*
* module entry point
*====================================================================*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+static struct pcmcia_driver nsp_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "nsp_cs",
+ },
+ .attach = nsp_cs_attach,
+ .detach = nsp_cs_detach,
+};
+#endif
+
static int __init nsp_cs_init(void)
{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+ nsp_msg(KERN_INFO, "loading...");
+
+ return pcmcia_register_driver(&nsp_driver);
+#else
servinfo_t serv;
- DEBUG(0, __FUNCTION__ "() in\n");
- DEBUG(0, "%s\n", version);
+ nsp_msg(KERN_INFO, "loading...");
CardServices(GetCardServicesInfo, &serv);
if (serv.Revision != CS_RELEASE_CODE) {
- printk(KERN_DEBUG "nsp_cs: Card Services release "
- "does not match!\n");
- return -1;
+ nsp_msg(KERN_DEBUG, "Card Services release does not match!");
+ return -EINVAL;
}
register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
- DEBUG(0, __FUNCTION__ "() out\n");
+ nsp_dbg(NSP_DEBUG_INIT, "out");
return 0;
+#endif
}
-
-static void __exit nsp_cs_cleanup(void)
+static void __exit nsp_cs_exit(void)
{
- DEBUG(0, __FUNCTION__ "() unloading\n");
+ nsp_msg(KERN_INFO, "unloading...");
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+ pcmcia_unregister_driver(&nsp_driver);
+#else
unregister_pcmcia_driver(&dev_info);
+#endif
+
+ /* XXX: this really needs to move into generic code.. */
while (dev_list != NULL) {
if (dev_list->state & DEV_CONFIG) {
- nsp_cs_release((u_long)dev_list);
+ nsp_cs_release(dev_list);
}
nsp_cs_detach(dev_list);
}
}
-module_init(nsp_cs_init);
-module_exit(nsp_cs_cleanup);
-/*
- *
- *
- */
+module_init(nsp_cs_init)
+module_exit(nsp_cs_exit)
/* end */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)