1*4882a593Smuzhiyun /*======================================================================
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
4*4882a593Smuzhiyun By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Ver.2.8 Support 32bit MMIO mode
7*4882a593Smuzhiyun Support Synchronous Data Transfer Request (SDTR) mode
8*4882a593Smuzhiyun Ver.2.0 Support 32bit PIO mode
9*4882a593Smuzhiyun Ver.1.1.2 Fix for scatter list buffer exceeds
10*4882a593Smuzhiyun Ver.1.1 Support scatter list
11*4882a593Smuzhiyun Ver.0.1 Initial version
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun This software may be used and distributed according to the terms of
14*4882a593Smuzhiyun the GNU General Public License.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun ======================================================================*/
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /***********************************************************************
19*4882a593Smuzhiyun This driver is for these PCcards.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun I-O DATA PCSC-F (Workbit NinjaSCSI-3)
22*4882a593Smuzhiyun "WBT", "NinjaSCSI-3", "R1.0"
23*4882a593Smuzhiyun I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
24*4882a593Smuzhiyun "IO DATA", "CBSC16 ", "1"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun ***********************************************************************/
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/module.h>
29*4882a593Smuzhiyun #include <linux/kernel.h>
30*4882a593Smuzhiyun #include <linux/init.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun #include <linux/string.h>
33*4882a593Smuzhiyun #include <linux/timer.h>
34*4882a593Smuzhiyun #include <linux/ioport.h>
35*4882a593Smuzhiyun #include <linux/delay.h>
36*4882a593Smuzhiyun #include <linux/interrupt.h>
37*4882a593Smuzhiyun #include <linux/major.h>
38*4882a593Smuzhiyun #include <linux/blkdev.h>
39*4882a593Smuzhiyun #include <linux/stat.h>
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #include <asm/io.h>
42*4882a593Smuzhiyun #include <asm/irq.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include <../drivers/scsi/scsi.h>
45*4882a593Smuzhiyun #include <scsi/scsi_host.h>
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <scsi/scsi.h>
48*4882a593Smuzhiyun #include <scsi/scsi_ioctl.h>
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
51*4882a593Smuzhiyun #include <pcmcia/cisreg.h>
52*4882a593Smuzhiyun #include <pcmcia/ds.h>
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #include "nsp_cs.h"
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
57*4882a593Smuzhiyun MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
58*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
59*4882a593Smuzhiyun MODULE_LICENSE("GPL");
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun #include "nsp_io.h"
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /*====================================================================*/
64*4882a593Smuzhiyun /* Parameters that can be set with 'insmod' */
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static int nsp_burst_mode = BURST_MEM32;
67*4882a593Smuzhiyun module_param(nsp_burst_mode, int, 0);
68*4882a593Smuzhiyun MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* Release IO ports after configuration? */
71*4882a593Smuzhiyun static bool free_ports = 0;
72*4882a593Smuzhiyun module_param(free_ports, bool, 0);
73*4882a593Smuzhiyun MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun static struct scsi_host_template nsp_driver_template = {
76*4882a593Smuzhiyun .proc_name = "nsp_cs",
77*4882a593Smuzhiyun .show_info = nsp_show_info,
78*4882a593Smuzhiyun .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
79*4882a593Smuzhiyun .info = nsp_info,
80*4882a593Smuzhiyun .queuecommand = nsp_queuecommand,
81*4882a593Smuzhiyun /* .eh_abort_handler = nsp_eh_abort,*/
82*4882a593Smuzhiyun .eh_bus_reset_handler = nsp_eh_bus_reset,
83*4882a593Smuzhiyun .eh_host_reset_handler = nsp_eh_host_reset,
84*4882a593Smuzhiyun .can_queue = 1,
85*4882a593Smuzhiyun .this_id = NSP_INITIATOR_ID,
86*4882a593Smuzhiyun .sg_tablesize = SG_ALL,
87*4882a593Smuzhiyun .dma_boundary = PAGE_SIZE - 1,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * debug, error print
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun #ifndef NSP_DEBUG
98*4882a593Smuzhiyun # define NSP_DEBUG_MASK 0x000000
99*4882a593Smuzhiyun # define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
100*4882a593Smuzhiyun # define nsp_dbg(mask, args...) /* */
101*4882a593Smuzhiyun #else
102*4882a593Smuzhiyun # define NSP_DEBUG_MASK 0xffffff
103*4882a593Smuzhiyun # define nsp_msg(type, args...) \
104*4882a593Smuzhiyun nsp_cs_message (__func__, __LINE__, (type), args)
105*4882a593Smuzhiyun # define nsp_dbg(mask, args...) \
106*4882a593Smuzhiyun nsp_cs_dmessage(__func__, __LINE__, (mask), args)
107*4882a593Smuzhiyun #endif
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun #define NSP_DEBUG_QUEUECOMMAND BIT(0)
110*4882a593Smuzhiyun #define NSP_DEBUG_REGISTER BIT(1)
111*4882a593Smuzhiyun #define NSP_DEBUG_AUTOSCSI BIT(2)
112*4882a593Smuzhiyun #define NSP_DEBUG_INTR BIT(3)
113*4882a593Smuzhiyun #define NSP_DEBUG_SGLIST BIT(4)
114*4882a593Smuzhiyun #define NSP_DEBUG_BUSFREE BIT(5)
115*4882a593Smuzhiyun #define NSP_DEBUG_CDB_CONTENTS BIT(6)
116*4882a593Smuzhiyun #define NSP_DEBUG_RESELECTION BIT(7)
117*4882a593Smuzhiyun #define NSP_DEBUG_MSGINOCCUR BIT(8)
118*4882a593Smuzhiyun #define NSP_DEBUG_EEPROM BIT(9)
119*4882a593Smuzhiyun #define NSP_DEBUG_MSGOUTOCCUR BIT(10)
120*4882a593Smuzhiyun #define NSP_DEBUG_BUSRESET BIT(11)
121*4882a593Smuzhiyun #define NSP_DEBUG_RESTART BIT(12)
122*4882a593Smuzhiyun #define NSP_DEBUG_SYNC BIT(13)
123*4882a593Smuzhiyun #define NSP_DEBUG_WAIT BIT(14)
124*4882a593Smuzhiyun #define NSP_DEBUG_TARGETFLAG BIT(15)
125*4882a593Smuzhiyun #define NSP_DEBUG_PROC BIT(16)
126*4882a593Smuzhiyun #define NSP_DEBUG_INIT BIT(17)
127*4882a593Smuzhiyun #define NSP_DEBUG_DATA_IO BIT(18)
128*4882a593Smuzhiyun #define NSP_SPECIAL_PRINT_REGISTER BIT(20)
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #define NSP_DEBUG_BUF_LEN 150
131*4882a593Smuzhiyun
nsp_inc_resid(struct scsi_cmnd * SCpnt,int residInc)132*4882a593Smuzhiyun static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun __printf(4, 5)
nsp_cs_message(const char * func,int line,char * type,char * fmt,...)138*4882a593Smuzhiyun static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun va_list args;
141*4882a593Smuzhiyun char buf[NSP_DEBUG_BUF_LEN];
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun va_start(args, fmt);
144*4882a593Smuzhiyun vsnprintf(buf, sizeof(buf), fmt, args);
145*4882a593Smuzhiyun va_end(args);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun #ifndef NSP_DEBUG
148*4882a593Smuzhiyun printk("%snsp_cs: %s\n", type, buf);
149*4882a593Smuzhiyun #else
150*4882a593Smuzhiyun printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun #ifdef NSP_DEBUG
nsp_cs_dmessage(const char * func,int line,int mask,char * fmt,...)155*4882a593Smuzhiyun static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun va_list args;
158*4882a593Smuzhiyun char buf[NSP_DEBUG_BUF_LEN];
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun va_start(args, fmt);
161*4882a593Smuzhiyun vsnprintf(buf, sizeof(buf), fmt, args);
162*4882a593Smuzhiyun va_end(args);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (mask & NSP_DEBUG_MASK) {
165*4882a593Smuzhiyun printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun #endif
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /***********************************************************/
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*====================================================
173*4882a593Smuzhiyun * Clenaup parameters and call done() functions.
174*4882a593Smuzhiyun * You must be set SCpnt->result before call this function.
175*4882a593Smuzhiyun */
nsp_scsi_done(struct scsi_cmnd * SCpnt)176*4882a593Smuzhiyun static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun data->CurrentSC = NULL;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun SCpnt->scsi_done(SCpnt);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
nsp_queuecommand_lck(struct scsi_cmnd * SCpnt,void (* done)(struct scsi_cmnd *))185*4882a593Smuzhiyun static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt,
186*4882a593Smuzhiyun void (*done)(struct scsi_cmnd *))
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun #ifdef NSP_DEBUG
189*4882a593Smuzhiyun /*unsigned int host_id = SCpnt->device->host->this_id;*/
190*4882a593Smuzhiyun /*unsigned int base = SCpnt->device->host->io_port;*/
191*4882a593Smuzhiyun unsigned char target = scmd_id(SCpnt);
192*4882a593Smuzhiyun #endif
193*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
196*4882a593Smuzhiyun "SCpnt=0x%p target=%d lun=%llu sglist=0x%p bufflen=%d sg_count=%d",
197*4882a593Smuzhiyun SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
198*4882a593Smuzhiyun scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
199*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun SCpnt->scsi_done = done;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (data->CurrentSC != NULL) {
204*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
205*4882a593Smuzhiyun SCpnt->result = DID_BAD_TARGET << 16;
206*4882a593Smuzhiyun nsp_scsi_done(SCpnt);
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun #if 0
211*4882a593Smuzhiyun /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
212*4882a593Smuzhiyun This makes kernel crash when suspending... */
213*4882a593Smuzhiyun if (data->ScsiInfo->stop != 0) {
214*4882a593Smuzhiyun nsp_msg(KERN_INFO, "suspending device. reject command.");
215*4882a593Smuzhiyun SCpnt->result = DID_BAD_TARGET << 16;
216*4882a593Smuzhiyun nsp_scsi_done(SCpnt);
217*4882a593Smuzhiyun return SCSI_MLQUEUE_HOST_BUSY;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun #endif
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun show_command(SCpnt);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun data->CurrentSC = SCpnt;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun SCpnt->SCp.Status = CHECK_CONDITION;
226*4882a593Smuzhiyun SCpnt->SCp.Message = 0;
227*4882a593Smuzhiyun SCpnt->SCp.have_data_in = IO_UNKNOWN;
228*4882a593Smuzhiyun SCpnt->SCp.sent_command = 0;
229*4882a593Smuzhiyun SCpnt->SCp.phase = PH_UNDETERMINED;
230*4882a593Smuzhiyun scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* setup scratch area
233*4882a593Smuzhiyun SCp.ptr : buffer pointer
234*4882a593Smuzhiyun SCp.this_residual : buffer length
235*4882a593Smuzhiyun SCp.buffer : next buffer
236*4882a593Smuzhiyun SCp.buffers_residual : left buffers in list
237*4882a593Smuzhiyun SCp.phase : current state of the command */
238*4882a593Smuzhiyun if (scsi_bufflen(SCpnt)) {
239*4882a593Smuzhiyun SCpnt->SCp.buffer = scsi_sglist(SCpnt);
240*4882a593Smuzhiyun SCpnt->SCp.ptr = BUFFER_ADDR;
241*4882a593Smuzhiyun SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
242*4882a593Smuzhiyun SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
243*4882a593Smuzhiyun } else {
244*4882a593Smuzhiyun SCpnt->SCp.ptr = NULL;
245*4882a593Smuzhiyun SCpnt->SCp.this_residual = 0;
246*4882a593Smuzhiyun SCpnt->SCp.buffer = NULL;
247*4882a593Smuzhiyun SCpnt->SCp.buffers_residual = 0;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun if (nsphw_start_selection(SCpnt) == FALSE) {
251*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
252*4882a593Smuzhiyun SCpnt->result = DID_BUS_BUSY << 16;
253*4882a593Smuzhiyun nsp_scsi_done(SCpnt);
254*4882a593Smuzhiyun return 0;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
259*4882a593Smuzhiyun #ifdef NSP_DEBUG
260*4882a593Smuzhiyun data->CmdId++;
261*4882a593Smuzhiyun #endif
262*4882a593Smuzhiyun return 0;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
DEF_SCSI_QCMD(nsp_queuecommand)265*4882a593Smuzhiyun static DEF_SCSI_QCMD(nsp_queuecommand)
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun * setup PIO FIFO transfer mode and enable/disable to data out
269*4882a593Smuzhiyun */
270*4882a593Smuzhiyun static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun unsigned int base = data->BaseAddress;
273*4882a593Smuzhiyun unsigned char transfer_mode_reg;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (enabled != FALSE) {
278*4882a593Smuzhiyun transfer_mode_reg = TRANSFER_GO | BRAIND;
279*4882a593Smuzhiyun } else {
280*4882a593Smuzhiyun transfer_mode_reg = 0;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun transfer_mode_reg |= data->TransferMode;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
nsphw_init_sync(nsp_hw_data * data)288*4882a593Smuzhiyun static void nsphw_init_sync(nsp_hw_data *data)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
291*4882a593Smuzhiyun .SyncPeriod = 0,
292*4882a593Smuzhiyun .SyncOffset = 0
293*4882a593Smuzhiyun };
294*4882a593Smuzhiyun int i;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* setup sync data */
297*4882a593Smuzhiyun for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
298*4882a593Smuzhiyun data->Sync[i] = tmp_sync;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun * Initialize Ninja hardware
304*4882a593Smuzhiyun */
nsphw_init(nsp_hw_data * data)305*4882a593Smuzhiyun static int nsphw_init(nsp_hw_data *data)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun unsigned int base = data->BaseAddress;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun data->ScsiClockDiv = CLOCK_40M | FAST_20;
312*4882a593Smuzhiyun data->CurrentSC = NULL;
313*4882a593Smuzhiyun data->FifoCount = 0;
314*4882a593Smuzhiyun data->TransferMode = MODE_IO8;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun nsphw_init_sync(data);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /* block all interrupts */
319*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /* setup SCSI interface */
322*4882a593Smuzhiyun nsp_write(base, IFSELECT, IF_IFSEL);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun nsp_index_write(base, SCSIIRQMODE, 0);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun nsp_index_write(base, TRANSFERMODE, MODE_IO8);
327*4882a593Smuzhiyun nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun nsp_index_write(base, PARITYCTRL, 0);
330*4882a593Smuzhiyun nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
331*4882a593Smuzhiyun ACK_COUNTER_CLEAR |
332*4882a593Smuzhiyun REQ_COUNTER_CLEAR |
333*4882a593Smuzhiyun HOST_COUNTER_CLEAR);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* setup fifo asic */
336*4882a593Smuzhiyun nsp_write(base, IFSELECT, IF_REGSEL);
337*4882a593Smuzhiyun nsp_index_write(base, TERMPWRCTRL, 0);
338*4882a593Smuzhiyun if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
339*4882a593Smuzhiyun nsp_msg(KERN_INFO, "terminator power on");
340*4882a593Smuzhiyun nsp_index_write(base, TERMPWRCTRL, POWER_ON);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun nsp_index_write(base, TIMERCOUNT, 0);
344*4882a593Smuzhiyun nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun nsp_index_write(base, SYNCREG, 0);
347*4882a593Smuzhiyun nsp_index_write(base, ACKWIDTH, 0);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* enable interrupts and ack them */
350*4882a593Smuzhiyun nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
351*4882a593Smuzhiyun RESELECT_EI |
352*4882a593Smuzhiyun SCSI_RESET_IRQ_EI );
353*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun nsp_setup_fifo(data, FALSE);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun return TRUE;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /*
361*4882a593Smuzhiyun * Start selection phase
362*4882a593Smuzhiyun */
nsphw_start_selection(struct scsi_cmnd * SCpnt)363*4882a593Smuzhiyun static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun unsigned int host_id = SCpnt->device->host->this_id;
366*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
367*4882a593Smuzhiyun unsigned char target = scmd_id(SCpnt);
368*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
369*4882a593Smuzhiyun int time_out;
370*4882a593Smuzhiyun unsigned char phase, arbit;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun phase = nsp_index_read(base, SCSIBUSMON);
375*4882a593Smuzhiyun if(phase != BUSMON_BUS_FREE) {
376*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
377*4882a593Smuzhiyun return FALSE;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* start arbitration */
381*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
382*4882a593Smuzhiyun SCpnt->SCp.phase = PH_ARBSTART;
383*4882a593Smuzhiyun nsp_index_write(base, SETARBIT, ARBIT_GO);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun time_out = 1000;
386*4882a593Smuzhiyun do {
387*4882a593Smuzhiyun /* XXX: what a stupid chip! */
388*4882a593Smuzhiyun arbit = nsp_index_read(base, ARBITSTATUS);
389*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
390*4882a593Smuzhiyun udelay(1); /* hold 1.2us */
391*4882a593Smuzhiyun } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
392*4882a593Smuzhiyun (time_out-- != 0));
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun if (!(arbit & ARBIT_WIN)) {
395*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
396*4882a593Smuzhiyun nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
397*4882a593Smuzhiyun return FALSE;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* assert select line */
401*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
402*4882a593Smuzhiyun SCpnt->SCp.phase = PH_SELSTART;
403*4882a593Smuzhiyun udelay(3); /* wait 2.4us */
404*4882a593Smuzhiyun nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
405*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
406*4882a593Smuzhiyun udelay(2); /* wait >1.2us */
407*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
408*4882a593Smuzhiyun nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
409*4882a593Smuzhiyun /*udelay(1);*/ /* wait >90ns */
410*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* check selection timeout */
413*4882a593Smuzhiyun nsp_start_timer(SCpnt, 1000/51);
414*4882a593Smuzhiyun data->SelectionTimeOut = 1;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun return TRUE;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun struct nsp_sync_table {
420*4882a593Smuzhiyun unsigned int min_period;
421*4882a593Smuzhiyun unsigned int max_period;
422*4882a593Smuzhiyun unsigned int chip_period;
423*4882a593Smuzhiyun unsigned int ack_width;
424*4882a593Smuzhiyun };
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun static struct nsp_sync_table nsp_sync_table_40M[] = {
427*4882a593Smuzhiyun {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
428*4882a593Smuzhiyun {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
429*4882a593Smuzhiyun {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
430*4882a593Smuzhiyun {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
431*4882a593Smuzhiyun { 0, 0, 0, 0},
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun static struct nsp_sync_table nsp_sync_table_20M[] = {
435*4882a593Smuzhiyun {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
436*4882a593Smuzhiyun {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
437*4882a593Smuzhiyun {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
438*4882a593Smuzhiyun { 0, 0, 0, 0},
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /*
442*4882a593Smuzhiyun * setup synchronous data transfer mode
443*4882a593Smuzhiyun */
nsp_analyze_sdtr(struct scsi_cmnd * SCpnt)444*4882a593Smuzhiyun static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun unsigned char target = scmd_id(SCpnt);
447*4882a593Smuzhiyun // unsigned char lun = SCpnt->device->lun;
448*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
449*4882a593Smuzhiyun sync_data *sync = &(data->Sync[target]);
450*4882a593Smuzhiyun struct nsp_sync_table *sync_table;
451*4882a593Smuzhiyun unsigned int period, offset;
452*4882a593Smuzhiyun int i;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_SYNC, "in");
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun period = sync->SyncPeriod;
458*4882a593Smuzhiyun offset = sync->SyncOffset;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
463*4882a593Smuzhiyun sync_table = nsp_sync_table_20M;
464*4882a593Smuzhiyun } else {
465*4882a593Smuzhiyun sync_table = nsp_sync_table_40M;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
469*4882a593Smuzhiyun if ( period >= sync_table->min_period &&
470*4882a593Smuzhiyun period <= sync_table->max_period ) {
471*4882a593Smuzhiyun break;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun if (period != 0 && sync_table->max_period == 0) {
476*4882a593Smuzhiyun /*
477*4882a593Smuzhiyun * No proper period/offset found
478*4882a593Smuzhiyun */
479*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun sync->SyncPeriod = 0;
482*4882a593Smuzhiyun sync->SyncOffset = 0;
483*4882a593Smuzhiyun sync->SyncRegister = 0;
484*4882a593Smuzhiyun sync->AckWidth = 0;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return FALSE;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
490*4882a593Smuzhiyun (offset & SYNCREG_OFFSET_MASK);
491*4882a593Smuzhiyun sync->AckWidth = sync_table->ack_width;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun return TRUE;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun /*
500*4882a593Smuzhiyun * start ninja hardware timer
501*4882a593Smuzhiyun */
nsp_start_timer(struct scsi_cmnd * SCpnt,int time)502*4882a593Smuzhiyun static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
505*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
508*4882a593Smuzhiyun data->TimerCount = time;
509*4882a593Smuzhiyun nsp_index_write(base, TIMERCOUNT, time);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun /*
513*4882a593Smuzhiyun * wait for bus phase change
514*4882a593Smuzhiyun */
nsp_negate_signal(struct scsi_cmnd * SCpnt,unsigned char mask,char * str)515*4882a593Smuzhiyun static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
516*4882a593Smuzhiyun char *str)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
519*4882a593Smuzhiyun unsigned char reg;
520*4882a593Smuzhiyun int time_out;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "in");
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun time_out = 100;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun do {
527*4882a593Smuzhiyun reg = nsp_index_read(base, SCSIBUSMON);
528*4882a593Smuzhiyun if (reg == 0xff) {
529*4882a593Smuzhiyun break;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun } while ((--time_out != 0) && (reg & mask) != 0);
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun if (time_out == 0) {
534*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, " %s signal off timeout", str);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return 0;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /*
541*4882a593Smuzhiyun * expect Ninja Irq
542*4882a593Smuzhiyun */
nsp_expect_signal(struct scsi_cmnd * SCpnt,unsigned char current_phase,unsigned char mask)543*4882a593Smuzhiyun static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
544*4882a593Smuzhiyun unsigned char current_phase,
545*4882a593Smuzhiyun unsigned char mask)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
548*4882a593Smuzhiyun int time_out;
549*4882a593Smuzhiyun unsigned char phase, i_src;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun time_out = 100;
554*4882a593Smuzhiyun do {
555*4882a593Smuzhiyun phase = nsp_index_read(base, SCSIBUSMON);
556*4882a593Smuzhiyun if (phase == 0xff) {
557*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
558*4882a593Smuzhiyun return -1;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun i_src = nsp_read(base, IRQSTATUS);
561*4882a593Smuzhiyun if (i_src & IRQSTATUS_SCSI) {
562*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
563*4882a593Smuzhiyun return 0;
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
566*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
567*4882a593Smuzhiyun return 1;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun } while(time_out-- != 0);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "timeout");
572*4882a593Smuzhiyun return -1;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun * transfer SCSI message
577*4882a593Smuzhiyun */
nsp_xfer(struct scsi_cmnd * SCpnt,int phase)578*4882a593Smuzhiyun static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
581*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
582*4882a593Smuzhiyun char *buf = data->MsgBuffer;
583*4882a593Smuzhiyun int len = min(MSGBUF_SIZE, data->MsgLen);
584*4882a593Smuzhiyun int ptr;
585*4882a593Smuzhiyun int ret;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
588*4882a593Smuzhiyun for (ptr = 0; len > 0; len--, ptr++) {
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
591*4882a593Smuzhiyun if (ret <= 0) {
592*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
593*4882a593Smuzhiyun return 0;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /* if last byte, negate ATN */
597*4882a593Smuzhiyun if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
598*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* read & write message */
602*4882a593Smuzhiyun if (phase & BUSMON_IO) {
603*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
604*4882a593Smuzhiyun buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
605*4882a593Smuzhiyun } else {
606*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
607*4882a593Smuzhiyun nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun return len;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /*
616*4882a593Smuzhiyun * get extra SCSI data from fifo
617*4882a593Smuzhiyun */
nsp_dataphase_bypass(struct scsi_cmnd * SCpnt)618*4882a593Smuzhiyun static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
621*4882a593Smuzhiyun unsigned int count;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun if (SCpnt->SCp.have_data_in != IO_IN) {
626*4882a593Smuzhiyun return 0;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun count = nsp_fifo_count(SCpnt);
630*4882a593Smuzhiyun if (data->FifoCount == count) {
631*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
632*4882a593Smuzhiyun return 0;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /*
636*4882a593Smuzhiyun * XXX: NSP_QUIRK
637*4882a593Smuzhiyun * data phase skip only occures in case of SCSI_LOW_READ
638*4882a593Smuzhiyun */
639*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
640*4882a593Smuzhiyun SCpnt->SCp.phase = PH_DATA;
641*4882a593Smuzhiyun nsp_pio_read(SCpnt);
642*4882a593Smuzhiyun nsp_setup_fifo(data, FALSE);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /*
648*4882a593Smuzhiyun * accept reselection
649*4882a593Smuzhiyun */
nsp_reselected(struct scsi_cmnd * SCpnt)650*4882a593Smuzhiyun static int nsp_reselected(struct scsi_cmnd *SCpnt)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
653*4882a593Smuzhiyun unsigned int host_id = SCpnt->device->host->this_id;
654*4882a593Smuzhiyun //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
655*4882a593Smuzhiyun unsigned char bus_reg;
656*4882a593Smuzhiyun unsigned char id_reg, tmp;
657*4882a593Smuzhiyun int target;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_RESELECTION, "in");
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun id_reg = nsp_index_read(base, RESELECTID);
662*4882a593Smuzhiyun tmp = id_reg & (~BIT(host_id));
663*4882a593Smuzhiyun target = 0;
664*4882a593Smuzhiyun while(tmp != 0) {
665*4882a593Smuzhiyun if (tmp & BIT(0)) {
666*4882a593Smuzhiyun break;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun tmp >>= 1;
669*4882a593Smuzhiyun target++;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (scmd_id(SCpnt) != target) {
673*4882a593Smuzhiyun nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun nsp_nexus(SCpnt);
679*4882a593Smuzhiyun bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
680*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, bus_reg);
681*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun return TRUE;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /*
687*4882a593Smuzhiyun * count how many data transferd
688*4882a593Smuzhiyun */
nsp_fifo_count(struct scsi_cmnd * SCpnt)689*4882a593Smuzhiyun static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
692*4882a593Smuzhiyun unsigned int count;
693*4882a593Smuzhiyun unsigned int l, m, h;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun l = nsp_index_read(base, TRANSFERCOUNT);
698*4882a593Smuzhiyun m = nsp_index_read(base, TRANSFERCOUNT);
699*4882a593Smuzhiyun h = nsp_index_read(base, TRANSFERCOUNT);
700*4882a593Smuzhiyun nsp_index_read(base, TRANSFERCOUNT); /* required this! */
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun count = (h << 16) | (m << 8) | (l << 0);
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun return count;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun /* fifo size */
710*4882a593Smuzhiyun #define RFIFO_CRIT 64
711*4882a593Smuzhiyun #define WFIFO_CRIT 64
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /*
714*4882a593Smuzhiyun * read data in DATA IN phase
715*4882a593Smuzhiyun */
nsp_pio_read(struct scsi_cmnd * SCpnt)716*4882a593Smuzhiyun static void nsp_pio_read(struct scsi_cmnd *SCpnt)
717*4882a593Smuzhiyun {
718*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
719*4882a593Smuzhiyun unsigned long mmio_base = SCpnt->device->host->base;
720*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
721*4882a593Smuzhiyun long time_out;
722*4882a593Smuzhiyun int ocount, res;
723*4882a593Smuzhiyun unsigned char stat, fifo_stat;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun ocount = data->FifoCount;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun 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",
728*4882a593Smuzhiyun SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
729*4882a593Smuzhiyun SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
730*4882a593Smuzhiyun SCpnt->SCp.buffers_residual);
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun time_out = 1000;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun while ((time_out-- != 0) &&
735*4882a593Smuzhiyun (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun stat = nsp_index_read(base, SCSIBUSMON);
738*4882a593Smuzhiyun stat &= BUSMON_PHASE_MASK;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun res = nsp_fifo_count(SCpnt) - ocount;
742*4882a593Smuzhiyun //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);
743*4882a593Smuzhiyun if (res == 0) { /* if some data available ? */
744*4882a593Smuzhiyun if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
745*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
746*4882a593Smuzhiyun continue;
747*4882a593Smuzhiyun } else {
748*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
749*4882a593Smuzhiyun break;
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun fifo_stat = nsp_read(base, FIFOSTATUS);
754*4882a593Smuzhiyun if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
755*4882a593Smuzhiyun stat == BUSPHASE_DATA_IN) {
756*4882a593Smuzhiyun continue;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun res = min(res, SCpnt->SCp.this_residual);
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun switch (data->TransferMode) {
762*4882a593Smuzhiyun case MODE_IO32:
763*4882a593Smuzhiyun res &= ~(BIT(1)|BIT(0)); /* align 4 */
764*4882a593Smuzhiyun nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
765*4882a593Smuzhiyun break;
766*4882a593Smuzhiyun case MODE_IO8:
767*4882a593Smuzhiyun nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
768*4882a593Smuzhiyun break;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun case MODE_MEM32:
771*4882a593Smuzhiyun res &= ~(BIT(1)|BIT(0)); /* align 4 */
772*4882a593Smuzhiyun nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
773*4882a593Smuzhiyun break;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun default:
776*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
777*4882a593Smuzhiyun return;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun nsp_inc_resid(SCpnt, -res);
781*4882a593Smuzhiyun SCpnt->SCp.ptr += res;
782*4882a593Smuzhiyun SCpnt->SCp.this_residual -= res;
783*4882a593Smuzhiyun ocount += res;
784*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun /* go to next scatter list if available */
787*4882a593Smuzhiyun if (SCpnt->SCp.this_residual == 0 &&
788*4882a593Smuzhiyun SCpnt->SCp.buffers_residual != 0 ) {
789*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
790*4882a593Smuzhiyun SCpnt->SCp.buffers_residual--;
791*4882a593Smuzhiyun SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
792*4882a593Smuzhiyun SCpnt->SCp.ptr = BUFFER_ADDR;
793*4882a593Smuzhiyun SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
794*4882a593Smuzhiyun time_out = 1000;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun data->FifoCount = ocount;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun if (time_out < 0) {
803*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
804*4882a593Smuzhiyun scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
805*4882a593Smuzhiyun SCpnt->SCp.buffers_residual);
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
808*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
809*4882a593Smuzhiyun scsi_get_resid(SCpnt));
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun /*
813*4882a593Smuzhiyun * write data in DATA OUT phase
814*4882a593Smuzhiyun */
nsp_pio_write(struct scsi_cmnd * SCpnt)815*4882a593Smuzhiyun static void nsp_pio_write(struct scsi_cmnd *SCpnt)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
818*4882a593Smuzhiyun unsigned long mmio_base = SCpnt->device->host->base;
819*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
820*4882a593Smuzhiyun int time_out;
821*4882a593Smuzhiyun int ocount, res;
822*4882a593Smuzhiyun unsigned char stat;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun ocount = data->FifoCount;
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
827*4882a593Smuzhiyun data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
828*4882a593Smuzhiyun SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
829*4882a593Smuzhiyun scsi_get_resid(SCpnt));
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun time_out = 1000;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun while ((time_out-- != 0) &&
834*4882a593Smuzhiyun (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
835*4882a593Smuzhiyun stat = nsp_index_read(base, SCSIBUSMON);
836*4882a593Smuzhiyun stat &= BUSMON_PHASE_MASK;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun if (stat != BUSPHASE_DATA_OUT) {
839*4882a593Smuzhiyun res = ocount - nsp_fifo_count(SCpnt);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
842*4882a593Smuzhiyun /* Put back pointer */
843*4882a593Smuzhiyun nsp_inc_resid(SCpnt, res);
844*4882a593Smuzhiyun SCpnt->SCp.ptr -= res;
845*4882a593Smuzhiyun SCpnt->SCp.this_residual += res;
846*4882a593Smuzhiyun ocount -= res;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun res = ocount - nsp_fifo_count(SCpnt);
852*4882a593Smuzhiyun if (res > 0) { /* write all data? */
853*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
854*4882a593Smuzhiyun continue;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
860*4882a593Smuzhiyun switch (data->TransferMode) {
861*4882a593Smuzhiyun case MODE_IO32:
862*4882a593Smuzhiyun res &= ~(BIT(1)|BIT(0)); /* align 4 */
863*4882a593Smuzhiyun nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
864*4882a593Smuzhiyun break;
865*4882a593Smuzhiyun case MODE_IO8:
866*4882a593Smuzhiyun nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
867*4882a593Smuzhiyun break;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun case MODE_MEM32:
870*4882a593Smuzhiyun res &= ~(BIT(1)|BIT(0)); /* align 4 */
871*4882a593Smuzhiyun nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
872*4882a593Smuzhiyun break;
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun default:
875*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
876*4882a593Smuzhiyun break;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun nsp_inc_resid(SCpnt, -res);
880*4882a593Smuzhiyun SCpnt->SCp.ptr += res;
881*4882a593Smuzhiyun SCpnt->SCp.this_residual -= res;
882*4882a593Smuzhiyun ocount += res;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun /* go to next scatter list if available */
885*4882a593Smuzhiyun if (SCpnt->SCp.this_residual == 0 &&
886*4882a593Smuzhiyun SCpnt->SCp.buffers_residual != 0 ) {
887*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
888*4882a593Smuzhiyun SCpnt->SCp.buffers_residual--;
889*4882a593Smuzhiyun SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer);
890*4882a593Smuzhiyun SCpnt->SCp.ptr = BUFFER_ADDR;
891*4882a593Smuzhiyun SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
892*4882a593Smuzhiyun time_out = 1000;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun data->FifoCount = ocount;
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun if (time_out < 0) {
899*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
900*4882a593Smuzhiyun scsi_get_resid(SCpnt));
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
903*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
904*4882a593Smuzhiyun scsi_get_resid(SCpnt));
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun #undef RFIFO_CRIT
907*4882a593Smuzhiyun #undef WFIFO_CRIT
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun /*
910*4882a593Smuzhiyun * setup synchronous/asynchronous data transfer mode
911*4882a593Smuzhiyun */
nsp_nexus(struct scsi_cmnd * SCpnt)912*4882a593Smuzhiyun static int nsp_nexus(struct scsi_cmnd *SCpnt)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun unsigned int base = SCpnt->device->host->io_port;
915*4882a593Smuzhiyun unsigned char target = scmd_id(SCpnt);
916*4882a593Smuzhiyun // unsigned char lun = SCpnt->device->lun;
917*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
918*4882a593Smuzhiyun sync_data *sync = &(data->Sync[target]);
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun /* setup synch transfer registers */
923*4882a593Smuzhiyun nsp_index_write(base, SYNCREG, sync->SyncRegister);
924*4882a593Smuzhiyun nsp_index_write(base, ACKWIDTH, sync->AckWidth);
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun if (scsi_get_resid(SCpnt) % 4 != 0 ||
927*4882a593Smuzhiyun scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
928*4882a593Smuzhiyun data->TransferMode = MODE_IO8;
929*4882a593Smuzhiyun } else if (nsp_burst_mode == BURST_MEM32) {
930*4882a593Smuzhiyun data->TransferMode = MODE_MEM32;
931*4882a593Smuzhiyun } else if (nsp_burst_mode == BURST_IO32) {
932*4882a593Smuzhiyun data->TransferMode = MODE_IO32;
933*4882a593Smuzhiyun } else {
934*4882a593Smuzhiyun data->TransferMode = MODE_IO8;
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun /* setup pdma fifo */
938*4882a593Smuzhiyun nsp_setup_fifo(data, TRUE);
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun /* clear ack counter */
941*4882a593Smuzhiyun data->FifoCount = 0;
942*4882a593Smuzhiyun nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
943*4882a593Smuzhiyun ACK_COUNTER_CLEAR |
944*4882a593Smuzhiyun REQ_COUNTER_CLEAR |
945*4882a593Smuzhiyun HOST_COUNTER_CLEAR);
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun return 0;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun #include "nsp_message.c"
951*4882a593Smuzhiyun /*
952*4882a593Smuzhiyun * interrupt handler
953*4882a593Smuzhiyun */
nspintr(int irq,void * dev_id)954*4882a593Smuzhiyun static irqreturn_t nspintr(int irq, void *dev_id)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun unsigned int base;
957*4882a593Smuzhiyun unsigned char irq_status, irq_phase, phase;
958*4882a593Smuzhiyun struct scsi_cmnd *tmpSC;
959*4882a593Smuzhiyun unsigned char target, lun;
960*4882a593Smuzhiyun unsigned int *sync_neg;
961*4882a593Smuzhiyun int i, tmp;
962*4882a593Smuzhiyun nsp_hw_data *data;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
966*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun if ( dev_id != NULL &&
969*4882a593Smuzhiyun ((scsi_info_t *)dev_id)->host != NULL ) {
970*4882a593Smuzhiyun scsi_info_t *info = (scsi_info_t *)dev_id;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun data = (nsp_hw_data *)info->host->hostdata;
973*4882a593Smuzhiyun } else {
974*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
975*4882a593Smuzhiyun return IRQ_NONE;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun base = data->BaseAddress;
981*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun /*
984*4882a593Smuzhiyun * interrupt check
985*4882a593Smuzhiyun */
986*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
987*4882a593Smuzhiyun irq_status = nsp_read(base, IRQSTATUS);
988*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
989*4882a593Smuzhiyun if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
990*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, 0);
991*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
992*4882a593Smuzhiyun return IRQ_NONE;
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun /* XXX: IMPORTANT
996*4882a593Smuzhiyun * Do not read an irq_phase register if no scsi phase interrupt.
997*4882a593Smuzhiyun * Unless, you should lose a scsi phase interrupt.
998*4882a593Smuzhiyun */
999*4882a593Smuzhiyun phase = nsp_index_read(base, SCSIBUSMON);
1000*4882a593Smuzhiyun if((irq_status & IRQSTATUS_SCSI) != 0) {
1001*4882a593Smuzhiyun irq_phase = nsp_index_read(base, IRQPHASESENCE);
1002*4882a593Smuzhiyun } else {
1003*4882a593Smuzhiyun irq_phase = 0;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /*
1009*4882a593Smuzhiyun * timer interrupt handler (scsi vs timer interrupts)
1010*4882a593Smuzhiyun */
1011*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1012*4882a593Smuzhiyun if (data->TimerCount != 0) {
1013*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1014*4882a593Smuzhiyun nsp_index_write(base, TIMERCOUNT, 0);
1015*4882a593Smuzhiyun nsp_index_write(base, TIMERCOUNT, 0);
1016*4882a593Smuzhiyun data->TimerCount = 0;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1020*4882a593Smuzhiyun data->SelectionTimeOut == 0) {
1021*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1022*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1023*4882a593Smuzhiyun return IRQ_HANDLED;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun if ((irq_status & IRQSTATUS_SCSI) &&
1029*4882a593Smuzhiyun (irq_phase & SCSI_RESET_IRQ)) {
1030*4882a593Smuzhiyun nsp_msg(KERN_ERR, "bus reset (power off?)");
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun nsphw_init(data);
1033*4882a593Smuzhiyun nsp_bus_reset(data);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun if(data->CurrentSC != NULL) {
1036*4882a593Smuzhiyun tmpSC = data->CurrentSC;
1037*4882a593Smuzhiyun tmpSC->result = (DID_RESET << 16) |
1038*4882a593Smuzhiyun ((tmpSC->SCp.Message & 0xff) << 8) |
1039*4882a593Smuzhiyun ((tmpSC->SCp.Status & 0xff) << 0);
1040*4882a593Smuzhiyun nsp_scsi_done(tmpSC);
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun return IRQ_HANDLED;
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun if (data->CurrentSC == NULL) {
1046*4882a593Smuzhiyun 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);
1047*4882a593Smuzhiyun nsphw_init(data);
1048*4882a593Smuzhiyun nsp_bus_reset(data);
1049*4882a593Smuzhiyun return IRQ_HANDLED;
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun tmpSC = data->CurrentSC;
1053*4882a593Smuzhiyun target = tmpSC->device->id;
1054*4882a593Smuzhiyun lun = tmpSC->device->lun;
1055*4882a593Smuzhiyun sync_neg = &(data->Sync[target].SyncNegotiation);
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun /*
1058*4882a593Smuzhiyun * parse hardware SCSI irq reasons register
1059*4882a593Smuzhiyun */
1060*4882a593Smuzhiyun if (irq_status & IRQSTATUS_SCSI) {
1061*4882a593Smuzhiyun if (irq_phase & RESELECT_IRQ) {
1062*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "reselect");
1063*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1064*4882a593Smuzhiyun if (nsp_reselected(tmpSC) != FALSE) {
1065*4882a593Smuzhiyun return IRQ_HANDLED;
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1070*4882a593Smuzhiyun return IRQ_HANDLED;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun //show_phase(tmpSC);
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun switch(tmpSC->SCp.phase) {
1077*4882a593Smuzhiyun case PH_SELSTART:
1078*4882a593Smuzhiyun // *sync_neg = SYNC_NOT_YET;
1079*4882a593Smuzhiyun if ((phase & BUSMON_BSY) == 0) {
1080*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1081*4882a593Smuzhiyun if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1082*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1083*4882a593Smuzhiyun data->SelectionTimeOut = 0;
1084*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, 0);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun tmpSC->result = DID_TIME_OUT << 16;
1087*4882a593Smuzhiyun nsp_scsi_done(tmpSC);
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun return IRQ_HANDLED;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun data->SelectionTimeOut += 1;
1092*4882a593Smuzhiyun nsp_start_timer(tmpSC, 1000/51);
1093*4882a593Smuzhiyun return IRQ_HANDLED;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun /* attention assert */
1097*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1098*4882a593Smuzhiyun data->SelectionTimeOut = 0;
1099*4882a593Smuzhiyun tmpSC->SCp.phase = PH_SELECTED;
1100*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1101*4882a593Smuzhiyun udelay(1);
1102*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1103*4882a593Smuzhiyun return IRQ_HANDLED;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun break;
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun case PH_RESELECT:
1108*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1109*4882a593Smuzhiyun // *sync_neg = SYNC_NOT_YET;
1110*4882a593Smuzhiyun if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun tmpSC->result = DID_ABORT << 16;
1113*4882a593Smuzhiyun nsp_scsi_done(tmpSC);
1114*4882a593Smuzhiyun return IRQ_HANDLED;
1115*4882a593Smuzhiyun }
1116*4882a593Smuzhiyun fallthrough;
1117*4882a593Smuzhiyun default:
1118*4882a593Smuzhiyun if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1119*4882a593Smuzhiyun return IRQ_HANDLED;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun break;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun /*
1125*4882a593Smuzhiyun * SCSI sequencer
1126*4882a593Smuzhiyun */
1127*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun /* normal disconnect */
1130*4882a593Smuzhiyun if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1131*4882a593Smuzhiyun (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1132*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun //*sync_neg = SYNC_NOT_YET;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun /* all command complete and return status */
1137*4882a593Smuzhiyun if (tmpSC->SCp.Message == MSG_COMMAND_COMPLETE) {
1138*4882a593Smuzhiyun tmpSC->result = (DID_OK << 16) |
1139*4882a593Smuzhiyun ((tmpSC->SCp.Message & 0xff) << 8) |
1140*4882a593Smuzhiyun ((tmpSC->SCp.Status & 0xff) << 0);
1141*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1142*4882a593Smuzhiyun nsp_scsi_done(tmpSC);
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun return IRQ_HANDLED;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun return IRQ_HANDLED;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun /* check unexpected bus free state */
1152*4882a593Smuzhiyun if (phase == 0) {
1153*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun *sync_neg = SYNC_NG;
1156*4882a593Smuzhiyun tmpSC->result = DID_ERROR << 16;
1157*4882a593Smuzhiyun nsp_scsi_done(tmpSC);
1158*4882a593Smuzhiyun return IRQ_HANDLED;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun switch (phase & BUSMON_PHASE_MASK) {
1162*4882a593Smuzhiyun case BUSPHASE_COMMAND:
1163*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1164*4882a593Smuzhiyun if ((phase & BUSMON_REQ) == 0) {
1165*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1166*4882a593Smuzhiyun return IRQ_HANDLED;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun tmpSC->SCp.phase = PH_COMMAND;
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun nsp_nexus(tmpSC);
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun /* write scsi command */
1174*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1175*4882a593Smuzhiyun nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1176*4882a593Smuzhiyun for (i = 0; i < tmpSC->cmd_len; i++) {
1177*4882a593Smuzhiyun nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1180*4882a593Smuzhiyun break;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun case BUSPHASE_DATA_OUT:
1183*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun tmpSC->SCp.phase = PH_DATA;
1186*4882a593Smuzhiyun tmpSC->SCp.have_data_in = IO_OUT;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun nsp_pio_write(tmpSC);
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun break;
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun case BUSPHASE_DATA_IN:
1193*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun tmpSC->SCp.phase = PH_DATA;
1196*4882a593Smuzhiyun tmpSC->SCp.have_data_in = IO_IN;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun nsp_pio_read(tmpSC);
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun break;
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun case BUSPHASE_STATUS:
1203*4882a593Smuzhiyun nsp_dataphase_bypass(tmpSC);
1204*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun tmpSC->SCp.phase = PH_STATUS;
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1209*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun break;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun case BUSPHASE_MESSAGE_OUT:
1214*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1215*4882a593Smuzhiyun if ((phase & BUSMON_REQ) == 0) {
1216*4882a593Smuzhiyun goto timer_out;
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun tmpSC->SCp.phase = PH_MSG_OUT;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun //*sync_neg = SYNC_NOT_YET;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun data->MsgLen = i = 0;
1224*4882a593Smuzhiyun data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun if (*sync_neg == SYNC_NOT_YET) {
1227*4882a593Smuzhiyun data->Sync[target].SyncPeriod = 0;
1228*4882a593Smuzhiyun data->Sync[target].SyncOffset = 0;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun /**/
1231*4882a593Smuzhiyun data->MsgBuffer[i] = MSG_EXTENDED; i++;
1232*4882a593Smuzhiyun data->MsgBuffer[i] = 3; i++;
1233*4882a593Smuzhiyun data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1234*4882a593Smuzhiyun data->MsgBuffer[i] = 0x0c; i++;
1235*4882a593Smuzhiyun data->MsgBuffer[i] = 15; i++;
1236*4882a593Smuzhiyun /**/
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun data->MsgLen = i;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun nsp_analyze_sdtr(tmpSC);
1241*4882a593Smuzhiyun show_message(data);
1242*4882a593Smuzhiyun nsp_message_out(tmpSC);
1243*4882a593Smuzhiyun break;
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun case BUSPHASE_MESSAGE_IN:
1246*4882a593Smuzhiyun nsp_dataphase_bypass(tmpSC);
1247*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1248*4882a593Smuzhiyun if ((phase & BUSMON_REQ) == 0) {
1249*4882a593Smuzhiyun goto timer_out;
1250*4882a593Smuzhiyun }
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun tmpSC->SCp.phase = PH_MSG_IN;
1253*4882a593Smuzhiyun nsp_message_in(tmpSC);
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun /**/
1256*4882a593Smuzhiyun if (*sync_neg == SYNC_NOT_YET) {
1257*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun if (data->MsgLen >= 5 &&
1260*4882a593Smuzhiyun data->MsgBuffer[0] == MSG_EXTENDED &&
1261*4882a593Smuzhiyun data->MsgBuffer[1] == 3 &&
1262*4882a593Smuzhiyun data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1263*4882a593Smuzhiyun data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1264*4882a593Smuzhiyun data->Sync[target].SyncOffset = data->MsgBuffer[4];
1265*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1266*4882a593Smuzhiyun *sync_neg = SYNC_OK;
1267*4882a593Smuzhiyun } else {
1268*4882a593Smuzhiyun data->Sync[target].SyncPeriod = 0;
1269*4882a593Smuzhiyun data->Sync[target].SyncOffset = 0;
1270*4882a593Smuzhiyun *sync_neg = SYNC_NG;
1271*4882a593Smuzhiyun }
1272*4882a593Smuzhiyun nsp_analyze_sdtr(tmpSC);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun /**/
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun /* search last messeage byte */
1277*4882a593Smuzhiyun tmp = -1;
1278*4882a593Smuzhiyun for (i = 0; i < data->MsgLen; i++) {
1279*4882a593Smuzhiyun tmp = data->MsgBuffer[i];
1280*4882a593Smuzhiyun if (data->MsgBuffer[i] == MSG_EXTENDED) {
1281*4882a593Smuzhiyun i += (1 + data->MsgBuffer[i+1]);
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun }
1284*4882a593Smuzhiyun tmpSC->SCp.Message = tmp;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1287*4882a593Smuzhiyun show_message(data);
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun break;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun case BUSPHASE_SELECT:
1292*4882a593Smuzhiyun default:
1293*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun break;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun
1298*4882a593Smuzhiyun //nsp_dbg(NSP_DEBUG_INTR, "out");
1299*4882a593Smuzhiyun return IRQ_HANDLED;
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun timer_out:
1302*4882a593Smuzhiyun nsp_start_timer(tmpSC, 1000/102);
1303*4882a593Smuzhiyun return IRQ_HANDLED;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun #ifdef NSP_DEBUG
1307*4882a593Smuzhiyun #include "nsp_debug.c"
1308*4882a593Smuzhiyun #endif /* NSP_DEBUG */
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /*----------------------------------------------------------------*/
1311*4882a593Smuzhiyun /* look for ninja3 card and init if found */
1312*4882a593Smuzhiyun /*----------------------------------------------------------------*/
nsp_detect(struct scsi_host_template * sht)1313*4882a593Smuzhiyun static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun struct Scsi_Host *host; /* registered host structure */
1316*4882a593Smuzhiyun nsp_hw_data *data_b = &nsp_data_base, *data;
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
1319*4882a593Smuzhiyun host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
1320*4882a593Smuzhiyun if (host == NULL) {
1321*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "host failed");
1322*4882a593Smuzhiyun return NULL;
1323*4882a593Smuzhiyun }
1324*4882a593Smuzhiyun
1325*4882a593Smuzhiyun memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1326*4882a593Smuzhiyun data = (nsp_hw_data *)host->hostdata;
1327*4882a593Smuzhiyun data->ScsiInfo->host = host;
1328*4882a593Smuzhiyun #ifdef NSP_DEBUG
1329*4882a593Smuzhiyun data->CmdId = 0;
1330*4882a593Smuzhiyun #endif
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun host->unique_id = data->BaseAddress;
1335*4882a593Smuzhiyun host->io_port = data->BaseAddress;
1336*4882a593Smuzhiyun host->n_io_port = data->NumAddress;
1337*4882a593Smuzhiyun host->irq = data->IrqNumber;
1338*4882a593Smuzhiyun host->base = data->MmioAddress;
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun spin_lock_init(&(data->Lock));
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun snprintf(data->nspinfo,
1343*4882a593Smuzhiyun sizeof(data->nspinfo),
1344*4882a593Smuzhiyun "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1345*4882a593Smuzhiyun host->io_port, host->io_port + host->n_io_port - 1,
1346*4882a593Smuzhiyun host->base,
1347*4882a593Smuzhiyun host->irq);
1348*4882a593Smuzhiyun sht->name = data->nspinfo;
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "end");
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun return host; /* detect done. */
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun /*----------------------------------------------------------------*/
1357*4882a593Smuzhiyun /* return info string */
1358*4882a593Smuzhiyun /*----------------------------------------------------------------*/
nsp_info(struct Scsi_Host * shpnt)1359*4882a593Smuzhiyun static const char *nsp_info(struct Scsi_Host *shpnt)
1360*4882a593Smuzhiyun {
1361*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun return data->nspinfo;
1364*4882a593Smuzhiyun }
1365*4882a593Smuzhiyun
nsp_show_info(struct seq_file * m,struct Scsi_Host * host)1366*4882a593Smuzhiyun static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
1367*4882a593Smuzhiyun {
1368*4882a593Smuzhiyun int id;
1369*4882a593Smuzhiyun int speed;
1370*4882a593Smuzhiyun unsigned long flags;
1371*4882a593Smuzhiyun nsp_hw_data *data;
1372*4882a593Smuzhiyun int hostno;
1373*4882a593Smuzhiyun
1374*4882a593Smuzhiyun hostno = host->host_no;
1375*4882a593Smuzhiyun data = (nsp_hw_data *)host->hostdata;
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun seq_puts(m, "NinjaSCSI status\n\n"
1378*4882a593Smuzhiyun "Driver version: $Revision: 1.23 $\n");
1379*4882a593Smuzhiyun seq_printf(m, "SCSI host No.: %d\n", hostno);
1380*4882a593Smuzhiyun seq_printf(m, "IRQ: %d\n", host->irq);
1381*4882a593Smuzhiyun seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1382*4882a593Smuzhiyun seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1383*4882a593Smuzhiyun seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize);
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun seq_puts(m, "burst transfer mode: ");
1386*4882a593Smuzhiyun switch (nsp_burst_mode) {
1387*4882a593Smuzhiyun case BURST_IO8:
1388*4882a593Smuzhiyun seq_puts(m, "io8");
1389*4882a593Smuzhiyun break;
1390*4882a593Smuzhiyun case BURST_IO32:
1391*4882a593Smuzhiyun seq_puts(m, "io32");
1392*4882a593Smuzhiyun break;
1393*4882a593Smuzhiyun case BURST_MEM32:
1394*4882a593Smuzhiyun seq_puts(m, "mem32");
1395*4882a593Smuzhiyun break;
1396*4882a593Smuzhiyun default:
1397*4882a593Smuzhiyun seq_puts(m, "???");
1398*4882a593Smuzhiyun break;
1399*4882a593Smuzhiyun }
1400*4882a593Smuzhiyun seq_putc(m, '\n');
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun spin_lock_irqsave(&(data->Lock), flags);
1404*4882a593Smuzhiyun seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC);
1405*4882a593Smuzhiyun spin_unlock_irqrestore(&(data->Lock), flags);
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun seq_puts(m, "SDTR status\n");
1408*4882a593Smuzhiyun for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun seq_printf(m, "id %d: ", id);
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun if (id == host->this_id) {
1413*4882a593Smuzhiyun seq_puts(m, "----- NinjaSCSI-3 host adapter\n");
1414*4882a593Smuzhiyun continue;
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun switch(data->Sync[id].SyncNegotiation) {
1418*4882a593Smuzhiyun case SYNC_OK:
1419*4882a593Smuzhiyun seq_puts(m, " sync");
1420*4882a593Smuzhiyun break;
1421*4882a593Smuzhiyun case SYNC_NG:
1422*4882a593Smuzhiyun seq_puts(m, "async");
1423*4882a593Smuzhiyun break;
1424*4882a593Smuzhiyun case SYNC_NOT_YET:
1425*4882a593Smuzhiyun seq_puts(m, " none");
1426*4882a593Smuzhiyun break;
1427*4882a593Smuzhiyun default:
1428*4882a593Smuzhiyun seq_puts(m, "?????");
1429*4882a593Smuzhiyun break;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun if (data->Sync[id].SyncPeriod != 0) {
1433*4882a593Smuzhiyun speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun seq_printf(m, " transfer %d.%dMB/s, offset %d",
1436*4882a593Smuzhiyun speed / 1000,
1437*4882a593Smuzhiyun speed % 1000,
1438*4882a593Smuzhiyun data->Sync[id].SyncOffset
1439*4882a593Smuzhiyun );
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun seq_putc(m, '\n');
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun return 0;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun /*---------------------------------------------------------------*/
1447*4882a593Smuzhiyun /* error handler */
1448*4882a593Smuzhiyun /*---------------------------------------------------------------*/
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun /*
1451*4882a593Smuzhiyun static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun return nsp_eh_bus_reset(SCpnt);
1456*4882a593Smuzhiyun }*/
1457*4882a593Smuzhiyun
nsp_bus_reset(nsp_hw_data * data)1458*4882a593Smuzhiyun static int nsp_bus_reset(nsp_hw_data *data)
1459*4882a593Smuzhiyun {
1460*4882a593Smuzhiyun unsigned int base = data->BaseAddress;
1461*4882a593Smuzhiyun int i;
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1466*4882a593Smuzhiyun mdelay(100); /* 100ms */
1467*4882a593Smuzhiyun nsp_index_write(base, SCSIBUSCTRL, 0);
1468*4882a593Smuzhiyun for(i = 0; i < 5; i++) {
1469*4882a593Smuzhiyun nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1470*4882a593Smuzhiyun }
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun nsphw_init_sync(data);
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun return SUCCESS;
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun
nsp_eh_bus_reset(struct scsi_cmnd * SCpnt)1479*4882a593Smuzhiyun static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
1480*4882a593Smuzhiyun {
1481*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun return nsp_bus_reset(data);
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun
nsp_eh_host_reset(struct scsi_cmnd * SCpnt)1488*4882a593Smuzhiyun static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun nsphw_init(data);
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun return SUCCESS;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun /**********************************************************************
1501*4882a593Smuzhiyun PCMCIA functions
1502*4882a593Smuzhiyun **********************************************************************/
1503*4882a593Smuzhiyun
nsp_cs_probe(struct pcmcia_device * link)1504*4882a593Smuzhiyun static int nsp_cs_probe(struct pcmcia_device *link)
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun scsi_info_t *info;
1507*4882a593Smuzhiyun nsp_hw_data *data = &nsp_data_base;
1508*4882a593Smuzhiyun int ret;
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "in");
1511*4882a593Smuzhiyun
1512*4882a593Smuzhiyun /* Create new SCSI device */
1513*4882a593Smuzhiyun info = kzalloc(sizeof(*info), GFP_KERNEL);
1514*4882a593Smuzhiyun if (info == NULL) { return -ENOMEM; }
1515*4882a593Smuzhiyun info->p_dev = link;
1516*4882a593Smuzhiyun link->priv = info;
1517*4882a593Smuzhiyun data->ScsiInfo = info;
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun ret = nsp_cs_config(link);
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1524*4882a593Smuzhiyun return ret;
1525*4882a593Smuzhiyun } /* nsp_cs_attach */
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun
nsp_cs_detach(struct pcmcia_device * link)1528*4882a593Smuzhiyun static void nsp_cs_detach(struct pcmcia_device *link)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun ((scsi_info_t *)link->priv)->stop = 1;
1533*4882a593Smuzhiyun nsp_cs_release(link);
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun kfree(link->priv);
1536*4882a593Smuzhiyun link->priv = NULL;
1537*4882a593Smuzhiyun } /* nsp_cs_detach */
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun
nsp_cs_config_check(struct pcmcia_device * p_dev,void * priv_data)1540*4882a593Smuzhiyun static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
1541*4882a593Smuzhiyun {
1542*4882a593Smuzhiyun nsp_hw_data *data = priv_data;
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun if (p_dev->config_index == 0)
1545*4882a593Smuzhiyun return -ENODEV;
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun /* This reserves IO space but doesn't actually enable it */
1548*4882a593Smuzhiyun if (pcmcia_request_io(p_dev) != 0)
1549*4882a593Smuzhiyun goto next_entry;
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun if (resource_size(p_dev->resource[2])) {
1552*4882a593Smuzhiyun p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1553*4882a593Smuzhiyun WIN_MEMORY_TYPE_CM |
1554*4882a593Smuzhiyun WIN_ENABLE);
1555*4882a593Smuzhiyun if (p_dev->resource[2]->end < 0x1000)
1556*4882a593Smuzhiyun p_dev->resource[2]->end = 0x1000;
1557*4882a593Smuzhiyun if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
1558*4882a593Smuzhiyun goto next_entry;
1559*4882a593Smuzhiyun if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
1560*4882a593Smuzhiyun p_dev->card_addr) != 0)
1561*4882a593Smuzhiyun goto next_entry;
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun data->MmioAddress = (unsigned long)
1564*4882a593Smuzhiyun ioremap(p_dev->resource[2]->start,
1565*4882a593Smuzhiyun resource_size(p_dev->resource[2]));
1566*4882a593Smuzhiyun data->MmioLength = resource_size(p_dev->resource[2]);
1567*4882a593Smuzhiyun }
1568*4882a593Smuzhiyun /* If we got this far, we're cool! */
1569*4882a593Smuzhiyun return 0;
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun next_entry:
1572*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "next");
1573*4882a593Smuzhiyun pcmcia_disable_device(p_dev);
1574*4882a593Smuzhiyun return -ENODEV;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun
nsp_cs_config(struct pcmcia_device * link)1577*4882a593Smuzhiyun static int nsp_cs_config(struct pcmcia_device *link)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun int ret;
1580*4882a593Smuzhiyun scsi_info_t *info = link->priv;
1581*4882a593Smuzhiyun struct Scsi_Host *host;
1582*4882a593Smuzhiyun nsp_hw_data *data = &nsp_data_base;
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "in");
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
1587*4882a593Smuzhiyun CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM |
1588*4882a593Smuzhiyun CONF_AUTO_SET_IO;
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
1591*4882a593Smuzhiyun if (ret)
1592*4882a593Smuzhiyun goto cs_failed;
1593*4882a593Smuzhiyun
1594*4882a593Smuzhiyun if (pcmcia_request_irq(link, nspintr))
1595*4882a593Smuzhiyun goto cs_failed;
1596*4882a593Smuzhiyun
1597*4882a593Smuzhiyun ret = pcmcia_enable_device(link);
1598*4882a593Smuzhiyun if (ret)
1599*4882a593Smuzhiyun goto cs_failed;
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun if (free_ports) {
1602*4882a593Smuzhiyun if (link->resource[0]) {
1603*4882a593Smuzhiyun release_region(link->resource[0]->start,
1604*4882a593Smuzhiyun resource_size(link->resource[0]));
1605*4882a593Smuzhiyun }
1606*4882a593Smuzhiyun if (link->resource[1]) {
1607*4882a593Smuzhiyun release_region(link->resource[1]->start,
1608*4882a593Smuzhiyun resource_size(link->resource[1]));
1609*4882a593Smuzhiyun }
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun /* Set port and IRQ */
1613*4882a593Smuzhiyun data->BaseAddress = link->resource[0]->start;
1614*4882a593Smuzhiyun data->NumAddress = resource_size(link->resource[0]);
1615*4882a593Smuzhiyun data->IrqNumber = link->irq;
1616*4882a593Smuzhiyun
1617*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1618*4882a593Smuzhiyun data->BaseAddress, data->NumAddress, data->IrqNumber);
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun if(nsphw_init(data) == FALSE) {
1621*4882a593Smuzhiyun goto cs_failed;
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun
1624*4882a593Smuzhiyun host = nsp_detect(&nsp_driver_template);
1625*4882a593Smuzhiyun
1626*4882a593Smuzhiyun if (host == NULL) {
1627*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1628*4882a593Smuzhiyun goto cs_failed;
1629*4882a593Smuzhiyun }
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun
1632*4882a593Smuzhiyun ret = scsi_add_host (host, NULL);
1633*4882a593Smuzhiyun if (ret)
1634*4882a593Smuzhiyun goto cs_failed;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun scsi_scan_host(host);
1637*4882a593Smuzhiyun
1638*4882a593Smuzhiyun info->host = host;
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun return 0;
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun cs_failed:
1643*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "config fail");
1644*4882a593Smuzhiyun nsp_cs_release(link);
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun return -ENODEV;
1647*4882a593Smuzhiyun } /* nsp_cs_config */
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun
nsp_cs_release(struct pcmcia_device * link)1650*4882a593Smuzhiyun static void nsp_cs_release(struct pcmcia_device *link)
1651*4882a593Smuzhiyun {
1652*4882a593Smuzhiyun scsi_info_t *info = link->priv;
1653*4882a593Smuzhiyun nsp_hw_data *data = NULL;
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun if (info->host == NULL) {
1656*4882a593Smuzhiyun nsp_msg(KERN_DEBUG, "unexpected card release call.");
1657*4882a593Smuzhiyun } else {
1658*4882a593Smuzhiyun data = (nsp_hw_data *)info->host->hostdata;
1659*4882a593Smuzhiyun }
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1662*4882a593Smuzhiyun
1663*4882a593Smuzhiyun /* Unlink the device chain */
1664*4882a593Smuzhiyun if (info->host != NULL) {
1665*4882a593Smuzhiyun scsi_remove_host(info->host);
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun if (resource_size(link->resource[2])) {
1669*4882a593Smuzhiyun if (data != NULL) {
1670*4882a593Smuzhiyun iounmap((void *)(data->MmioAddress));
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun }
1673*4882a593Smuzhiyun pcmcia_disable_device(link);
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyun if (info->host != NULL) {
1676*4882a593Smuzhiyun scsi_host_put(info->host);
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun } /* nsp_cs_release */
1679*4882a593Smuzhiyun
nsp_cs_suspend(struct pcmcia_device * link)1680*4882a593Smuzhiyun static int nsp_cs_suspend(struct pcmcia_device *link)
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun scsi_info_t *info = link->priv;
1683*4882a593Smuzhiyun nsp_hw_data *data;
1684*4882a593Smuzhiyun
1685*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun if (info->host != NULL) {
1688*4882a593Smuzhiyun nsp_msg(KERN_INFO, "clear SDTR status");
1689*4882a593Smuzhiyun
1690*4882a593Smuzhiyun data = (nsp_hw_data *)info->host->hostdata;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun nsphw_init_sync(data);
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun info->stop = 1;
1696*4882a593Smuzhiyun
1697*4882a593Smuzhiyun return 0;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun
nsp_cs_resume(struct pcmcia_device * link)1700*4882a593Smuzhiyun static int nsp_cs_resume(struct pcmcia_device *link)
1701*4882a593Smuzhiyun {
1702*4882a593Smuzhiyun scsi_info_t *info = link->priv;
1703*4882a593Smuzhiyun nsp_hw_data *data;
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1706*4882a593Smuzhiyun
1707*4882a593Smuzhiyun info->stop = 0;
1708*4882a593Smuzhiyun
1709*4882a593Smuzhiyun if (info->host != NULL) {
1710*4882a593Smuzhiyun nsp_msg(KERN_INFO, "reset host and bus");
1711*4882a593Smuzhiyun
1712*4882a593Smuzhiyun data = (nsp_hw_data *)info->host->hostdata;
1713*4882a593Smuzhiyun
1714*4882a593Smuzhiyun nsphw_init (data);
1715*4882a593Smuzhiyun nsp_bus_reset(data);
1716*4882a593Smuzhiyun }
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun return 0;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun /*======================================================================*
1722*4882a593Smuzhiyun * module entry point
1723*4882a593Smuzhiyun *====================================================================*/
1724*4882a593Smuzhiyun static const struct pcmcia_device_id nsp_cs_ids[] = {
1725*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1726*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1727*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1728*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1729*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1730*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1731*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1732*4882a593Smuzhiyun PCMCIA_DEVICE_NULL
1733*4882a593Smuzhiyun };
1734*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1735*4882a593Smuzhiyun
1736*4882a593Smuzhiyun static struct pcmcia_driver nsp_driver = {
1737*4882a593Smuzhiyun .owner = THIS_MODULE,
1738*4882a593Smuzhiyun .name = "nsp_cs",
1739*4882a593Smuzhiyun .probe = nsp_cs_probe,
1740*4882a593Smuzhiyun .remove = nsp_cs_detach,
1741*4882a593Smuzhiyun .id_table = nsp_cs_ids,
1742*4882a593Smuzhiyun .suspend = nsp_cs_suspend,
1743*4882a593Smuzhiyun .resume = nsp_cs_resume,
1744*4882a593Smuzhiyun };
1745*4882a593Smuzhiyun module_pcmcia_driver(nsp_driver);
1746*4882a593Smuzhiyun
1747*4882a593Smuzhiyun /* end */
1748