blob: f2d79c3f0b8eef641fbaf42187133782c8101fee [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
28/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */
29
30#include <linux/version.h>
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/init.h>
34#include <linux/sched.h>
35#include <linux/slab.h>
36#include <linux/string.h>
37#include <linux/timer.h>
38#include <linux/ioport.h>
39#include <linux/delay.h>
40#include <linux/interrupt.h>
41#include <linux/major.h>
42#include <linux/blkdev.h>
43#include <linux/stat.h>
44
45#include <asm/io.h>
46#include <asm/irq.h>
47
48#include <../drivers/scsi/scsi.h>
49#include <scsi/scsi_host.h>
50
51#include <scsi/scsi.h>
52#include <scsi/scsi_ioctl.h>
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <pcmcia/cs_types.h>
55#include <pcmcia/cs.h>
56#include <pcmcia/cistpl.h>
57#include <pcmcia/cisreg.h>
58#include <pcmcia/ds.h>
59
60#include "nsp_cs.h"
61
62MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
63MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $");
64MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
65#ifdef MODULE_LICENSE
66MODULE_LICENSE("GPL");
67#endif
68
69#include "nsp_io.h"
70
71/*====================================================================*/
72/* Parameters that can be set with 'insmod' */
73
74static int nsp_burst_mode = BURST_MEM32;
75module_param(nsp_burst_mode, int, 0);
76MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
77
78/* Release IO ports after configuration? */
79static int free_ports = 0;
80module_param(free_ports, bool, 0);
81MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
82
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010083static struct scsi_host_template nsp_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 .proc_name = "nsp_cs",
85 .proc_info = nsp_proc_info,
86 .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
87#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
88 .detect = nsp_detect_old,
89 .release = nsp_release_old,
90#endif
91 .info = nsp_info,
92 .queuecommand = nsp_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -070093/* .eh_abort_handler = nsp_eh_abort,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 .eh_bus_reset_handler = nsp_eh_bus_reset,
95 .eh_host_reset_handler = nsp_eh_host_reset,
96 .can_queue = 1,
97 .this_id = NSP_INITIATOR_ID,
98 .sg_tablesize = SG_ALL,
99 .cmd_per_lun = 1,
100 .use_clustering = DISABLE_CLUSTERING,
101#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
102 .use_new_eh_code = 1,
103#endif
104};
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
107
108
109
110/*
111 * debug, error print
112 */
113#ifndef NSP_DEBUG
114# define NSP_DEBUG_MASK 0x000000
115# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
116# define nsp_dbg(mask, args...) /* */
117#else
118# define NSP_DEBUG_MASK 0xffffff
119# define nsp_msg(type, args...) \
120 nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
121# define nsp_dbg(mask, args...) \
122 nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
123#endif
124
125#define NSP_DEBUG_QUEUECOMMAND BIT(0)
126#define NSP_DEBUG_REGISTER BIT(1)
127#define NSP_DEBUG_AUTOSCSI BIT(2)
128#define NSP_DEBUG_INTR BIT(3)
129#define NSP_DEBUG_SGLIST BIT(4)
130#define NSP_DEBUG_BUSFREE BIT(5)
131#define NSP_DEBUG_CDB_CONTENTS BIT(6)
132#define NSP_DEBUG_RESELECTION BIT(7)
133#define NSP_DEBUG_MSGINOCCUR BIT(8)
134#define NSP_DEBUG_EEPROM BIT(9)
135#define NSP_DEBUG_MSGOUTOCCUR BIT(10)
136#define NSP_DEBUG_BUSRESET BIT(11)
137#define NSP_DEBUG_RESTART BIT(12)
138#define NSP_DEBUG_SYNC BIT(13)
139#define NSP_DEBUG_WAIT BIT(14)
140#define NSP_DEBUG_TARGETFLAG BIT(15)
141#define NSP_DEBUG_PROC BIT(16)
142#define NSP_DEBUG_INIT BIT(17)
143#define NSP_DEBUG_DATA_IO BIT(18)
144#define NSP_SPECIAL_PRINT_REGISTER BIT(20)
145
146#define NSP_DEBUG_BUF_LEN 150
147
148static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
149{
150 va_list args;
151 char buf[NSP_DEBUG_BUF_LEN];
152
153 va_start(args, fmt);
154 vsnprintf(buf, sizeof(buf), fmt, args);
155 va_end(args);
156
157#ifndef NSP_DEBUG
158 printk("%snsp_cs: %s\n", type, buf);
159#else
160 printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
161#endif
162}
163
164#ifdef NSP_DEBUG
165static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
166{
167 va_list args;
168 char buf[NSP_DEBUG_BUF_LEN];
169
170 va_start(args, fmt);
171 vsnprintf(buf, sizeof(buf), fmt, args);
172 va_end(args);
173
174 if (mask & NSP_DEBUG_MASK) {
175 printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
176 }
177}
178#endif
179
180/***********************************************************/
181
182/*====================================================
183 * Clenaup parameters and call done() functions.
184 * You must be set SCpnt->result before call this function.
185 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700186static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
189
190 data->CurrentSC = NULL;
191
192 SCpnt->scsi_done(SCpnt);
193}
194
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700195static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
196 void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
198#ifdef NSP_DEBUG
199 /*unsigned int host_id = SCpnt->device->host->this_id;*/
200 /*unsigned int base = SCpnt->device->host->io_port;*/
Jeff Garzik422c0d62005-10-24 18:05:09 -0400201 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#endif
203 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
204
205 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
206 SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
207 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
208
209 SCpnt->scsi_done = done;
210
211 if (data->CurrentSC != NULL) {
212 nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
213 SCpnt->result = DID_BAD_TARGET << 16;
214 nsp_scsi_done(SCpnt);
215 return 0;
216 }
217
218#if 0
219 /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
220 This makes kernel crash when suspending... */
221 if (data->ScsiInfo->stop != 0) {
222 nsp_msg(KERN_INFO, "suspending device. reject command.");
223 SCpnt->result = DID_BAD_TARGET << 16;
224 nsp_scsi_done(SCpnt);
225 return SCSI_MLQUEUE_HOST_BUSY;
226 }
227#endif
228
229 show_command(SCpnt);
230
231 data->CurrentSC = SCpnt;
232
233 SCpnt->SCp.Status = CHECK_CONDITION;
234 SCpnt->SCp.Message = 0;
235 SCpnt->SCp.have_data_in = IO_UNKNOWN;
236 SCpnt->SCp.sent_command = 0;
237 SCpnt->SCp.phase = PH_UNDETERMINED;
238 SCpnt->resid = SCpnt->request_bufflen;
239
240 /* setup scratch area
241 SCp.ptr : buffer pointer
242 SCp.this_residual : buffer length
243 SCp.buffer : next buffer
244 SCp.buffers_residual : left buffers in list
245 SCp.phase : current state of the command */
246 if (SCpnt->use_sg) {
247 SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
248 SCpnt->SCp.ptr = BUFFER_ADDR;
249 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
250 SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
251 } else {
252 SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
253 SCpnt->SCp.this_residual = SCpnt->request_bufflen;
254 SCpnt->SCp.buffer = NULL;
255 SCpnt->SCp.buffers_residual = 0;
256 }
257
258 if (nsphw_start_selection(SCpnt) == FALSE) {
259 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
260 SCpnt->result = DID_BUS_BUSY << 16;
261 nsp_scsi_done(SCpnt);
262 return 0;
263 }
264
265
266 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
267#ifdef NSP_DEBUG
268 data->CmdId++;
269#endif
270 return 0;
271}
272
273/*
274 * setup PIO FIFO transfer mode and enable/disable to data out
275 */
276static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
277{
278 unsigned int base = data->BaseAddress;
279 unsigned char transfer_mode_reg;
280
281 //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
282
283 if (enabled != FALSE) {
284 transfer_mode_reg = TRANSFER_GO | BRAIND;
285 } else {
286 transfer_mode_reg = 0;
287 }
288
289 transfer_mode_reg |= data->TransferMode;
290
291 nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
292}
293
294static void nsphw_init_sync(nsp_hw_data *data)
295{
296 sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
297 .SyncPeriod = 0,
298 .SyncOffset = 0
299 };
300 int i;
301
302 /* setup sync data */
303 for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
304 data->Sync[i] = tmp_sync;
305 }
306}
307
308/*
309 * Initialize Ninja hardware
310 */
311static int nsphw_init(nsp_hw_data *data)
312{
313 unsigned int base = data->BaseAddress;
314
315 nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
316
317 data->ScsiClockDiv = CLOCK_40M | FAST_20;
318 data->CurrentSC = NULL;
319 data->FifoCount = 0;
320 data->TransferMode = MODE_IO8;
321
322 nsphw_init_sync(data);
323
324 /* block all interrupts */
325 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
326
327 /* setup SCSI interface */
328 nsp_write(base, IFSELECT, IF_IFSEL);
329
330 nsp_index_write(base, SCSIIRQMODE, 0);
331
332 nsp_index_write(base, TRANSFERMODE, MODE_IO8);
333 nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
334
335 nsp_index_write(base, PARITYCTRL, 0);
336 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
337 ACK_COUNTER_CLEAR |
338 REQ_COUNTER_CLEAR |
339 HOST_COUNTER_CLEAR);
340
341 /* setup fifo asic */
342 nsp_write(base, IFSELECT, IF_REGSEL);
343 nsp_index_write(base, TERMPWRCTRL, 0);
344 if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
345 nsp_msg(KERN_INFO, "terminator power on");
346 nsp_index_write(base, TERMPWRCTRL, POWER_ON);
347 }
348
349 nsp_index_write(base, TIMERCOUNT, 0);
350 nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
351
352 nsp_index_write(base, SYNCREG, 0);
353 nsp_index_write(base, ACKWIDTH, 0);
354
355 /* enable interrupts and ack them */
356 nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
357 RESELECT_EI |
358 SCSI_RESET_IRQ_EI );
359 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
360
361 nsp_setup_fifo(data, FALSE);
362
363 return TRUE;
364}
365
366/*
367 * Start selection phase
368 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700369static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{
371 unsigned int host_id = SCpnt->device->host->this_id;
372 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400373 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
375 int time_out;
376 unsigned char phase, arbit;
377
378 //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
379
380 phase = nsp_index_read(base, SCSIBUSMON);
381 if(phase != BUSMON_BUS_FREE) {
382 //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
383 return FALSE;
384 }
385
386 /* start arbitration */
387 //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
388 SCpnt->SCp.phase = PH_ARBSTART;
389 nsp_index_write(base, SETARBIT, ARBIT_GO);
390
391 time_out = 1000;
392 do {
393 /* XXX: what a stupid chip! */
394 arbit = nsp_index_read(base, ARBITSTATUS);
395 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
396 udelay(1); /* hold 1.2us */
397 } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
398 (time_out-- != 0));
399
400 if (!(arbit & ARBIT_WIN)) {
401 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
402 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
403 return FALSE;
404 }
405
406 /* assert select line */
407 //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
408 SCpnt->SCp.phase = PH_SELSTART;
409 udelay(3); /* wait 2.4us */
410 nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
411 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
412 udelay(2); /* wait >1.2us */
413 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
414 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
415 /*udelay(1);*/ /* wait >90ns */
416 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
417
418 /* check selection timeout */
419 nsp_start_timer(SCpnt, 1000/51);
420 data->SelectionTimeOut = 1;
421
422 return TRUE;
423}
424
425struct nsp_sync_table {
426 unsigned int min_period;
427 unsigned int max_period;
428 unsigned int chip_period;
429 unsigned int ack_width;
430};
431
432static struct nsp_sync_table nsp_sync_table_40M[] = {
433 {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
434 {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
435 {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
436 {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
437 { 0, 0, 0, 0},
438};
439
440static struct nsp_sync_table nsp_sync_table_20M[] = {
441 {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
442 {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
443 {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
444 { 0, 0, 0, 0},
445};
446
447/*
448 * setup synchronous data transfer mode
449 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700450static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Jeff Garzik422c0d62005-10-24 18:05:09 -0400452 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453// unsigned char lun = SCpnt->device->lun;
454 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
455 sync_data *sync = &(data->Sync[target]);
456 struct nsp_sync_table *sync_table;
457 unsigned int period, offset;
458 int i;
459
460
461 nsp_dbg(NSP_DEBUG_SYNC, "in");
462
463 period = sync->SyncPeriod;
464 offset = sync->SyncOffset;
465
466 nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
467
468 if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
469 sync_table = nsp_sync_table_20M;
470 } else {
471 sync_table = nsp_sync_table_40M;
472 }
473
474 for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
475 if ( period >= sync_table->min_period &&
476 period <= sync_table->max_period ) {
477 break;
478 }
479 }
480
481 if (period != 0 && sync_table->max_period == 0) {
482 /*
483 * No proper period/offset found
484 */
485 nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
486
487 sync->SyncPeriod = 0;
488 sync->SyncOffset = 0;
489 sync->SyncRegister = 0;
490 sync->AckWidth = 0;
491
492 return FALSE;
493 }
494
495 sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
496 (offset & SYNCREG_OFFSET_MASK);
497 sync->AckWidth = sync_table->ack_width;
498
499 nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
500
501 return TRUE;
502}
503
504
505/*
506 * start ninja hardware timer
507 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700508static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 unsigned int base = SCpnt->device->host->io_port;
511 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
512
513 //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
514 data->TimerCount = time;
515 nsp_index_write(base, TIMERCOUNT, time);
516}
517
518/*
519 * wait for bus phase change
520 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700521static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
522 char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
524 unsigned int base = SCpnt->device->host->io_port;
525 unsigned char reg;
526 int time_out;
527
528 //nsp_dbg(NSP_DEBUG_INTR, "in");
529
530 time_out = 100;
531
532 do {
533 reg = nsp_index_read(base, SCSIBUSMON);
534 if (reg == 0xff) {
535 break;
536 }
537 } while ((time_out-- != 0) && (reg & mask) != 0);
538
539 if (time_out == 0) {
540 nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
541 }
542
543 return 0;
544}
545
546/*
547 * expect Ninja Irq
548 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700549static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
550 unsigned char current_phase,
551 unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 unsigned int base = SCpnt->device->host->io_port;
554 int time_out;
555 unsigned char phase, i_src;
556
557 //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
558
559 time_out = 100;
560 do {
561 phase = nsp_index_read(base, SCSIBUSMON);
562 if (phase == 0xff) {
563 //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
564 return -1;
565 }
566 i_src = nsp_read(base, IRQSTATUS);
567 if (i_src & IRQSTATUS_SCSI) {
568 //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
569 return 0;
570 }
571 if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
572 //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
573 return 1;
574 }
575 } while(time_out-- != 0);
576
577 //nsp_dbg(NSP_DEBUG_INTR, "timeout");
578 return -1;
579}
580
581/*
582 * transfer SCSI message
583 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700584static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 unsigned int base = SCpnt->device->host->io_port;
587 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
588 char *buf = data->MsgBuffer;
589 int len = min(MSGBUF_SIZE, data->MsgLen);
590 int ptr;
591 int ret;
592
593 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
594 for (ptr = 0; len > 0; len--, ptr++) {
595
596 ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
597 if (ret <= 0) {
598 nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
599 return 0;
600 }
601
602 /* if last byte, negate ATN */
603 if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
604 nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
605 }
606
607 /* read & write message */
608 if (phase & BUSMON_IO) {
609 nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
610 buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
611 } else {
612 nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
613 nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
614 }
615 nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
616
617 }
618 return len;
619}
620
621/*
622 * get extra SCSI data from fifo
623 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700624static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
627 unsigned int count;
628
629 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
630
631 if (SCpnt->SCp.have_data_in != IO_IN) {
632 return 0;
633 }
634
635 count = nsp_fifo_count(SCpnt);
636 if (data->FifoCount == count) {
637 //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
638 return 0;
639 }
640
641 /*
642 * XXX: NSP_QUIRK
643 * data phase skip only occures in case of SCSI_LOW_READ
644 */
645 nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
646 SCpnt->SCp.phase = PH_DATA;
647 nsp_pio_read(SCpnt);
648 nsp_setup_fifo(data, FALSE);
649
650 return 0;
651}
652
653/*
654 * accept reselection
655 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700656static int nsp_reselected(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 unsigned int base = SCpnt->device->host->io_port;
659 unsigned int host_id = SCpnt->device->host->this_id;
660 //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
661 unsigned char bus_reg;
662 unsigned char id_reg, tmp;
663 int target;
664
665 nsp_dbg(NSP_DEBUG_RESELECTION, "in");
666
667 id_reg = nsp_index_read(base, RESELECTID);
668 tmp = id_reg & (~BIT(host_id));
669 target = 0;
670 while(tmp != 0) {
671 if (tmp & BIT(0)) {
672 break;
673 }
674 tmp >>= 1;
675 target++;
676 }
677
Jeff Garzik422c0d62005-10-24 18:05:09 -0400678 if (scmd_id(SCpnt) != target) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
680 }
681
682 nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
683
684 nsp_nexus(SCpnt);
685 bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
686 nsp_index_write(base, SCSIBUSCTRL, bus_reg);
687 nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
688
689 return TRUE;
690}
691
692/*
693 * count how many data transferd
694 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700695static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
697 unsigned int base = SCpnt->device->host->io_port;
698 unsigned int count;
699 unsigned int l, m, h, dummy;
700
701 nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
702
703 l = nsp_index_read(base, TRANSFERCOUNT);
704 m = nsp_index_read(base, TRANSFERCOUNT);
705 h = nsp_index_read(base, TRANSFERCOUNT);
706 dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
707
708 count = (h << 16) | (m << 8) | (l << 0);
709
710 //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
711
712 return count;
713}
714
715/* fifo size */
716#define RFIFO_CRIT 64
717#define WFIFO_CRIT 64
718
719/*
720 * read data in DATA IN phase
721 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700722static void nsp_pio_read(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
724 unsigned int base = SCpnt->device->host->io_port;
725 unsigned long mmio_base = SCpnt->device->host->base;
726 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
727 long time_out;
728 int ocount, res;
729 unsigned char stat, fifo_stat;
730
731 ocount = data->FifoCount;
732
733 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",
734 SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
735
736 time_out = 1000;
737
738 while ((time_out-- != 0) &&
739 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
740
741 stat = nsp_index_read(base, SCSIBUSMON);
742 stat &= BUSMON_PHASE_MASK;
743
744
745 res = nsp_fifo_count(SCpnt) - ocount;
746 //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);
747 if (res == 0) { /* if some data avilable ? */
748 if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
749 //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
750 continue;
751 } else {
752 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
753 break;
754 }
755 }
756
757 fifo_stat = nsp_read(base, FIFOSTATUS);
758 if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
759 stat == BUSPHASE_DATA_IN) {
760 continue;
761 }
762
763 res = min(res, SCpnt->SCp.this_residual);
764
765 switch (data->TransferMode) {
766 case MODE_IO32:
767 res &= ~(BIT(1)|BIT(0)); /* align 4 */
768 nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
769 break;
770 case MODE_IO8:
771 nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
772 break;
773
774 case MODE_MEM32:
775 res &= ~(BIT(1)|BIT(0)); /* align 4 */
776 nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
777 break;
778
779 default:
780 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
781 return;
782 }
783
784 SCpnt->resid -= res;
785 SCpnt->SCp.ptr += res;
786 SCpnt->SCp.this_residual -= res;
787 ocount += res;
788 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
789
790 /* go to next scatter list if available */
791 if (SCpnt->SCp.this_residual == 0 &&
792 SCpnt->SCp.buffers_residual != 0 ) {
793 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
794 SCpnt->SCp.buffers_residual--;
795 SCpnt->SCp.buffer++;
796 SCpnt->SCp.ptr = BUFFER_ADDR;
797 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
798 time_out = 1000;
799
800 //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
801 }
802 }
803
804 data->FifoCount = ocount;
805
806 if (time_out == 0) {
807 nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
808 SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
809 }
810 nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
811 nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
812}
813
814/*
815 * write data in DATA OUT phase
816 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700817static void nsp_pio_write(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818{
819 unsigned int base = SCpnt->device->host->io_port;
820 unsigned long mmio_base = SCpnt->device->host->base;
821 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
822 int time_out;
823 int ocount, res;
824 unsigned char stat;
825
826 ocount = data->FifoCount;
827
828 nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
829 data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
830
831 time_out = 1000;
832
833 while ((time_out-- != 0) &&
834 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
835 stat = nsp_index_read(base, SCSIBUSMON);
836 stat &= BUSMON_PHASE_MASK;
837
838 if (stat != BUSPHASE_DATA_OUT) {
839 res = ocount - nsp_fifo_count(SCpnt);
840
841 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
842 /* Put back pointer */
843 SCpnt->resid += res;
844 SCpnt->SCp.ptr -= res;
845 SCpnt->SCp.this_residual += res;
846 ocount -= res;
847
848 break;
849 }
850
851 res = ocount - nsp_fifo_count(SCpnt);
852 if (res > 0) { /* write all data? */
853 nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
854 continue;
855 }
856
857 res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
858
859 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
860 switch (data->TransferMode) {
861 case MODE_IO32:
862 res &= ~(BIT(1)|BIT(0)); /* align 4 */
863 nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
864 break;
865 case MODE_IO8:
866 nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
867 break;
868
869 case MODE_MEM32:
870 res &= ~(BIT(1)|BIT(0)); /* align 4 */
871 nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
872 break;
873
874 default:
875 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
876 break;
877 }
878
879 SCpnt->resid -= res;
880 SCpnt->SCp.ptr += res;
881 SCpnt->SCp.this_residual -= res;
882 ocount += res;
883
884 /* go to next scatter list if available */
885 if (SCpnt->SCp.this_residual == 0 &&
886 SCpnt->SCp.buffers_residual != 0 ) {
887 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
888 SCpnt->SCp.buffers_residual--;
889 SCpnt->SCp.buffer++;
890 SCpnt->SCp.ptr = BUFFER_ADDR;
891 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
892 time_out = 1000;
893 }
894 }
895
896 data->FifoCount = ocount;
897
898 if (time_out == 0) {
899 nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
900 }
901 nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
902 nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
903}
904#undef RFIFO_CRIT
905#undef WFIFO_CRIT
906
907/*
908 * setup synchronous/asynchronous data transfer mode
909 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700910static int nsp_nexus(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400913 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914// unsigned char lun = SCpnt->device->lun;
915 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
916 sync_data *sync = &(data->Sync[target]);
917
918 //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
919
920 /* setup synch transfer registers */
921 nsp_index_write(base, SYNCREG, sync->SyncRegister);
922 nsp_index_write(base, ACKWIDTH, sync->AckWidth);
923
924 if (SCpnt->use_sg == 0 ||
925 SCpnt->resid % 4 != 0 ||
926 SCpnt->resid <= PAGE_SIZE ) {
927 data->TransferMode = MODE_IO8;
928 } else if (nsp_burst_mode == BURST_MEM32) {
929 data->TransferMode = MODE_MEM32;
930 } else if (nsp_burst_mode == BURST_IO32) {
931 data->TransferMode = MODE_IO32;
932 } else {
933 data->TransferMode = MODE_IO8;
934 }
935
936 /* setup pdma fifo */
937 nsp_setup_fifo(data, TRUE);
938
939 /* clear ack counter */
940 data->FifoCount = 0;
941 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
942 ACK_COUNTER_CLEAR |
943 REQ_COUNTER_CLEAR |
944 HOST_COUNTER_CLEAR);
945
946 return 0;
947}
948
949#include "nsp_message.c"
950/*
951 * interrupt handler
952 */
David Howells7d12e782006-10-05 14:55:46 +0100953static irqreturn_t nspintr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954{
955 unsigned int base;
956 unsigned char irq_status, irq_phase, phase;
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700957 struct scsi_cmnd *tmpSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 unsigned char target, lun;
959 unsigned int *sync_neg;
960 int i, tmp;
961 nsp_hw_data *data;
962
963
964 //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
965 //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
966
967 if ( dev_id != NULL &&
968 ((scsi_info_t *)dev_id)->host != NULL ) {
969 scsi_info_t *info = (scsi_info_t *)dev_id;
970
971 data = (nsp_hw_data *)info->host->hostdata;
972 } else {
973 nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
974 return IRQ_NONE;
975 }
976
977 //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
978
979 base = data->BaseAddress;
980 //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
981
982 /*
983 * interrupt check
984 */
985 nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
986 irq_status = nsp_read(base, IRQSTATUS);
987 //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
988 if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
989 nsp_write(base, IRQCONTROL, 0);
990 //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
991 return IRQ_NONE;
992 }
993
994 /* XXX: IMPORTANT
995 * Do not read an irq_phase register if no scsi phase interrupt.
996 * Unless, you should lose a scsi phase interrupt.
997 */
998 phase = nsp_index_read(base, SCSIBUSMON);
999 if((irq_status & IRQSTATUS_SCSI) != 0) {
1000 irq_phase = nsp_index_read(base, IRQPHASESENCE);
1001 } else {
1002 irq_phase = 0;
1003 }
1004
1005 //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1006
1007 /*
1008 * timer interrupt handler (scsi vs timer interrupts)
1009 */
1010 //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1011 if (data->TimerCount != 0) {
1012 //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1013 nsp_index_write(base, TIMERCOUNT, 0);
1014 nsp_index_write(base, TIMERCOUNT, 0);
1015 data->TimerCount = 0;
1016 }
1017
1018 if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1019 data->SelectionTimeOut == 0) {
1020 //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1021 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1022 return IRQ_HANDLED;
1023 }
1024
1025 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1026
1027 if ((irq_status & IRQSTATUS_SCSI) &&
1028 (irq_phase & SCSI_RESET_IRQ)) {
1029 nsp_msg(KERN_ERR, "bus reset (power off?)");
1030
1031 nsphw_init(data);
1032 nsp_bus_reset(data);
1033
1034 if(data->CurrentSC != NULL) {
1035 tmpSC = data->CurrentSC;
1036 tmpSC->result = (DID_RESET << 16) |
1037 ((tmpSC->SCp.Message & 0xff) << 8) |
1038 ((tmpSC->SCp.Status & 0xff) << 0);
1039 nsp_scsi_done(tmpSC);
1040 }
1041 return IRQ_HANDLED;
1042 }
1043
1044 if (data->CurrentSC == NULL) {
1045 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);
1046 nsphw_init(data);
1047 nsp_bus_reset(data);
1048 return IRQ_HANDLED;
1049 }
1050
1051 tmpSC = data->CurrentSC;
1052 target = tmpSC->device->id;
1053 lun = tmpSC->device->lun;
1054 sync_neg = &(data->Sync[target].SyncNegotiation);
1055
1056 /*
1057 * parse hardware SCSI irq reasons register
1058 */
1059 if (irq_status & IRQSTATUS_SCSI) {
1060 if (irq_phase & RESELECT_IRQ) {
1061 nsp_dbg(NSP_DEBUG_INTR, "reselect");
1062 nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1063 if (nsp_reselected(tmpSC) != FALSE) {
1064 return IRQ_HANDLED;
1065 }
1066 }
1067
1068 if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1069 return IRQ_HANDLED;
1070 }
1071 }
1072
1073 //show_phase(tmpSC);
1074
1075 switch(tmpSC->SCp.phase) {
1076 case PH_SELSTART:
1077 // *sync_neg = SYNC_NOT_YET;
1078 if ((phase & BUSMON_BSY) == 0) {
1079 //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1080 if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1081 nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1082 data->SelectionTimeOut = 0;
1083 nsp_index_write(base, SCSIBUSCTRL, 0);
1084
1085 tmpSC->result = DID_TIME_OUT << 16;
1086 nsp_scsi_done(tmpSC);
1087
1088 return IRQ_HANDLED;
1089 }
1090 data->SelectionTimeOut += 1;
1091 nsp_start_timer(tmpSC, 1000/51);
1092 return IRQ_HANDLED;
1093 }
1094
1095 /* attention assert */
1096 //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1097 data->SelectionTimeOut = 0;
1098 tmpSC->SCp.phase = PH_SELECTED;
1099 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1100 udelay(1);
1101 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1102 return IRQ_HANDLED;
1103
1104 break;
1105
1106 case PH_RESELECT:
1107 //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1108 // *sync_neg = SYNC_NOT_YET;
1109 if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1110
1111 tmpSC->result = DID_ABORT << 16;
1112 nsp_scsi_done(tmpSC);
1113 return IRQ_HANDLED;
1114 }
1115 /* fall thru */
1116 default:
1117 if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1118 return IRQ_HANDLED;
1119 }
1120 break;
1121 }
1122
1123 /*
1124 * SCSI sequencer
1125 */
1126 //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1127
1128 /* normal disconnect */
1129 if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1130 (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1131 nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1132
1133 //*sync_neg = SYNC_NOT_YET;
1134
1135 if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
1136 tmpSC->result = (DID_OK << 16) |
1137 ((tmpSC->SCp.Message & 0xff) << 8) |
1138 ((tmpSC->SCp.Status & 0xff) << 0);
1139 nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1140 nsp_scsi_done(tmpSC);
1141
1142 return IRQ_HANDLED;
1143 }
1144
1145 return IRQ_HANDLED;
1146 }
1147
1148
1149 /* check unexpected bus free state */
1150 if (phase == 0) {
1151 nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1152
1153 *sync_neg = SYNC_NG;
1154 tmpSC->result = DID_ERROR << 16;
1155 nsp_scsi_done(tmpSC);
1156 return IRQ_HANDLED;
1157 }
1158
1159 switch (phase & BUSMON_PHASE_MASK) {
1160 case BUSPHASE_COMMAND:
1161 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1162 if ((phase & BUSMON_REQ) == 0) {
1163 nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1164 return IRQ_HANDLED;
1165 }
1166
1167 tmpSC->SCp.phase = PH_COMMAND;
1168
1169 nsp_nexus(tmpSC);
1170
1171 /* write scsi command */
1172 nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1173 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1174 for (i = 0; i < tmpSC->cmd_len; i++) {
1175 nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1176 }
1177 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1178 break;
1179
1180 case BUSPHASE_DATA_OUT:
1181 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1182
1183 tmpSC->SCp.phase = PH_DATA;
1184 tmpSC->SCp.have_data_in = IO_OUT;
1185
1186 nsp_pio_write(tmpSC);
1187
1188 break;
1189
1190 case BUSPHASE_DATA_IN:
1191 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1192
1193 tmpSC->SCp.phase = PH_DATA;
1194 tmpSC->SCp.have_data_in = IO_IN;
1195
1196 nsp_pio_read(tmpSC);
1197
1198 break;
1199
1200 case BUSPHASE_STATUS:
1201 nsp_dataphase_bypass(tmpSC);
1202 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1203
1204 tmpSC->SCp.phase = PH_STATUS;
1205
1206 tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1207 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1208
1209 break;
1210
1211 case BUSPHASE_MESSAGE_OUT:
1212 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1213 if ((phase & BUSMON_REQ) == 0) {
1214 goto timer_out;
1215 }
1216
1217 tmpSC->SCp.phase = PH_MSG_OUT;
1218
1219 //*sync_neg = SYNC_NOT_YET;
1220
1221 data->MsgLen = i = 0;
1222 data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1223
1224 if (*sync_neg == SYNC_NOT_YET) {
1225 data->Sync[target].SyncPeriod = 0;
1226 data->Sync[target].SyncOffset = 0;
1227
1228 /**/
1229 data->MsgBuffer[i] = MSG_EXTENDED; i++;
1230 data->MsgBuffer[i] = 3; i++;
1231 data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1232 data->MsgBuffer[i] = 0x0c; i++;
1233 data->MsgBuffer[i] = 15; i++;
1234 /**/
1235 }
1236 data->MsgLen = i;
1237
1238 nsp_analyze_sdtr(tmpSC);
1239 show_message(data);
1240 nsp_message_out(tmpSC);
1241 break;
1242
1243 case BUSPHASE_MESSAGE_IN:
1244 nsp_dataphase_bypass(tmpSC);
1245 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1246 if ((phase & BUSMON_REQ) == 0) {
1247 goto timer_out;
1248 }
1249
1250 tmpSC->SCp.phase = PH_MSG_IN;
1251 nsp_message_in(tmpSC);
1252
1253 /**/
1254 if (*sync_neg == SYNC_NOT_YET) {
1255 //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1256
1257 if (data->MsgLen >= 5 &&
1258 data->MsgBuffer[0] == MSG_EXTENDED &&
1259 data->MsgBuffer[1] == 3 &&
1260 data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1261 data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1262 data->Sync[target].SyncOffset = data->MsgBuffer[4];
1263 //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1264 *sync_neg = SYNC_OK;
1265 } else {
1266 data->Sync[target].SyncPeriod = 0;
1267 data->Sync[target].SyncOffset = 0;
1268 *sync_neg = SYNC_NG;
1269 }
1270 nsp_analyze_sdtr(tmpSC);
1271 }
1272 /**/
1273
1274 /* search last messeage byte */
1275 tmp = -1;
1276 for (i = 0; i < data->MsgLen; i++) {
1277 tmp = data->MsgBuffer[i];
1278 if (data->MsgBuffer[i] == MSG_EXTENDED) {
1279 i += (1 + data->MsgBuffer[i+1]);
1280 }
1281 }
1282 tmpSC->SCp.Message = tmp;
1283
1284 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1285 show_message(data);
1286
1287 break;
1288
1289 case BUSPHASE_SELECT:
1290 default:
1291 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1292
1293 break;
1294 }
1295
1296 //nsp_dbg(NSP_DEBUG_INTR, "out");
1297 return IRQ_HANDLED;
1298
1299timer_out:
1300 nsp_start_timer(tmpSC, 1000/102);
1301 return IRQ_HANDLED;
1302}
1303
1304#ifdef NSP_DEBUG
1305#include "nsp_debug.c"
1306#endif /* NSP_DEBUG */
1307
1308/*----------------------------------------------------------------*/
1309/* look for ninja3 card and init if found */
1310/*----------------------------------------------------------------*/
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001311static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312{
1313 struct Scsi_Host *host; /* registered host structure */
1314 nsp_hw_data *data_b = &nsp_data_base, *data;
1315
1316 nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
1317#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
1318 host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
1319#else
1320 host = scsi_register(sht, sizeof(nsp_hw_data));
1321#endif
1322 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
1358#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001359static int nsp_detect_old(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360{
1361 if (nsp_detect(sht) == NULL) {
1362 return 0;
1363 } else {
1364 //MOD_INC_USE_COUNT;
1365 return 1;
1366 }
1367}
1368
1369
1370static int nsp_release_old(struct Scsi_Host *shpnt)
1371{
1372 //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1373
1374 /* PCMCIA Card Service dose same things below. */
1375 /* So we do nothing. */
1376 //if (shpnt->irq) {
1377 // free_irq(shpnt->irq, data->ScsiInfo);
1378 //}
1379 //if (shpnt->io_port) {
1380 // release_region(shpnt->io_port, shpnt->n_io_port);
1381 //}
1382
1383 //MOD_DEC_USE_COUNT;
1384
1385 return 0;
1386}
1387#endif
1388
1389/*----------------------------------------------------------------*/
1390/* return info string */
1391/*----------------------------------------------------------------*/
1392static const char *nsp_info(struct Scsi_Host *shpnt)
1393{
1394 nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1395
1396 return data->nspinfo;
1397}
1398
1399#undef SPRINTF
1400#define SPRINTF(args...) \
1401 do { \
1402 if(length > (pos - buffer)) { \
1403 pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
1404 nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
1405 } \
1406 } while(0)
1407static int
1408nsp_proc_info(
1409#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
1410 struct Scsi_Host *host,
1411#endif
1412 char *buffer,
1413 char **start,
1414 off_t offset,
1415 int length,
1416#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
1417 int hostno,
1418#endif
1419 int inout)
1420{
1421 int id;
1422 char *pos = buffer;
1423 int thislength;
1424 int speed;
1425 unsigned long flags;
1426 nsp_hw_data *data;
1427#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
1428 struct Scsi_Host *host;
1429#else
1430 int hostno;
1431#endif
1432 if (inout) {
1433 return -EINVAL;
1434 }
1435
1436#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
1437 hostno = host->host_no;
1438#else
1439 /* search this HBA host */
1440 host = scsi_host_hn_get(hostno);
1441 if (host == NULL) {
1442 return -ESRCH;
1443 }
1444#endif
1445 data = (nsp_hw_data *)host->hostdata;
1446
1447
1448 SPRINTF("NinjaSCSI status\n\n");
1449 SPRINTF("Driver version: $Revision: 1.23 $\n");
1450 SPRINTF("SCSI host No.: %d\n", hostno);
1451 SPRINTF("IRQ: %d\n", host->irq);
1452 SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1453 SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1454 SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
1455
1456 SPRINTF("burst transfer mode: ");
1457 switch (nsp_burst_mode) {
1458 case BURST_IO8:
1459 SPRINTF("io8");
1460 break;
1461 case BURST_IO32:
1462 SPRINTF("io32");
1463 break;
1464 case BURST_MEM32:
1465 SPRINTF("mem32");
1466 break;
1467 default:
1468 SPRINTF("???");
1469 break;
1470 }
1471 SPRINTF("\n");
1472
1473
1474 spin_lock_irqsave(&(data->Lock), flags);
1475 SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
1476 spin_unlock_irqrestore(&(data->Lock), flags);
1477
1478 SPRINTF("SDTR status\n");
1479 for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1480
1481 SPRINTF("id %d: ", id);
1482
1483 if (id == host->this_id) {
1484 SPRINTF("----- NinjaSCSI-3 host adapter\n");
1485 continue;
1486 }
1487
1488 switch(data->Sync[id].SyncNegotiation) {
1489 case SYNC_OK:
1490 SPRINTF(" sync");
1491 break;
1492 case SYNC_NG:
1493 SPRINTF("async");
1494 break;
1495 case SYNC_NOT_YET:
1496 SPRINTF(" none");
1497 break;
1498 default:
1499 SPRINTF("?????");
1500 break;
1501 }
1502
1503 if (data->Sync[id].SyncPeriod != 0) {
1504 speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1505
1506 SPRINTF(" transfer %d.%dMB/s, offset %d",
1507 speed / 1000,
1508 speed % 1000,
1509 data->Sync[id].SyncOffset
1510 );
1511 }
1512 SPRINTF("\n");
1513 }
1514
1515 thislength = pos - (buffer + offset);
1516
1517 if(thislength < 0) {
1518 *start = NULL;
1519 return 0;
1520 }
1521
1522
1523 thislength = min(thislength, length);
1524 *start = buffer + offset;
1525
1526 return thislength;
1527}
1528#undef SPRINTF
1529
1530/*---------------------------------------------------------------*/
1531/* error handler */
1532/*---------------------------------------------------------------*/
1533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534/*
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001535static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
1537 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1538
1539 return nsp_eh_bus_reset(SCpnt);
1540}*/
1541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542static int nsp_bus_reset(nsp_hw_data *data)
1543{
1544 unsigned int base = data->BaseAddress;
1545 int i;
1546
1547 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1548
1549 nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1550 mdelay(100); /* 100ms */
1551 nsp_index_write(base, SCSIBUSCTRL, 0);
1552 for(i = 0; i < 5; i++) {
1553 nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1554 }
1555
1556 nsphw_init_sync(data);
1557
1558 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1559
1560 return SUCCESS;
1561}
1562
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001563static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
1565 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1566
1567 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1568
1569 return nsp_bus_reset(data);
1570}
1571
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001572static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573{
1574 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1575
1576 nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1577
1578 nsphw_init(data);
1579
1580 return SUCCESS;
1581}
1582
1583
1584/**********************************************************************
1585 PCMCIA functions
1586**********************************************************************/
1587
1588/*======================================================================
1589 nsp_cs_attach() creates an "instance" of the driver, allocating
1590 local data structures for one device. The device is registered
1591 with Card Services.
1592
1593 The dev_link structure is initialized, but we don't actually
1594 configure the card at this point -- we wait until we receive a
1595 card insertion event.
1596======================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001597static int nsp_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598{
1599 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 nsp_hw_data *data = &nsp_data_base;
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001601 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602
1603 nsp_dbg(NSP_DEBUG_INIT, "in");
1604
1605 /* Create new SCSI device */
1606 info = kmalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001607 if (info == NULL) { return -ENOMEM; }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 memset(info, 0, sizeof(*info));
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001609 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 link->priv = info;
1611 data->ScsiInfo = info;
1612
1613 nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1614
1615 /* The io structure describes IO port mapping */
1616 link->io.NumPorts1 = 0x10;
1617 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1618 link->io.IOAddrLines = 10; /* not used */
1619
1620 /* Interrupt setup */
1621 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
1622 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
1623
1624 /* Interrupt handler */
1625 link->irq.Handler = &nspintr;
1626 link->irq.Instance = info;
James Bottomleyc4e00fa2006-07-03 09:41:12 -05001627 link->irq.Attributes |= IRQF_SHARED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 /* General socket configuration */
1630 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 link->conf.IntType = INT_MEMORY_AND_IO;
1632 link->conf.Present = PRESENT_OPTION;
1633
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001634 ret = nsp_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
1636 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001637 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638} /* nsp_cs_attach */
1639
1640
1641/*======================================================================
1642 This deletes a driver "instance". The device is de-registered
1643 with Card Services. If it has been released, all local data
1644 structures are freed. Otherwise, the structures will be freed
1645 when the device is released.
1646======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001647static void nsp_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1650
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001651 ((scsi_info_t *)link->priv)->stop = 1;
1652 nsp_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 kfree(link->priv);
1655 link->priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656} /* nsp_cs_detach */
1657
1658
1659/*======================================================================
1660 nsp_cs_config() is scheduled to run after a CARD_INSERTION event
1661 is received, to configure the PCMCIA socket, and to make the
1662 ethernet device available to the system.
1663======================================================================*/
1664#define CS_CHECK(fn, ret) \
1665do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
1666/*====================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001667static int nsp_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001669 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 scsi_info_t *info = link->priv;
1671 tuple_t tuple;
1672 cisparse_t parse;
1673 int last_ret, last_fn;
1674 unsigned char tuple_data[64];
1675 config_info_t conf;
1676 win_req_t req;
1677 memreq_t map;
1678 cistpl_cftable_entry_t dflt = { 0 };
1679 struct Scsi_Host *host;
1680 nsp_hw_data *data = &nsp_data_base;
1681#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
Christoph Hellwigf64a1812005-10-31 18:32:08 +01001682 struct scsi_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 dev_node_t **tail, *node;
1684#endif
1685
1686 nsp_dbg(NSP_DEBUG_INIT, "in");
1687
1688 tuple.DesiredTuple = CISTPL_CONFIG;
1689 tuple.Attributes = 0;
1690 tuple.TupleData = tuple_data;
1691 tuple.TupleDataMax = sizeof(tuple_data);
1692 tuple.TupleOffset = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001693 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
1694 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
1695 CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 link->conf.ConfigBase = parse.config.base;
1697 link->conf.Present = parse.config.rmask[0];
1698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 /* Look up the current Vcc */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001700 CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001703 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 while (1) {
1705 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
1706
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001707 if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
1708 pcmcia_parse_tuple(link, &tuple, &parse) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 goto next_entry;
1710
1711 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
1712 if (cfg->index == 0) { goto next_entry; }
1713 link->conf.ConfigIndex = cfg->index;
1714
1715 /* Does this card need audio output? */
1716 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
1717 link->conf.Attributes |= CONF_ENABLE_SPKR;
1718 link->conf.Status = CCSR_AUDIO_ENA;
1719 }
1720
1721 /* Use power settings for Vcc and Vpp if present */
1722 /* Note that the CIS values need to be rescaled */
1723 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
1724 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
1725 goto next_entry;
1726 }
1727 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
1728 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
1729 goto next_entry;
1730 }
1731 }
1732
1733 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001734 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
1736 } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowski70294b42006-01-15 12:43:16 +01001737 link->conf.Vpp =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
1739 }
1740
1741 /* Do we need to allocate an interrupt? */
1742 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
1743 link->conf.Attributes |= CONF_ENABLE_IRQ;
1744 }
1745
1746 /* IO window settings */
1747 link->io.NumPorts1 = link->io.NumPorts2 = 0;
1748 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
1749 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
1750 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
1751 if (!(io->flags & CISTPL_IO_8BIT))
1752 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
1753 if (!(io->flags & CISTPL_IO_16BIT))
1754 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
1755 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
1756 link->io.BasePort1 = io->win[0].base;
1757 link->io.NumPorts1 = io->win[0].len;
1758 if (io->nwin > 1) {
1759 link->io.Attributes2 = link->io.Attributes1;
1760 link->io.BasePort2 = io->win[1].base;
1761 link->io.NumPorts2 = io->win[1].len;
1762 }
1763 /* This reserves IO space but doesn't actually enable it */
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001764 if (pcmcia_request_io(link, &link->io) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 goto next_entry;
1766 }
1767
1768 if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
1769 cistpl_mem_t *mem =
1770 (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
1771 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
1772 req.Attributes |= WIN_ENABLE;
1773 req.Base = mem->win[0].host_addr;
1774 req.Size = mem->win[0].len;
1775 if (req.Size < 0x1000) {
1776 req.Size = 0x1000;
1777 }
1778 req.AccessSpeed = 0;
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001779 if (pcmcia_request_window(&link, &req, &link->win) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 goto next_entry;
1781 map.Page = 0; map.CardOffset = mem->win[0].card_addr;
1782 if (pcmcia_map_mem_page(link->win, &map) != 0)
1783 goto next_entry;
1784
1785 data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
1786 data->MmioLength = req.Size;
1787 }
1788 /* If we got this far, we're cool! */
1789 break;
1790
1791 next_entry:
1792 nsp_dbg(NSP_DEBUG_INIT, "next");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001793 pcmcia_disable_device(link);
1794 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 }
1796
1797 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001798 CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001800 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802 if (free_ports) {
1803 if (link->io.BasePort1) {
1804 release_region(link->io.BasePort1, link->io.NumPorts1);
1805 }
1806 if (link->io.BasePort2) {
1807 release_region(link->io.BasePort2, link->io.NumPorts2);
1808 }
1809 }
1810
1811 /* Set port and IRQ */
1812 data->BaseAddress = link->io.BasePort1;
1813 data->NumAddress = link->io.NumPorts1;
1814 data->IrqNumber = link->irq.AssignedIRQ;
1815
1816 nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1817 data->BaseAddress, data->NumAddress, data->IrqNumber);
1818
1819 if(nsphw_init(data) == FALSE) {
1820 goto cs_failed;
1821 }
1822
1823#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
1824 host = nsp_detect(&nsp_driver_template);
1825#else
1826 scsi_register_host(&nsp_driver_template);
1827 for (host = scsi_host_get_next(NULL); host != NULL;
1828 host = scsi_host_get_next(host)) {
1829 if (host->hostt == &nsp_driver_template) {
1830 break;
1831 }
1832 }
1833#endif
1834
1835 if (host == NULL) {
1836 nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1837 goto cs_failed;
1838 }
1839
1840
1841#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001842 ret = scsi_add_host (host, NULL);
1843 if (ret)
1844 goto cs_failed;
1845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 scsi_scan_host(host);
1847
1848 snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
Dominik Brodowskifd238232006-03-05 10:45:09 +01001849 link->dev_node = &info->node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 info->host = host;
1851
1852#else
1853 nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
Dominik Brodowskifd238232006-03-05 10:45:09 +01001854 tail = &link->dev_node;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 info->ndev = 0;
1856
1857 nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
1858
1859 for (dev = host->host_queue; dev != NULL; dev = dev->next) {
1860 unsigned long id;
1861 id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) +
1862 ((dev->channel & 0x0f) << 8) +
1863 ((dev->host->host_no & 0x0f) << 12);
1864 node = &info->node[info->ndev];
1865 node->minor = 0;
1866 switch (dev->type) {
1867 case TYPE_TAPE:
1868 node->major = SCSI_TAPE_MAJOR;
1869 snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
1870 break;
1871 case TYPE_DISK:
1872 case TYPE_MOD:
1873 node->major = SCSI_DISK0_MAJOR;
1874 snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
1875 break;
1876 case TYPE_ROM:
1877 case TYPE_WORM:
1878 node->major = SCSI_CDROM_MAJOR;
1879 snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
1880 break;
1881 default:
1882 node->major = SCSI_GENERIC_MAJOR;
1883 snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
1884 break;
1885 }
1886 *tail = node; tail = &node->next;
1887 info->ndev++;
1888 info->host = dev->host;
1889 }
1890
1891 *tail = NULL;
1892 if (info->ndev == 0) {
1893 nsp_msg(KERN_INFO, "no SCSI devices found");
1894 }
1895 nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
1896#endif
1897
1898 /* Finally, report what we've done */
Dominik Brodowski70294b42006-01-15 12:43:16 +01001899 printk(KERN_INFO "nsp_cs: index 0x%02x: ",
1900 link->conf.ConfigIndex);
1901 if (link->conf.Vpp) {
1902 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 }
1904 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
1905 printk(", irq %d", link->irq.AssignedIRQ);
1906 }
1907 if (link->io.NumPorts1) {
1908 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
1909 link->io.BasePort1+link->io.NumPorts1-1);
1910 }
1911 if (link->io.NumPorts2)
1912 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
1913 link->io.BasePort2+link->io.NumPorts2-1);
1914 if (link->win)
1915 printk(", mem 0x%06lx-0x%06lx", req.Base,
1916 req.Base+req.Size-1);
1917 printk("\n");
1918
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001919 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921 cs_failed:
1922 nsp_dbg(NSP_DEBUG_INIT, "config fail");
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001923 cs_error(link, last_fn, last_ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 nsp_cs_release(link);
1925
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001926 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927} /* nsp_cs_config */
1928#undef CS_CHECK
1929
1930
1931/*======================================================================
1932 After a card is removed, nsp_cs_release() will unregister the net
1933 device, and release the PCMCIA configuration. If the device is
1934 still open, this will be postponed until it is closed.
1935======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001936static void nsp_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937{
1938 scsi_info_t *info = link->priv;
1939 nsp_hw_data *data = NULL;
1940
1941 if (info->host == NULL) {
1942 nsp_msg(KERN_DEBUG, "unexpected card release call.");
1943 } else {
1944 data = (nsp_hw_data *)info->host->hostdata;
1945 }
1946
1947 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1948
1949 /* Unlink the device chain */
1950#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
1951 if (info->host != NULL) {
1952 scsi_remove_host(info->host);
1953 }
1954#else
1955 scsi_unregister_host(&nsp_driver_template);
1956#endif
Dominik Brodowskifd238232006-03-05 10:45:09 +01001957 link->dev_node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 if (link->win) {
1960 if (data != NULL) {
1961 iounmap((void *)(data->MmioAddress));
1962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001964 pcmcia_disable_device(link);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
1967 if (info->host != NULL) {
1968 scsi_host_put(info->host);
1969 }
1970#endif
1971} /* nsp_cs_release */
1972
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001973static int nsp_cs_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001974{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001975 scsi_info_t *info = link->priv;
1976 nsp_hw_data *data;
1977
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001978 nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1979
1980 if (info->host != NULL) {
1981 nsp_msg(KERN_INFO, "clear SDTR status");
1982
1983 data = (nsp_hw_data *)info->host->hostdata;
1984
1985 nsphw_init_sync(data);
1986 }
1987
1988 info->stop = 1;
1989
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001990 return 0;
1991}
1992
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001993static int nsp_cs_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001994{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001995 scsi_info_t *info = link->priv;
1996 nsp_hw_data *data;
1997
1998 nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1999
Dominik Brodowski98e4c282005-11-14 21:21:18 +01002000 info->stop = 0;
2001
2002 if (info->host != NULL) {
2003 nsp_msg(KERN_INFO, "reset host and bus");
2004
2005 data = (nsp_hw_data *)info->host->hostdata;
2006
2007 nsphw_init (data);
2008 nsp_bus_reset(data);
2009 }
2010
2011 return 0;
2012}
2013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014/*======================================================================*
2015 * module entry point
2016 *====================================================================*/
2017#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
Dominik Brodowskiaba14102005-06-27 16:28:40 -07002018static struct pcmcia_device_id nsp_cs_ids[] = {
2019 PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
2020 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
2021 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
2022 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
2023 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
2024 PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
2025 PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
2026 PCMCIA_DEVICE_NULL
2027};
2028MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
2029
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030static struct pcmcia_driver nsp_driver = {
Dominik Brodowski1e212f32005-07-07 17:59:00 -07002031 .owner = THIS_MODULE,
2032 .drv = {
2033 .name = "nsp_cs",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02002035 .probe = nsp_cs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01002036 .remove = nsp_cs_detach,
Dominik Brodowskiaba14102005-06-27 16:28:40 -07002037 .id_table = nsp_cs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01002038 .suspend = nsp_cs_suspend,
2039 .resume = nsp_cs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040};
2041#endif
2042
2043static int __init nsp_cs_init(void)
2044{
2045#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
2046 nsp_msg(KERN_INFO, "loading...");
2047
2048 return pcmcia_register_driver(&nsp_driver);
2049#else
2050 servinfo_t serv;
2051
2052 nsp_msg(KERN_INFO, "loading...");
2053 pcmcia_get_card_services_info(&serv);
Pavel Roskin2ffe6e22005-07-07 17:59:04 -07002054 if (serv.Revision != CS_RELEASE_CODE) {
2055 nsp_msg(KERN_DEBUG, "Card Services release does not match!");
2056 return -EINVAL;
2057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
2059
2060 nsp_dbg(NSP_DEBUG_INIT, "out");
2061 return 0;
2062#endif
2063}
2064
2065static void __exit nsp_cs_exit(void)
2066{
2067 nsp_msg(KERN_INFO, "unloading...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 pcmcia_unregister_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069}
2070
2071
2072module_init(nsp_cs_init)
2073module_exit(nsp_cs_exit)
2074
2075/* end */