blob: 344d49900b4c4e6eddefa2c15c1cf988606d9229 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
4 By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
5
6 Ver.2.8 Support 32bit MMIO mode
7 Support Synchronous Data Transfer Request (SDTR) mode
8 Ver.2.0 Support 32bit PIO mode
9 Ver.1.1.2 Fix for scatter list buffer exceeds
10 Ver.1.1 Support scatter list
11 Ver.0.1 Initial version
12
13 This software may be used and distributed according to the terms of
14 the GNU General Public License.
15
16======================================================================*/
17
18/***********************************************************************
19 This driver is for these PCcards.
20
21 I-O DATA PCSC-F (Workbit NinjaSCSI-3)
22 "WBT", "NinjaSCSI-3", "R1.0"
23 I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
24 "IO DATA", "CBSC16 ", "1"
25
26***********************************************************************/
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/timer.h>
34#include <linux/ioport.h>
35#include <linux/delay.h>
36#include <linux/interrupt.h>
37#include <linux/major.h>
38#include <linux/blkdev.h>
39#include <linux/stat.h>
40
41#include <asm/io.h>
42#include <asm/irq.h>
43
44#include <../drivers/scsi/scsi.h>
45#include <scsi/scsi_host.h>
46
47#include <scsi/scsi.h>
48#include <scsi/scsi_ioctl.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <pcmcia/cistpl.h>
51#include <pcmcia/cisreg.h>
52#include <pcmcia/ds.h>
53
54#include "nsp_cs.h"
55
56MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
Adrian Bunk774251e2007-10-02 14:38:01 -070057MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
Linus Torvalds1da177e2005-04-16 15:20:36 -070058MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
59#ifdef MODULE_LICENSE
60MODULE_LICENSE("GPL");
61#endif
62
63#include "nsp_io.h"
64
65/*====================================================================*/
66/* Parameters that can be set with 'insmod' */
67
68static int nsp_burst_mode = BURST_MEM32;
69module_param(nsp_burst_mode, int, 0);
70MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
71
72/* Release IO ports after configuration? */
73static int free_ports = 0;
74module_param(free_ports, bool, 0);
75MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
76
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010077static struct scsi_host_template nsp_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 .proc_name = "nsp_cs",
79 .proc_info = nsp_proc_info,
80 .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 .info = nsp_info,
82 .queuecommand = nsp_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -070083/* .eh_abort_handler = nsp_eh_abort,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 .eh_bus_reset_handler = nsp_eh_bus_reset,
85 .eh_host_reset_handler = nsp_eh_host_reset,
86 .can_queue = 1,
87 .this_id = NSP_INITIATOR_ID,
88 .sg_tablesize = SG_ALL,
89 .cmd_per_lun = 1,
90 .use_clustering = DISABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -070091};
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
94
95
96
97/*
98 * debug, error print
99 */
100#ifndef NSP_DEBUG
101# define NSP_DEBUG_MASK 0x000000
102# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
103# define nsp_dbg(mask, args...) /* */
104#else
105# define NSP_DEBUG_MASK 0xffffff
106# define nsp_msg(type, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700107 nsp_cs_message (__func__, __LINE__, (type), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108# define nsp_dbg(mask, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700109 nsp_cs_dmessage(__func__, __LINE__, (mask), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#endif
111
112#define NSP_DEBUG_QUEUECOMMAND BIT(0)
113#define NSP_DEBUG_REGISTER BIT(1)
114#define NSP_DEBUG_AUTOSCSI BIT(2)
115#define NSP_DEBUG_INTR BIT(3)
116#define NSP_DEBUG_SGLIST BIT(4)
117#define NSP_DEBUG_BUSFREE BIT(5)
118#define NSP_DEBUG_CDB_CONTENTS BIT(6)
119#define NSP_DEBUG_RESELECTION BIT(7)
120#define NSP_DEBUG_MSGINOCCUR BIT(8)
121#define NSP_DEBUG_EEPROM BIT(9)
122#define NSP_DEBUG_MSGOUTOCCUR BIT(10)
123#define NSP_DEBUG_BUSRESET BIT(11)
124#define NSP_DEBUG_RESTART BIT(12)
125#define NSP_DEBUG_SYNC BIT(13)
126#define NSP_DEBUG_WAIT BIT(14)
127#define NSP_DEBUG_TARGETFLAG BIT(15)
128#define NSP_DEBUG_PROC BIT(16)
129#define NSP_DEBUG_INIT BIT(17)
130#define NSP_DEBUG_DATA_IO BIT(18)
131#define NSP_SPECIAL_PRINT_REGISTER BIT(20)
132
133#define NSP_DEBUG_BUF_LEN 150
134
Boaz Harrosh040cd232007-08-16 13:01:05 +0300135static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
136{
137 scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
138}
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
141{
142 va_list args;
143 char buf[NSP_DEBUG_BUF_LEN];
144
145 va_start(args, fmt);
146 vsnprintf(buf, sizeof(buf), fmt, args);
147 va_end(args);
148
149#ifndef NSP_DEBUG
150 printk("%snsp_cs: %s\n", type, buf);
151#else
152 printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
153#endif
154}
155
156#ifdef NSP_DEBUG
157static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
158{
159 va_list args;
160 char buf[NSP_DEBUG_BUF_LEN];
161
162 va_start(args, fmt);
163 vsnprintf(buf, sizeof(buf), fmt, args);
164 va_end(args);
165
166 if (mask & NSP_DEBUG_MASK) {
167 printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
168 }
169}
170#endif
171
172/***********************************************************/
173
174/*====================================================
175 * Clenaup parameters and call done() functions.
176 * You must be set SCpnt->result before call this function.
177 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700178static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179{
180 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
181
182 data->CurrentSC = NULL;
183
184 SCpnt->scsi_done(SCpnt);
185}
186
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700187static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
188 void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
190#ifdef NSP_DEBUG
191 /*unsigned int host_id = SCpnt->device->host->this_id;*/
192 /*unsigned int base = SCpnt->device->host->io_port;*/
Jeff Garzik422c0d62005-10-24 18:05:09 -0400193 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194#endif
195 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
196
Boaz Harrosh040cd232007-08-16 13:01:05 +0300197 nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
198 "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
199 SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
200 scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
202
203 SCpnt->scsi_done = done;
204
205 if (data->CurrentSC != NULL) {
206 nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
207 SCpnt->result = DID_BAD_TARGET << 16;
208 nsp_scsi_done(SCpnt);
209 return 0;
210 }
211
212#if 0
213 /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
214 This makes kernel crash when suspending... */
215 if (data->ScsiInfo->stop != 0) {
216 nsp_msg(KERN_INFO, "suspending device. reject command.");
217 SCpnt->result = DID_BAD_TARGET << 16;
218 nsp_scsi_done(SCpnt);
219 return SCSI_MLQUEUE_HOST_BUSY;
220 }
221#endif
222
223 show_command(SCpnt);
224
225 data->CurrentSC = SCpnt;
226
227 SCpnt->SCp.Status = CHECK_CONDITION;
228 SCpnt->SCp.Message = 0;
229 SCpnt->SCp.have_data_in = IO_UNKNOWN;
230 SCpnt->SCp.sent_command = 0;
231 SCpnt->SCp.phase = PH_UNDETERMINED;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300232 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 /* setup scratch area
235 SCp.ptr : buffer pointer
236 SCp.this_residual : buffer length
237 SCp.buffer : next buffer
238 SCp.buffers_residual : left buffers in list
239 SCp.phase : current state of the command */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300240 if (scsi_bufflen(SCpnt)) {
241 SCpnt->SCp.buffer = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 SCpnt->SCp.ptr = BUFFER_ADDR;
243 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300244 SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 } else {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300246 SCpnt->SCp.ptr = NULL;
247 SCpnt->SCp.this_residual = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 SCpnt->SCp.buffer = NULL;
249 SCpnt->SCp.buffers_residual = 0;
250 }
251
252 if (nsphw_start_selection(SCpnt) == FALSE) {
253 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
254 SCpnt->result = DID_BUS_BUSY << 16;
255 nsp_scsi_done(SCpnt);
256 return 0;
257 }
258
259
260 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
261#ifdef NSP_DEBUG
262 data->CmdId++;
263#endif
264 return 0;
265}
266
267/*
268 * setup PIO FIFO transfer mode and enable/disable to data out
269 */
270static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
271{
272 unsigned int base = data->BaseAddress;
273 unsigned char transfer_mode_reg;
274
275 //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
276
277 if (enabled != FALSE) {
278 transfer_mode_reg = TRANSFER_GO | BRAIND;
279 } else {
280 transfer_mode_reg = 0;
281 }
282
283 transfer_mode_reg |= data->TransferMode;
284
285 nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
286}
287
288static void nsphw_init_sync(nsp_hw_data *data)
289{
290 sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
291 .SyncPeriod = 0,
292 .SyncOffset = 0
293 };
294 int i;
295
296 /* setup sync data */
297 for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
298 data->Sync[i] = tmp_sync;
299 }
300}
301
302/*
303 * Initialize Ninja hardware
304 */
305static int nsphw_init(nsp_hw_data *data)
306{
307 unsigned int base = data->BaseAddress;
308
309 nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
310
311 data->ScsiClockDiv = CLOCK_40M | FAST_20;
312 data->CurrentSC = NULL;
313 data->FifoCount = 0;
314 data->TransferMode = MODE_IO8;
315
316 nsphw_init_sync(data);
317
318 /* block all interrupts */
319 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
320
321 /* setup SCSI interface */
322 nsp_write(base, IFSELECT, IF_IFSEL);
323
324 nsp_index_write(base, SCSIIRQMODE, 0);
325
326 nsp_index_write(base, TRANSFERMODE, MODE_IO8);
327 nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
328
329 nsp_index_write(base, PARITYCTRL, 0);
330 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
331 ACK_COUNTER_CLEAR |
332 REQ_COUNTER_CLEAR |
333 HOST_COUNTER_CLEAR);
334
335 /* setup fifo asic */
336 nsp_write(base, IFSELECT, IF_REGSEL);
337 nsp_index_write(base, TERMPWRCTRL, 0);
338 if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
339 nsp_msg(KERN_INFO, "terminator power on");
340 nsp_index_write(base, TERMPWRCTRL, POWER_ON);
341 }
342
343 nsp_index_write(base, TIMERCOUNT, 0);
344 nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
345
346 nsp_index_write(base, SYNCREG, 0);
347 nsp_index_write(base, ACKWIDTH, 0);
348
349 /* enable interrupts and ack them */
350 nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
351 RESELECT_EI |
352 SCSI_RESET_IRQ_EI );
353 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
354
355 nsp_setup_fifo(data, FALSE);
356
357 return TRUE;
358}
359
360/*
361 * Start selection phase
362 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700363static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365 unsigned int host_id = SCpnt->device->host->this_id;
366 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400367 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
369 int time_out;
370 unsigned char phase, arbit;
371
372 //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
373
374 phase = nsp_index_read(base, SCSIBUSMON);
375 if(phase != BUSMON_BUS_FREE) {
376 //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
377 return FALSE;
378 }
379
380 /* start arbitration */
381 //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
382 SCpnt->SCp.phase = PH_ARBSTART;
383 nsp_index_write(base, SETARBIT, ARBIT_GO);
384
385 time_out = 1000;
386 do {
387 /* XXX: what a stupid chip! */
388 arbit = nsp_index_read(base, ARBITSTATUS);
389 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
390 udelay(1); /* hold 1.2us */
391 } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
392 (time_out-- != 0));
393
394 if (!(arbit & ARBIT_WIN)) {
395 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
396 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
397 return FALSE;
398 }
399
400 /* assert select line */
401 //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
402 SCpnt->SCp.phase = PH_SELSTART;
403 udelay(3); /* wait 2.4us */
404 nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
405 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
406 udelay(2); /* wait >1.2us */
407 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
408 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
409 /*udelay(1);*/ /* wait >90ns */
410 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
411
412 /* check selection timeout */
413 nsp_start_timer(SCpnt, 1000/51);
414 data->SelectionTimeOut = 1;
415
416 return TRUE;
417}
418
419struct nsp_sync_table {
420 unsigned int min_period;
421 unsigned int max_period;
422 unsigned int chip_period;
423 unsigned int ack_width;
424};
425
426static struct nsp_sync_table nsp_sync_table_40M[] = {
427 {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
428 {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
429 {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
430 {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
431 { 0, 0, 0, 0},
432};
433
434static struct nsp_sync_table nsp_sync_table_20M[] = {
435 {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
436 {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
437 {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
438 { 0, 0, 0, 0},
439};
440
441/*
442 * setup synchronous data transfer mode
443 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700444static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Jeff Garzik422c0d62005-10-24 18:05:09 -0400446 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447// unsigned char lun = SCpnt->device->lun;
448 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
449 sync_data *sync = &(data->Sync[target]);
450 struct nsp_sync_table *sync_table;
451 unsigned int period, offset;
452 int i;
453
454
455 nsp_dbg(NSP_DEBUG_SYNC, "in");
456
457 period = sync->SyncPeriod;
458 offset = sync->SyncOffset;
459
460 nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
461
462 if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
463 sync_table = nsp_sync_table_20M;
464 } else {
465 sync_table = nsp_sync_table_40M;
466 }
467
468 for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
469 if ( period >= sync_table->min_period &&
470 period <= sync_table->max_period ) {
471 break;
472 }
473 }
474
475 if (period != 0 && sync_table->max_period == 0) {
476 /*
477 * No proper period/offset found
478 */
479 nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
480
481 sync->SyncPeriod = 0;
482 sync->SyncOffset = 0;
483 sync->SyncRegister = 0;
484 sync->AckWidth = 0;
485
486 return FALSE;
487 }
488
489 sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
490 (offset & SYNCREG_OFFSET_MASK);
491 sync->AckWidth = sync_table->ack_width;
492
493 nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
494
495 return TRUE;
496}
497
498
499/*
500 * start ninja hardware timer
501 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700502static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 unsigned int base = SCpnt->device->host->io_port;
505 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
506
507 //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
508 data->TimerCount = time;
509 nsp_index_write(base, TIMERCOUNT, time);
510}
511
512/*
513 * wait for bus phase change
514 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700515static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
516 char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 unsigned int base = SCpnt->device->host->io_port;
519 unsigned char reg;
520 int time_out;
521
522 //nsp_dbg(NSP_DEBUG_INTR, "in");
523
524 time_out = 100;
525
526 do {
527 reg = nsp_index_read(base, SCSIBUSMON);
528 if (reg == 0xff) {
529 break;
530 }
Roel Kluin0454c742009-06-10 12:56:59 -0700531 } while ((--time_out != 0) && (reg & mask) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 if (time_out == 0) {
534 nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
535 }
536
537 return 0;
538}
539
540/*
541 * expect Ninja Irq
542 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700543static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
544 unsigned char current_phase,
545 unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 unsigned int base = SCpnt->device->host->io_port;
548 int time_out;
549 unsigned char phase, i_src;
550
551 //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
552
553 time_out = 100;
554 do {
555 phase = nsp_index_read(base, SCSIBUSMON);
556 if (phase == 0xff) {
557 //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
558 return -1;
559 }
560 i_src = nsp_read(base, IRQSTATUS);
561 if (i_src & IRQSTATUS_SCSI) {
562 //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
563 return 0;
564 }
565 if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
566 //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
567 return 1;
568 }
569 } while(time_out-- != 0);
570
571 //nsp_dbg(NSP_DEBUG_INTR, "timeout");
572 return -1;
573}
574
575/*
576 * transfer SCSI message
577 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700578static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579{
580 unsigned int base = SCpnt->device->host->io_port;
581 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
582 char *buf = data->MsgBuffer;
583 int len = min(MSGBUF_SIZE, data->MsgLen);
584 int ptr;
585 int ret;
586
587 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
588 for (ptr = 0; len > 0; len--, ptr++) {
589
590 ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
591 if (ret <= 0) {
592 nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
593 return 0;
594 }
595
596 /* if last byte, negate ATN */
597 if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
598 nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
599 }
600
601 /* read & write message */
602 if (phase & BUSMON_IO) {
603 nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
604 buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
605 } else {
606 nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
607 nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
608 }
609 nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
610
611 }
612 return len;
613}
614
615/*
616 * get extra SCSI data from fifo
617 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700618static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
620 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
621 unsigned int count;
622
623 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
624
625 if (SCpnt->SCp.have_data_in != IO_IN) {
626 return 0;
627 }
628
629 count = nsp_fifo_count(SCpnt);
630 if (data->FifoCount == count) {
631 //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
632 return 0;
633 }
634
635 /*
636 * XXX: NSP_QUIRK
637 * data phase skip only occures in case of SCSI_LOW_READ
638 */
639 nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
640 SCpnt->SCp.phase = PH_DATA;
641 nsp_pio_read(SCpnt);
642 nsp_setup_fifo(data, FALSE);
643
644 return 0;
645}
646
647/*
648 * accept reselection
649 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700650static int nsp_reselected(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651{
652 unsigned int base = SCpnt->device->host->io_port;
653 unsigned int host_id = SCpnt->device->host->this_id;
654 //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
655 unsigned char bus_reg;
656 unsigned char id_reg, tmp;
657 int target;
658
659 nsp_dbg(NSP_DEBUG_RESELECTION, "in");
660
661 id_reg = nsp_index_read(base, RESELECTID);
662 tmp = id_reg & (~BIT(host_id));
663 target = 0;
664 while(tmp != 0) {
665 if (tmp & BIT(0)) {
666 break;
667 }
668 tmp >>= 1;
669 target++;
670 }
671
Jeff Garzik422c0d62005-10-24 18:05:09 -0400672 if (scmd_id(SCpnt) != target) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
674 }
675
676 nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
677
678 nsp_nexus(SCpnt);
679 bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
680 nsp_index_write(base, SCSIBUSCTRL, bus_reg);
681 nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
682
683 return TRUE;
684}
685
686/*
687 * count how many data transferd
688 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700689static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 unsigned int base = SCpnt->device->host->io_port;
692 unsigned int count;
693 unsigned int l, m, h, dummy;
694
695 nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
696
697 l = nsp_index_read(base, TRANSFERCOUNT);
698 m = nsp_index_read(base, TRANSFERCOUNT);
699 h = nsp_index_read(base, TRANSFERCOUNT);
700 dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
701
702 count = (h << 16) | (m << 8) | (l << 0);
703
704 //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
705
706 return count;
707}
708
709/* fifo size */
710#define RFIFO_CRIT 64
711#define WFIFO_CRIT 64
712
713/*
714 * read data in DATA IN phase
715 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700716static void nsp_pio_read(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 unsigned int base = SCpnt->device->host->io_port;
719 unsigned long mmio_base = SCpnt->device->host->base;
720 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
721 long time_out;
722 int ocount, res;
723 unsigned char stat, fifo_stat;
724
725 ocount = data->FifoCount;
726
727 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",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300728 SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
729 SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
730 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 time_out = 1000;
733
734 while ((time_out-- != 0) &&
735 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
736
737 stat = nsp_index_read(base, SCSIBUSMON);
738 stat &= BUSMON_PHASE_MASK;
739
740
741 res = nsp_fifo_count(SCpnt) - ocount;
742 //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 if (res == 0) { /* if some data avilable ? */
744 if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
745 //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
746 continue;
747 } else {
748 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
749 break;
750 }
751 }
752
753 fifo_stat = nsp_read(base, FIFOSTATUS);
754 if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
755 stat == BUSPHASE_DATA_IN) {
756 continue;
757 }
758
759 res = min(res, SCpnt->SCp.this_residual);
760
761 switch (data->TransferMode) {
762 case MODE_IO32:
763 res &= ~(BIT(1)|BIT(0)); /* align 4 */
764 nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
765 break;
766 case MODE_IO8:
767 nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
768 break;
769
770 case MODE_MEM32:
771 res &= ~(BIT(1)|BIT(0)); /* align 4 */
772 nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
773 break;
774
775 default:
776 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
777 return;
778 }
779
Boaz Harrosh040cd232007-08-16 13:01:05 +0300780 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 SCpnt->SCp.ptr += res;
782 SCpnt->SCp.this_residual -= res;
783 ocount += res;
784 //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
786 /* go to next scatter list if available */
787 if (SCpnt->SCp.this_residual == 0 &&
788 SCpnt->SCp.buffers_residual != 0 ) {
789 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
790 SCpnt->SCp.buffers_residual--;
791 SCpnt->SCp.buffer++;
792 SCpnt->SCp.ptr = BUFFER_ADDR;
793 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
794 time_out = 1000;
795
796 //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
797 }
798 }
799
800 data->FifoCount = ocount;
801
Roel Kluin0454c742009-06-10 12:56:59 -0700802 if (time_out < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300804 scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
805 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807 nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300808 nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
809 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
812/*
813 * write data in DATA OUT phase
814 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700815static void nsp_pio_write(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
817 unsigned int base = SCpnt->device->host->io_port;
818 unsigned long mmio_base = SCpnt->device->host->base;
819 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
820 int time_out;
821 int ocount, res;
822 unsigned char stat;
823
824 ocount = data->FifoCount;
825
826 nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300827 data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
828 SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
829 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 time_out = 1000;
832
833 while ((time_out-- != 0) &&
834 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
835 stat = nsp_index_read(base, SCSIBUSMON);
836 stat &= BUSMON_PHASE_MASK;
837
838 if (stat != BUSPHASE_DATA_OUT) {
839 res = ocount - nsp_fifo_count(SCpnt);
840
841 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
842 /* Put back pointer */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300843 nsp_inc_resid(SCpnt, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 SCpnt->SCp.ptr -= res;
845 SCpnt->SCp.this_residual += res;
846 ocount -= res;
847
848 break;
849 }
850
851 res = ocount - nsp_fifo_count(SCpnt);
852 if (res > 0) { /* write all data? */
853 nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
854 continue;
855 }
856
857 res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
858
859 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
860 switch (data->TransferMode) {
861 case MODE_IO32:
862 res &= ~(BIT(1)|BIT(0)); /* align 4 */
863 nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
864 break;
865 case MODE_IO8:
866 nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
867 break;
868
869 case MODE_MEM32:
870 res &= ~(BIT(1)|BIT(0)); /* align 4 */
871 nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
872 break;
873
874 default:
875 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
876 break;
877 }
878
Boaz Harrosh040cd232007-08-16 13:01:05 +0300879 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 SCpnt->SCp.ptr += res;
881 SCpnt->SCp.this_residual -= res;
882 ocount += res;
883
884 /* go to next scatter list if available */
885 if (SCpnt->SCp.this_residual == 0 &&
886 SCpnt->SCp.buffers_residual != 0 ) {
887 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
888 SCpnt->SCp.buffers_residual--;
889 SCpnt->SCp.buffer++;
890 SCpnt->SCp.ptr = BUFFER_ADDR;
891 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
892 time_out = 1000;
893 }
894 }
895
896 data->FifoCount = ocount;
897
Roel Kluin0454c742009-06-10 12:56:59 -0700898 if (time_out < 0) {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300899 nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
900 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300903 nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
904 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905}
906#undef RFIFO_CRIT
907#undef WFIFO_CRIT
908
909/*
910 * setup synchronous/asynchronous data transfer mode
911 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700912static int nsp_nexus(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913{
914 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400915 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916// unsigned char lun = SCpnt->device->lun;
917 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
918 sync_data *sync = &(data->Sync[target]);
919
920 //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
921
922 /* setup synch transfer registers */
923 nsp_index_write(base, SYNCREG, sync->SyncRegister);
924 nsp_index_write(base, ACKWIDTH, sync->AckWidth);
925
Boaz Harrosh040cd232007-08-16 13:01:05 +0300926 if (scsi_get_resid(SCpnt) % 4 != 0 ||
927 scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 data->TransferMode = MODE_IO8;
929 } else if (nsp_burst_mode == BURST_MEM32) {
930 data->TransferMode = MODE_MEM32;
931 } else if (nsp_burst_mode == BURST_IO32) {
932 data->TransferMode = MODE_IO32;
933 } else {
934 data->TransferMode = MODE_IO8;
935 }
936
937 /* setup pdma fifo */
938 nsp_setup_fifo(data, TRUE);
939
940 /* clear ack counter */
941 data->FifoCount = 0;
942 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
943 ACK_COUNTER_CLEAR |
944 REQ_COUNTER_CLEAR |
945 HOST_COUNTER_CLEAR);
946
947 return 0;
948}
949
950#include "nsp_message.c"
951/*
952 * interrupt handler
953 */
David Howells7d12e782006-10-05 14:55:46 +0100954static irqreturn_t nspintr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 unsigned int base;
957 unsigned char irq_status, irq_phase, phase;
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700958 struct scsi_cmnd *tmpSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 unsigned char target, lun;
960 unsigned int *sync_neg;
961 int i, tmp;
962 nsp_hw_data *data;
963
964
965 //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
966 //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
967
968 if ( dev_id != NULL &&
969 ((scsi_info_t *)dev_id)->host != NULL ) {
970 scsi_info_t *info = (scsi_info_t *)dev_id;
971
972 data = (nsp_hw_data *)info->host->hostdata;
973 } else {
974 nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
975 return IRQ_NONE;
976 }
977
978 //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
979
980 base = data->BaseAddress;
981 //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
982
983 /*
984 * interrupt check
985 */
986 nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
987 irq_status = nsp_read(base, IRQSTATUS);
988 //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
989 if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
990 nsp_write(base, IRQCONTROL, 0);
991 //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
992 return IRQ_NONE;
993 }
994
995 /* XXX: IMPORTANT
996 * Do not read an irq_phase register if no scsi phase interrupt.
997 * Unless, you should lose a scsi phase interrupt.
998 */
999 phase = nsp_index_read(base, SCSIBUSMON);
1000 if((irq_status & IRQSTATUS_SCSI) != 0) {
1001 irq_phase = nsp_index_read(base, IRQPHASESENCE);
1002 } else {
1003 irq_phase = 0;
1004 }
1005
1006 //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1007
1008 /*
1009 * timer interrupt handler (scsi vs timer interrupts)
1010 */
1011 //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1012 if (data->TimerCount != 0) {
1013 //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1014 nsp_index_write(base, TIMERCOUNT, 0);
1015 nsp_index_write(base, TIMERCOUNT, 0);
1016 data->TimerCount = 0;
1017 }
1018
1019 if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1020 data->SelectionTimeOut == 0) {
1021 //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1022 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1023 return IRQ_HANDLED;
1024 }
1025
1026 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1027
1028 if ((irq_status & IRQSTATUS_SCSI) &&
1029 (irq_phase & SCSI_RESET_IRQ)) {
1030 nsp_msg(KERN_ERR, "bus reset (power off?)");
1031
1032 nsphw_init(data);
1033 nsp_bus_reset(data);
1034
1035 if(data->CurrentSC != NULL) {
1036 tmpSC = data->CurrentSC;
1037 tmpSC->result = (DID_RESET << 16) |
1038 ((tmpSC->SCp.Message & 0xff) << 8) |
1039 ((tmpSC->SCp.Status & 0xff) << 0);
1040 nsp_scsi_done(tmpSC);
1041 }
1042 return IRQ_HANDLED;
1043 }
1044
1045 if (data->CurrentSC == NULL) {
1046 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 nsphw_init(data);
1048 nsp_bus_reset(data);
1049 return IRQ_HANDLED;
1050 }
1051
1052 tmpSC = data->CurrentSC;
1053 target = tmpSC->device->id;
1054 lun = tmpSC->device->lun;
1055 sync_neg = &(data->Sync[target].SyncNegotiation);
1056
1057 /*
1058 * parse hardware SCSI irq reasons register
1059 */
1060 if (irq_status & IRQSTATUS_SCSI) {
1061 if (irq_phase & RESELECT_IRQ) {
1062 nsp_dbg(NSP_DEBUG_INTR, "reselect");
1063 nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1064 if (nsp_reselected(tmpSC) != FALSE) {
1065 return IRQ_HANDLED;
1066 }
1067 }
1068
1069 if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1070 return IRQ_HANDLED;
1071 }
1072 }
1073
1074 //show_phase(tmpSC);
1075
1076 switch(tmpSC->SCp.phase) {
1077 case PH_SELSTART:
1078 // *sync_neg = SYNC_NOT_YET;
1079 if ((phase & BUSMON_BSY) == 0) {
1080 //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1081 if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1082 nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1083 data->SelectionTimeOut = 0;
1084 nsp_index_write(base, SCSIBUSCTRL, 0);
1085
1086 tmpSC->result = DID_TIME_OUT << 16;
1087 nsp_scsi_done(tmpSC);
1088
1089 return IRQ_HANDLED;
1090 }
1091 data->SelectionTimeOut += 1;
1092 nsp_start_timer(tmpSC, 1000/51);
1093 return IRQ_HANDLED;
1094 }
1095
1096 /* attention assert */
1097 //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1098 data->SelectionTimeOut = 0;
1099 tmpSC->SCp.phase = PH_SELECTED;
1100 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1101 udelay(1);
1102 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1103 return IRQ_HANDLED;
1104
1105 break;
1106
1107 case PH_RESELECT:
1108 //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1109 // *sync_neg = SYNC_NOT_YET;
1110 if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1111
1112 tmpSC->result = DID_ABORT << 16;
1113 nsp_scsi_done(tmpSC);
1114 return IRQ_HANDLED;
1115 }
1116 /* fall thru */
1117 default:
1118 if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1119 return IRQ_HANDLED;
1120 }
1121 break;
1122 }
1123
1124 /*
1125 * SCSI sequencer
1126 */
1127 //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1128
1129 /* normal disconnect */
1130 if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1131 (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1132 nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1133
1134 //*sync_neg = SYNC_NOT_YET;
1135
1136 if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
1137 tmpSC->result = (DID_OK << 16) |
1138 ((tmpSC->SCp.Message & 0xff) << 8) |
1139 ((tmpSC->SCp.Status & 0xff) << 0);
1140 nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1141 nsp_scsi_done(tmpSC);
1142
1143 return IRQ_HANDLED;
1144 }
1145
1146 return IRQ_HANDLED;
1147 }
1148
1149
1150 /* check unexpected bus free state */
1151 if (phase == 0) {
1152 nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1153
1154 *sync_neg = SYNC_NG;
1155 tmpSC->result = DID_ERROR << 16;
1156 nsp_scsi_done(tmpSC);
1157 return IRQ_HANDLED;
1158 }
1159
1160 switch (phase & BUSMON_PHASE_MASK) {
1161 case BUSPHASE_COMMAND:
1162 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1163 if ((phase & BUSMON_REQ) == 0) {
1164 nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1165 return IRQ_HANDLED;
1166 }
1167
1168 tmpSC->SCp.phase = PH_COMMAND;
1169
1170 nsp_nexus(tmpSC);
1171
1172 /* write scsi command */
1173 nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1174 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1175 for (i = 0; i < tmpSC->cmd_len; i++) {
1176 nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1177 }
1178 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1179 break;
1180
1181 case BUSPHASE_DATA_OUT:
1182 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1183
1184 tmpSC->SCp.phase = PH_DATA;
1185 tmpSC->SCp.have_data_in = IO_OUT;
1186
1187 nsp_pio_write(tmpSC);
1188
1189 break;
1190
1191 case BUSPHASE_DATA_IN:
1192 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1193
1194 tmpSC->SCp.phase = PH_DATA;
1195 tmpSC->SCp.have_data_in = IO_IN;
1196
1197 nsp_pio_read(tmpSC);
1198
1199 break;
1200
1201 case BUSPHASE_STATUS:
1202 nsp_dataphase_bypass(tmpSC);
1203 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1204
1205 tmpSC->SCp.phase = PH_STATUS;
1206
1207 tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1208 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1209
1210 break;
1211
1212 case BUSPHASE_MESSAGE_OUT:
1213 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1214 if ((phase & BUSMON_REQ) == 0) {
1215 goto timer_out;
1216 }
1217
1218 tmpSC->SCp.phase = PH_MSG_OUT;
1219
1220 //*sync_neg = SYNC_NOT_YET;
1221
1222 data->MsgLen = i = 0;
1223 data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1224
1225 if (*sync_neg == SYNC_NOT_YET) {
1226 data->Sync[target].SyncPeriod = 0;
1227 data->Sync[target].SyncOffset = 0;
1228
1229 /**/
1230 data->MsgBuffer[i] = MSG_EXTENDED; i++;
1231 data->MsgBuffer[i] = 3; i++;
1232 data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1233 data->MsgBuffer[i] = 0x0c; i++;
1234 data->MsgBuffer[i] = 15; i++;
1235 /**/
1236 }
1237 data->MsgLen = i;
1238
1239 nsp_analyze_sdtr(tmpSC);
1240 show_message(data);
1241 nsp_message_out(tmpSC);
1242 break;
1243
1244 case BUSPHASE_MESSAGE_IN:
1245 nsp_dataphase_bypass(tmpSC);
1246 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1247 if ((phase & BUSMON_REQ) == 0) {
1248 goto timer_out;
1249 }
1250
1251 tmpSC->SCp.phase = PH_MSG_IN;
1252 nsp_message_in(tmpSC);
1253
1254 /**/
1255 if (*sync_neg == SYNC_NOT_YET) {
1256 //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1257
1258 if (data->MsgLen >= 5 &&
1259 data->MsgBuffer[0] == MSG_EXTENDED &&
1260 data->MsgBuffer[1] == 3 &&
1261 data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1262 data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1263 data->Sync[target].SyncOffset = data->MsgBuffer[4];
1264 //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1265 *sync_neg = SYNC_OK;
1266 } else {
1267 data->Sync[target].SyncPeriod = 0;
1268 data->Sync[target].SyncOffset = 0;
1269 *sync_neg = SYNC_NG;
1270 }
1271 nsp_analyze_sdtr(tmpSC);
1272 }
1273 /**/
1274
1275 /* search last messeage byte */
1276 tmp = -1;
1277 for (i = 0; i < data->MsgLen; i++) {
1278 tmp = data->MsgBuffer[i];
1279 if (data->MsgBuffer[i] == MSG_EXTENDED) {
1280 i += (1 + data->MsgBuffer[i+1]);
1281 }
1282 }
1283 tmpSC->SCp.Message = tmp;
1284
1285 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1286 show_message(data);
1287
1288 break;
1289
1290 case BUSPHASE_SELECT:
1291 default:
1292 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1293
1294 break;
1295 }
1296
1297 //nsp_dbg(NSP_DEBUG_INTR, "out");
1298 return IRQ_HANDLED;
1299
1300timer_out:
1301 nsp_start_timer(tmpSC, 1000/102);
1302 return IRQ_HANDLED;
1303}
1304
1305#ifdef NSP_DEBUG
1306#include "nsp_debug.c"
1307#endif /* NSP_DEBUG */
1308
1309/*----------------------------------------------------------------*/
1310/* look for ninja3 card and init if found */
1311/*----------------------------------------------------------------*/
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001312static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313{
1314 struct Scsi_Host *host; /* registered host structure */
1315 nsp_hw_data *data_b = &nsp_data_base, *data;
1316
1317 nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (host == NULL) {
1320 nsp_dbg(NSP_DEBUG_INIT, "host failed");
1321 return NULL;
1322 }
1323
1324 memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1325 data = (nsp_hw_data *)host->hostdata;
1326 data->ScsiInfo->host = host;
1327#ifdef NSP_DEBUG
1328 data->CmdId = 0;
1329#endif
1330
1331 nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1332
1333 host->unique_id = data->BaseAddress;
1334 host->io_port = data->BaseAddress;
1335 host->n_io_port = data->NumAddress;
1336 host->irq = data->IrqNumber;
1337 host->base = data->MmioAddress;
1338
1339 spin_lock_init(&(data->Lock));
1340
1341 snprintf(data->nspinfo,
1342 sizeof(data->nspinfo),
1343 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1344 host->io_port, host->io_port + host->n_io_port - 1,
1345 host->base,
1346 host->irq);
1347 sht->name = data->nspinfo;
1348
1349 nsp_dbg(NSP_DEBUG_INIT, "end");
1350
1351
1352 return host; /* detect done. */
1353}
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355/*----------------------------------------------------------------*/
1356/* return info string */
1357/*----------------------------------------------------------------*/
1358static const char *nsp_info(struct Scsi_Host *shpnt)
1359{
1360 nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1361
1362 return data->nspinfo;
1363}
1364
1365#undef SPRINTF
1366#define SPRINTF(args...) \
1367 do { \
1368 if(length > (pos - buffer)) { \
1369 pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
1370 nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
1371 } \
1372 } while(0)
Adrian Bunk774251e2007-10-02 14:38:01 -07001373
1374static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
1375 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 int id;
1378 char *pos = buffer;
1379 int thislength;
1380 int speed;
1381 unsigned long flags;
1382 nsp_hw_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 int hostno;
Adrian Bunk774251e2007-10-02 14:38:01 -07001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (inout) {
1386 return -EINVAL;
1387 }
1388
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 hostno = host->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 data = (nsp_hw_data *)host->hostdata;
1391
1392
1393 SPRINTF("NinjaSCSI status\n\n");
1394 SPRINTF("Driver version: $Revision: 1.23 $\n");
1395 SPRINTF("SCSI host No.: %d\n", hostno);
1396 SPRINTF("IRQ: %d\n", host->irq);
1397 SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1398 SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1399 SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
1400
1401 SPRINTF("burst transfer mode: ");
1402 switch (nsp_burst_mode) {
1403 case BURST_IO8:
1404 SPRINTF("io8");
1405 break;
1406 case BURST_IO32:
1407 SPRINTF("io32");
1408 break;
1409 case BURST_MEM32:
1410 SPRINTF("mem32");
1411 break;
1412 default:
1413 SPRINTF("???");
1414 break;
1415 }
1416 SPRINTF("\n");
1417
1418
1419 spin_lock_irqsave(&(data->Lock), flags);
1420 SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
1421 spin_unlock_irqrestore(&(data->Lock), flags);
1422
1423 SPRINTF("SDTR status\n");
1424 for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1425
1426 SPRINTF("id %d: ", id);
1427
1428 if (id == host->this_id) {
1429 SPRINTF("----- NinjaSCSI-3 host adapter\n");
1430 continue;
1431 }
1432
1433 switch(data->Sync[id].SyncNegotiation) {
1434 case SYNC_OK:
1435 SPRINTF(" sync");
1436 break;
1437 case SYNC_NG:
1438 SPRINTF("async");
1439 break;
1440 case SYNC_NOT_YET:
1441 SPRINTF(" none");
1442 break;
1443 default:
1444 SPRINTF("?????");
1445 break;
1446 }
1447
1448 if (data->Sync[id].SyncPeriod != 0) {
1449 speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1450
1451 SPRINTF(" transfer %d.%dMB/s, offset %d",
1452 speed / 1000,
1453 speed % 1000,
1454 data->Sync[id].SyncOffset
1455 );
1456 }
1457 SPRINTF("\n");
1458 }
1459
1460 thislength = pos - (buffer + offset);
1461
1462 if(thislength < 0) {
1463 *start = NULL;
1464 return 0;
1465 }
1466
1467
1468 thislength = min(thislength, length);
1469 *start = buffer + offset;
1470
1471 return thislength;
1472}
1473#undef SPRINTF
1474
1475/*---------------------------------------------------------------*/
1476/* error handler */
1477/*---------------------------------------------------------------*/
1478
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479/*
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001480static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481{
1482 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1483
1484 return nsp_eh_bus_reset(SCpnt);
1485}*/
1486
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487static int nsp_bus_reset(nsp_hw_data *data)
1488{
1489 unsigned int base = data->BaseAddress;
1490 int i;
1491
1492 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1493
1494 nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1495 mdelay(100); /* 100ms */
1496 nsp_index_write(base, SCSIBUSCTRL, 0);
1497 for(i = 0; i < 5; i++) {
1498 nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1499 }
1500
1501 nsphw_init_sync(data);
1502
1503 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1504
1505 return SUCCESS;
1506}
1507
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001508static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509{
1510 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1511
1512 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1513
1514 return nsp_bus_reset(data);
1515}
1516
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001517static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518{
1519 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1520
1521 nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1522
1523 nsphw_init(data);
1524
1525 return SUCCESS;
1526}
1527
1528
1529/**********************************************************************
1530 PCMCIA functions
1531**********************************************************************/
1532
1533/*======================================================================
1534 nsp_cs_attach() creates an "instance" of the driver, allocating
1535 local data structures for one device. The device is registered
1536 with Card Services.
1537
1538 The dev_link structure is initialized, but we don't actually
1539 configure the card at this point -- we wait until we receive a
1540 card insertion event.
1541======================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001542static int nsp_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 nsp_hw_data *data = &nsp_data_base;
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001546 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 nsp_dbg(NSP_DEBUG_INIT, "in");
1549
1550 /* Create new SCSI device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001551 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001552 if (info == NULL) { return -ENOMEM; }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001553 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 link->priv = info;
1555 data->ScsiInfo = info;
1556
1557 nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1558
1559 /* The io structure describes IO port mapping */
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001560 link->resource[0]->end = 0x10;
1561 link->resource[0]->flags = IO_DATA_PATH_WIDTH_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 /* General socket configuration */
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001564 link->config_flags |= CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001566 ret = nsp_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001569 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570} /* nsp_cs_attach */
1571
1572
1573/*======================================================================
1574 This deletes a driver "instance". The device is de-registered
1575 with Card Services. If it has been released, all local data
1576 structures are freed. Otherwise, the structures will be freed
1577 when the device is released.
1578======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001579static void nsp_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1582
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001583 ((scsi_info_t *)link->priv)->stop = 1;
1584 nsp_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 kfree(link->priv);
1587 link->priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588} /* nsp_cs_detach */
1589
1590
1591/*======================================================================
1592 nsp_cs_config() is scheduled to run after a CARD_INSERTION event
1593 is received, to configure the PCMCIA socket, and to make the
1594 ethernet device available to the system.
1595======================================================================*/
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001596
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001597static int nsp_cs_config_check(struct pcmcia_device *p_dev,
1598 cistpl_cftable_entry_t *cfg,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001599 cistpl_cftable_entry_t *dflt,
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001600 void *priv_data)
1601{
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001602 nsp_hw_data *data = priv_data;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001603
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001604 if (cfg->index == 0)
1605 return -ENODEV;
1606
Dominik Brodowski440eed42010-07-30 09:51:52 +02001607 /* IO window settings */
1608 p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
1609 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
1610 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
1611 p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
1612 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
1613 p_dev->resource[0]->flags |=
1614 pcmcia_io_cfg_data_width(io->flags);
1615 p_dev->resource[0]->start = io->win[0].base;
1616 p_dev->resource[0]->end = io->win[0].len;
1617 if (io->nwin > 1) {
1618 p_dev->resource[1]->flags = p_dev->resource[0]->flags;
1619 p_dev->resource[1]->start = io->win[1].base;
1620 p_dev->resource[1]->end = io->win[1].len;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001621 }
Dominik Brodowski440eed42010-07-30 09:51:52 +02001622 /* This reserves IO space but doesn't actually enable it */
1623 if (pcmcia_request_io(p_dev) != 0)
1624 goto next_entry;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001625 }
1626
Dominik Brodowski440eed42010-07-30 09:51:52 +02001627 if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
1628 cistpl_mem_t *mem =
1629 (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
1630 p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1631 WIN_MEMORY_TYPE_CM |
1632 WIN_ENABLE);
1633 p_dev->resource[2]->start = mem->win[0].host_addr;
1634 p_dev->resource[2]->end = mem->win[0].len;
1635 if (p_dev->resource[2]->end < 0x1000)
1636 p_dev->resource[2]->end = 0x1000;
1637 if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
1638 goto next_entry;
1639 if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
1640 mem->win[0].card_addr) != 0)
1641 goto next_entry;
1642
1643 data->MmioAddress = (unsigned long)
1644 ioremap_nocache(p_dev->resource[2]->start,
1645 resource_size(p_dev->resource[2]));
1646 data->MmioLength = resource_size(p_dev->resource[2]);
1647 }
1648 /* If we got this far, we're cool! */
1649 return 0;
1650
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001651next_entry:
1652 nsp_dbg(NSP_DEBUG_INIT, "next");
1653 pcmcia_disable_device(p_dev);
1654 return -ENODEV;
1655}
1656
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001657static int nsp_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658{
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001659 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 scsi_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 struct Scsi_Host *host;
1662 nsp_hw_data *data = &nsp_data_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 nsp_dbg(NSP_DEBUG_INIT, "in");
1665
Dominik Brodowski440eed42010-07-30 09:51:52 +02001666 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
1667 CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO;
1668
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001669 ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
Dan Carpentere794c012010-03-15 11:25:10 +03001670 if (ret)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001671 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Dominik Brodowskieb141202010-03-07 12:21:16 +01001673 if (pcmcia_request_irq(link, nspintr))
1674 goto cs_failed;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001675
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001676 ret = pcmcia_enable_device(link);
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001677 if (ret)
1678 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680 if (free_ports) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001681 if (link->resource[0]) {
1682 release_region(link->resource[0]->start,
1683 resource_size(link->resource[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001685 if (link->resource[1]) {
1686 release_region(link->resource[1]->start,
1687 resource_size(link->resource[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 }
1689 }
1690
1691 /* Set port and IRQ */
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001692 data->BaseAddress = link->resource[0]->start;
1693 data->NumAddress = resource_size(link->resource[0]);
Dominik Brodowskieb141202010-03-07 12:21:16 +01001694 data->IrqNumber = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1697 data->BaseAddress, data->NumAddress, data->IrqNumber);
1698
1699 if(nsphw_init(data) == FALSE) {
1700 goto cs_failed;
1701 }
1702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 host = nsp_detect(&nsp_driver_template);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
1705 if (host == NULL) {
1706 nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1707 goto cs_failed;
1708 }
1709
1710
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001711 ret = scsi_add_host (host, NULL);
1712 if (ret)
1713 goto cs_failed;
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 scsi_scan_host(host);
1716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 info->host = host;
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 /* Finally, report what we've done */
Dominik Brodowski70294b42006-01-15 12:43:16 +01001720 printk(KERN_INFO "nsp_cs: index 0x%02x: ",
Dominik Brodowski7feabb62010-07-29 18:35:47 +02001721 link->config_index);
Dominik Brodowskie8405f02010-07-29 15:50:55 +02001722 if (link->vpp) {
1723 printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001725 printk(", irq %d", link->irq);
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001726 if (link->resource[0])
1727 printk(", io %pR", link->resource[0]);
1728 if (link->resource[1])
1729 printk(" & %pR", link->resource[1]);
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001730 if (link->resource[2])
1731 printk(", mem %pR", link->resource[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 printk("\n");
1733
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001734 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 cs_failed:
1737 nsp_dbg(NSP_DEBUG_INIT, "config fail");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 nsp_cs_release(link);
1739
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001740 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741} /* nsp_cs_config */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743
1744/*======================================================================
1745 After a card is removed, nsp_cs_release() will unregister the net
1746 device, and release the PCMCIA configuration. If the device is
1747 still open, this will be postponed until it is closed.
1748======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001749static void nsp_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
1751 scsi_info_t *info = link->priv;
1752 nsp_hw_data *data = NULL;
1753
1754 if (info->host == NULL) {
1755 nsp_msg(KERN_DEBUG, "unexpected card release call.");
1756 } else {
1757 data = (nsp_hw_data *)info->host->hostdata;
1758 }
1759
1760 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1761
1762 /* Unlink the device chain */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 if (info->host != NULL) {
1764 scsi_remove_host(info->host);
1765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001767 if (resource_size(link->resource[2])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 if (data != NULL) {
1769 iounmap((void *)(data->MmioAddress));
1770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001772 pcmcia_disable_device(link);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (info->host != NULL) {
1775 scsi_host_put(info->host);
1776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777} /* nsp_cs_release */
1778
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001779static int nsp_cs_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001780{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001781 scsi_info_t *info = link->priv;
1782 nsp_hw_data *data;
1783
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001784 nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1785
1786 if (info->host != NULL) {
1787 nsp_msg(KERN_INFO, "clear SDTR status");
1788
1789 data = (nsp_hw_data *)info->host->hostdata;
1790
1791 nsphw_init_sync(data);
1792 }
1793
1794 info->stop = 1;
1795
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001796 return 0;
1797}
1798
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001799static int nsp_cs_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001800{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001801 scsi_info_t *info = link->priv;
1802 nsp_hw_data *data;
1803
1804 nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1805
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001806 info->stop = 0;
1807
1808 if (info->host != NULL) {
1809 nsp_msg(KERN_INFO, "reset host and bus");
1810
1811 data = (nsp_hw_data *)info->host->hostdata;
1812
1813 nsphw_init (data);
1814 nsp_bus_reset(data);
1815 }
1816
1817 return 0;
1818}
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820/*======================================================================*
1821 * module entry point
1822 *====================================================================*/
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001823static struct pcmcia_device_id nsp_cs_ids[] = {
1824 PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1825 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1826 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1827 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1828 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1829 PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1830 PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1831 PCMCIA_DEVICE_NULL
1832};
1833MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835static struct pcmcia_driver nsp_driver = {
Dominik Brodowski1e212f32005-07-07 17:59:00 -07001836 .owner = THIS_MODULE,
1837 .drv = {
1838 .name = "nsp_cs",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001840 .probe = nsp_cs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01001841 .remove = nsp_cs_detach,
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001842 .id_table = nsp_cs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001843 .suspend = nsp_cs_suspend,
1844 .resume = nsp_cs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847static int __init nsp_cs_init(void)
1848{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 nsp_msg(KERN_INFO, "loading...");
1850
1851 return pcmcia_register_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852}
1853
1854static void __exit nsp_cs_exit(void)
1855{
1856 nsp_msg(KERN_INFO, "unloading...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 pcmcia_unregister_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858}
1859
1860
1861module_init(nsp_cs_init)
1862module_exit(nsp_cs_exit)
1863
1864/* end */