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