blob: b90cade36746dcf4367796673af1338746725e00 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
4 By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
5
6 Ver.2.8 Support 32bit MMIO mode
7 Support Synchronous Data Transfer Request (SDTR) mode
8 Ver.2.0 Support 32bit PIO mode
9 Ver.1.1.2 Fix for scatter list buffer exceeds
10 Ver.1.1 Support scatter list
11 Ver.0.1 Initial version
12
13 This software may be used and distributed according to the terms of
14 the GNU General Public License.
15
16======================================================================*/
17
18/***********************************************************************
19 This driver is for these PCcards.
20
21 I-O DATA PCSC-F (Workbit NinjaSCSI-3)
22 "WBT", "NinjaSCSI-3", "R1.0"
23 I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
24 "IO DATA", "CBSC16 ", "1"
25
26***********************************************************************/
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/timer.h>
34#include <linux/ioport.h>
35#include <linux/delay.h>
36#include <linux/interrupt.h>
37#include <linux/major.h>
38#include <linux/blkdev.h>
39#include <linux/stat.h>
40
41#include <asm/io.h>
42#include <asm/irq.h>
43
44#include <../drivers/scsi/scsi.h>
45#include <scsi/scsi_host.h>
46
47#include <scsi/scsi.h>
48#include <scsi/scsi_ioctl.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <pcmcia/cs.h>
51#include <pcmcia/cistpl.h>
52#include <pcmcia/cisreg.h>
53#include <pcmcia/ds.h>
54
55#include "nsp_cs.h"
56
57MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
Adrian Bunk774251e2007-10-02 14:38:01 -070058MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
Linus Torvalds1da177e2005-04-16 15:20:36 -070059MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
60#ifdef MODULE_LICENSE
61MODULE_LICENSE("GPL");
62#endif
63
64#include "nsp_io.h"
65
66/*====================================================================*/
67/* Parameters that can be set with 'insmod' */
68
69static int nsp_burst_mode = BURST_MEM32;
70module_param(nsp_burst_mode, int, 0);
71MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
72
73/* Release IO ports after configuration? */
74static int free_ports = 0;
75module_param(free_ports, bool, 0);
76MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
77
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +010078static struct scsi_host_template nsp_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 .proc_name = "nsp_cs",
80 .proc_info = nsp_proc_info,
81 .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 .info = nsp_info,
83 .queuecommand = nsp_queuecommand,
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* .eh_abort_handler = nsp_eh_abort,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 .eh_bus_reset_handler = nsp_eh_bus_reset,
86 .eh_host_reset_handler = nsp_eh_host_reset,
87 .can_queue = 1,
88 .this_id = NSP_INITIATOR_ID,
89 .sg_tablesize = SG_ALL,
90 .cmd_per_lun = 1,
91 .use_clustering = DISABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -070092};
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
95
96
97
98/*
99 * debug, error print
100 */
101#ifndef NSP_DEBUG
102# define NSP_DEBUG_MASK 0x000000
103# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
104# define nsp_dbg(mask, args...) /* */
105#else
106# define NSP_DEBUG_MASK 0xffffff
107# define nsp_msg(type, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700108 nsp_cs_message (__func__, __LINE__, (type), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109# define nsp_dbg(mask, args...) \
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700110 nsp_cs_dmessage(__func__, __LINE__, (mask), args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#endif
112
113#define NSP_DEBUG_QUEUECOMMAND BIT(0)
114#define NSP_DEBUG_REGISTER BIT(1)
115#define NSP_DEBUG_AUTOSCSI BIT(2)
116#define NSP_DEBUG_INTR BIT(3)
117#define NSP_DEBUG_SGLIST BIT(4)
118#define NSP_DEBUG_BUSFREE BIT(5)
119#define NSP_DEBUG_CDB_CONTENTS BIT(6)
120#define NSP_DEBUG_RESELECTION BIT(7)
121#define NSP_DEBUG_MSGINOCCUR BIT(8)
122#define NSP_DEBUG_EEPROM BIT(9)
123#define NSP_DEBUG_MSGOUTOCCUR BIT(10)
124#define NSP_DEBUG_BUSRESET BIT(11)
125#define NSP_DEBUG_RESTART BIT(12)
126#define NSP_DEBUG_SYNC BIT(13)
127#define NSP_DEBUG_WAIT BIT(14)
128#define NSP_DEBUG_TARGETFLAG BIT(15)
129#define NSP_DEBUG_PROC BIT(16)
130#define NSP_DEBUG_INIT BIT(17)
131#define NSP_DEBUG_DATA_IO BIT(18)
132#define NSP_SPECIAL_PRINT_REGISTER BIT(20)
133
134#define NSP_DEBUG_BUF_LEN 150
135
Boaz Harrosh040cd232007-08-16 13:01:05 +0300136static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
137{
138 scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
139}
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
142{
143 va_list args;
144 char buf[NSP_DEBUG_BUF_LEN];
145
146 va_start(args, fmt);
147 vsnprintf(buf, sizeof(buf), fmt, args);
148 va_end(args);
149
150#ifndef NSP_DEBUG
151 printk("%snsp_cs: %s\n", type, buf);
152#else
153 printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
154#endif
155}
156
157#ifdef NSP_DEBUG
158static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
159{
160 va_list args;
161 char buf[NSP_DEBUG_BUF_LEN];
162
163 va_start(args, fmt);
164 vsnprintf(buf, sizeof(buf), fmt, args);
165 va_end(args);
166
167 if (mask & NSP_DEBUG_MASK) {
168 printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
169 }
170}
171#endif
172
173/***********************************************************/
174
175/*====================================================
176 * Clenaup parameters and call done() functions.
177 * You must be set SCpnt->result before call this function.
178 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700179static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
182
183 data->CurrentSC = NULL;
184
185 SCpnt->scsi_done(SCpnt);
186}
187
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700188static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
189 void (*done)(struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
191#ifdef NSP_DEBUG
192 /*unsigned int host_id = SCpnt->device->host->this_id;*/
193 /*unsigned int base = SCpnt->device->host->io_port;*/
Jeff Garzik422c0d62005-10-24 18:05:09 -0400194 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195#endif
196 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
197
Boaz Harrosh040cd232007-08-16 13:01:05 +0300198 nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
199 "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
200 SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
201 scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
203
204 SCpnt->scsi_done = done;
205
206 if (data->CurrentSC != NULL) {
207 nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
208 SCpnt->result = DID_BAD_TARGET << 16;
209 nsp_scsi_done(SCpnt);
210 return 0;
211 }
212
213#if 0
214 /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
215 This makes kernel crash when suspending... */
216 if (data->ScsiInfo->stop != 0) {
217 nsp_msg(KERN_INFO, "suspending device. reject command.");
218 SCpnt->result = DID_BAD_TARGET << 16;
219 nsp_scsi_done(SCpnt);
220 return SCSI_MLQUEUE_HOST_BUSY;
221 }
222#endif
223
224 show_command(SCpnt);
225
226 data->CurrentSC = SCpnt;
227
228 SCpnt->SCp.Status = CHECK_CONDITION;
229 SCpnt->SCp.Message = 0;
230 SCpnt->SCp.have_data_in = IO_UNKNOWN;
231 SCpnt->SCp.sent_command = 0;
232 SCpnt->SCp.phase = PH_UNDETERMINED;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300233 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 /* setup scratch area
236 SCp.ptr : buffer pointer
237 SCp.this_residual : buffer length
238 SCp.buffer : next buffer
239 SCp.buffers_residual : left buffers in list
240 SCp.phase : current state of the command */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300241 if (scsi_bufflen(SCpnt)) {
242 SCpnt->SCp.buffer = scsi_sglist(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 SCpnt->SCp.ptr = BUFFER_ADDR;
244 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
Boaz Harrosh040cd232007-08-16 13:01:05 +0300245 SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 } else {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300247 SCpnt->SCp.ptr = NULL;
248 SCpnt->SCp.this_residual = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 SCpnt->SCp.buffer = NULL;
250 SCpnt->SCp.buffers_residual = 0;
251 }
252
253 if (nsphw_start_selection(SCpnt) == FALSE) {
254 nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
255 SCpnt->result = DID_BUS_BUSY << 16;
256 nsp_scsi_done(SCpnt);
257 return 0;
258 }
259
260
261 //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
262#ifdef NSP_DEBUG
263 data->CmdId++;
264#endif
265 return 0;
266}
267
268/*
269 * setup PIO FIFO transfer mode and enable/disable to data out
270 */
271static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
272{
273 unsigned int base = data->BaseAddress;
274 unsigned char transfer_mode_reg;
275
276 //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
277
278 if (enabled != FALSE) {
279 transfer_mode_reg = TRANSFER_GO | BRAIND;
280 } else {
281 transfer_mode_reg = 0;
282 }
283
284 transfer_mode_reg |= data->TransferMode;
285
286 nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
287}
288
289static void nsphw_init_sync(nsp_hw_data *data)
290{
291 sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
292 .SyncPeriod = 0,
293 .SyncOffset = 0
294 };
295 int i;
296
297 /* setup sync data */
298 for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
299 data->Sync[i] = tmp_sync;
300 }
301}
302
303/*
304 * Initialize Ninja hardware
305 */
306static int nsphw_init(nsp_hw_data *data)
307{
308 unsigned int base = data->BaseAddress;
309
310 nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
311
312 data->ScsiClockDiv = CLOCK_40M | FAST_20;
313 data->CurrentSC = NULL;
314 data->FifoCount = 0;
315 data->TransferMode = MODE_IO8;
316
317 nsphw_init_sync(data);
318
319 /* block all interrupts */
320 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
321
322 /* setup SCSI interface */
323 nsp_write(base, IFSELECT, IF_IFSEL);
324
325 nsp_index_write(base, SCSIIRQMODE, 0);
326
327 nsp_index_write(base, TRANSFERMODE, MODE_IO8);
328 nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
329
330 nsp_index_write(base, PARITYCTRL, 0);
331 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
332 ACK_COUNTER_CLEAR |
333 REQ_COUNTER_CLEAR |
334 HOST_COUNTER_CLEAR);
335
336 /* setup fifo asic */
337 nsp_write(base, IFSELECT, IF_REGSEL);
338 nsp_index_write(base, TERMPWRCTRL, 0);
339 if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
340 nsp_msg(KERN_INFO, "terminator power on");
341 nsp_index_write(base, TERMPWRCTRL, POWER_ON);
342 }
343
344 nsp_index_write(base, TIMERCOUNT, 0);
345 nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
346
347 nsp_index_write(base, SYNCREG, 0);
348 nsp_index_write(base, ACKWIDTH, 0);
349
350 /* enable interrupts and ack them */
351 nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
352 RESELECT_EI |
353 SCSI_RESET_IRQ_EI );
354 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
355
356 nsp_setup_fifo(data, FALSE);
357
358 return TRUE;
359}
360
361/*
362 * Start selection phase
363 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700364static int nsphw_start_selection(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366 unsigned int host_id = SCpnt->device->host->this_id;
367 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400368 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
370 int time_out;
371 unsigned char phase, arbit;
372
373 //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
374
375 phase = nsp_index_read(base, SCSIBUSMON);
376 if(phase != BUSMON_BUS_FREE) {
377 //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
378 return FALSE;
379 }
380
381 /* start arbitration */
382 //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
383 SCpnt->SCp.phase = PH_ARBSTART;
384 nsp_index_write(base, SETARBIT, ARBIT_GO);
385
386 time_out = 1000;
387 do {
388 /* XXX: what a stupid chip! */
389 arbit = nsp_index_read(base, ARBITSTATUS);
390 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
391 udelay(1); /* hold 1.2us */
392 } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
393 (time_out-- != 0));
394
395 if (!(arbit & ARBIT_WIN)) {
396 //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
397 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
398 return FALSE;
399 }
400
401 /* assert select line */
402 //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
403 SCpnt->SCp.phase = PH_SELSTART;
404 udelay(3); /* wait 2.4us */
405 nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
406 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
407 udelay(2); /* wait >1.2us */
408 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
409 nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
410 /*udelay(1);*/ /* wait >90ns */
411 nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
412
413 /* check selection timeout */
414 nsp_start_timer(SCpnt, 1000/51);
415 data->SelectionTimeOut = 1;
416
417 return TRUE;
418}
419
420struct nsp_sync_table {
421 unsigned int min_period;
422 unsigned int max_period;
423 unsigned int chip_period;
424 unsigned int ack_width;
425};
426
427static struct nsp_sync_table nsp_sync_table_40M[] = {
428 {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
429 {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
430 {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
431 {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
432 { 0, 0, 0, 0},
433};
434
435static struct nsp_sync_table nsp_sync_table_20M[] = {
436 {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
437 {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
438 {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
439 { 0, 0, 0, 0},
440};
441
442/*
443 * setup synchronous data transfer mode
444 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700445static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Jeff Garzik422c0d62005-10-24 18:05:09 -0400447 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448// unsigned char lun = SCpnt->device->lun;
449 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
450 sync_data *sync = &(data->Sync[target]);
451 struct nsp_sync_table *sync_table;
452 unsigned int period, offset;
453 int i;
454
455
456 nsp_dbg(NSP_DEBUG_SYNC, "in");
457
458 period = sync->SyncPeriod;
459 offset = sync->SyncOffset;
460
461 nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
462
463 if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
464 sync_table = nsp_sync_table_20M;
465 } else {
466 sync_table = nsp_sync_table_40M;
467 }
468
469 for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
470 if ( period >= sync_table->min_period &&
471 period <= sync_table->max_period ) {
472 break;
473 }
474 }
475
476 if (period != 0 && sync_table->max_period == 0) {
477 /*
478 * No proper period/offset found
479 */
480 nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
481
482 sync->SyncPeriod = 0;
483 sync->SyncOffset = 0;
484 sync->SyncRegister = 0;
485 sync->AckWidth = 0;
486
487 return FALSE;
488 }
489
490 sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
491 (offset & SYNCREG_OFFSET_MASK);
492 sync->AckWidth = sync_table->ack_width;
493
494 nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
495
496 return TRUE;
497}
498
499
500/*
501 * start ninja hardware timer
502 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700503static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 unsigned int base = SCpnt->device->host->io_port;
506 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
507
508 //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
509 data->TimerCount = time;
510 nsp_index_write(base, TIMERCOUNT, time);
511}
512
513/*
514 * wait for bus phase change
515 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700516static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
517 char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 unsigned int base = SCpnt->device->host->io_port;
520 unsigned char reg;
521 int time_out;
522
523 //nsp_dbg(NSP_DEBUG_INTR, "in");
524
525 time_out = 100;
526
527 do {
528 reg = nsp_index_read(base, SCSIBUSMON);
529 if (reg == 0xff) {
530 break;
531 }
Roel Kluin0454c742009-06-10 12:56:59 -0700532 } while ((--time_out != 0) && (reg & mask) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 if (time_out == 0) {
535 nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
536 }
537
538 return 0;
539}
540
541/*
542 * expect Ninja Irq
543 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700544static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
545 unsigned char current_phase,
546 unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 unsigned int base = SCpnt->device->host->io_port;
549 int time_out;
550 unsigned char phase, i_src;
551
552 //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
553
554 time_out = 100;
555 do {
556 phase = nsp_index_read(base, SCSIBUSMON);
557 if (phase == 0xff) {
558 //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
559 return -1;
560 }
561 i_src = nsp_read(base, IRQSTATUS);
562 if (i_src & IRQSTATUS_SCSI) {
563 //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
564 return 0;
565 }
566 if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
567 //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
568 return 1;
569 }
570 } while(time_out-- != 0);
571
572 //nsp_dbg(NSP_DEBUG_INTR, "timeout");
573 return -1;
574}
575
576/*
577 * transfer SCSI message
578 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700579static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
581 unsigned int base = SCpnt->device->host->io_port;
582 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
583 char *buf = data->MsgBuffer;
584 int len = min(MSGBUF_SIZE, data->MsgLen);
585 int ptr;
586 int ret;
587
588 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
589 for (ptr = 0; len > 0; len--, ptr++) {
590
591 ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
592 if (ret <= 0) {
593 nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
594 return 0;
595 }
596
597 /* if last byte, negate ATN */
598 if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
599 nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
600 }
601
602 /* read & write message */
603 if (phase & BUSMON_IO) {
604 nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
605 buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
606 } else {
607 nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
608 nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
609 }
610 nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
611
612 }
613 return len;
614}
615
616/*
617 * get extra SCSI data from fifo
618 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700619static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
621 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
622 unsigned int count;
623
624 //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
625
626 if (SCpnt->SCp.have_data_in != IO_IN) {
627 return 0;
628 }
629
630 count = nsp_fifo_count(SCpnt);
631 if (data->FifoCount == count) {
632 //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
633 return 0;
634 }
635
636 /*
637 * XXX: NSP_QUIRK
638 * data phase skip only occures in case of SCSI_LOW_READ
639 */
640 nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
641 SCpnt->SCp.phase = PH_DATA;
642 nsp_pio_read(SCpnt);
643 nsp_setup_fifo(data, FALSE);
644
645 return 0;
646}
647
648/*
649 * accept reselection
650 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700651static int nsp_reselected(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
653 unsigned int base = SCpnt->device->host->io_port;
654 unsigned int host_id = SCpnt->device->host->this_id;
655 //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
656 unsigned char bus_reg;
657 unsigned char id_reg, tmp;
658 int target;
659
660 nsp_dbg(NSP_DEBUG_RESELECTION, "in");
661
662 id_reg = nsp_index_read(base, RESELECTID);
663 tmp = id_reg & (~BIT(host_id));
664 target = 0;
665 while(tmp != 0) {
666 if (tmp & BIT(0)) {
667 break;
668 }
669 tmp >>= 1;
670 target++;
671 }
672
Jeff Garzik422c0d62005-10-24 18:05:09 -0400673 if (scmd_id(SCpnt) != target) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
675 }
676
677 nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
678
679 nsp_nexus(SCpnt);
680 bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
681 nsp_index_write(base, SCSIBUSCTRL, bus_reg);
682 nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
683
684 return TRUE;
685}
686
687/*
688 * count how many data transferd
689 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700690static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
692 unsigned int base = SCpnt->device->host->io_port;
693 unsigned int count;
694 unsigned int l, m, h, dummy;
695
696 nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
697
698 l = nsp_index_read(base, TRANSFERCOUNT);
699 m = nsp_index_read(base, TRANSFERCOUNT);
700 h = nsp_index_read(base, TRANSFERCOUNT);
701 dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
702
703 count = (h << 16) | (m << 8) | (l << 0);
704
705 //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
706
707 return count;
708}
709
710/* fifo size */
711#define RFIFO_CRIT 64
712#define WFIFO_CRIT 64
713
714/*
715 * read data in DATA IN phase
716 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700717static void nsp_pio_read(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 unsigned int base = SCpnt->device->host->io_port;
720 unsigned long mmio_base = SCpnt->device->host->base;
721 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
722 long time_out;
723 int ocount, res;
724 unsigned char stat, fifo_stat;
725
726 ocount = data->FifoCount;
727
728 nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300729 SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
730 SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
731 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
733 time_out = 1000;
734
735 while ((time_out-- != 0) &&
736 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
737
738 stat = nsp_index_read(base, SCSIBUSMON);
739 stat &= BUSMON_PHASE_MASK;
740
741
742 res = nsp_fifo_count(SCpnt) - ocount;
743 //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);
744 if (res == 0) { /* if some data avilable ? */
745 if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
746 //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
747 continue;
748 } else {
749 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
750 break;
751 }
752 }
753
754 fifo_stat = nsp_read(base, FIFOSTATUS);
755 if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
756 stat == BUSPHASE_DATA_IN) {
757 continue;
758 }
759
760 res = min(res, SCpnt->SCp.this_residual);
761
762 switch (data->TransferMode) {
763 case MODE_IO32:
764 res &= ~(BIT(1)|BIT(0)); /* align 4 */
765 nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
766 break;
767 case MODE_IO8:
768 nsp_fifo8_read (base, SCpnt->SCp.ptr, res );
769 break;
770
771 case MODE_MEM32:
772 res &= ~(BIT(1)|BIT(0)); /* align 4 */
773 nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
774 break;
775
776 default:
777 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
778 return;
779 }
780
Boaz Harrosh040cd232007-08-16 13:01:05 +0300781 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 SCpnt->SCp.ptr += res;
783 SCpnt->SCp.this_residual -= res;
784 ocount += res;
785 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
786
787 /* go to next scatter list if available */
788 if (SCpnt->SCp.this_residual == 0 &&
789 SCpnt->SCp.buffers_residual != 0 ) {
790 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
791 SCpnt->SCp.buffers_residual--;
792 SCpnt->SCp.buffer++;
793 SCpnt->SCp.ptr = BUFFER_ADDR;
794 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
795 time_out = 1000;
796
797 //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
798 }
799 }
800
801 data->FifoCount = ocount;
802
Roel Kluin0454c742009-06-10 12:56:59 -0700803 if (time_out < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300805 scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
806 SCpnt->SCp.buffers_residual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 }
808 nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300809 nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
810 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811}
812
813/*
814 * write data in DATA OUT phase
815 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700816static void nsp_pio_write(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
818 unsigned int base = SCpnt->device->host->io_port;
819 unsigned long mmio_base = SCpnt->device->host->base;
820 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
821 int time_out;
822 int ocount, res;
823 unsigned char stat;
824
825 ocount = data->FifoCount;
826
827 nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
Boaz Harrosh040cd232007-08-16 13:01:05 +0300828 data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
829 SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
830 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 time_out = 1000;
833
834 while ((time_out-- != 0) &&
835 (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
836 stat = nsp_index_read(base, SCSIBUSMON);
837 stat &= BUSMON_PHASE_MASK;
838
839 if (stat != BUSPHASE_DATA_OUT) {
840 res = ocount - nsp_fifo_count(SCpnt);
841
842 nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
843 /* Put back pointer */
Boaz Harrosh040cd232007-08-16 13:01:05 +0300844 nsp_inc_resid(SCpnt, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 SCpnt->SCp.ptr -= res;
846 SCpnt->SCp.this_residual += res;
847 ocount -= res;
848
849 break;
850 }
851
852 res = ocount - nsp_fifo_count(SCpnt);
853 if (res > 0) { /* write all data? */
854 nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
855 continue;
856 }
857
858 res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
859
860 //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
861 switch (data->TransferMode) {
862 case MODE_IO32:
863 res &= ~(BIT(1)|BIT(0)); /* align 4 */
864 nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
865 break;
866 case MODE_IO8:
867 nsp_fifo8_write (base, SCpnt->SCp.ptr, res );
868 break;
869
870 case MODE_MEM32:
871 res &= ~(BIT(1)|BIT(0)); /* align 4 */
872 nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
873 break;
874
875 default:
876 nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
877 break;
878 }
879
Boaz Harrosh040cd232007-08-16 13:01:05 +0300880 nsp_inc_resid(SCpnt, -res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 SCpnt->SCp.ptr += res;
882 SCpnt->SCp.this_residual -= res;
883 ocount += res;
884
885 /* go to next scatter list if available */
886 if (SCpnt->SCp.this_residual == 0 &&
887 SCpnt->SCp.buffers_residual != 0 ) {
888 //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
889 SCpnt->SCp.buffers_residual--;
890 SCpnt->SCp.buffer++;
891 SCpnt->SCp.ptr = BUFFER_ADDR;
892 SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
893 time_out = 1000;
894 }
895 }
896
897 data->FifoCount = ocount;
898
Roel Kluin0454c742009-06-10 12:56:59 -0700899 if (time_out < 0) {
Boaz Harrosh040cd232007-08-16 13:01:05 +0300900 nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
901 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
Boaz Harrosh040cd232007-08-16 13:01:05 +0300904 nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
905 scsi_get_resid(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907#undef RFIFO_CRIT
908#undef WFIFO_CRIT
909
910/*
911 * setup synchronous/asynchronous data transfer mode
912 */
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700913static int nsp_nexus(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914{
915 unsigned int base = SCpnt->device->host->io_port;
Jeff Garzik422c0d62005-10-24 18:05:09 -0400916 unsigned char target = scmd_id(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917// unsigned char lun = SCpnt->device->lun;
918 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
919 sync_data *sync = &(data->Sync[target]);
920
921 //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
922
923 /* setup synch transfer registers */
924 nsp_index_write(base, SYNCREG, sync->SyncRegister);
925 nsp_index_write(base, ACKWIDTH, sync->AckWidth);
926
Boaz Harrosh040cd232007-08-16 13:01:05 +0300927 if (scsi_get_resid(SCpnt) % 4 != 0 ||
928 scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 data->TransferMode = MODE_IO8;
930 } else if (nsp_burst_mode == BURST_MEM32) {
931 data->TransferMode = MODE_MEM32;
932 } else if (nsp_burst_mode == BURST_IO32) {
933 data->TransferMode = MODE_IO32;
934 } else {
935 data->TransferMode = MODE_IO8;
936 }
937
938 /* setup pdma fifo */
939 nsp_setup_fifo(data, TRUE);
940
941 /* clear ack counter */
942 data->FifoCount = 0;
943 nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
944 ACK_COUNTER_CLEAR |
945 REQ_COUNTER_CLEAR |
946 HOST_COUNTER_CLEAR);
947
948 return 0;
949}
950
951#include "nsp_message.c"
952/*
953 * interrupt handler
954 */
David Howells7d12e782006-10-05 14:55:46 +0100955static irqreturn_t nspintr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956{
957 unsigned int base;
958 unsigned char irq_status, irq_phase, phase;
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -0700959 struct scsi_cmnd *tmpSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 unsigned char target, lun;
961 unsigned int *sync_neg;
962 int i, tmp;
963 nsp_hw_data *data;
964
965
966 //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
967 //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
968
969 if ( dev_id != NULL &&
970 ((scsi_info_t *)dev_id)->host != NULL ) {
971 scsi_info_t *info = (scsi_info_t *)dev_id;
972
973 data = (nsp_hw_data *)info->host->hostdata;
974 } else {
975 nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
976 return IRQ_NONE;
977 }
978
979 //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
980
981 base = data->BaseAddress;
982 //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
983
984 /*
985 * interrupt check
986 */
987 nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
988 irq_status = nsp_read(base, IRQSTATUS);
989 //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
990 if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
991 nsp_write(base, IRQCONTROL, 0);
992 //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
993 return IRQ_NONE;
994 }
995
996 /* XXX: IMPORTANT
997 * Do not read an irq_phase register if no scsi phase interrupt.
998 * Unless, you should lose a scsi phase interrupt.
999 */
1000 phase = nsp_index_read(base, SCSIBUSMON);
1001 if((irq_status & IRQSTATUS_SCSI) != 0) {
1002 irq_phase = nsp_index_read(base, IRQPHASESENCE);
1003 } else {
1004 irq_phase = 0;
1005 }
1006
1007 //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
1008
1009 /*
1010 * timer interrupt handler (scsi vs timer interrupts)
1011 */
1012 //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
1013 if (data->TimerCount != 0) {
1014 //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
1015 nsp_index_write(base, TIMERCOUNT, 0);
1016 nsp_index_write(base, TIMERCOUNT, 0);
1017 data->TimerCount = 0;
1018 }
1019
1020 if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
1021 data->SelectionTimeOut == 0) {
1022 //nsp_dbg(NSP_DEBUG_INTR, "timer start");
1023 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
1024 return IRQ_HANDLED;
1025 }
1026
1027 nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
1028
1029 if ((irq_status & IRQSTATUS_SCSI) &&
1030 (irq_phase & SCSI_RESET_IRQ)) {
1031 nsp_msg(KERN_ERR, "bus reset (power off?)");
1032
1033 nsphw_init(data);
1034 nsp_bus_reset(data);
1035
1036 if(data->CurrentSC != NULL) {
1037 tmpSC = data->CurrentSC;
1038 tmpSC->result = (DID_RESET << 16) |
1039 ((tmpSC->SCp.Message & 0xff) << 8) |
1040 ((tmpSC->SCp.Status & 0xff) << 0);
1041 nsp_scsi_done(tmpSC);
1042 }
1043 return IRQ_HANDLED;
1044 }
1045
1046 if (data->CurrentSC == NULL) {
1047 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);
1048 nsphw_init(data);
1049 nsp_bus_reset(data);
1050 return IRQ_HANDLED;
1051 }
1052
1053 tmpSC = data->CurrentSC;
1054 target = tmpSC->device->id;
1055 lun = tmpSC->device->lun;
1056 sync_neg = &(data->Sync[target].SyncNegotiation);
1057
1058 /*
1059 * parse hardware SCSI irq reasons register
1060 */
1061 if (irq_status & IRQSTATUS_SCSI) {
1062 if (irq_phase & RESELECT_IRQ) {
1063 nsp_dbg(NSP_DEBUG_INTR, "reselect");
1064 nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
1065 if (nsp_reselected(tmpSC) != FALSE) {
1066 return IRQ_HANDLED;
1067 }
1068 }
1069
1070 if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
1071 return IRQ_HANDLED;
1072 }
1073 }
1074
1075 //show_phase(tmpSC);
1076
1077 switch(tmpSC->SCp.phase) {
1078 case PH_SELSTART:
1079 // *sync_neg = SYNC_NOT_YET;
1080 if ((phase & BUSMON_BSY) == 0) {
1081 //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
1082 if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
1083 nsp_dbg(NSP_DEBUG_INTR, "selection time out");
1084 data->SelectionTimeOut = 0;
1085 nsp_index_write(base, SCSIBUSCTRL, 0);
1086
1087 tmpSC->result = DID_TIME_OUT << 16;
1088 nsp_scsi_done(tmpSC);
1089
1090 return IRQ_HANDLED;
1091 }
1092 data->SelectionTimeOut += 1;
1093 nsp_start_timer(tmpSC, 1000/51);
1094 return IRQ_HANDLED;
1095 }
1096
1097 /* attention assert */
1098 //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
1099 data->SelectionTimeOut = 0;
1100 tmpSC->SCp.phase = PH_SELECTED;
1101 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
1102 udelay(1);
1103 nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
1104 return IRQ_HANDLED;
1105
1106 break;
1107
1108 case PH_RESELECT:
1109 //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
1110 // *sync_neg = SYNC_NOT_YET;
1111 if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
1112
1113 tmpSC->result = DID_ABORT << 16;
1114 nsp_scsi_done(tmpSC);
1115 return IRQ_HANDLED;
1116 }
1117 /* fall thru */
1118 default:
1119 if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
1120 return IRQ_HANDLED;
1121 }
1122 break;
1123 }
1124
1125 /*
1126 * SCSI sequencer
1127 */
1128 //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
1129
1130 /* normal disconnect */
1131 if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
1132 (irq_phase & LATCHED_BUS_FREE) != 0 ) {
1133 nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1134
1135 //*sync_neg = SYNC_NOT_YET;
1136
1137 if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */
1138 tmpSC->result = (DID_OK << 16) |
1139 ((tmpSC->SCp.Message & 0xff) << 8) |
1140 ((tmpSC->SCp.Status & 0xff) << 0);
1141 nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
1142 nsp_scsi_done(tmpSC);
1143
1144 return IRQ_HANDLED;
1145 }
1146
1147 return IRQ_HANDLED;
1148 }
1149
1150
1151 /* check unexpected bus free state */
1152 if (phase == 0) {
1153 nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
1154
1155 *sync_neg = SYNC_NG;
1156 tmpSC->result = DID_ERROR << 16;
1157 nsp_scsi_done(tmpSC);
1158 return IRQ_HANDLED;
1159 }
1160
1161 switch (phase & BUSMON_PHASE_MASK) {
1162 case BUSPHASE_COMMAND:
1163 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
1164 if ((phase & BUSMON_REQ) == 0) {
1165 nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
1166 return IRQ_HANDLED;
1167 }
1168
1169 tmpSC->SCp.phase = PH_COMMAND;
1170
1171 nsp_nexus(tmpSC);
1172
1173 /* write scsi command */
1174 nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
1175 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
1176 for (i = 0; i < tmpSC->cmd_len; i++) {
1177 nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
1178 }
1179 nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
1180 break;
1181
1182 case BUSPHASE_DATA_OUT:
1183 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
1184
1185 tmpSC->SCp.phase = PH_DATA;
1186 tmpSC->SCp.have_data_in = IO_OUT;
1187
1188 nsp_pio_write(tmpSC);
1189
1190 break;
1191
1192 case BUSPHASE_DATA_IN:
1193 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
1194
1195 tmpSC->SCp.phase = PH_DATA;
1196 tmpSC->SCp.have_data_in = IO_IN;
1197
1198 nsp_pio_read(tmpSC);
1199
1200 break;
1201
1202 case BUSPHASE_STATUS:
1203 nsp_dataphase_bypass(tmpSC);
1204 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
1205
1206 tmpSC->SCp.phase = PH_STATUS;
1207
1208 tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
1209 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
1210
1211 break;
1212
1213 case BUSPHASE_MESSAGE_OUT:
1214 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
1215 if ((phase & BUSMON_REQ) == 0) {
1216 goto timer_out;
1217 }
1218
1219 tmpSC->SCp.phase = PH_MSG_OUT;
1220
1221 //*sync_neg = SYNC_NOT_YET;
1222
1223 data->MsgLen = i = 0;
1224 data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
1225
1226 if (*sync_neg == SYNC_NOT_YET) {
1227 data->Sync[target].SyncPeriod = 0;
1228 data->Sync[target].SyncOffset = 0;
1229
1230 /**/
1231 data->MsgBuffer[i] = MSG_EXTENDED; i++;
1232 data->MsgBuffer[i] = 3; i++;
1233 data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
1234 data->MsgBuffer[i] = 0x0c; i++;
1235 data->MsgBuffer[i] = 15; i++;
1236 /**/
1237 }
1238 data->MsgLen = i;
1239
1240 nsp_analyze_sdtr(tmpSC);
1241 show_message(data);
1242 nsp_message_out(tmpSC);
1243 break;
1244
1245 case BUSPHASE_MESSAGE_IN:
1246 nsp_dataphase_bypass(tmpSC);
1247 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
1248 if ((phase & BUSMON_REQ) == 0) {
1249 goto timer_out;
1250 }
1251
1252 tmpSC->SCp.phase = PH_MSG_IN;
1253 nsp_message_in(tmpSC);
1254
1255 /**/
1256 if (*sync_neg == SYNC_NOT_YET) {
1257 //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
1258
1259 if (data->MsgLen >= 5 &&
1260 data->MsgBuffer[0] == MSG_EXTENDED &&
1261 data->MsgBuffer[1] == 3 &&
1262 data->MsgBuffer[2] == MSG_EXT_SDTR ) {
1263 data->Sync[target].SyncPeriod = data->MsgBuffer[3];
1264 data->Sync[target].SyncOffset = data->MsgBuffer[4];
1265 //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
1266 *sync_neg = SYNC_OK;
1267 } else {
1268 data->Sync[target].SyncPeriod = 0;
1269 data->Sync[target].SyncOffset = 0;
1270 *sync_neg = SYNC_NG;
1271 }
1272 nsp_analyze_sdtr(tmpSC);
1273 }
1274 /**/
1275
1276 /* search last messeage byte */
1277 tmp = -1;
1278 for (i = 0; i < data->MsgLen; i++) {
1279 tmp = data->MsgBuffer[i];
1280 if (data->MsgBuffer[i] == MSG_EXTENDED) {
1281 i += (1 + data->MsgBuffer[i+1]);
1282 }
1283 }
1284 tmpSC->SCp.Message = tmp;
1285
1286 nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
1287 show_message(data);
1288
1289 break;
1290
1291 case BUSPHASE_SELECT:
1292 default:
1293 nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
1294
1295 break;
1296 }
1297
1298 //nsp_dbg(NSP_DEBUG_INTR, "out");
1299 return IRQ_HANDLED;
1300
1301timer_out:
1302 nsp_start_timer(tmpSC, 1000/102);
1303 return IRQ_HANDLED;
1304}
1305
1306#ifdef NSP_DEBUG
1307#include "nsp_debug.c"
1308#endif /* NSP_DEBUG */
1309
1310/*----------------------------------------------------------------*/
1311/* look for ninja3 card and init if found */
1312/*----------------------------------------------------------------*/
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001313static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
1315 struct Scsi_Host *host; /* registered host structure */
1316 nsp_hw_data *data_b = &nsp_data_base, *data;
1317
1318 nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (host == NULL) {
1321 nsp_dbg(NSP_DEBUG_INIT, "host failed");
1322 return NULL;
1323 }
1324
1325 memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
1326 data = (nsp_hw_data *)host->hostdata;
1327 data->ScsiInfo->host = host;
1328#ifdef NSP_DEBUG
1329 data->CmdId = 0;
1330#endif
1331
1332 nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
1333
1334 host->unique_id = data->BaseAddress;
1335 host->io_port = data->BaseAddress;
1336 host->n_io_port = data->NumAddress;
1337 host->irq = data->IrqNumber;
1338 host->base = data->MmioAddress;
1339
1340 spin_lock_init(&(data->Lock));
1341
1342 snprintf(data->nspinfo,
1343 sizeof(data->nspinfo),
1344 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
1345 host->io_port, host->io_port + host->n_io_port - 1,
1346 host->base,
1347 host->irq);
1348 sht->name = data->nspinfo;
1349
1350 nsp_dbg(NSP_DEBUG_INIT, "end");
1351
1352
1353 return host; /* detect done. */
1354}
1355
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356/*----------------------------------------------------------------*/
1357/* return info string */
1358/*----------------------------------------------------------------*/
1359static const char *nsp_info(struct Scsi_Host *shpnt)
1360{
1361 nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
1362
1363 return data->nspinfo;
1364}
1365
1366#undef SPRINTF
1367#define SPRINTF(args...) \
1368 do { \
1369 if(length > (pos - buffer)) { \
1370 pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
1371 nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
1372 } \
1373 } while(0)
Adrian Bunk774251e2007-10-02 14:38:01 -07001374
1375static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
1376 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377{
1378 int id;
1379 char *pos = buffer;
1380 int thislength;
1381 int speed;
1382 unsigned long flags;
1383 nsp_hw_data *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 int hostno;
Adrian Bunk774251e2007-10-02 14:38:01 -07001385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (inout) {
1387 return -EINVAL;
1388 }
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 hostno = host->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 data = (nsp_hw_data *)host->hostdata;
1392
1393
1394 SPRINTF("NinjaSCSI status\n\n");
1395 SPRINTF("Driver version: $Revision: 1.23 $\n");
1396 SPRINTF("SCSI host No.: %d\n", hostno);
1397 SPRINTF("IRQ: %d\n", host->irq);
1398 SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
1399 SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
1400 SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
1401
1402 SPRINTF("burst transfer mode: ");
1403 switch (nsp_burst_mode) {
1404 case BURST_IO8:
1405 SPRINTF("io8");
1406 break;
1407 case BURST_IO32:
1408 SPRINTF("io32");
1409 break;
1410 case BURST_MEM32:
1411 SPRINTF("mem32");
1412 break;
1413 default:
1414 SPRINTF("???");
1415 break;
1416 }
1417 SPRINTF("\n");
1418
1419
1420 spin_lock_irqsave(&(data->Lock), flags);
1421 SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
1422 spin_unlock_irqrestore(&(data->Lock), flags);
1423
1424 SPRINTF("SDTR status\n");
1425 for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
1426
1427 SPRINTF("id %d: ", id);
1428
1429 if (id == host->this_id) {
1430 SPRINTF("----- NinjaSCSI-3 host adapter\n");
1431 continue;
1432 }
1433
1434 switch(data->Sync[id].SyncNegotiation) {
1435 case SYNC_OK:
1436 SPRINTF(" sync");
1437 break;
1438 case SYNC_NG:
1439 SPRINTF("async");
1440 break;
1441 case SYNC_NOT_YET:
1442 SPRINTF(" none");
1443 break;
1444 default:
1445 SPRINTF("?????");
1446 break;
1447 }
1448
1449 if (data->Sync[id].SyncPeriod != 0) {
1450 speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
1451
1452 SPRINTF(" transfer %d.%dMB/s, offset %d",
1453 speed / 1000,
1454 speed % 1000,
1455 data->Sync[id].SyncOffset
1456 );
1457 }
1458 SPRINTF("\n");
1459 }
1460
1461 thislength = pos - (buffer + offset);
1462
1463 if(thislength < 0) {
1464 *start = NULL;
1465 return 0;
1466 }
1467
1468
1469 thislength = min(thislength, length);
1470 *start = buffer + offset;
1471
1472 return thislength;
1473}
1474#undef SPRINTF
1475
1476/*---------------------------------------------------------------*/
1477/* error handler */
1478/*---------------------------------------------------------------*/
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480/*
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001481static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
1483 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1484
1485 return nsp_eh_bus_reset(SCpnt);
1486}*/
1487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488static int nsp_bus_reset(nsp_hw_data *data)
1489{
1490 unsigned int base = data->BaseAddress;
1491 int i;
1492
1493 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
1494
1495 nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
1496 mdelay(100); /* 100ms */
1497 nsp_index_write(base, SCSIBUSCTRL, 0);
1498 for(i = 0; i < 5; i++) {
1499 nsp_index_read(base, IRQPHASESENCE); /* dummy read */
1500 }
1501
1502 nsphw_init_sync(data);
1503
1504 nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
1505
1506 return SUCCESS;
1507}
1508
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001509static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510{
1511 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1512
1513 nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
1514
1515 return nsp_bus_reset(data);
1516}
1517
Henrik Kretzschmar0fc82d52006-10-10 14:41:41 -07001518static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
1520 nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1521
1522 nsp_dbg(NSP_DEBUG_BUSRESET, "in");
1523
1524 nsphw_init(data);
1525
1526 return SUCCESS;
1527}
1528
1529
1530/**********************************************************************
1531 PCMCIA functions
1532**********************************************************************/
1533
1534/*======================================================================
1535 nsp_cs_attach() creates an "instance" of the driver, allocating
1536 local data structures for one device. The device is registered
1537 with Card Services.
1538
1539 The dev_link structure is initialized, but we don't actually
1540 configure the card at this point -- we wait until we receive a
1541 card insertion event.
1542======================================================================*/
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001543static int nsp_cs_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544{
1545 scsi_info_t *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 nsp_hw_data *data = &nsp_data_base;
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001547 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
1549 nsp_dbg(NSP_DEBUG_INIT, "in");
1550
1551 /* Create new SCSI device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -07001552 info = kzalloc(sizeof(*info), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001553 if (info == NULL) { return -ENOMEM; }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001554 info->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 link->priv = info;
1556 data->ScsiInfo = info;
1557
1558 nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
1559
1560 /* The io structure describes IO port mapping */
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001561 link->resource[0]->end = 0x10;
1562 link->resource[0]->flags = IO_DATA_PATH_WIDTH_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 /* General socket configuration */
1565 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 link->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001568 ret = nsp_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
1570 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001571 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572} /* nsp_cs_attach */
1573
1574
1575/*======================================================================
1576 This deletes a driver "instance". The device is de-registered
1577 with Card Services. If it has been released, all local data
1578 structures are freed. Otherwise, the structures will be freed
1579 when the device is released.
1580======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001581static void nsp_cs_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
1584
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001585 ((scsi_info_t *)link->priv)->stop = 1;
1586 nsp_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 kfree(link->priv);
1589 link->priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590} /* nsp_cs_detach */
1591
1592
1593/*======================================================================
1594 nsp_cs_config() is scheduled to run after a CARD_INSERTION event
1595 is received, to configure the PCMCIA socket, and to make the
1596 ethernet device available to the system.
1597======================================================================*/
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001598
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001599static int nsp_cs_config_check(struct pcmcia_device *p_dev,
1600 cistpl_cftable_entry_t *cfg,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001601 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +02001602 unsigned int vcc,
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001603 void *priv_data)
1604{
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001605 nsp_hw_data *data = priv_data;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001606
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001607 if (cfg->index == 0)
1608 return -ENODEV;
1609
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001610 /* Does this card need audio output? */
Dominik Brodowskifc301102010-07-29 16:19:39 +02001611 if (cfg->flags & CISTPL_CFTABLE_AUDIO)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001612 p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001613
1614 /* Use power settings for Vcc and Vpp if present */
1615 /* Note that the CIS values need to be rescaled */
1616 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
Dominik Brodowskiad913c12008-08-02 16:12:00 +02001617 if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001618 return -ENODEV;
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001619 else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
Dominik Brodowskiad913c12008-08-02 16:12:00 +02001620 if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001621 return -ENODEV;
1622 }
1623
1624 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowskie8405f02010-07-29 15:50:55 +02001625 p_dev->vpp =
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001626 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001627 } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
Dominik Brodowskie8405f02010-07-29 15:50:55 +02001628 p_dev->vpp =
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001629 dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001630 }
1631
1632 /* Do we need to allocate an interrupt? */
Dominik Brodowskieb141202010-03-07 12:21:16 +01001633 p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001634
1635 /* IO window settings */
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001636 p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001637 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
1638 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001639 p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
1640 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
1641 p_dev->resource[0]->flags |=
1642 pcmcia_io_cfg_data_width(io->flags);
1643 p_dev->resource[0]->start = io->win[0].base;
1644 p_dev->resource[0]->end = io->win[0].len;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001645 if (io->nwin > 1) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001646 p_dev->resource[1]->flags =
1647 p_dev->resource[0]->flags;
1648 p_dev->resource[1]->start = io->win[1].base;
1649 p_dev->resource[1]->end = io->win[1].len;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001650 }
1651 /* This reserves IO space but doesn't actually enable it */
Dominik Brodowski90abdc32010-07-24 17:23:51 +02001652 if (pcmcia_request_io(p_dev) != 0)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001653 goto next_entry;
1654 }
1655
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001656 if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001657 cistpl_mem_t *mem =
Dominik Brodowski8e2fc392008-08-02 15:30:31 +02001658 (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001659 p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1660 WIN_MEMORY_TYPE_CM |
1661 WIN_ENABLE);
1662 p_dev->resource[2]->start = mem->win[0].host_addr;
1663 p_dev->resource[2]->end = mem->win[0].len;
1664 if (p_dev->resource[2]->end < 0x1000)
1665 p_dev->resource[2]->end = 0x1000;
1666 if (pcmcia_request_window(p_dev, p_dev->resource[2],
1667 0) != 0)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001668 goto next_entry;
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001669 if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
Dominik Brodowskib5cb2592010-07-24 18:46:42 +02001670 mem->win[0].card_addr) != 0)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001671 goto next_entry;
1672
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001673 data->MmioAddress = (unsigned long)
1674 ioremap_nocache(p_dev->resource[2]->start,
1675 resource_size(p_dev->resource[2]));
1676 data->MmioLength = resource_size(p_dev->resource[2]);
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001677 }
1678 /* If we got this far, we're cool! */
1679 return 0;
1680 }
1681
1682next_entry:
1683 nsp_dbg(NSP_DEBUG_INIT, "next");
1684 pcmcia_disable_device(p_dev);
1685 return -ENODEV;
1686}
1687
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001688static int nsp_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689{
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001690 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 scsi_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 struct Scsi_Host *host;
1693 nsp_hw_data *data = &nsp_data_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
1695 nsp_dbg(NSP_DEBUG_INIT, "in");
1696
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001697 ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
Dan Carpentere794c012010-03-15 11:25:10 +03001698 if (ret)
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001699 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
Dominik Brodowskieb141202010-03-07 12:21:16 +01001701 if (pcmcia_request_irq(link, nspintr))
1702 goto cs_failed;
Dominik Brodowski0e6f9d22008-07-29 08:38:55 +02001703
1704 ret = pcmcia_request_configuration(link, &link->conf);
1705 if (ret)
1706 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 if (free_ports) {
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001709 if (link->resource[0]) {
1710 release_region(link->resource[0]->start,
1711 resource_size(link->resource[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001713 if (link->resource[1]) {
1714 release_region(link->resource[1]->start,
1715 resource_size(link->resource[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717 }
1718
1719 /* Set port and IRQ */
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001720 data->BaseAddress = link->resource[0]->start;
1721 data->NumAddress = resource_size(link->resource[0]);
Dominik Brodowskieb141202010-03-07 12:21:16 +01001722 data->IrqNumber = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
1725 data->BaseAddress, data->NumAddress, data->IrqNumber);
1726
1727 if(nsphw_init(data) == FALSE) {
1728 goto cs_failed;
1729 }
1730
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 host = nsp_detect(&nsp_driver_template);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 if (host == NULL) {
1734 nsp_dbg(NSP_DEBUG_INIT, "detect failed");
1735 goto cs_failed;
1736 }
1737
1738
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001739 ret = scsi_add_host (host, NULL);
1740 if (ret)
1741 goto cs_failed;
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 scsi_scan_host(host);
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 info->host = host;
1746
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 /* Finally, report what we've done */
Dominik Brodowski70294b42006-01-15 12:43:16 +01001748 printk(KERN_INFO "nsp_cs: index 0x%02x: ",
1749 link->conf.ConfigIndex);
Dominik Brodowskie8405f02010-07-29 15:50:55 +02001750 if (link->vpp) {
1751 printk(", Vpp %d.%d", link->vpp/10, link->vpp%10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
1753 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
Dominik Brodowskieb141202010-03-07 12:21:16 +01001754 printk(", irq %d", link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 }
Dominik Brodowski9a017a92010-07-24 15:58:54 +02001756 if (link->resource[0])
1757 printk(", io %pR", link->resource[0]);
1758 if (link->resource[1])
1759 printk(" & %pR", link->resource[1]);
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001760 if (link->resource[2])
1761 printk(", mem %pR", link->resource[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 printk("\n");
1763
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001764 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
1766 cs_failed:
1767 nsp_dbg(NSP_DEBUG_INIT, "config fail");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 nsp_cs_release(link);
1769
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001770 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771} /* nsp_cs_config */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
1773
1774/*======================================================================
1775 After a card is removed, nsp_cs_release() will unregister the net
1776 device, and release the PCMCIA configuration. If the device is
1777 still open, this will be postponed until it is closed.
1778======================================================================*/
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001779static void nsp_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780{
1781 scsi_info_t *info = link->priv;
1782 nsp_hw_data *data = NULL;
1783
1784 if (info->host == NULL) {
1785 nsp_msg(KERN_DEBUG, "unexpected card release call.");
1786 } else {
1787 data = (nsp_hw_data *)info->host->hostdata;
1788 }
1789
1790 nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
1791
1792 /* Unlink the device chain */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if (info->host != NULL) {
1794 scsi_remove_host(info->host);
1795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Dominik Brodowskicdb13802010-07-28 10:59:06 +02001797 if (resource_size(link->resource[2])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if (data != NULL) {
1799 iounmap((void *)(data->MmioAddress));
1800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001802 pcmcia_disable_device(link);
Dominik Brodowski5f2a71f2006-01-15 09:32:39 +01001803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 if (info->host != NULL) {
1805 scsi_host_put(info->host);
1806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807} /* nsp_cs_release */
1808
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001809static int nsp_cs_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001810{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001811 scsi_info_t *info = link->priv;
1812 nsp_hw_data *data;
1813
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001814 nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
1815
1816 if (info->host != NULL) {
1817 nsp_msg(KERN_INFO, "clear SDTR status");
1818
1819 data = (nsp_hw_data *)info->host->hostdata;
1820
1821 nsphw_init_sync(data);
1822 }
1823
1824 info->stop = 1;
1825
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001826 return 0;
1827}
1828
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001829static int nsp_cs_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001830{
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001831 scsi_info_t *info = link->priv;
1832 nsp_hw_data *data;
1833
1834 nsp_dbg(NSP_DEBUG_INIT, "event: resume");
1835
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001836 info->stop = 0;
1837
1838 if (info->host != NULL) {
1839 nsp_msg(KERN_INFO, "reset host and bus");
1840
1841 data = (nsp_hw_data *)info->host->hostdata;
1842
1843 nsphw_init (data);
1844 nsp_bus_reset(data);
1845 }
1846
1847 return 0;
1848}
1849
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850/*======================================================================*
1851 * module entry point
1852 *====================================================================*/
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001853static struct pcmcia_device_id nsp_cs_ids[] = {
1854 PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1855 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1856 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1857 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1858 PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1859 PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1860 PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1861 PCMCIA_DEVICE_NULL
1862};
1863MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865static struct pcmcia_driver nsp_driver = {
Dominik Brodowski1e212f32005-07-07 17:59:00 -07001866 .owner = THIS_MODULE,
1867 .drv = {
1868 .name = "nsp_cs",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001870 .probe = nsp_cs_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01001871 .remove = nsp_cs_detach,
Dominik Brodowskiaba14102005-06-27 16:28:40 -07001872 .id_table = nsp_cs_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001873 .suspend = nsp_cs_suspend,
1874 .resume = nsp_cs_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877static int __init nsp_cs_init(void)
1878{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 nsp_msg(KERN_INFO, "loading...");
1880
1881 return pcmcia_register_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882}
1883
1884static void __exit nsp_cs_exit(void)
1885{
1886 nsp_msg(KERN_INFO, "unloading...");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 pcmcia_unregister_driver(&nsp_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888}
1889
1890
1891module_init(nsp_cs_init)
1892module_exit(nsp_cs_exit)
1893
1894/* end */