blob: 24e6cb8396e35e9bcebe890e9352f1cddc613c80 [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/cs_types.h>
51#include <pcmcia/cs.h>
52#include <pcmcia/cistpl.h>
53#include <pcmcia/cisreg.h>
54#include <pcmcia/ds.h>
55
56#include "nsp_cs.h"
57
58MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
Adrian Bunk774251e2007-10-02 14:38:01 -070059MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
Linus Torvalds1da177e2005-04-16 15:20:36 -070060MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
61#ifdef MODULE_LICENSE
62MODULE_LICENSE("GPL");
63#endif
64
65#include "nsp_io.h"
66
67/*====================================================================*/
68/* Parameters that can be set with 'insmod' */
69
70static int nsp_burst_mode = BURST_MEM32;
71module_param(nsp_burst_mode, int, 0);
72MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
73
74/* Release IO ports after configuration? */
75static int free_ports = 0;
76module_param(free_ports, bool, 0);
77MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
78
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010079static struct scsi_host_template nsp_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 .proc_name = "nsp_cs",
81 .proc_info = nsp_proc_info,
82 .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 .info = nsp_info,
84 .queuecommand = nsp_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* .eh_abort_handler = nsp_eh_abort,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 .eh_bus_reset_handler = nsp_eh_bus_reset,
87 .eh_host_reset_handler = nsp_eh_host_reset,
88 .can_queue = 1,
89 .this_id = NSP_INITIATOR_ID,
90 .sg_tablesize = SG_ALL,
91 .cmd_per_lun = 1,
92 .use_clustering = DISABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -070093};
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
96
97
98
99/*
100 * debug, error print
101 */
102#ifndef NSP_DEBUG
103# define NSP_DEBUG_MASK 0x000000
104# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
105# define nsp_dbg(mask, args...) /* */
106#else
107# define NSP_DEBUG_MASK 0xffffff
108# define nsp_msg(type, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700109 nsp_cs_message (__func__, __LINE__, (type), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110# define nsp_dbg(mask, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700111 nsp_cs_dmessage(__func__, __LINE__, (mask), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#endif
113
114#define NSP_DEBUG_QUEUECOMMAND BIT(0)
115#define NSP_DEBUG_REGISTER BIT(1)
116#define NSP_DEBUG_AUTOSCSI BIT(2)
117#define NSP_DEBUG_INTR BIT(3)
118#define NSP_DEBUG_SGLIST BIT(4)
119#define NSP_DEBUG_BUSFREE BIT(5)
120#define NSP_DEBUG_CDB_CONTENTS BIT(6)
121#define NSP_DEBUG_RESELECTION BIT(7)
122#define NSP_DEBUG_MSGINOCCUR BIT(8)
123#define NSP_DEBUG_EEPROM BIT(9)
124#define NSP_DEBUG_MSGOUTOCCUR BIT(10)
125#define NSP_DEBUG_BUSRESET BIT(11)
126#define NSP_DEBUG_RESTART BIT(12)
127#define NSP_DEBUG_SYNC BIT(13)
128#define NSP_DEBUG_WAIT BIT(14)
129#define NSP_DEBUG_TARGETFLAG BIT(15)
130#define NSP_DEBUG_PROC BIT(16)
131#define NSP_DEBUG_INIT BIT(17)
132#define NSP_DEBUG_DATA_IO BIT(18)
133#define NSP_SPECIAL_PRINT_REGISTER BIT(20)
134
135#define NSP_DEBUG_BUF_LEN 150
136
Boaz Harrosh040cd232007-08-16 13:01:05 +0300137static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
138{
139 scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
140}
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
143{
144 va_list args;
145 char buf[NSP_DEBUG_BUF_LEN];
146
147 va_start(args, fmt);
148 vsnprintf(buf, sizeof(buf), fmt, args);
149 va_end(args);
150
151#ifndef NSP_DEBUG
152 printk("%snsp_cs: %s\n", type, buf);
153#else
154 printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
155#endif
156}
157
158#ifdef NSP_DEBUG
159static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
160{
161 va_list args;
162 char buf[NSP_DEBUG_BUF_LEN];
163
164 va_start(args, fmt);
165 vsnprintf(buf, sizeof(buf), fmt, args);
166 va_end(args);
167
168 if (mask & NSP_DEBUG_MASK) {
169 printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
170 }
171}
172#endif
173
174/***********************************************************/
175
176/*====================================================
177 * Clenaup parameters and call done() functions.
178 * You must be set SCpnt->result before call this function.
179 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700180static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
182 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
183
184 data->CurrentSC = NULL;
185
186 SCpnt->scsi_done(SCpnt);
187}
188
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700189static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
190 void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
192#ifdef NSP_DEBUG
193 /*unsigned int host_id = SCpnt->device->host->this_id;*/
194 /*unsigned int base = SCpnt->device->host->io_port;*/
Jeff Garzik422c0d62005-10-24 18:05:09 -0400195 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196#endif
197 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
198
Boaz Harrosh040cd232007-08-16 13:01:05 +0300199 nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
200 "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
201 SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
202 scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
204
205 SCpnt->scsi_done = done;
206
207 if (data->CurrentSC != NULL) {
208 nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
209 SCpnt->result = DID_BAD_TARGET << 16;
210 nsp_scsi_done(SCpnt);
211 return 0;
212 }
213
214#if 0
215 /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
216 This makes kernel crash when suspending... */
217 if (data->ScsiInfo->stop != 0) {
218 nsp_msg(KERN_INFO, "suspending device. reject command.");
219 SCpnt->result = DID_BAD_TARGET << 16;
220 nsp_scsi_done(SCpnt);
221 return SCSI_MLQUEUE_HOST_BUSY;
222 }
223#endif
224
225 show_command(SCpnt);
226
227 data->CurrentSC = SCpnt;
228
229 SCpnt->SCp.Status = CHECK_CONDITION;
230 SCpnt->SCp.Message = 0;
231 SCpnt->SCp.have_data_in = IO_UNKNOWN;
232 SCpnt->SCp.sent_command = 0;
233 SCpnt->SCp.phase = PH_UNDETERMINED;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300234 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236 /* setup scratch area
237 SCp.ptr : buffer pointer
238 SCp.this_residual : buffer length
239 SCp.buffer : next buffer
240 SCp.buffers_residual : left buffers in list
241 SCp.phase : current state of the command */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300242 if (scsi_bufflen(SCpnt)) {
243 SCpnt->SCp.buffer = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 SCpnt->SCp.ptr = BUFFER_ADDR;
245 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300246 SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 } else {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300248 SCpnt->SCp.ptr = NULL;
249 SCpnt->SCp.this_residual = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 SCpnt->SCp.buffer = NULL;
251 SCpnt->SCp.buffers_residual = 0;
252 }
253
254 if (nsphw_start_selection(SCpnt) == FALSE) {
255 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
256 SCpnt->result = DID_BUS_BUSY << 16;
257 nsp_scsi_done(SCpnt);
258 return 0;
259 }
260
261
262 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
263#ifdef NSP_DEBUG
264 data->CmdId++;
265#endif
266 return 0;
267}
268
269/*
270 * setup PIO FIFO transfer mode and enable/disable to data out
271 */
272static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
273{
274 unsigned int base = data->BaseAddress;
275 unsigned char transfer_mode_reg;
276
277 //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
278
279 if (enabled != FALSE) {
280 transfer_mode_reg = TRANSFER_GO | BRAIND;
281 } else {
282 transfer_mode_reg = 0;
283 }
284
285 transfer_mode_reg |= data->TransferMode;
286
287 nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
288}
289
290static void nsphw_init_sync(nsp_hw_data *data)
291{
292 sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
293 .SyncPeriod = 0,
294 .SyncOffset = 0
295 };
296 int i;
297
298 /* setup sync data */
299 for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
300 data->Sync[i] = tmp_sync;
301 }
302}
303
304/*
305 * Initialize Ninja hardware
306 */
307static int nsphw_init(nsp_hw_data *data)
308{
309 unsigned int base = data->BaseAddress;
310
311 nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
312
313 data->ScsiClockDiv = CLOCK_40M | FAST_20;
314 data->CurrentSC = NULL;
315 data->FifoCount = 0;
316 data->TransferMode = MODE_IO8;
317
318 nsphw_init_sync(data);
319
320 /* block all interrupts */
321 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
322
323 /* setup SCSI interface */
324 nsp_write(base, IFSELECT, IF_IFSEL);
325
326 nsp_index_write(base, SCSIIRQMODE, 0);
327
328 nsp_index_write(base, TRANSFERMODE, MODE_IO8);
329 nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
330
331 nsp_index_write(base, PARITYCTRL, 0);
332 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
333 ACK_COUNTER_CLEAR |
334 REQ_COUNTER_CLEAR |
335 HOST_COUNTER_CLEAR);
336
337 /* setup fifo asic */
338 nsp_write(base, IFSELECT, IF_REGSEL);
339 nsp_index_write(base, TERMPWRCTRL, 0);
340 if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
341 nsp_msg(KERN_INFO, "terminator power on");
342 nsp_index_write(base, TERMPWRCTRL, POWER_ON);
343 }
344
345 nsp_index_write(base, TIMERCOUNT, 0);
346 nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
347
348 nsp_index_write(base, SYNCREG, 0);
349 nsp_index_write(base, ACKWIDTH, 0);
350
351 /* enable interrupts and ack them */
352 nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
353 RESELECT_EI |
354 SCSI_RESET_IRQ_EI );
355 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
356
357 nsp_setup_fifo(data, FALSE);
358
359 return TRUE;
360}
361
362/*
363 * Start selection phase
364 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700365static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
367 unsigned int host_id = SCpnt->device->host->this_id;
368 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400369 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
371 int time_out;
372 unsigned char phase, arbit;
373
374 //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
375
376 phase = nsp_index_read(base, SCSIBUSMON);
377 if(phase != BUSMON_BUS_FREE) {
378 //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
379 return FALSE;
380 }
381
382 /* start arbitration */
383 //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
384 SCpnt->SCp.phase = PH_ARBSTART;
385 nsp_index_write(base, SETARBIT, ARBIT_GO);
386
387 time_out = 1000;
388 do {
389 /* XXX: what a stupid chip! */
390 arbit = nsp_index_read(base, ARBITSTATUS);
391 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
392 udelay(1); /* hold 1.2us */
393 } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
394 (time_out-- != 0));
395
396 if (!(arbit & ARBIT_WIN)) {
397 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
398 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
399 return FALSE;
400 }
401
402 /* assert select line */
403 //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
404 SCpnt->SCp.phase = PH_SELSTART;
405 udelay(3); /* wait 2.4us */
406 nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
407 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
408 udelay(2); /* wait >1.2us */
409 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
410 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
411 /*udelay(1);*/ /* wait >90ns */
412 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
413
414 /* check selection timeout */
415 nsp_start_timer(SCpnt, 1000/51);
416 data->SelectionTimeOut = 1;
417
418 return TRUE;
419}
420
421struct nsp_sync_table {
422 unsigned int min_period;
423 unsigned int max_period;
424 unsigned int chip_period;
425 unsigned int ack_width;
426};
427
428static struct nsp_sync_table nsp_sync_table_40M[] = {
429 {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
430 {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
431 {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
432 {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
433 { 0, 0, 0, 0},
434};
435
436static struct nsp_sync_table nsp_sync_table_20M[] = {
437 {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
438 {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
439 {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
440 { 0, 0, 0, 0},
441};
442
443/*
444 * setup synchronous data transfer mode
445 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700446static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Jeff Garzik422c0d62005-10-24 18:05:09 -0400448 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449// unsigned char lun = SCpnt->device->lun;
450 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
451 sync_data *sync = &(data->Sync[target]);
452 struct nsp_sync_table *sync_table;
453 unsigned int period, offset;
454 int i;
455
456
457 nsp_dbg(NSP_DEBUG_SYNC, "in");
458
459 period = sync->SyncPeriod;
460 offset = sync->SyncOffset;
461
462 nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
463
464 if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
465 sync_table = nsp_sync_table_20M;
466 } else {
467 sync_table = nsp_sync_table_40M;
468 }
469
470 for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
471 if ( period >= sync_table->min_period &&
472 period <= sync_table->max_period ) {
473 break;
474 }
475 }
476
477 if (period != 0 && sync_table->max_period == 0) {
478 /*
479 * No proper period/offset found
480 */
481 nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
482
483 sync->SyncPeriod = 0;
484 sync->SyncOffset = 0;
485 sync->SyncRegister = 0;
486 sync->AckWidth = 0;
487
488 return FALSE;
489 }
490
491 sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
492 (offset & SYNCREG_OFFSET_MASK);
493 sync->AckWidth = sync_table->ack_width;
494
495 nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
496
497 return TRUE;
498}
499
500
501/*
502 * start ninja hardware timer
503 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700504static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
506 unsigned int base = SCpnt->device->host->io_port;
507 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
508
509 //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
510 data->TimerCount = time;
511 nsp_index_write(base, TIMERCOUNT, time);
512}
513
514/*
515 * wait for bus phase change
516 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700517static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
518 char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
520 unsigned int base = SCpnt->device->host->io_port;
521 unsigned char reg;
522 int time_out;
523
524 //nsp_dbg(NSP_DEBUG_INTR, "in");
525
526 time_out = 100;
527
528 do {
529 reg = nsp_index_read(base, SCSIBUSMON);
530 if (reg == 0xff) {
531 break;
532 }
533 } while ((time_out-- != 0) && (reg & mask) != 0);
534
535 if (time_out == 0) {
536 nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
537 }
538
539 return 0;
540}
541
542/*
543 * expect Ninja Irq
544 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700545static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
546 unsigned char current_phase,
547 unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
549 unsigned int base = SCpnt->device->host->io_port;
550 int time_out;
551 unsigned char phase, i_src;
552
553 //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
554
555 time_out = 100;
556 do {
557 phase = nsp_index_read(base, SCSIBUSMON);
558 if (phase == 0xff) {
559 //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
560 return -1;
561 }
562 i_src = nsp_read(base, IRQSTATUS);
563 if (i_src & IRQSTATUS_SCSI) {
564 //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
565 return 0;
566 }
567 if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
568 //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
569 return 1;
570 }
571 } while(time_out-- != 0);
572
573 //nsp_dbg(NSP_DEBUG_INTR, "timeout");
574 return -1;
575}
576
577/*
578 * transfer SCSI message
579 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700580static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
582 unsigned int base = SCpnt->device->host->io_port;
583 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
584 char *buf = data->MsgBuffer;
585 int len = min(MSGBUF_SIZE, data->MsgLen);
586 int ptr;
587 int ret;
588
589 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
590 for (ptr = 0; len > 0; len--, ptr++) {
591
592 ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
593 if (ret <= 0) {
594 nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
595 return 0;
596 }
597
598 /* if last byte, negate ATN */
599 if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
600 nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
601 }
602
603 /* read & write message */
604 if (phase & BUSMON_IO) {
605 nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
606 buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
607 } else {
608 nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
609 nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
610 }
611 nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
612
613 }
614 return len;
615}
616
617/*
618 * get extra SCSI data from fifo
619 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700620static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621{
622 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
623 unsigned int count;
624
625 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
626
627 if (SCpnt->SCp.have_data_in != IO_IN) {
628 return 0;
629 }
630
631 count = nsp_fifo_count(SCpnt);
632 if (data->FifoCount == count) {
633 //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
634 return 0;
635 }
636
637 /*
638 * XXX: NSP_QUIRK
639 * data phase skip only occures in case of SCSI_LOW_READ
640 */
641 nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
642 SCpnt->SCp.phase = PH_DATA;
643 nsp_pio_read(SCpnt);
644 nsp_setup_fifo(data, FALSE);
645
646 return 0;
647}
648
649/*
650 * accept reselection
651 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700652static int nsp_reselected(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653{
654 unsigned int base = SCpnt->device->host->io_port;
655 unsigned int host_id = SCpnt->device->host->this_id;
656 //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
657 unsigned char bus_reg;
658 unsigned char id_reg, tmp;
659 int target;
660
661 nsp_dbg(NSP_DEBUG_RESELECTION, "in");
662
663 id_reg = nsp_index_read(base, RESELECTID);
664 tmp = id_reg & (~BIT(host_id));
665 target = 0;
666 while(tmp != 0) {
667 if (tmp & BIT(0)) {
668 break;
669 }
670 tmp >>= 1;
671 target++;
672 }
673
Jeff Garzik422c0d62005-10-24 18:05:09 -0400674 if (scmd_id(SCpnt) != target) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
676 }
677
678 nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
679
680 nsp_nexus(SCpnt);
681 bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
682 nsp_index_write(base, SCSIBUSCTRL, bus_reg);
683 nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
684
685 return TRUE;
686}
687
688/*
689 * count how many data transferd
690 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700691static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
693 unsigned int base = SCpnt->device->host->io_port;
694 unsigned int count;
695 unsigned int l, m, h, dummy;
696
697 nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
698
699 l = nsp_index_read(base, TRANSFERCOUNT);
700 m = nsp_index_read(base, TRANSFERCOUNT);
701 h = nsp_index_read(base, TRANSFERCOUNT);
702 dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
703
704 count = (h << 16) | (m << 8) | (l << 0);
705
706 //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
707
708 return count;
709}
710
711/* fifo size */
712#define RFIFO_CRIT 64
713#define WFIFO_CRIT 64
714
715/*
716 * read data in DATA IN phase
717 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700718static void nsp_pio_read(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 unsigned int base = SCpnt->device->host->io_port;
721 unsigned long mmio_base = SCpnt->device->host->base;
722 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
723 long time_out;
724 int ocount, res;
725 unsigned char stat, fifo_stat;
726
727 ocount = data->FifoCount;
728
729 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 +0300730 SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
731 SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
732 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 time_out = 1000;
735
736 while ((time_out-- != 0) &&
737 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
738
739 stat = nsp_index_read(base, SCSIBUSMON);
740 stat &= BUSMON_PHASE_MASK;
741
742
743 res = nsp_fifo_count(SCpnt) - ocount;
744 //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);
745 if (res == 0) { /* if some data avilable ? */
746 if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
747 //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
748 continue;
749 } else {
750 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
751 break;
752 }
753 }
754
755 fifo_stat = nsp_read(base, FIFOSTATUS);
756 if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
757 stat == BUSPHASE_DATA_IN) {
758 continue;
759 }
760
761 res = min(res, SCpnt->SCp.this_residual);
762
763 switch (data->TransferMode) {
764 case MODE_IO32:
765 res &= ~(BIT(1)|BIT(0)); /* align 4 */
766 nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
767 break;
768 case MODE_IO8:
769 nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
770 break;
771
772 case MODE_MEM32:
773 res &= ~(BIT(1)|BIT(0)); /* align 4 */
774 nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
775 break;
776
777 default:
778 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
779 return;
780 }
781
Boaz Harrosh040cd232007-08-16 13:01:05 +0300782 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 SCpnt->SCp.ptr += res;
784 SCpnt->SCp.this_residual -= res;
785 ocount += res;
786 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
787
788 /* go to next scatter list if available */
789 if (SCpnt->SCp.this_residual == 0 &&
790 SCpnt->SCp.buffers_residual != 0 ) {
791 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
792 SCpnt->SCp.buffers_residual--;
793 SCpnt->SCp.buffer++;
794 SCpnt->SCp.ptr = BUFFER_ADDR;
795 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
796 time_out = 1000;
797
798 //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
799 }
800 }
801
802 data->FifoCount = ocount;
803
804 if (time_out == 0) {
805 nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300806 scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
807 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
809 nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300810 nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
811 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812}
813
814/*
815 * write data in DATA OUT phase
816 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700817static void nsp_pio_write(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 unsigned int base = SCpnt->device->host->io_port;
820 unsigned long mmio_base = SCpnt->device->host->base;
821 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
822 int time_out;
823 int ocount, res;
824 unsigned char stat;
825
826 ocount = data->FifoCount;
827
828 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 +0300829 data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
830 SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
831 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833 time_out = 1000;
834
835 while ((time_out-- != 0) &&
836 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
837 stat = nsp_index_read(base, SCSIBUSMON);
838 stat &= BUSMON_PHASE_MASK;
839
840 if (stat != BUSPHASE_DATA_OUT) {
841 res = ocount - nsp_fifo_count(SCpnt);
842
843 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
844 /* Put back pointer */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300845 nsp_inc_resid(SCpnt, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 SCpnt->SCp.ptr -= res;
847 SCpnt->SCp.this_residual += res;
848 ocount -= res;
849
850 break;
851 }
852
853 res = ocount - nsp_fifo_count(SCpnt);
854 if (res > 0) { /* write all data? */
855 nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
856 continue;
857 }
858
859 res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
860
861 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
862 switch (data->TransferMode) {
863 case MODE_IO32:
864 res &= ~(BIT(1)|BIT(0)); /* align 4 */
865 nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
866 break;
867 case MODE_IO8:
868 nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
869 break;
870
871 case MODE_MEM32:
872 res &= ~(BIT(1)|BIT(0)); /* align 4 */
873 nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
874 break;
875
876 default:
877 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
878 break;
879 }
880
Boaz Harrosh040cd232007-08-16 13:01:05 +0300881 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 SCpnt->SCp.ptr += res;
883 SCpnt->SCp.this_residual -= res;
884 ocount += res;
885
886 /* go to next scatter list if available */
887 if (SCpnt->SCp.this_residual == 0 &&
888 SCpnt->SCp.buffers_residual != 0 ) {
889 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
890 SCpnt->SCp.buffers_residual--;
891 SCpnt->SCp.buffer++;
892 SCpnt->SCp.ptr = BUFFER_ADDR;
893 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
894 time_out = 1000;
895 }
896 }
897
898 data->FifoCount = ocount;
899
900 if (time_out == 0) {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300901 nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
902 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300905 nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
906 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908#undef RFIFO_CRIT
909#undef WFIFO_CRIT
910
911/*
912 * setup synchronous/asynchronous data transfer mode
913 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700914static int nsp_nexus(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915{
916 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400917 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918// unsigned char lun = SCpnt->device->lun;
919 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
920 sync_data *sync = &(data->Sync[target]);
921
922 //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
923
924 /* setup synch transfer registers */
925 nsp_index_write(base, SYNCREG, sync->SyncRegister);
926 nsp_index_write(base, ACKWIDTH, sync->AckWidth);
927
Boaz Harrosh040cd232007-08-16 13:01:05 +0300928 if (scsi_get_resid(SCpnt) % 4 != 0 ||
929 scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 data->TransferMode = MODE_IO8;
931 } else if (nsp_burst_mode == BURST_MEM32) {
932 data->TransferMode = MODE_MEM32;
933 } else if (nsp_burst_mode == BURST_IO32) {
934 data->TransferMode = MODE_IO32;
935 } else {
936 data->TransferMode = MODE_IO8;
937 }
938
939 /* setup pdma fifo */
940 nsp_setup_fifo(data, TRUE);
941
942 /* clear ack counter */
943 data->FifoCount = 0;
944 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
945 ACK_COUNTER_CLEAR |
946 REQ_COUNTER_CLEAR |
947 HOST_COUNTER_CLEAR);
948
949 return 0;
950}
951
952#include "nsp_message.c"
953/*
954 * interrupt handler
955 */
David Howells7d12e782006-10-05 14:55:46 +0100956static irqreturn_t nspintr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957{
958 unsigned int base;
959 unsigned char irq_status, irq_phase, phase;
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700960 struct scsi_cmnd *tmpSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 unsigned char target, lun;
962 unsigned int *sync_neg;
963 int i, tmp;
964 nsp_hw_data *data;
965
966
967 //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
968 //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
969
970 if ( dev_id != NULL &&
971 ((scsi_info_t *)dev_id)->host != NULL ) {
972 scsi_info_t *info = (scsi_info_t *)dev_id;
973
974 data = (nsp_hw_data *)info->host->hostdata;
975 } else {
976 nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
977 return IRQ_NONE;
978 }
979
980 //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
981
982 base = data->BaseAddress;
983 //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
984
985 /*
986 * interrupt check
987 */
988 nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
989 irq_status = nsp_read(base, IRQSTATUS);
990 //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
991 if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
992 nsp_write(base, IRQCONTROL, 0);
993 //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
994 return IRQ_NONE;
995 }
996
997 /* XXX: IMPORTANT
998 * Do not read an irq_phase register if no scsi phase interrupt.
999 * Unless, you should lose a scsi phase interrupt.
1000 */
1001 phase = nsp_index_read(base, SCSIBUSMON);
1002 if((irq_status & IRQSTATUS_SCSI) != 0) {
1003 irq_phase = nsp_index_read(base, IRQPHASESENCE);
1004 } else {
1005 irq_phase = 0;
1006 }
1007
1008 //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1009
1010 /*
1011 * timer interrupt handler (scsi vs timer interrupts)
1012 */
1013 //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1014 if (data->TimerCount != 0) {
1015 //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1016 nsp_index_write(base, TIMERCOUNT, 0);
1017 nsp_index_write(base, TIMERCOUNT, 0);
1018 data->TimerCount = 0;
1019 }
1020
1021 if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1022 data->SelectionTimeOut == 0) {
1023 //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1024 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1025 return IRQ_HANDLED;
1026 }
1027
1028 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1029
1030 if ((irq_status & IRQSTATUS_SCSI) &&
1031 (irq_phase & SCSI_RESET_IRQ)) {
1032 nsp_msg(KERN_ERR, "bus reset (power off?)");
1033
1034 nsphw_init(data);
1035 nsp_bus_reset(data);
1036
1037 if(data->CurrentSC != NULL) {
1038 tmpSC = data->CurrentSC;
1039 tmpSC->result = (DID_RESET << 16) |
1040 ((tmpSC->SCp.Message & 0xff) << 8) |
1041 ((tmpSC->SCp.Status & 0xff) << 0);
1042 nsp_scsi_done(tmpSC);
1043 }
1044 return IRQ_HANDLED;
1045 }
1046
1047 if (data->CurrentSC == NULL) {
1048 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);
1049 nsphw_init(data);
1050 nsp_bus_reset(data);
1051 return IRQ_HANDLED;
1052 }
1053
1054 tmpSC = data->CurrentSC;
1055 target = tmpSC->device->id;
1056 lun = tmpSC->device->lun;
1057 sync_neg = &(data->Sync[target].SyncNegotiation);
1058
1059 /*
1060 * parse hardware SCSI irq reasons register
1061 */
1062 if (irq_status & IRQSTATUS_SCSI) {
1063 if (irq_phase & RESELECT_IRQ) {
1064 nsp_dbg(NSP_DEBUG_INTR, "reselect");
1065 nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1066 if (nsp_reselected(tmpSC) != FALSE) {
1067 return IRQ_HANDLED;
1068 }
1069 }
1070
1071 if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1072 return IRQ_HANDLED;
1073 }
1074 }
1075
1076 //show_phase(tmpSC);
1077
1078 switch(tmpSC->SCp.phase) {
1079 case PH_SELSTART:
1080 // *sync_neg = SYNC_NOT_YET;
1081 if ((phase & BUSMON_BSY) == 0) {
1082 //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1083 if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1084 nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1085 data->SelectionTimeOut = 0;
1086 nsp_index_write(base, SCSIBUSCTRL, 0);
1087
1088 tmpSC->result = DID_TIME_OUT << 16;
1089 nsp_scsi_done(tmpSC);
1090
1091 return IRQ_HANDLED;
1092 }
1093 data->SelectionTimeOut += 1;
1094 nsp_start_timer(tmpSC, 1000/51);
1095 return IRQ_HANDLED;
1096 }
1097
1098 /* attention assert */
1099 //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1100 data->SelectionTimeOut = 0;
1101 tmpSC->SCp.phase = PH_SELECTED;
1102 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1103 udelay(1);
1104 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1105 return IRQ_HANDLED;
1106
1107 break;
1108
1109 case PH_RESELECT:
1110 //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1111 // *sync_neg = SYNC_NOT_YET;
1112 if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1113
1114 tmpSC->result = DID_ABORT << 16;
1115 nsp_scsi_done(tmpSC);
1116 return IRQ_HANDLED;
1117 }
1118 /* fall thru */
1119 default:
1120 if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1121 return IRQ_HANDLED;
1122 }
1123 break;
1124 }
1125
1126 /*
1127 * SCSI sequencer
1128 */
1129 //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1130
1131 /* normal disconnect */
1132 if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1133 (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1134 nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1135
1136 //*sync_neg = SYNC_NOT_YET;
1137
1138 if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
1139 tmpSC->result = (DID_OK << 16) |
1140 ((tmpSC->SCp.Message & 0xff) << 8) |
1141 ((tmpSC->SCp.Status & 0xff) << 0);
1142 nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1143 nsp_scsi_done(tmpSC);
1144
1145 return IRQ_HANDLED;
1146 }
1147
1148 return IRQ_HANDLED;
1149 }
1150
1151
1152 /* check unexpected bus free state */
1153 if (phase == 0) {
1154 nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1155
1156 *sync_neg = SYNC_NG;
1157 tmpSC->result = DID_ERROR << 16;
1158 nsp_scsi_done(tmpSC);
1159 return IRQ_HANDLED;
1160 }
1161
1162 switch (phase & BUSMON_PHASE_MASK) {
1163 case BUSPHASE_COMMAND:
1164 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1165 if ((phase & BUSMON_REQ) == 0) {
1166 nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1167 return IRQ_HANDLED;
1168 }
1169
1170 tmpSC->SCp.phase = PH_COMMAND;
1171
1172 nsp_nexus(tmpSC);
1173
1174 /* write scsi command */
1175 nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1176 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1177 for (i = 0; i < tmpSC->cmd_len; i++) {
1178 nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1179 }
1180 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1181 break;
1182
1183 case BUSPHASE_DATA_OUT:
1184 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1185
1186 tmpSC->SCp.phase = PH_DATA;
1187 tmpSC->SCp.have_data_in = IO_OUT;
1188
1189 nsp_pio_write(tmpSC);
1190
1191 break;
1192
1193 case BUSPHASE_DATA_IN:
1194 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1195
1196 tmpSC->SCp.phase = PH_DATA;
1197 tmpSC->SCp.have_data_in = IO_IN;
1198
1199 nsp_pio_read(tmpSC);
1200
1201 break;
1202
1203 case BUSPHASE_STATUS:
1204 nsp_dataphase_bypass(tmpSC);
1205 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1206
1207 tmpSC->SCp.phase = PH_STATUS;
1208
1209 tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1210 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1211
1212 break;
1213
1214 case BUSPHASE_MESSAGE_OUT:
1215 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1216 if ((phase & BUSMON_REQ) == 0) {
1217 goto timer_out;
1218 }
1219
1220 tmpSC->SCp.phase = PH_MSG_OUT;
1221
1222 //*sync_neg = SYNC_NOT_YET;
1223
1224 data->MsgLen = i = 0;
1225 data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1226
1227 if (*sync_neg == SYNC_NOT_YET) {
1228 data->Sync[target].SyncPeriod = 0;
1229 data->Sync[target].SyncOffset = 0;
1230
1231 /**/
1232 data->MsgBuffer[i] = MSG_EXTENDED; i++;
1233 data->MsgBuffer[i] = 3; i++;
1234 data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1235 data->MsgBuffer[i] = 0x0c; i++;
1236 data->MsgBuffer[i] = 15; i++;
1237 /**/
1238 }
1239 data->MsgLen = i;
1240
1241 nsp_analyze_sdtr(tmpSC);
1242 show_message(data);
1243 nsp_message_out(tmpSC);
1244 break;
1245
1246 case BUSPHASE_MESSAGE_IN:
1247 nsp_dataphase_bypass(tmpSC);
1248 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1249 if ((phase & BUSMON_REQ) == 0) {
1250 goto timer_out;
1251 }
1252
1253 tmpSC->SCp.phase = PH_MSG_IN;
1254 nsp_message_in(tmpSC);
1255
1256 /**/
1257 if (*sync_neg == SYNC_NOT_YET) {
1258 //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1259
1260 if (data->MsgLen >= 5 &&
1261 data->MsgBuffer[0] == MSG_EXTENDED &&
1262 data->MsgBuffer[1] == 3 &&
1263 data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1264 data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1265 data->Sync[target].SyncOffset = data->MsgBuffer[4];
1266 //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1267 *sync_neg = SYNC_OK;
1268 } else {
1269 data->Sync[target].SyncPeriod = 0;
1270 data->Sync[target].SyncOffset = 0;
1271 *sync_neg = SYNC_NG;
1272 }
1273 nsp_analyze_sdtr(tmpSC);
1274 }
1275 /**/
1276
1277 /* search last messeage byte */
1278 tmp = -1;
1279 for (i = 0; i < data->MsgLen; i++) {
1280 tmp = data->MsgBuffer[i];
1281 if (data->MsgBuffer[i] == MSG_EXTENDED) {
1282 i += (1 + data->MsgBuffer[i+1]);
1283 }
1284 }
1285 tmpSC->SCp.Message = tmp;
1286
1287 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1288 show_message(data);
1289
1290 break;
1291
1292 case BUSPHASE_SELECT:
1293 default:
1294 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1295
1296 break;
1297 }
1298
1299 //nsp_dbg(NSP_DEBUG_INTR, "out");
1300 return IRQ_HANDLED;
1301
1302timer_out:
1303 nsp_start_timer(tmpSC, 1000/102);
1304 return IRQ_HANDLED;
1305}
1306
1307#ifdef NSP_DEBUG
1308#include "nsp_debug.c"
1309#endif /* NSP_DEBUG */
1310
1311/*----------------------------------------------------------------*/
1312/* look for ninja3 card and init if found */
1313/*----------------------------------------------------------------*/
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001314static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315{
1316 struct Scsi_Host *host; /* registered host structure */
1317 nsp_hw_data *data_b = &nsp_data_base, *data;
1318
1319 nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 if (host == NULL) {
1322 nsp_dbg(NSP_DEBUG_INIT, "host failed");
1323 return NULL;
1324 }
1325
1326 memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1327 data = (nsp_hw_data *)host->hostdata;
1328 data->ScsiInfo->host = host;
1329#ifdef NSP_DEBUG
1330 data->CmdId = 0;
1331#endif
1332
1333 nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1334
1335 host->unique_id = data->BaseAddress;
1336 host->io_port = data->BaseAddress;
1337 host->n_io_port = data->NumAddress;
1338 host->irq = data->IrqNumber;
1339 host->base = data->MmioAddress;
1340
1341 spin_lock_init(&(data->Lock));
1342
1343 snprintf(data->nspinfo,
1344 sizeof(data->nspinfo),
1345 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1346 host->io_port, host->io_port + host->n_io_port - 1,
1347 host->base,
1348 host->irq);
1349 sht->name = data->nspinfo;
1350
1351 nsp_dbg(NSP_DEBUG_INIT, "end");
1352
1353
1354 return host; /* detect done. */
1355}
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357/*----------------------------------------------------------------*/
1358/* return info string */
1359/*----------------------------------------------------------------*/
1360static const char *nsp_info(struct Scsi_Host *shpnt)
1361{
1362 nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1363
1364 return data->nspinfo;
1365}
1366
1367#undef SPRINTF
1368#define SPRINTF(args...) \
1369 do { \
1370 if(length > (pos - buffer)) { \
1371 pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
1372 nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
1373 } \
1374 } while(0)
Adrian Bunk774251e2007-10-02 14:38:01 -07001375
1376static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
1377 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
1379 int id;
1380 char *pos = buffer;
1381 int thislength;
1382 int speed;
1383 unsigned long flags;
1384 nsp_hw_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 int hostno;
Adrian Bunk774251e2007-10-02 14:38:01 -07001386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 if (inout) {
1388 return -EINVAL;
1389 }
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 hostno = host->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 data = (nsp_hw_data *)host->hostdata;
1393
1394
1395 SPRINTF("NinjaSCSI status\n\n");
1396 SPRINTF("Driver version: $Revision: 1.23 $\n");
1397 SPRINTF("SCSI host No.: %d\n", hostno);
1398 SPRINTF("IRQ: %d\n", host->irq);
1399 SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1400 SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1401 SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
1402
1403 SPRINTF("burst transfer mode: ");
1404 switch (nsp_burst_mode) {
1405 case BURST_IO8:
1406 SPRINTF("io8");
1407 break;
1408 case BURST_IO32:
1409 SPRINTF("io32");
1410 break;
1411 case BURST_MEM32:
1412 SPRINTF("mem32");
1413 break;
1414 default:
1415 SPRINTF("???");
1416 break;
1417 }
1418 SPRINTF("\n");
1419
1420
1421 spin_lock_irqsave(&(data->Lock), flags);
1422 SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
1423 spin_unlock_irqrestore(&(data->Lock), flags);
1424
1425 SPRINTF("SDTR status\n");
1426 for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1427
1428 SPRINTF("id %d: ", id);
1429
1430 if (id == host->this_id) {
1431 SPRINTF("----- NinjaSCSI-3 host adapter\n");
1432 continue;
1433 }
1434
1435 switch(data->Sync[id].SyncNegotiation) {
1436 case SYNC_OK:
1437 SPRINTF(" sync");
1438 break;
1439 case SYNC_NG:
1440 SPRINTF("async");
1441 break;
1442 case SYNC_NOT_YET:
1443 SPRINTF(" none");
1444 break;
1445 default:
1446 SPRINTF("?????");
1447 break;
1448 }
1449
1450 if (data->Sync[id].SyncPeriod != 0) {
1451 speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1452
1453 SPRINTF(" transfer %d.%dMB/s, offset %d",
1454 speed / 1000,
1455 speed % 1000,
1456 data->Sync[id].SyncOffset
1457 );
1458 }
1459 SPRINTF("\n");
1460 }
1461
1462 thislength = pos - (buffer + offset);
1463
1464 if(thislength < 0) {
1465 *start = NULL;
1466 return 0;
1467 }
1468
1469
1470 thislength = min(thislength, length);
1471 *start = buffer + offset;
1472
1473 return thislength;
1474}
1475#undef SPRINTF
1476
1477/*---------------------------------------------------------------*/
1478/* error handler */
1479/*---------------------------------------------------------------*/
1480
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481/*
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001482static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1485
1486 return nsp_eh_bus_reset(SCpnt);
1487}*/
1488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489static int nsp_bus_reset(nsp_hw_data *data)
1490{
1491 unsigned int base = data->BaseAddress;
1492 int i;
1493
1494 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1495
1496 nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1497 mdelay(100); /* 100ms */
1498 nsp_index_write(base, SCSIBUSCTRL, 0);
1499 for(i = 0; i < 5; i++) {
1500 nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1501 }
1502
1503 nsphw_init_sync(data);
1504
1505 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1506
1507 return SUCCESS;
1508}
1509
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001510static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1513
1514 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1515
1516 return nsp_bus_reset(data);
1517}
1518
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001519static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520{
1521 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1522
1523 nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1524
1525 nsphw_init(data);
1526
1527 return SUCCESS;
1528}
1529
1530
1531/**********************************************************************
1532 PCMCIA functions
1533**********************************************************************/
1534
1535/*======================================================================
1536 nsp_cs_attach() creates an "instance" of the driver, allocating
1537 local data structures for one device. The device is registered
1538 with Card Services.
1539
1540 The dev_link structure is initialized, but we don't actually
1541 configure the card at this point -- we wait until we receive a
1542 card insertion event.
1543======================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001544static int nsp_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 nsp_hw_data *data = &nsp_data_base;
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001548 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 nsp_dbg(NSP_DEBUG_INIT, "in");
1551
1552 /* Create new SCSI device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001553 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001554 if (info == NULL) { return -ENOMEM; }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001555 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 link->priv = info;
1557 data->ScsiInfo = info;
1558
1559 nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1560
1561 /* The io structure describes IO port mapping */
1562 link->io.NumPorts1 = 0x10;
1563 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1564 link->io.IOAddrLines = 10; /* not used */
1565
1566 /* Interrupt setup */
1567 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
1568 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
1569
1570 /* Interrupt handler */
1571 link->irq.Handler = &nspintr;
1572 link->irq.Instance = info;
James Bottomleyc4e00fa2006-07-03 09:41:12 -05001573 link->irq.Attributes |= IRQF_SHARED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /* General socket configuration */
1576 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 link->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001579 ret = nsp_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001582 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583} /* nsp_cs_attach */
1584
1585
1586/*======================================================================
1587 This deletes a driver "instance". The device is de-registered
1588 with Card Services. If it has been released, all local data
1589 structures are freed. Otherwise, the structures will be freed
1590 when the device is released.
1591======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001592static void nsp_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1595
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001596 ((scsi_info_t *)link->priv)->stop = 1;
1597 nsp_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 kfree(link->priv);
1600 link->priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601} /* nsp_cs_detach */
1602
1603
1604/*======================================================================
1605 nsp_cs_config() is scheduled to run after a CARD_INSERTION event
1606 is received, to configure the PCMCIA socket, and to make the
1607 ethernet device available to the system.
1608======================================================================*/
1609#define CS_CHECK(fn, ret) \
1610do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
1611/*====================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001612static int nsp_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001614 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 scsi_info_t *info = link->priv;
1616 tuple_t tuple;
1617 cisparse_t parse;
1618 int last_ret, last_fn;
1619 unsigned char tuple_data[64];
1620 config_info_t conf;
1621 win_req_t req;
1622 memreq_t map;
1623 cistpl_cftable_entry_t dflt = { 0 };
1624 struct Scsi_Host *host;
1625 nsp_hw_data *data = &nsp_data_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 nsp_dbg(NSP_DEBUG_INIT, "in");
1628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 tuple.Attributes = 0;
1630 tuple.TupleData = tuple_data;
1631 tuple.TupleDataMax = sizeof(tuple_data);
1632 tuple.TupleOffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 /* Look up the current Vcc */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001635 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001638 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 while (1) {
1640 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
1641
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001642 if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
1643 pcmcia_parse_tuple(link, &tuple, &parse) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 goto next_entry;
1645
1646 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
1647 if (cfg->index == 0) { goto next_entry; }
1648 link->conf.ConfigIndex = cfg->index;
1649
1650 /* Does this card need audio output? */
1651 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
1652 link->conf.Attributes |= CONF_ENABLE_SPKR;
1653 link->conf.Status = CCSR_AUDIO_ENA;
1654 }
1655
1656 /* Use power settings for Vcc and Vpp if present */
1657 /* Note that the CIS values need to be rescaled */
1658 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
1659 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
1660 goto next_entry;
1661 }
1662 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
1663 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
1664 goto next_entry;
1665 }
1666 }
1667
1668 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001669 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
1671 } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001672 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
1674 }
1675
1676 /* Do we need to allocate an interrupt? */
1677 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
1678 link->conf.Attributes |= CONF_ENABLE_IRQ;
1679 }
1680
1681 /* IO window settings */
1682 link->io.NumPorts1 = link->io.NumPorts2 = 0;
1683 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
1684 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
1685 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1686 if (!(io->flags & CISTPL_IO_8BIT))
1687 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
1688 if (!(io->flags & CISTPL_IO_16BIT))
1689 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
1690 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
1691 link->io.BasePort1 = io->win[0].base;
1692 link->io.NumPorts1 = io->win[0].len;
1693 if (io->nwin > 1) {
1694 link->io.Attributes2 = link->io.Attributes1;
1695 link->io.BasePort2 = io->win[1].base;
1696 link->io.NumPorts2 = io->win[1].len;
1697 }
1698 /* This reserves IO space but doesn't actually enable it */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001699 if (pcmcia_request_io(link, &link->io) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 goto next_entry;
1701 }
1702
1703 if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
1704 cistpl_mem_t *mem =
1705 (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
1706 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
1707 req.Attributes |= WIN_ENABLE;
1708 req.Base = mem->win[0].host_addr;
1709 req.Size = mem->win[0].len;
1710 if (req.Size < 0x1000) {
1711 req.Size = 0x1000;
1712 }
1713 req.AccessSpeed = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001714 if (pcmcia_request_window(&link, &req, &link->win) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 goto next_entry;
1716 map.Page = 0; map.CardOffset = mem->win[0].card_addr;
1717 if (pcmcia_map_mem_page(link->win, &map) != 0)
1718 goto next_entry;
1719
1720 data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
1721 data->MmioLength = req.Size;
1722 }
1723 /* If we got this far, we're cool! */
1724 break;
1725
1726 next_entry:
1727 nsp_dbg(NSP_DEBUG_INIT, "next");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001728 pcmcia_disable_device(link);
1729 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
1731
1732 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001733 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001735 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737 if (free_ports) {
1738 if (link->io.BasePort1) {
1739 release_region(link->io.BasePort1, link->io.NumPorts1);
1740 }
1741 if (link->io.BasePort2) {
1742 release_region(link->io.BasePort2, link->io.NumPorts2);
1743 }
1744 }
1745
1746 /* Set port and IRQ */
1747 data->BaseAddress = link->io.BasePort1;
1748 data->NumAddress = link->io.NumPorts1;
1749 data->IrqNumber = link->irq.AssignedIRQ;
1750
1751 nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1752 data->BaseAddress, data->NumAddress, data->IrqNumber);
1753
1754 if(nsphw_init(data) == FALSE) {
1755 goto cs_failed;
1756 }
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 host = nsp_detect(&nsp_driver_template);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 if (host == NULL) {
1761 nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1762 goto cs_failed;
1763 }
1764
1765
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001766 ret = scsi_add_host (host, NULL);
1767 if (ret)
1768 goto cs_failed;
1769
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 scsi_scan_host(host);
1771
1772 snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
Dominik Brodowskifd238232006-03-05 10:45:09 +01001773 link->dev_node = &info->node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 info->host = host;
1775
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 /* Finally, report what we've done */
Dominik Brodowski70294b42006-01-15 12:43:16 +01001777 printk(KERN_INFO "nsp_cs: index 0x%02x: ",
1778 link->conf.ConfigIndex);
1779 if (link->conf.Vpp) {
1780 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 }
1782 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
1783 printk(", irq %d", link->irq.AssignedIRQ);
1784 }
1785 if (link->io.NumPorts1) {
1786 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
1787 link->io.BasePort1+link->io.NumPorts1-1);
1788 }
1789 if (link->io.NumPorts2)
1790 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
1791 link->io.BasePort2+link->io.NumPorts2-1);
1792 if (link->win)
1793 printk(", mem 0x%06lx-0x%06lx", req.Base,
1794 req.Base+req.Size-1);
1795 printk("\n");
1796
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
1799 cs_failed:
1800 nsp_dbg(NSP_DEBUG_INIT, "config fail");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001801 cs_error(link, last_fn, last_ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 nsp_cs_release(link);
1803
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001804 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805} /* nsp_cs_config */
1806#undef CS_CHECK
1807
1808
1809/*======================================================================
1810 After a card is removed, nsp_cs_release() will unregister the net
1811 device, and release the PCMCIA configuration. If the device is
1812 still open, this will be postponed until it is closed.
1813======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001814static void nsp_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815{
1816 scsi_info_t *info = link->priv;
1817 nsp_hw_data *data = NULL;
1818
1819 if (info->host == NULL) {
1820 nsp_msg(KERN_DEBUG, "unexpected card release call.");
1821 } else {
1822 data = (nsp_hw_data *)info->host->hostdata;
1823 }
1824
1825 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1826
1827 /* Unlink the device chain */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (info->host != NULL) {
1829 scsi_remove_host(info->host);
1830 }
Dominik Brodowskifd238232006-03-05 10:45:09 +01001831 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
1833 if (link->win) {
1834 if (data != NULL) {
1835 iounmap((void *)(data->MmioAddress));
1836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001838 pcmcia_disable_device(link);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 if (info->host != NULL) {
1841 scsi_host_put(info->host);
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843} /* nsp_cs_release */
1844
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001845static int nsp_cs_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001846{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001847 scsi_info_t *info = link->priv;
1848 nsp_hw_data *data;
1849
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001850 nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1851
1852 if (info->host != NULL) {
1853 nsp_msg(KERN_INFO, "clear SDTR status");
1854
1855 data = (nsp_hw_data *)info->host->hostdata;
1856
1857 nsphw_init_sync(data);
1858 }
1859
1860 info->stop = 1;
1861
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001862 return 0;
1863}
1864
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001865static int nsp_cs_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001866{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001867 scsi_info_t *info = link->priv;
1868 nsp_hw_data *data;
1869
1870 nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1871
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001872 info->stop = 0;
1873
1874 if (info->host != NULL) {
1875 nsp_msg(KERN_INFO, "reset host and bus");
1876
1877 data = (nsp_hw_data *)info->host->hostdata;
1878
1879 nsphw_init (data);
1880 nsp_bus_reset(data);
1881 }
1882
1883 return 0;
1884}
1885
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886/*======================================================================*
1887 * module entry point
1888 *====================================================================*/
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001889static struct pcmcia_device_id nsp_cs_ids[] = {
1890 PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1891 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1892 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1893 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1894 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1895 PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1896 PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1897 PCMCIA_DEVICE_NULL
1898};
1899MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1900
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901static struct pcmcia_driver nsp_driver = {
Dominik Brodowski1e212f32005-07-07 17:59:00 -07001902 .owner = THIS_MODULE,
1903 .drv = {
1904 .name = "nsp_cs",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001906 .probe = nsp_cs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01001907 .remove = nsp_cs_detach,
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001908 .id_table = nsp_cs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001909 .suspend = nsp_cs_suspend,
1910 .resume = nsp_cs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913static int __init nsp_cs_init(void)
1914{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 nsp_msg(KERN_INFO, "loading...");
1916
1917 return pcmcia_register_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918}
1919
1920static void __exit nsp_cs_exit(void)
1921{
1922 nsp_msg(KERN_INFO, "unloading...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 pcmcia_unregister_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924}
1925
1926
1927module_init(nsp_cs_init)
1928module_exit(nsp_cs_exit)
1929
1930/* end */