blob: a45d89b14147576fac94963774c4ec1241f15183 [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
138static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
139{
140 va_list args;
141 char buf[NSP_DEBUG_BUF_LEN];
142
143 va_start(args, fmt);
144 vsnprintf(buf, sizeof(buf), fmt, args);
145 va_end(args);
146
147#ifndef NSP_DEBUG
148 printk("%snsp_cs: %s\n", type, buf);
149#else
150 printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
151#endif
152}
153
154#ifdef NSP_DEBUG
155static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
156{
157 va_list args;
158 char buf[NSP_DEBUG_BUF_LEN];
159
160 va_start(args, fmt);
161 vsnprintf(buf, sizeof(buf), fmt, args);
162 va_end(args);
163
164 if (mask & NSP_DEBUG_MASK) {
165 printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
166 }
167}
168#endif
169
170/***********************************************************/
171
172/*====================================================
173 * Clenaup parameters and call done() functions.
174 * You must be set SCpnt->result before call this function.
175 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700176static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
179
180 data->CurrentSC = NULL;
181
182 SCpnt->scsi_done(SCpnt);
183}
184
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700185static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
186 void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188#ifdef NSP_DEBUG
189 /*unsigned int host_id = SCpnt->device->host->this_id;*/
190 /*unsigned int base = SCpnt->device->host->io_port;*/
Jeff Garzik422c0d62005-10-24 18:05:09 -0400191 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#endif
193 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
194
195 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
196 SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
197 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
198
199 SCpnt->scsi_done = done;
200
201 if (data->CurrentSC != NULL) {
202 nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
203 SCpnt->result = DID_BAD_TARGET << 16;
204 nsp_scsi_done(SCpnt);
205 return 0;
206 }
207
208#if 0
209 /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
210 This makes kernel crash when suspending... */
211 if (data->ScsiInfo->stop != 0) {
212 nsp_msg(KERN_INFO, "suspending device. reject command.");
213 SCpnt->result = DID_BAD_TARGET << 16;
214 nsp_scsi_done(SCpnt);
215 return SCSI_MLQUEUE_HOST_BUSY;
216 }
217#endif
218
219 show_command(SCpnt);
220
221 data->CurrentSC = SCpnt;
222
223 SCpnt->SCp.Status = CHECK_CONDITION;
224 SCpnt->SCp.Message = 0;
225 SCpnt->SCp.have_data_in = IO_UNKNOWN;
226 SCpnt->SCp.sent_command = 0;
227 SCpnt->SCp.phase = PH_UNDETERMINED;
228 SCpnt->resid = SCpnt->request_bufflen;
229
230 /* setup scratch area
231 SCp.ptr : buffer pointer
232 SCp.this_residual : buffer length
233 SCp.buffer : next buffer
234 SCp.buffers_residual : left buffers in list
235 SCp.phase : current state of the command */
236 if (SCpnt->use_sg) {
237 SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
238 SCpnt->SCp.ptr = BUFFER_ADDR;
239 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
240 SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
241 } else {
242 SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
243 SCpnt->SCp.this_residual = SCpnt->request_bufflen;
244 SCpnt->SCp.buffer = NULL;
245 SCpnt->SCp.buffers_residual = 0;
246 }
247
248 if (nsphw_start_selection(SCpnt) == FALSE) {
249 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
250 SCpnt->result = DID_BUS_BUSY << 16;
251 nsp_scsi_done(SCpnt);
252 return 0;
253 }
254
255
256 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
257#ifdef NSP_DEBUG
258 data->CmdId++;
259#endif
260 return 0;
261}
262
263/*
264 * setup PIO FIFO transfer mode and enable/disable to data out
265 */
266static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
267{
268 unsigned int base = data->BaseAddress;
269 unsigned char transfer_mode_reg;
270
271 //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
272
273 if (enabled != FALSE) {
274 transfer_mode_reg = TRANSFER_GO | BRAIND;
275 } else {
276 transfer_mode_reg = 0;
277 }
278
279 transfer_mode_reg |= data->TransferMode;
280
281 nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
282}
283
284static void nsphw_init_sync(nsp_hw_data *data)
285{
286 sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
287 .SyncPeriod = 0,
288 .SyncOffset = 0
289 };
290 int i;
291
292 /* setup sync data */
293 for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
294 data->Sync[i] = tmp_sync;
295 }
296}
297
298/*
299 * Initialize Ninja hardware
300 */
301static int nsphw_init(nsp_hw_data *data)
302{
303 unsigned int base = data->BaseAddress;
304
305 nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
306
307 data->ScsiClockDiv = CLOCK_40M | FAST_20;
308 data->CurrentSC = NULL;
309 data->FifoCount = 0;
310 data->TransferMode = MODE_IO8;
311
312 nsphw_init_sync(data);
313
314 /* block all interrupts */
315 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
316
317 /* setup SCSI interface */
318 nsp_write(base, IFSELECT, IF_IFSEL);
319
320 nsp_index_write(base, SCSIIRQMODE, 0);
321
322 nsp_index_write(base, TRANSFERMODE, MODE_IO8);
323 nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
324
325 nsp_index_write(base, PARITYCTRL, 0);
326 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
327 ACK_COUNTER_CLEAR |
328 REQ_COUNTER_CLEAR |
329 HOST_COUNTER_CLEAR);
330
331 /* setup fifo asic */
332 nsp_write(base, IFSELECT, IF_REGSEL);
333 nsp_index_write(base, TERMPWRCTRL, 0);
334 if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
335 nsp_msg(KERN_INFO, "terminator power on");
336 nsp_index_write(base, TERMPWRCTRL, POWER_ON);
337 }
338
339 nsp_index_write(base, TIMERCOUNT, 0);
340 nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
341
342 nsp_index_write(base, SYNCREG, 0);
343 nsp_index_write(base, ACKWIDTH, 0);
344
345 /* enable interrupts and ack them */
346 nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
347 RESELECT_EI |
348 SCSI_RESET_IRQ_EI );
349 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
350
351 nsp_setup_fifo(data, FALSE);
352
353 return TRUE;
354}
355
356/*
357 * Start selection phase
358 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700359static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 unsigned int host_id = SCpnt->device->host->this_id;
362 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400363 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
365 int time_out;
366 unsigned char phase, arbit;
367
368 //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
369
370 phase = nsp_index_read(base, SCSIBUSMON);
371 if(phase != BUSMON_BUS_FREE) {
372 //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
373 return FALSE;
374 }
375
376 /* start arbitration */
377 //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
378 SCpnt->SCp.phase = PH_ARBSTART;
379 nsp_index_write(base, SETARBIT, ARBIT_GO);
380
381 time_out = 1000;
382 do {
383 /* XXX: what a stupid chip! */
384 arbit = nsp_index_read(base, ARBITSTATUS);
385 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
386 udelay(1); /* hold 1.2us */
387 } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
388 (time_out-- != 0));
389
390 if (!(arbit & ARBIT_WIN)) {
391 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
392 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
393 return FALSE;
394 }
395
396 /* assert select line */
397 //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
398 SCpnt->SCp.phase = PH_SELSTART;
399 udelay(3); /* wait 2.4us */
400 nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
401 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
402 udelay(2); /* wait >1.2us */
403 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
404 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
405 /*udelay(1);*/ /* wait >90ns */
406 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
407
408 /* check selection timeout */
409 nsp_start_timer(SCpnt, 1000/51);
410 data->SelectionTimeOut = 1;
411
412 return TRUE;
413}
414
415struct nsp_sync_table {
416 unsigned int min_period;
417 unsigned int max_period;
418 unsigned int chip_period;
419 unsigned int ack_width;
420};
421
422static struct nsp_sync_table nsp_sync_table_40M[] = {
423 {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
424 {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
425 {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
426 {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
427 { 0, 0, 0, 0},
428};
429
430static struct nsp_sync_table nsp_sync_table_20M[] = {
431 {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
432 {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
433 {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
434 { 0, 0, 0, 0},
435};
436
437/*
438 * setup synchronous data transfer mode
439 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700440static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
Jeff Garzik422c0d62005-10-24 18:05:09 -0400442 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443// unsigned char lun = SCpnt->device->lun;
444 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
445 sync_data *sync = &(data->Sync[target]);
446 struct nsp_sync_table *sync_table;
447 unsigned int period, offset;
448 int i;
449
450
451 nsp_dbg(NSP_DEBUG_SYNC, "in");
452
453 period = sync->SyncPeriod;
454 offset = sync->SyncOffset;
455
456 nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
457
458 if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
459 sync_table = nsp_sync_table_20M;
460 } else {
461 sync_table = nsp_sync_table_40M;
462 }
463
464 for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
465 if ( period >= sync_table->min_period &&
466 period <= sync_table->max_period ) {
467 break;
468 }
469 }
470
471 if (period != 0 && sync_table->max_period == 0) {
472 /*
473 * No proper period/offset found
474 */
475 nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
476
477 sync->SyncPeriod = 0;
478 sync->SyncOffset = 0;
479 sync->SyncRegister = 0;
480 sync->AckWidth = 0;
481
482 return FALSE;
483 }
484
485 sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
486 (offset & SYNCREG_OFFSET_MASK);
487 sync->AckWidth = sync_table->ack_width;
488
489 nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
490
491 return TRUE;
492}
493
494
495/*
496 * start ninja hardware timer
497 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700498static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 unsigned int base = SCpnt->device->host->io_port;
501 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
502
503 //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
504 data->TimerCount = time;
505 nsp_index_write(base, TIMERCOUNT, time);
506}
507
508/*
509 * wait for bus phase change
510 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700511static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
512 char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 unsigned int base = SCpnt->device->host->io_port;
515 unsigned char reg;
516 int time_out;
517
518 //nsp_dbg(NSP_DEBUG_INTR, "in");
519
520 time_out = 100;
521
522 do {
523 reg = nsp_index_read(base, SCSIBUSMON);
524 if (reg == 0xff) {
525 break;
526 }
527 } while ((time_out-- != 0) && (reg & mask) != 0);
528
529 if (time_out == 0) {
530 nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
531 }
532
533 return 0;
534}
535
536/*
537 * expect Ninja Irq
538 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700539static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
540 unsigned char current_phase,
541 unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 unsigned int base = SCpnt->device->host->io_port;
544 int time_out;
545 unsigned char phase, i_src;
546
547 //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
548
549 time_out = 100;
550 do {
551 phase = nsp_index_read(base, SCSIBUSMON);
552 if (phase == 0xff) {
553 //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
554 return -1;
555 }
556 i_src = nsp_read(base, IRQSTATUS);
557 if (i_src & IRQSTATUS_SCSI) {
558 //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
559 return 0;
560 }
561 if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
562 //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
563 return 1;
564 }
565 } while(time_out-- != 0);
566
567 //nsp_dbg(NSP_DEBUG_INTR, "timeout");
568 return -1;
569}
570
571/*
572 * transfer SCSI message
573 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700574static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 unsigned int base = SCpnt->device->host->io_port;
577 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
578 char *buf = data->MsgBuffer;
579 int len = min(MSGBUF_SIZE, data->MsgLen);
580 int ptr;
581 int ret;
582
583 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
584 for (ptr = 0; len > 0; len--, ptr++) {
585
586 ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
587 if (ret <= 0) {
588 nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
589 return 0;
590 }
591
592 /* if last byte, negate ATN */
593 if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
594 nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
595 }
596
597 /* read & write message */
598 if (phase & BUSMON_IO) {
599 nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
600 buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
601 } else {
602 nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
603 nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
604 }
605 nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
606
607 }
608 return len;
609}
610
611/*
612 * get extra SCSI data from fifo
613 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700614static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
616 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
617 unsigned int count;
618
619 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
620
621 if (SCpnt->SCp.have_data_in != IO_IN) {
622 return 0;
623 }
624
625 count = nsp_fifo_count(SCpnt);
626 if (data->FifoCount == count) {
627 //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
628 return 0;
629 }
630
631 /*
632 * XXX: NSP_QUIRK
633 * data phase skip only occures in case of SCSI_LOW_READ
634 */
635 nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
636 SCpnt->SCp.phase = PH_DATA;
637 nsp_pio_read(SCpnt);
638 nsp_setup_fifo(data, FALSE);
639
640 return 0;
641}
642
643/*
644 * accept reselection
645 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700646static int nsp_reselected(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647{
648 unsigned int base = SCpnt->device->host->io_port;
649 unsigned int host_id = SCpnt->device->host->this_id;
650 //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
651 unsigned char bus_reg;
652 unsigned char id_reg, tmp;
653 int target;
654
655 nsp_dbg(NSP_DEBUG_RESELECTION, "in");
656
657 id_reg = nsp_index_read(base, RESELECTID);
658 tmp = id_reg & (~BIT(host_id));
659 target = 0;
660 while(tmp != 0) {
661 if (tmp & BIT(0)) {
662 break;
663 }
664 tmp >>= 1;
665 target++;
666 }
667
Jeff Garzik422c0d62005-10-24 18:05:09 -0400668 if (scmd_id(SCpnt) != target) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
670 }
671
672 nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
673
674 nsp_nexus(SCpnt);
675 bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
676 nsp_index_write(base, SCSIBUSCTRL, bus_reg);
677 nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
678
679 return TRUE;
680}
681
682/*
683 * count how many data transferd
684 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700685static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 unsigned int base = SCpnt->device->host->io_port;
688 unsigned int count;
689 unsigned int l, m, h, dummy;
690
691 nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
692
693 l = nsp_index_read(base, TRANSFERCOUNT);
694 m = nsp_index_read(base, TRANSFERCOUNT);
695 h = nsp_index_read(base, TRANSFERCOUNT);
696 dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
697
698 count = (h << 16) | (m << 8) | (l << 0);
699
700 //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
701
702 return count;
703}
704
705/* fifo size */
706#define RFIFO_CRIT 64
707#define WFIFO_CRIT 64
708
709/*
710 * read data in DATA IN phase
711 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700712static void nsp_pio_read(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 unsigned int base = SCpnt->device->host->io_port;
715 unsigned long mmio_base = SCpnt->device->host->base;
716 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
717 long time_out;
718 int ocount, res;
719 unsigned char stat, fifo_stat;
720
721 ocount = data->FifoCount;
722
723 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",
724 SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
725
726 time_out = 1000;
727
728 while ((time_out-- != 0) &&
729 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
730
731 stat = nsp_index_read(base, SCSIBUSMON);
732 stat &= BUSMON_PHASE_MASK;
733
734
735 res = nsp_fifo_count(SCpnt) - ocount;
736 //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);
737 if (res == 0) { /* if some data avilable ? */
738 if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
739 //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
740 continue;
741 } else {
742 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
743 break;
744 }
745 }
746
747 fifo_stat = nsp_read(base, FIFOSTATUS);
748 if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
749 stat == BUSPHASE_DATA_IN) {
750 continue;
751 }
752
753 res = min(res, SCpnt->SCp.this_residual);
754
755 switch (data->TransferMode) {
756 case MODE_IO32:
757 res &= ~(BIT(1)|BIT(0)); /* align 4 */
758 nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
759 break;
760 case MODE_IO8:
761 nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
762 break;
763
764 case MODE_MEM32:
765 res &= ~(BIT(1)|BIT(0)); /* align 4 */
766 nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
767 break;
768
769 default:
770 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
771 return;
772 }
773
774 SCpnt->resid -= res;
775 SCpnt->SCp.ptr += res;
776 SCpnt->SCp.this_residual -= res;
777 ocount += res;
778 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
779
780 /* go to next scatter list if available */
781 if (SCpnt->SCp.this_residual == 0 &&
782 SCpnt->SCp.buffers_residual != 0 ) {
783 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
784 SCpnt->SCp.buffers_residual--;
785 SCpnt->SCp.buffer++;
786 SCpnt->SCp.ptr = BUFFER_ADDR;
787 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
788 time_out = 1000;
789
790 //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
791 }
792 }
793
794 data->FifoCount = ocount;
795
796 if (time_out == 0) {
797 nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
798 SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
799 }
800 nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
801 nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
802}
803
804/*
805 * write data in DATA OUT phase
806 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700807static void nsp_pio_write(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808{
809 unsigned int base = SCpnt->device->host->io_port;
810 unsigned long mmio_base = SCpnt->device->host->base;
811 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
812 int time_out;
813 int ocount, res;
814 unsigned char stat;
815
816 ocount = data->FifoCount;
817
818 nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
819 data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
820
821 time_out = 1000;
822
823 while ((time_out-- != 0) &&
824 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
825 stat = nsp_index_read(base, SCSIBUSMON);
826 stat &= BUSMON_PHASE_MASK;
827
828 if (stat != BUSPHASE_DATA_OUT) {
829 res = ocount - nsp_fifo_count(SCpnt);
830
831 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
832 /* Put back pointer */
833 SCpnt->resid += res;
834 SCpnt->SCp.ptr -= res;
835 SCpnt->SCp.this_residual += res;
836 ocount -= res;
837
838 break;
839 }
840
841 res = ocount - nsp_fifo_count(SCpnt);
842 if (res > 0) { /* write all data? */
843 nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
844 continue;
845 }
846
847 res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
848
849 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
850 switch (data->TransferMode) {
851 case MODE_IO32:
852 res &= ~(BIT(1)|BIT(0)); /* align 4 */
853 nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
854 break;
855 case MODE_IO8:
856 nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
857 break;
858
859 case MODE_MEM32:
860 res &= ~(BIT(1)|BIT(0)); /* align 4 */
861 nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
862 break;
863
864 default:
865 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
866 break;
867 }
868
869 SCpnt->resid -= res;
870 SCpnt->SCp.ptr += res;
871 SCpnt->SCp.this_residual -= res;
872 ocount += res;
873
874 /* go to next scatter list if available */
875 if (SCpnt->SCp.this_residual == 0 &&
876 SCpnt->SCp.buffers_residual != 0 ) {
877 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
878 SCpnt->SCp.buffers_residual--;
879 SCpnt->SCp.buffer++;
880 SCpnt->SCp.ptr = BUFFER_ADDR;
881 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
882 time_out = 1000;
883 }
884 }
885
886 data->FifoCount = ocount;
887
888 if (time_out == 0) {
889 nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
890 }
891 nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
892 nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
893}
894#undef RFIFO_CRIT
895#undef WFIFO_CRIT
896
897/*
898 * setup synchronous/asynchronous data transfer mode
899 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700900static int nsp_nexus(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400903 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904// unsigned char lun = SCpnt->device->lun;
905 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
906 sync_data *sync = &(data->Sync[target]);
907
908 //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
909
910 /* setup synch transfer registers */
911 nsp_index_write(base, SYNCREG, sync->SyncRegister);
912 nsp_index_write(base, ACKWIDTH, sync->AckWidth);
913
914 if (SCpnt->use_sg == 0 ||
915 SCpnt->resid % 4 != 0 ||
916 SCpnt->resid <= PAGE_SIZE ) {
917 data->TransferMode = MODE_IO8;
918 } else if (nsp_burst_mode == BURST_MEM32) {
919 data->TransferMode = MODE_MEM32;
920 } else if (nsp_burst_mode == BURST_IO32) {
921 data->TransferMode = MODE_IO32;
922 } else {
923 data->TransferMode = MODE_IO8;
924 }
925
926 /* setup pdma fifo */
927 nsp_setup_fifo(data, TRUE);
928
929 /* clear ack counter */
930 data->FifoCount = 0;
931 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
932 ACK_COUNTER_CLEAR |
933 REQ_COUNTER_CLEAR |
934 HOST_COUNTER_CLEAR);
935
936 return 0;
937}
938
939#include "nsp_message.c"
940/*
941 * interrupt handler
942 */
David Howells7d12e782006-10-05 14:55:46 +0100943static irqreturn_t nspintr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
945 unsigned int base;
946 unsigned char irq_status, irq_phase, phase;
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700947 struct scsi_cmnd *tmpSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 unsigned char target, lun;
949 unsigned int *sync_neg;
950 int i, tmp;
951 nsp_hw_data *data;
952
953
954 //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
955 //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
956
957 if ( dev_id != NULL &&
958 ((scsi_info_t *)dev_id)->host != NULL ) {
959 scsi_info_t *info = (scsi_info_t *)dev_id;
960
961 data = (nsp_hw_data *)info->host->hostdata;
962 } else {
963 nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
964 return IRQ_NONE;
965 }
966
967 //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
968
969 base = data->BaseAddress;
970 //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
971
972 /*
973 * interrupt check
974 */
975 nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
976 irq_status = nsp_read(base, IRQSTATUS);
977 //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
978 if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
979 nsp_write(base, IRQCONTROL, 0);
980 //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
981 return IRQ_NONE;
982 }
983
984 /* XXX: IMPORTANT
985 * Do not read an irq_phase register if no scsi phase interrupt.
986 * Unless, you should lose a scsi phase interrupt.
987 */
988 phase = nsp_index_read(base, SCSIBUSMON);
989 if((irq_status & IRQSTATUS_SCSI) != 0) {
990 irq_phase = nsp_index_read(base, IRQPHASESENCE);
991 } else {
992 irq_phase = 0;
993 }
994
995 //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
996
997 /*
998 * timer interrupt handler (scsi vs timer interrupts)
999 */
1000 //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1001 if (data->TimerCount != 0) {
1002 //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1003 nsp_index_write(base, TIMERCOUNT, 0);
1004 nsp_index_write(base, TIMERCOUNT, 0);
1005 data->TimerCount = 0;
1006 }
1007
1008 if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1009 data->SelectionTimeOut == 0) {
1010 //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1011 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1012 return IRQ_HANDLED;
1013 }
1014
1015 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1016
1017 if ((irq_status & IRQSTATUS_SCSI) &&
1018 (irq_phase & SCSI_RESET_IRQ)) {
1019 nsp_msg(KERN_ERR, "bus reset (power off?)");
1020
1021 nsphw_init(data);
1022 nsp_bus_reset(data);
1023
1024 if(data->CurrentSC != NULL) {
1025 tmpSC = data->CurrentSC;
1026 tmpSC->result = (DID_RESET << 16) |
1027 ((tmpSC->SCp.Message & 0xff) << 8) |
1028 ((tmpSC->SCp.Status & 0xff) << 0);
1029 nsp_scsi_done(tmpSC);
1030 }
1031 return IRQ_HANDLED;
1032 }
1033
1034 if (data->CurrentSC == NULL) {
1035 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);
1036 nsphw_init(data);
1037 nsp_bus_reset(data);
1038 return IRQ_HANDLED;
1039 }
1040
1041 tmpSC = data->CurrentSC;
1042 target = tmpSC->device->id;
1043 lun = tmpSC->device->lun;
1044 sync_neg = &(data->Sync[target].SyncNegotiation);
1045
1046 /*
1047 * parse hardware SCSI irq reasons register
1048 */
1049 if (irq_status & IRQSTATUS_SCSI) {
1050 if (irq_phase & RESELECT_IRQ) {
1051 nsp_dbg(NSP_DEBUG_INTR, "reselect");
1052 nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1053 if (nsp_reselected(tmpSC) != FALSE) {
1054 return IRQ_HANDLED;
1055 }
1056 }
1057
1058 if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1059 return IRQ_HANDLED;
1060 }
1061 }
1062
1063 //show_phase(tmpSC);
1064
1065 switch(tmpSC->SCp.phase) {
1066 case PH_SELSTART:
1067 // *sync_neg = SYNC_NOT_YET;
1068 if ((phase & BUSMON_BSY) == 0) {
1069 //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1070 if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1071 nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1072 data->SelectionTimeOut = 0;
1073 nsp_index_write(base, SCSIBUSCTRL, 0);
1074
1075 tmpSC->result = DID_TIME_OUT << 16;
1076 nsp_scsi_done(tmpSC);
1077
1078 return IRQ_HANDLED;
1079 }
1080 data->SelectionTimeOut += 1;
1081 nsp_start_timer(tmpSC, 1000/51);
1082 return IRQ_HANDLED;
1083 }
1084
1085 /* attention assert */
1086 //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1087 data->SelectionTimeOut = 0;
1088 tmpSC->SCp.phase = PH_SELECTED;
1089 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1090 udelay(1);
1091 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1092 return IRQ_HANDLED;
1093
1094 break;
1095
1096 case PH_RESELECT:
1097 //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1098 // *sync_neg = SYNC_NOT_YET;
1099 if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1100
1101 tmpSC->result = DID_ABORT << 16;
1102 nsp_scsi_done(tmpSC);
1103 return IRQ_HANDLED;
1104 }
1105 /* fall thru */
1106 default:
1107 if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1108 return IRQ_HANDLED;
1109 }
1110 break;
1111 }
1112
1113 /*
1114 * SCSI sequencer
1115 */
1116 //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1117
1118 /* normal disconnect */
1119 if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1120 (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1121 nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1122
1123 //*sync_neg = SYNC_NOT_YET;
1124
1125 if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
1126 tmpSC->result = (DID_OK << 16) |
1127 ((tmpSC->SCp.Message & 0xff) << 8) |
1128 ((tmpSC->SCp.Status & 0xff) << 0);
1129 nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1130 nsp_scsi_done(tmpSC);
1131
1132 return IRQ_HANDLED;
1133 }
1134
1135 return IRQ_HANDLED;
1136 }
1137
1138
1139 /* check unexpected bus free state */
1140 if (phase == 0) {
1141 nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1142
1143 *sync_neg = SYNC_NG;
1144 tmpSC->result = DID_ERROR << 16;
1145 nsp_scsi_done(tmpSC);
1146 return IRQ_HANDLED;
1147 }
1148
1149 switch (phase & BUSMON_PHASE_MASK) {
1150 case BUSPHASE_COMMAND:
1151 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1152 if ((phase & BUSMON_REQ) == 0) {
1153 nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1154 return IRQ_HANDLED;
1155 }
1156
1157 tmpSC->SCp.phase = PH_COMMAND;
1158
1159 nsp_nexus(tmpSC);
1160
1161 /* write scsi command */
1162 nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1163 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1164 for (i = 0; i < tmpSC->cmd_len; i++) {
1165 nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1166 }
1167 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1168 break;
1169
1170 case BUSPHASE_DATA_OUT:
1171 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1172
1173 tmpSC->SCp.phase = PH_DATA;
1174 tmpSC->SCp.have_data_in = IO_OUT;
1175
1176 nsp_pio_write(tmpSC);
1177
1178 break;
1179
1180 case BUSPHASE_DATA_IN:
1181 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1182
1183 tmpSC->SCp.phase = PH_DATA;
1184 tmpSC->SCp.have_data_in = IO_IN;
1185
1186 nsp_pio_read(tmpSC);
1187
1188 break;
1189
1190 case BUSPHASE_STATUS:
1191 nsp_dataphase_bypass(tmpSC);
1192 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1193
1194 tmpSC->SCp.phase = PH_STATUS;
1195
1196 tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1197 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1198
1199 break;
1200
1201 case BUSPHASE_MESSAGE_OUT:
1202 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1203 if ((phase & BUSMON_REQ) == 0) {
1204 goto timer_out;
1205 }
1206
1207 tmpSC->SCp.phase = PH_MSG_OUT;
1208
1209 //*sync_neg = SYNC_NOT_YET;
1210
1211 data->MsgLen = i = 0;
1212 data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1213
1214 if (*sync_neg == SYNC_NOT_YET) {
1215 data->Sync[target].SyncPeriod = 0;
1216 data->Sync[target].SyncOffset = 0;
1217
1218 /**/
1219 data->MsgBuffer[i] = MSG_EXTENDED; i++;
1220 data->MsgBuffer[i] = 3; i++;
1221 data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1222 data->MsgBuffer[i] = 0x0c; i++;
1223 data->MsgBuffer[i] = 15; i++;
1224 /**/
1225 }
1226 data->MsgLen = i;
1227
1228 nsp_analyze_sdtr(tmpSC);
1229 show_message(data);
1230 nsp_message_out(tmpSC);
1231 break;
1232
1233 case BUSPHASE_MESSAGE_IN:
1234 nsp_dataphase_bypass(tmpSC);
1235 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1236 if ((phase & BUSMON_REQ) == 0) {
1237 goto timer_out;
1238 }
1239
1240 tmpSC->SCp.phase = PH_MSG_IN;
1241 nsp_message_in(tmpSC);
1242
1243 /**/
1244 if (*sync_neg == SYNC_NOT_YET) {
1245 //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1246
1247 if (data->MsgLen >= 5 &&
1248 data->MsgBuffer[0] == MSG_EXTENDED &&
1249 data->MsgBuffer[1] == 3 &&
1250 data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1251 data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1252 data->Sync[target].SyncOffset = data->MsgBuffer[4];
1253 //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1254 *sync_neg = SYNC_OK;
1255 } else {
1256 data->Sync[target].SyncPeriod = 0;
1257 data->Sync[target].SyncOffset = 0;
1258 *sync_neg = SYNC_NG;
1259 }
1260 nsp_analyze_sdtr(tmpSC);
1261 }
1262 /**/
1263
1264 /* search last messeage byte */
1265 tmp = -1;
1266 for (i = 0; i < data->MsgLen; i++) {
1267 tmp = data->MsgBuffer[i];
1268 if (data->MsgBuffer[i] == MSG_EXTENDED) {
1269 i += (1 + data->MsgBuffer[i+1]);
1270 }
1271 }
1272 tmpSC->SCp.Message = tmp;
1273
1274 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1275 show_message(data);
1276
1277 break;
1278
1279 case BUSPHASE_SELECT:
1280 default:
1281 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1282
1283 break;
1284 }
1285
1286 //nsp_dbg(NSP_DEBUG_INTR, "out");
1287 return IRQ_HANDLED;
1288
1289timer_out:
1290 nsp_start_timer(tmpSC, 1000/102);
1291 return IRQ_HANDLED;
1292}
1293
1294#ifdef NSP_DEBUG
1295#include "nsp_debug.c"
1296#endif /* NSP_DEBUG */
1297
1298/*----------------------------------------------------------------*/
1299/* look for ninja3 card and init if found */
1300/*----------------------------------------------------------------*/
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001301static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
1303 struct Scsi_Host *host; /* registered host structure */
1304 nsp_hw_data *data_b = &nsp_data_base, *data;
1305
1306 nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (host == NULL) {
1309 nsp_dbg(NSP_DEBUG_INIT, "host failed");
1310 return NULL;
1311 }
1312
1313 memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1314 data = (nsp_hw_data *)host->hostdata;
1315 data->ScsiInfo->host = host;
1316#ifdef NSP_DEBUG
1317 data->CmdId = 0;
1318#endif
1319
1320 nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1321
1322 host->unique_id = data->BaseAddress;
1323 host->io_port = data->BaseAddress;
1324 host->n_io_port = data->NumAddress;
1325 host->irq = data->IrqNumber;
1326 host->base = data->MmioAddress;
1327
1328 spin_lock_init(&(data->Lock));
1329
1330 snprintf(data->nspinfo,
1331 sizeof(data->nspinfo),
1332 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1333 host->io_port, host->io_port + host->n_io_port - 1,
1334 host->base,
1335 host->irq);
1336 sht->name = data->nspinfo;
1337
1338 nsp_dbg(NSP_DEBUG_INIT, "end");
1339
1340
1341 return host; /* detect done. */
1342}
1343
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344/*----------------------------------------------------------------*/
1345/* return info string */
1346/*----------------------------------------------------------------*/
1347static const char *nsp_info(struct Scsi_Host *shpnt)
1348{
1349 nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1350
1351 return data->nspinfo;
1352}
1353
1354#undef SPRINTF
1355#define SPRINTF(args...) \
1356 do { \
1357 if(length > (pos - buffer)) { \
1358 pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
1359 nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
1360 } \
1361 } while(0)
Adrian Bunk774251e2007-10-02 14:38:01 -07001362
1363static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
1364 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 int id;
1367 char *pos = buffer;
1368 int thislength;
1369 int speed;
1370 unsigned long flags;
1371 nsp_hw_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 int hostno;
Adrian Bunk774251e2007-10-02 14:38:01 -07001373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (inout) {
1375 return -EINVAL;
1376 }
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 hostno = host->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 data = (nsp_hw_data *)host->hostdata;
1380
1381
1382 SPRINTF("NinjaSCSI status\n\n");
1383 SPRINTF("Driver version: $Revision: 1.23 $\n");
1384 SPRINTF("SCSI host No.: %d\n", hostno);
1385 SPRINTF("IRQ: %d\n", host->irq);
1386 SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1387 SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1388 SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
1389
1390 SPRINTF("burst transfer mode: ");
1391 switch (nsp_burst_mode) {
1392 case BURST_IO8:
1393 SPRINTF("io8");
1394 break;
1395 case BURST_IO32:
1396 SPRINTF("io32");
1397 break;
1398 case BURST_MEM32:
1399 SPRINTF("mem32");
1400 break;
1401 default:
1402 SPRINTF("???");
1403 break;
1404 }
1405 SPRINTF("\n");
1406
1407
1408 spin_lock_irqsave(&(data->Lock), flags);
1409 SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
1410 spin_unlock_irqrestore(&(data->Lock), flags);
1411
1412 SPRINTF("SDTR status\n");
1413 for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1414
1415 SPRINTF("id %d: ", id);
1416
1417 if (id == host->this_id) {
1418 SPRINTF("----- NinjaSCSI-3 host adapter\n");
1419 continue;
1420 }
1421
1422 switch(data->Sync[id].SyncNegotiation) {
1423 case SYNC_OK:
1424 SPRINTF(" sync");
1425 break;
1426 case SYNC_NG:
1427 SPRINTF("async");
1428 break;
1429 case SYNC_NOT_YET:
1430 SPRINTF(" none");
1431 break;
1432 default:
1433 SPRINTF("?????");
1434 break;
1435 }
1436
1437 if (data->Sync[id].SyncPeriod != 0) {
1438 speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1439
1440 SPRINTF(" transfer %d.%dMB/s, offset %d",
1441 speed / 1000,
1442 speed % 1000,
1443 data->Sync[id].SyncOffset
1444 );
1445 }
1446 SPRINTF("\n");
1447 }
1448
1449 thislength = pos - (buffer + offset);
1450
1451 if(thislength < 0) {
1452 *start = NULL;
1453 return 0;
1454 }
1455
1456
1457 thislength = min(thislength, length);
1458 *start = buffer + offset;
1459
1460 return thislength;
1461}
1462#undef SPRINTF
1463
1464/*---------------------------------------------------------------*/
1465/* error handler */
1466/*---------------------------------------------------------------*/
1467
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468/*
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001469static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
1471 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1472
1473 return nsp_eh_bus_reset(SCpnt);
1474}*/
1475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476static int nsp_bus_reset(nsp_hw_data *data)
1477{
1478 unsigned int base = data->BaseAddress;
1479 int i;
1480
1481 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1482
1483 nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1484 mdelay(100); /* 100ms */
1485 nsp_index_write(base, SCSIBUSCTRL, 0);
1486 for(i = 0; i < 5; i++) {
1487 nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1488 }
1489
1490 nsphw_init_sync(data);
1491
1492 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1493
1494 return SUCCESS;
1495}
1496
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001497static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498{
1499 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1500
1501 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1502
1503 return nsp_bus_reset(data);
1504}
1505
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001506static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507{
1508 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1509
1510 nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1511
1512 nsphw_init(data);
1513
1514 return SUCCESS;
1515}
1516
1517
1518/**********************************************************************
1519 PCMCIA functions
1520**********************************************************************/
1521
1522/*======================================================================
1523 nsp_cs_attach() creates an "instance" of the driver, allocating
1524 local data structures for one device. The device is registered
1525 with Card Services.
1526
1527 The dev_link structure is initialized, but we don't actually
1528 configure the card at this point -- we wait until we receive a
1529 card insertion event.
1530======================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001531static int nsp_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 nsp_hw_data *data = &nsp_data_base;
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001535 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 nsp_dbg(NSP_DEBUG_INIT, "in");
1538
1539 /* Create new SCSI device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001540 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001541 if (info == NULL) { return -ENOMEM; }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001542 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 link->priv = info;
1544 data->ScsiInfo = info;
1545
1546 nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1547
1548 /* The io structure describes IO port mapping */
1549 link->io.NumPorts1 = 0x10;
1550 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1551 link->io.IOAddrLines = 10; /* not used */
1552
1553 /* Interrupt setup */
1554 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
1555 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
1556
1557 /* Interrupt handler */
1558 link->irq.Handler = &nspintr;
1559 link->irq.Instance = info;
James Bottomleyc4e00fa2006-07-03 09:41:12 -05001560 link->irq.Attributes |= IRQF_SHARED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 /* General socket configuration */
1563 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 link->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001566 ret = nsp_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001569 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570} /* nsp_cs_attach */
1571
1572
1573/*======================================================================
1574 This deletes a driver "instance". The device is de-registered
1575 with Card Services. If it has been released, all local data
1576 structures are freed. Otherwise, the structures will be freed
1577 when the device is released.
1578======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001579static void nsp_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1582
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001583 ((scsi_info_t *)link->priv)->stop = 1;
1584 nsp_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 kfree(link->priv);
1587 link->priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588} /* nsp_cs_detach */
1589
1590
1591/*======================================================================
1592 nsp_cs_config() is scheduled to run after a CARD_INSERTION event
1593 is received, to configure the PCMCIA socket, and to make the
1594 ethernet device available to the system.
1595======================================================================*/
1596#define CS_CHECK(fn, ret) \
1597do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
1598/*====================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001599static int nsp_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001601 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 scsi_info_t *info = link->priv;
1603 tuple_t tuple;
1604 cisparse_t parse;
1605 int last_ret, last_fn;
1606 unsigned char tuple_data[64];
1607 config_info_t conf;
1608 win_req_t req;
1609 memreq_t map;
1610 cistpl_cftable_entry_t dflt = { 0 };
1611 struct Scsi_Host *host;
1612 nsp_hw_data *data = &nsp_data_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
1614 nsp_dbg(NSP_DEBUG_INIT, "in");
1615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 tuple.Attributes = 0;
1617 tuple.TupleData = tuple_data;
1618 tuple.TupleDataMax = sizeof(tuple_data);
1619 tuple.TupleOffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* Look up the current Vcc */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001622 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001625 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 while (1) {
1627 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
1628
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001629 if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
1630 pcmcia_parse_tuple(link, &tuple, &parse) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 goto next_entry;
1632
1633 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
1634 if (cfg->index == 0) { goto next_entry; }
1635 link->conf.ConfigIndex = cfg->index;
1636
1637 /* Does this card need audio output? */
1638 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
1639 link->conf.Attributes |= CONF_ENABLE_SPKR;
1640 link->conf.Status = CCSR_AUDIO_ENA;
1641 }
1642
1643 /* Use power settings for Vcc and Vpp if present */
1644 /* Note that the CIS values need to be rescaled */
1645 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
1646 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
1647 goto next_entry;
1648 }
1649 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
1650 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
1651 goto next_entry;
1652 }
1653 }
1654
1655 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001656 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
1658 } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001659 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
1661 }
1662
1663 /* Do we need to allocate an interrupt? */
1664 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
1665 link->conf.Attributes |= CONF_ENABLE_IRQ;
1666 }
1667
1668 /* IO window settings */
1669 link->io.NumPorts1 = link->io.NumPorts2 = 0;
1670 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
1671 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
1672 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1673 if (!(io->flags & CISTPL_IO_8BIT))
1674 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
1675 if (!(io->flags & CISTPL_IO_16BIT))
1676 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
1677 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
1678 link->io.BasePort1 = io->win[0].base;
1679 link->io.NumPorts1 = io->win[0].len;
1680 if (io->nwin > 1) {
1681 link->io.Attributes2 = link->io.Attributes1;
1682 link->io.BasePort2 = io->win[1].base;
1683 link->io.NumPorts2 = io->win[1].len;
1684 }
1685 /* This reserves IO space but doesn't actually enable it */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001686 if (pcmcia_request_io(link, &link->io) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 goto next_entry;
1688 }
1689
1690 if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
1691 cistpl_mem_t *mem =
1692 (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
1693 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
1694 req.Attributes |= WIN_ENABLE;
1695 req.Base = mem->win[0].host_addr;
1696 req.Size = mem->win[0].len;
1697 if (req.Size < 0x1000) {
1698 req.Size = 0x1000;
1699 }
1700 req.AccessSpeed = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001701 if (pcmcia_request_window(&link, &req, &link->win) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 goto next_entry;
1703 map.Page = 0; map.CardOffset = mem->win[0].card_addr;
1704 if (pcmcia_map_mem_page(link->win, &map) != 0)
1705 goto next_entry;
1706
1707 data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
1708 data->MmioLength = req.Size;
1709 }
1710 /* If we got this far, we're cool! */
1711 break;
1712
1713 next_entry:
1714 nsp_dbg(NSP_DEBUG_INIT, "next");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001715 pcmcia_disable_device(link);
1716 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 }
1718
1719 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001720 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001722 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 if (free_ports) {
1725 if (link->io.BasePort1) {
1726 release_region(link->io.BasePort1, link->io.NumPorts1);
1727 }
1728 if (link->io.BasePort2) {
1729 release_region(link->io.BasePort2, link->io.NumPorts2);
1730 }
1731 }
1732
1733 /* Set port and IRQ */
1734 data->BaseAddress = link->io.BasePort1;
1735 data->NumAddress = link->io.NumPorts1;
1736 data->IrqNumber = link->irq.AssignedIRQ;
1737
1738 nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1739 data->BaseAddress, data->NumAddress, data->IrqNumber);
1740
1741 if(nsphw_init(data) == FALSE) {
1742 goto cs_failed;
1743 }
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 host = nsp_detect(&nsp_driver_template);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 if (host == NULL) {
1748 nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1749 goto cs_failed;
1750 }
1751
1752
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001753 ret = scsi_add_host (host, NULL);
1754 if (ret)
1755 goto cs_failed;
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 scsi_scan_host(host);
1758
1759 snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
Dominik Brodowskifd238232006-03-05 10:45:09 +01001760 link->dev_node = &info->node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 info->host = host;
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 /* Finally, report what we've done */
Dominik Brodowski70294b42006-01-15 12:43:16 +01001764 printk(KERN_INFO "nsp_cs: index 0x%02x: ",
1765 link->conf.ConfigIndex);
1766 if (link->conf.Vpp) {
1767 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 }
1769 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
1770 printk(", irq %d", link->irq.AssignedIRQ);
1771 }
1772 if (link->io.NumPorts1) {
1773 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
1774 link->io.BasePort1+link->io.NumPorts1-1);
1775 }
1776 if (link->io.NumPorts2)
1777 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
1778 link->io.BasePort2+link->io.NumPorts2-1);
1779 if (link->win)
1780 printk(", mem 0x%06lx-0x%06lx", req.Base,
1781 req.Base+req.Size-1);
1782 printk("\n");
1783
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001784 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 cs_failed:
1787 nsp_dbg(NSP_DEBUG_INIT, "config fail");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001788 cs_error(link, last_fn, last_ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 nsp_cs_release(link);
1790
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001791 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792} /* nsp_cs_config */
1793#undef CS_CHECK
1794
1795
1796/*======================================================================
1797 After a card is removed, nsp_cs_release() will unregister the net
1798 device, and release the PCMCIA configuration. If the device is
1799 still open, this will be postponed until it is closed.
1800======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001801static void nsp_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802{
1803 scsi_info_t *info = link->priv;
1804 nsp_hw_data *data = NULL;
1805
1806 if (info->host == NULL) {
1807 nsp_msg(KERN_DEBUG, "unexpected card release call.");
1808 } else {
1809 data = (nsp_hw_data *)info->host->hostdata;
1810 }
1811
1812 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1813
1814 /* Unlink the device chain */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if (info->host != NULL) {
1816 scsi_remove_host(info->host);
1817 }
Dominik Brodowskifd238232006-03-05 10:45:09 +01001818 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820 if (link->win) {
1821 if (data != NULL) {
1822 iounmap((void *)(data->MmioAddress));
1823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001825 pcmcia_disable_device(link);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001826
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 if (info->host != NULL) {
1828 scsi_host_put(info->host);
1829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830} /* nsp_cs_release */
1831
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001832static int nsp_cs_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001833{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001834 scsi_info_t *info = link->priv;
1835 nsp_hw_data *data;
1836
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001837 nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1838
1839 if (info->host != NULL) {
1840 nsp_msg(KERN_INFO, "clear SDTR status");
1841
1842 data = (nsp_hw_data *)info->host->hostdata;
1843
1844 nsphw_init_sync(data);
1845 }
1846
1847 info->stop = 1;
1848
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001849 return 0;
1850}
1851
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001852static int nsp_cs_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001853{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001854 scsi_info_t *info = link->priv;
1855 nsp_hw_data *data;
1856
1857 nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1858
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001859 info->stop = 0;
1860
1861 if (info->host != NULL) {
1862 nsp_msg(KERN_INFO, "reset host and bus");
1863
1864 data = (nsp_hw_data *)info->host->hostdata;
1865
1866 nsphw_init (data);
1867 nsp_bus_reset(data);
1868 }
1869
1870 return 0;
1871}
1872
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873/*======================================================================*
1874 * module entry point
1875 *====================================================================*/
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001876static struct pcmcia_device_id nsp_cs_ids[] = {
1877 PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1878 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1879 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1880 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1881 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1882 PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1883 PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1884 PCMCIA_DEVICE_NULL
1885};
1886MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888static struct pcmcia_driver nsp_driver = {
Dominik Brodowski1e212f32005-07-07 17:59:00 -07001889 .owner = THIS_MODULE,
1890 .drv = {
1891 .name = "nsp_cs",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001893 .probe = nsp_cs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01001894 .remove = nsp_cs_detach,
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001895 .id_table = nsp_cs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001896 .suspend = nsp_cs_suspend,
1897 .resume = nsp_cs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900static int __init nsp_cs_init(void)
1901{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 nsp_msg(KERN_INFO, "loading...");
1903
1904 return pcmcia_register_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905}
1906
1907static void __exit nsp_cs_exit(void)
1908{
1909 nsp_msg(KERN_INFO, "unloading...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 pcmcia_unregister_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911}
1912
1913
1914module_init(nsp_cs_init)
1915module_exit(nsp_cs_exit)
1916
1917/* end */