11da177e4SLinus Torvalds /*======================================================================
21da177e4SLinus Torvalds
31da177e4SLinus Torvalds NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
41da177e4SLinus Torvalds By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds Ver.2.8 Support 32bit MMIO mode
71da177e4SLinus Torvalds Support Synchronous Data Transfer Request (SDTR) mode
81da177e4SLinus Torvalds Ver.2.0 Support 32bit PIO mode
91da177e4SLinus Torvalds Ver.1.1.2 Fix for scatter list buffer exceeds
101da177e4SLinus Torvalds Ver.1.1 Support scatter list
111da177e4SLinus Torvalds Ver.0.1 Initial version
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds This software may be used and distributed according to the terms of
141da177e4SLinus Torvalds the GNU General Public License.
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds ======================================================================*/
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds /***********************************************************************
191da177e4SLinus Torvalds This driver is for these PCcards.
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds I-O DATA PCSC-F (Workbit NinjaSCSI-3)
221da177e4SLinus Torvalds "WBT", "NinjaSCSI-3", "R1.0"
231da177e4SLinus Torvalds I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
241da177e4SLinus Torvalds "IO DATA", "CBSC16 ", "1"
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds ***********************************************************************/
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds #include <linux/kernel.h>
301da177e4SLinus Torvalds #include <linux/init.h>
311da177e4SLinus Torvalds #include <linux/slab.h>
321da177e4SLinus Torvalds #include <linux/string.h>
331da177e4SLinus Torvalds #include <linux/timer.h>
341da177e4SLinus Torvalds #include <linux/ioport.h>
351da177e4SLinus Torvalds #include <linux/delay.h>
361da177e4SLinus Torvalds #include <linux/interrupt.h>
371da177e4SLinus Torvalds #include <linux/major.h>
381da177e4SLinus Torvalds #include <linux/blkdev.h>
391da177e4SLinus Torvalds #include <linux/stat.h>
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds #include <asm/io.h>
421da177e4SLinus Torvalds #include <asm/irq.h>
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds #include <scsi/scsi.h>
4553555fb7SBart Van Assche #include <scsi/scsi_cmnd.h>
4653555fb7SBart Van Assche #include <scsi/scsi_host.h>
471da177e4SLinus Torvalds #include <scsi/scsi_ioctl.h>
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
501da177e4SLinus Torvalds #include <pcmcia/cisreg.h>
511da177e4SLinus Torvalds #include <pcmcia/ds.h>
521da177e4SLinus Torvalds
531da177e4SLinus Torvalds #include "nsp_cs.h"
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
56774251efSAdrian Bunk MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
571da177e4SLinus Torvalds MODULE_LICENSE("GPL");
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds #include "nsp_io.h"
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds /*====================================================================*/
621da177e4SLinus Torvalds /* Parameters that can be set with 'insmod' */
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds static int nsp_burst_mode = BURST_MEM32;
651da177e4SLinus Torvalds module_param(nsp_burst_mode, int, 0);
661da177e4SLinus Torvalds MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds /* Release IO ports after configuration? */
6990ab5ee9SRusty Russell static bool free_ports = 0;
701da177e4SLinus Torvalds module_param(free_ports, bool, 0);
711da177e4SLinus Torvalds MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
721da177e4SLinus Torvalds
nsp_priv(struct scsi_cmnd * cmd)73ea39700fSBart Van Assche static struct scsi_pointer *nsp_priv(struct scsi_cmnd *cmd)
74ea39700fSBart Van Assche {
75ea39700fSBart Van Assche return scsi_cmd_priv(cmd);
76ea39700fSBart Van Assche }
77ea39700fSBart Van Assche
78d0be4a7dSChristoph Hellwig static struct scsi_host_template nsp_driver_template = {
791da177e4SLinus Torvalds .proc_name = "nsp_cs",
8063fd57cbSAl Viro .show_info = nsp_show_info,
811da177e4SLinus Torvalds .name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
821da177e4SLinus Torvalds .info = nsp_info,
831da177e4SLinus Torvalds .queuecommand = nsp_queuecommand,
841da177e4SLinus Torvalds /* .eh_abort_handler = nsp_eh_abort,*/
851da177e4SLinus Torvalds .eh_bus_reset_handler = nsp_eh_bus_reset,
861da177e4SLinus Torvalds .eh_host_reset_handler = nsp_eh_host_reset,
871da177e4SLinus Torvalds .can_queue = 1,
881da177e4SLinus Torvalds .this_id = NSP_INITIATOR_ID,
891da177e4SLinus Torvalds .sg_tablesize = SG_ALL,
904af14d11SChristoph Hellwig .dma_boundary = PAGE_SIZE - 1,
91ea39700fSBart Van Assche .cmd_size = sizeof(struct scsi_pointer),
921da177e4SLinus Torvalds };
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds /*
991da177e4SLinus Torvalds * debug, error print
1001da177e4SLinus Torvalds */
1011da177e4SLinus Torvalds #ifndef NSP_DEBUG
1021da177e4SLinus Torvalds # define NSP_DEBUG_MASK 0x000000
1031da177e4SLinus Torvalds # define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
1041da177e4SLinus Torvalds # define nsp_dbg(mask, args...) /* */
1051da177e4SLinus Torvalds #else
1061da177e4SLinus Torvalds # define NSP_DEBUG_MASK 0xffffff
1071da177e4SLinus Torvalds # define nsp_msg(type, args...) \
108cadbd4a5SHarvey Harrison nsp_cs_message (__func__, __LINE__, (type), args)
1091da177e4SLinus Torvalds # define nsp_dbg(mask, args...) \
110cadbd4a5SHarvey Harrison nsp_cs_dmessage(__func__, __LINE__, (mask), args)
1111da177e4SLinus Torvalds #endif
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds #define NSP_DEBUG_QUEUECOMMAND BIT(0)
1141da177e4SLinus Torvalds #define NSP_DEBUG_REGISTER BIT(1)
1151da177e4SLinus Torvalds #define NSP_DEBUG_AUTOSCSI BIT(2)
1161da177e4SLinus Torvalds #define NSP_DEBUG_INTR BIT(3)
1171da177e4SLinus Torvalds #define NSP_DEBUG_SGLIST BIT(4)
1181da177e4SLinus Torvalds #define NSP_DEBUG_BUSFREE BIT(5)
1191da177e4SLinus Torvalds #define NSP_DEBUG_CDB_CONTENTS BIT(6)
1201da177e4SLinus Torvalds #define NSP_DEBUG_RESELECTION BIT(7)
1211da177e4SLinus Torvalds #define NSP_DEBUG_MSGINOCCUR BIT(8)
1221da177e4SLinus Torvalds #define NSP_DEBUG_EEPROM BIT(9)
1231da177e4SLinus Torvalds #define NSP_DEBUG_MSGOUTOCCUR BIT(10)
1241da177e4SLinus Torvalds #define NSP_DEBUG_BUSRESET BIT(11)
1251da177e4SLinus Torvalds #define NSP_DEBUG_RESTART BIT(12)
1261da177e4SLinus Torvalds #define NSP_DEBUG_SYNC BIT(13)
1271da177e4SLinus Torvalds #define NSP_DEBUG_WAIT BIT(14)
1281da177e4SLinus Torvalds #define NSP_DEBUG_TARGETFLAG BIT(15)
1291da177e4SLinus Torvalds #define NSP_DEBUG_PROC BIT(16)
1301da177e4SLinus Torvalds #define NSP_DEBUG_INIT BIT(17)
1311da177e4SLinus Torvalds #define NSP_DEBUG_DATA_IO BIT(18)
1321da177e4SLinus Torvalds #define NSP_SPECIAL_PRINT_REGISTER BIT(20)
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvalds #define NSP_DEBUG_BUF_LEN 150
1351da177e4SLinus Torvalds
nsp_inc_resid(struct scsi_cmnd * SCpnt,int residInc)136040cd232SBoaz Harrosh static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
137040cd232SBoaz Harrosh {
138040cd232SBoaz Harrosh scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
139040cd232SBoaz Harrosh }
140040cd232SBoaz Harrosh
141af0b55d0SLee Jones __printf(4, 5)
nsp_cs_message(const char * func,int line,char * type,char * fmt,...)1421da177e4SLinus Torvalds static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds va_list args;
1451da177e4SLinus Torvalds char buf[NSP_DEBUG_BUF_LEN];
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds va_start(args, fmt);
1481da177e4SLinus Torvalds vsnprintf(buf, sizeof(buf), fmt, args);
1491da177e4SLinus Torvalds va_end(args);
1501da177e4SLinus Torvalds
1511da177e4SLinus Torvalds #ifndef NSP_DEBUG
1521da177e4SLinus Torvalds printk("%snsp_cs: %s\n", type, buf);
1531da177e4SLinus Torvalds #else
1541da177e4SLinus Torvalds printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
1551da177e4SLinus Torvalds #endif
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds #ifdef NSP_DEBUG
nsp_cs_dmessage(const char * func,int line,int mask,char * fmt,...)1591da177e4SLinus Torvalds static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds va_list args;
1621da177e4SLinus Torvalds char buf[NSP_DEBUG_BUF_LEN];
1631da177e4SLinus Torvalds
1641da177e4SLinus Torvalds va_start(args, fmt);
1651da177e4SLinus Torvalds vsnprintf(buf, sizeof(buf), fmt, args);
1661da177e4SLinus Torvalds va_end(args);
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds if (mask & NSP_DEBUG_MASK) {
1691da177e4SLinus Torvalds printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds #endif
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds /***********************************************************/
1751da177e4SLinus Torvalds
1761da177e4SLinus Torvalds /*====================================================
1771da177e4SLinus Torvalds * Clenaup parameters and call done() functions.
1781da177e4SLinus Torvalds * You must be set SCpnt->result before call this function.
1791da177e4SLinus Torvalds */
nsp_scsi_done(struct scsi_cmnd * SCpnt)1800fc82d5eSHenrik Kretzschmar static void nsp_scsi_done(struct scsi_cmnd *SCpnt)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds data->CurrentSC = NULL;
1851da177e4SLinus Torvalds
186ca0d62d2SBart Van Assche scsi_done(SCpnt);
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
nsp_queuecommand_lck(struct scsi_cmnd * const SCpnt)189ea39700fSBart Van Assche static int nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt)
1901da177e4SLinus Torvalds {
191ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
1921da177e4SLinus Torvalds #ifdef NSP_DEBUG
1931da177e4SLinus Torvalds /*unsigned int host_id = SCpnt->device->host->this_id;*/
1941da177e4SLinus Torvalds /*unsigned int base = SCpnt->device->host->io_port;*/
195422c0d61SJeff Garzik unsigned char target = scmd_id(SCpnt);
1961da177e4SLinus Torvalds #endif
1971da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
1981da177e4SLinus Torvalds
199040cd232SBoaz Harrosh nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
2009cb78c16SHannes Reinecke "SCpnt=0x%p target=%d lun=%llu sglist=0x%p bufflen=%d sg_count=%d",
201040cd232SBoaz Harrosh SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
202040cd232SBoaz Harrosh scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
2031da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds if (data->CurrentSC != NULL) {
2061da177e4SLinus Torvalds nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
2071da177e4SLinus Torvalds SCpnt->result = DID_BAD_TARGET << 16;
2081da177e4SLinus Torvalds nsp_scsi_done(SCpnt);
2091da177e4SLinus Torvalds return 0;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds #if 0
2131da177e4SLinus Torvalds /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
2141da177e4SLinus Torvalds This makes kernel crash when suspending... */
2151da177e4SLinus Torvalds if (data->ScsiInfo->stop != 0) {
2161da177e4SLinus Torvalds nsp_msg(KERN_INFO, "suspending device. reject command.");
2171da177e4SLinus Torvalds SCpnt->result = DID_BAD_TARGET << 16;
2181da177e4SLinus Torvalds nsp_scsi_done(SCpnt);
2191da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY;
2201da177e4SLinus Torvalds }
2211da177e4SLinus Torvalds #endif
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds show_command(SCpnt);
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds data->CurrentSC = SCpnt;
2261da177e4SLinus Torvalds
227ea39700fSBart Van Assche scsi_pointer->Status = SAM_STAT_CHECK_CONDITION;
228ea39700fSBart Van Assche scsi_pointer->Message = 0;
229ea39700fSBart Van Assche scsi_pointer->have_data_in = IO_UNKNOWN;
230ea39700fSBart Van Assche scsi_pointer->sent_command = 0;
231ea39700fSBart Van Assche scsi_pointer->phase = PH_UNDETERMINED;
232040cd232SBoaz Harrosh scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds /* setup scratch area
2351da177e4SLinus Torvalds SCp.ptr : buffer pointer
2361da177e4SLinus Torvalds SCp.this_residual : buffer length
2371da177e4SLinus Torvalds SCp.buffer : next buffer
2381da177e4SLinus Torvalds SCp.buffers_residual : left buffers in list
2391da177e4SLinus Torvalds SCp.phase : current state of the command */
240040cd232SBoaz Harrosh if (scsi_bufflen(SCpnt)) {
241ea39700fSBart Van Assche scsi_pointer->buffer = scsi_sglist(SCpnt);
242ea39700fSBart Van Assche scsi_pointer->ptr = BUFFER_ADDR(SCpnt);
243ea39700fSBart Van Assche scsi_pointer->this_residual = scsi_pointer->buffer->length;
244ea39700fSBart Van Assche scsi_pointer->buffers_residual = scsi_sg_count(SCpnt) - 1;
2451da177e4SLinus Torvalds } else {
246ea39700fSBart Van Assche scsi_pointer->ptr = NULL;
247ea39700fSBart Van Assche scsi_pointer->this_residual = 0;
248ea39700fSBart Van Assche scsi_pointer->buffer = NULL;
249ea39700fSBart Van Assche scsi_pointer->buffers_residual = 0;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds
252dfab1e53SBart Van Assche if (!nsphw_start_selection(SCpnt)) {
2531da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
2541da177e4SLinus Torvalds SCpnt->result = DID_BUS_BUSY << 16;
2551da177e4SLinus Torvalds nsp_scsi_done(SCpnt);
2561da177e4SLinus Torvalds return 0;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
2611da177e4SLinus Torvalds #ifdef NSP_DEBUG
2621da177e4SLinus Torvalds data->CmdId++;
2631da177e4SLinus Torvalds #endif
2641da177e4SLinus Torvalds return 0;
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds
DEF_SCSI_QCMD(nsp_queuecommand)267f281233dSJeff Garzik static DEF_SCSI_QCMD(nsp_queuecommand)
268f281233dSJeff Garzik
2691da177e4SLinus Torvalds /*
2701da177e4SLinus Torvalds * setup PIO FIFO transfer mode and enable/disable to data out
2711da177e4SLinus Torvalds */
272dfab1e53SBart Van Assche static void nsp_setup_fifo(nsp_hw_data *data, bool enabled)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds unsigned int base = data->BaseAddress;
2751da177e4SLinus Torvalds unsigned char transfer_mode_reg;
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
2781da177e4SLinus Torvalds
279dfab1e53SBart Van Assche if (enabled) {
2801da177e4SLinus Torvalds transfer_mode_reg = TRANSFER_GO | BRAIND;
2811da177e4SLinus Torvalds } else {
2821da177e4SLinus Torvalds transfer_mode_reg = 0;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds transfer_mode_reg |= data->TransferMode;
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds
nsphw_init_sync(nsp_hw_data * data)2901da177e4SLinus Torvalds static void nsphw_init_sync(nsp_hw_data *data)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
2931da177e4SLinus Torvalds .SyncPeriod = 0,
2941da177e4SLinus Torvalds .SyncOffset = 0
2951da177e4SLinus Torvalds };
2961da177e4SLinus Torvalds int i;
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds /* setup sync data */
2991da177e4SLinus Torvalds for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
3001da177e4SLinus Torvalds data->Sync[i] = tmp_sync;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds
3041da177e4SLinus Torvalds /*
3051da177e4SLinus Torvalds * Initialize Ninja hardware
3061da177e4SLinus Torvalds */
nsphw_init(nsp_hw_data * data)30772961735SBart Van Assche static void nsphw_init(nsp_hw_data *data)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds unsigned int base = data->BaseAddress;
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds data->ScsiClockDiv = CLOCK_40M | FAST_20;
3141da177e4SLinus Torvalds data->CurrentSC = NULL;
3151da177e4SLinus Torvalds data->FifoCount = 0;
3161da177e4SLinus Torvalds data->TransferMode = MODE_IO8;
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds nsphw_init_sync(data);
3191da177e4SLinus Torvalds
3201da177e4SLinus Torvalds /* block all interrupts */
3211da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
3221da177e4SLinus Torvalds
3231da177e4SLinus Torvalds /* setup SCSI interface */
3241da177e4SLinus Torvalds nsp_write(base, IFSELECT, IF_IFSEL);
3251da177e4SLinus Torvalds
3261da177e4SLinus Torvalds nsp_index_write(base, SCSIIRQMODE, 0);
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds nsp_index_write(base, TRANSFERMODE, MODE_IO8);
3291da177e4SLinus Torvalds nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv);
3301da177e4SLinus Torvalds
3311da177e4SLinus Torvalds nsp_index_write(base, PARITYCTRL, 0);
3321da177e4SLinus Torvalds nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
3331da177e4SLinus Torvalds ACK_COUNTER_CLEAR |
3341da177e4SLinus Torvalds REQ_COUNTER_CLEAR |
3351da177e4SLinus Torvalds HOST_COUNTER_CLEAR);
3361da177e4SLinus Torvalds
3371da177e4SLinus Torvalds /* setup fifo asic */
3381da177e4SLinus Torvalds nsp_write(base, IFSELECT, IF_REGSEL);
3391da177e4SLinus Torvalds nsp_index_write(base, TERMPWRCTRL, 0);
3401da177e4SLinus Torvalds if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
3411da177e4SLinus Torvalds nsp_msg(KERN_INFO, "terminator power on");
3421da177e4SLinus Torvalds nsp_index_write(base, TERMPWRCTRL, POWER_ON);
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds nsp_index_write(base, TIMERCOUNT, 0);
3461da177e4SLinus Torvalds nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */
3471da177e4SLinus Torvalds
3481da177e4SLinus Torvalds nsp_index_write(base, SYNCREG, 0);
3491da177e4SLinus Torvalds nsp_index_write(base, ACKWIDTH, 0);
3501da177e4SLinus Torvalds
3511da177e4SLinus Torvalds /* enable interrupts and ack them */
3521da177e4SLinus Torvalds nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI |
3531da177e4SLinus Torvalds RESELECT_EI |
3541da177e4SLinus Torvalds SCSI_RESET_IRQ_EI );
3551da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
3561da177e4SLinus Torvalds
357dfab1e53SBart Van Assche nsp_setup_fifo(data, false);
3581da177e4SLinus Torvalds }
3591da177e4SLinus Torvalds
3601da177e4SLinus Torvalds /*
3611da177e4SLinus Torvalds * Start selection phase
3621da177e4SLinus Torvalds */
nsphw_start_selection(struct scsi_cmnd * const SCpnt)363ea39700fSBart Van Assche static bool nsphw_start_selection(struct scsi_cmnd *const SCpnt)
3641da177e4SLinus Torvalds {
365ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
3661da177e4SLinus Torvalds unsigned int host_id = SCpnt->device->host->this_id;
3671da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
368422c0d61SJeff Garzik unsigned char target = scmd_id(SCpnt);
3691da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
3701da177e4SLinus Torvalds int time_out;
3711da177e4SLinus Torvalds unsigned char phase, arbit;
3721da177e4SLinus Torvalds
3731da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "in");
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds phase = nsp_index_read(base, SCSIBUSMON);
3761da177e4SLinus Torvalds if(phase != BUSMON_BUS_FREE) {
3771da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
378dfab1e53SBart Van Assche return false;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds /* start arbitration */
3821da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
383ea39700fSBart Van Assche scsi_pointer->phase = PH_ARBSTART;
3841da177e4SLinus Torvalds nsp_index_write(base, SETARBIT, ARBIT_GO);
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds time_out = 1000;
3871da177e4SLinus Torvalds do {
3881da177e4SLinus Torvalds /* XXX: what a stupid chip! */
3891da177e4SLinus Torvalds arbit = nsp_index_read(base, ARBITSTATUS);
3901da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
3911da177e4SLinus Torvalds udelay(1); /* hold 1.2us */
3921da177e4SLinus Torvalds } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
3931da177e4SLinus Torvalds (time_out-- != 0));
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds if (!(arbit & ARBIT_WIN)) {
3961da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
3971da177e4SLinus Torvalds nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
398dfab1e53SBart Van Assche return false;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds /* assert select line */
4021da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
403ea39700fSBart Van Assche scsi_pointer->phase = PH_SELSTART;
4041da177e4SLinus Torvalds udelay(3); /* wait 2.4us */
4051da177e4SLinus Torvalds nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
4061da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN);
4071da177e4SLinus Torvalds udelay(2); /* wait >1.2us */
4081da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
4091da177e4SLinus Torvalds nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
4101da177e4SLinus Torvalds /*udelay(1);*/ /* wait >90ns */
4111da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds /* check selection timeout */
4141da177e4SLinus Torvalds nsp_start_timer(SCpnt, 1000/51);
4151da177e4SLinus Torvalds data->SelectionTimeOut = 1;
4161da177e4SLinus Torvalds
417dfab1e53SBart Van Assche return true;
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds
4201da177e4SLinus Torvalds struct nsp_sync_table {
4211da177e4SLinus Torvalds unsigned int min_period;
4221da177e4SLinus Torvalds unsigned int max_period;
4231da177e4SLinus Torvalds unsigned int chip_period;
4241da177e4SLinus Torvalds unsigned int ack_width;
4251da177e4SLinus Torvalds };
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds static struct nsp_sync_table nsp_sync_table_40M[] = {
4281da177e4SLinus Torvalds {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/
4291da177e4SLinus Torvalds {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/
4301da177e4SLinus Torvalds {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/
4311da177e4SLinus Torvalds {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/
4321da177e4SLinus Torvalds { 0, 0, 0, 0},
4331da177e4SLinus Torvalds };
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds static struct nsp_sync_table nsp_sync_table_20M[] = {
4361da177e4SLinus Torvalds {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/
4371da177e4SLinus Torvalds {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/
4381da177e4SLinus Torvalds {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/
4391da177e4SLinus Torvalds { 0, 0, 0, 0},
4401da177e4SLinus Torvalds };
4411da177e4SLinus Torvalds
4421da177e4SLinus Torvalds /*
4431da177e4SLinus Torvalds * setup synchronous data transfer mode
4441da177e4SLinus Torvalds */
nsp_analyze_sdtr(struct scsi_cmnd * SCpnt)4450fc82d5eSHenrik Kretzschmar static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt)
4461da177e4SLinus Torvalds {
447422c0d61SJeff Garzik unsigned char target = scmd_id(SCpnt);
4481da177e4SLinus Torvalds // unsigned char lun = SCpnt->device->lun;
4491da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
4501da177e4SLinus Torvalds sync_data *sync = &(data->Sync[target]);
4511da177e4SLinus Torvalds struct nsp_sync_table *sync_table;
4521da177e4SLinus Torvalds unsigned int period, offset;
4531da177e4SLinus Torvalds
4541da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_SYNC, "in");
4551da177e4SLinus Torvalds
4561da177e4SLinus Torvalds period = sync->SyncPeriod;
4571da177e4SLinus Torvalds offset = sync->SyncOffset;
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
4621da177e4SLinus Torvalds sync_table = nsp_sync_table_20M;
4631da177e4SLinus Torvalds } else {
4641da177e4SLinus Torvalds sync_table = nsp_sync_table_40M;
4651da177e4SLinus Torvalds }
4661da177e4SLinus Torvalds
467*25ad6f63SColin Ian King for (; sync_table->max_period != 0; sync_table++) {
4681da177e4SLinus Torvalds if ( period >= sync_table->min_period &&
4691da177e4SLinus Torvalds period <= sync_table->max_period ) {
4701da177e4SLinus Torvalds break;
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds
4741da177e4SLinus Torvalds if (period != 0 && sync_table->max_period == 0) {
4751da177e4SLinus Torvalds /*
4761da177e4SLinus Torvalds * No proper period/offset found
4771da177e4SLinus Torvalds */
4781da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
4791da177e4SLinus Torvalds
4801da177e4SLinus Torvalds sync->SyncPeriod = 0;
4811da177e4SLinus Torvalds sync->SyncOffset = 0;
4821da177e4SLinus Torvalds sync->SyncRegister = 0;
4831da177e4SLinus Torvalds sync->AckWidth = 0;
4841da177e4SLinus Torvalds
485dfab1e53SBart Van Assche return false;
4861da177e4SLinus Torvalds }
4871da177e4SLinus Torvalds
4881da177e4SLinus Torvalds sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
4891da177e4SLinus Torvalds (offset & SYNCREG_OFFSET_MASK);
4901da177e4SLinus Torvalds sync->AckWidth = sync_table->ack_width;
4911da177e4SLinus Torvalds
4921da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
4931da177e4SLinus Torvalds
494dfab1e53SBart Van Assche return true;
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds /*
4991da177e4SLinus Torvalds * start ninja hardware timer
5001da177e4SLinus Torvalds */
nsp_start_timer(struct scsi_cmnd * SCpnt,int time)5010fc82d5eSHenrik Kretzschmar static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time)
5021da177e4SLinus Torvalds {
5031da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
5041da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
5051da177e4SLinus Torvalds
5061da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
5071da177e4SLinus Torvalds data->TimerCount = time;
5081da177e4SLinus Torvalds nsp_index_write(base, TIMERCOUNT, time);
5091da177e4SLinus Torvalds }
5101da177e4SLinus Torvalds
5111da177e4SLinus Torvalds /*
5121da177e4SLinus Torvalds * wait for bus phase change
5131da177e4SLinus Torvalds */
nsp_negate_signal(struct scsi_cmnd * SCpnt,unsigned char mask,char * str)5140fc82d5eSHenrik Kretzschmar static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask,
5150fc82d5eSHenrik Kretzschmar char *str)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
5181da177e4SLinus Torvalds unsigned char reg;
5191da177e4SLinus Torvalds int time_out;
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "in");
5221da177e4SLinus Torvalds
5231da177e4SLinus Torvalds time_out = 100;
5241da177e4SLinus Torvalds
5251da177e4SLinus Torvalds do {
5261da177e4SLinus Torvalds reg = nsp_index_read(base, SCSIBUSMON);
5271da177e4SLinus Torvalds if (reg == 0xff) {
5281da177e4SLinus Torvalds break;
5291da177e4SLinus Torvalds }
5300454c740SRoel Kluin } while ((--time_out != 0) && (reg & mask) != 0);
5311da177e4SLinus Torvalds
5321da177e4SLinus Torvalds if (time_out == 0) {
5339b13494cSMasanari Iida nsp_msg(KERN_DEBUG, " %s signal off timeout", str);
5341da177e4SLinus Torvalds }
5351da177e4SLinus Torvalds
5361da177e4SLinus Torvalds return 0;
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds
5391da177e4SLinus Torvalds /*
5401da177e4SLinus Torvalds * expect Ninja Irq
5411da177e4SLinus Torvalds */
nsp_expect_signal(struct scsi_cmnd * SCpnt,unsigned char current_phase,unsigned char mask)5420fc82d5eSHenrik Kretzschmar static int nsp_expect_signal(struct scsi_cmnd *SCpnt,
5431da177e4SLinus Torvalds unsigned char current_phase,
5441da177e4SLinus Torvalds unsigned char mask)
5451da177e4SLinus Torvalds {
5461da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
5471da177e4SLinus Torvalds int time_out;
5481da177e4SLinus Torvalds unsigned char phase, i_src;
5491da177e4SLinus Torvalds
5501da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
5511da177e4SLinus Torvalds
5521da177e4SLinus Torvalds time_out = 100;
5531da177e4SLinus Torvalds do {
5541da177e4SLinus Torvalds phase = nsp_index_read(base, SCSIBUSMON);
5551da177e4SLinus Torvalds if (phase == 0xff) {
5561da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "ret -1");
5571da177e4SLinus Torvalds return -1;
5581da177e4SLinus Torvalds }
5591da177e4SLinus Torvalds i_src = nsp_read(base, IRQSTATUS);
5601da177e4SLinus Torvalds if (i_src & IRQSTATUS_SCSI) {
5611da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
5621da177e4SLinus Torvalds return 0;
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
5651da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
5661da177e4SLinus Torvalds return 1;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds } while(time_out-- != 0);
5691da177e4SLinus Torvalds
5701da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "timeout");
5711da177e4SLinus Torvalds return -1;
5721da177e4SLinus Torvalds }
5731da177e4SLinus Torvalds
5741da177e4SLinus Torvalds /*
5751da177e4SLinus Torvalds * transfer SCSI message
5761da177e4SLinus Torvalds */
nsp_xfer(struct scsi_cmnd * const SCpnt,int phase)577ea39700fSBart Van Assche static int nsp_xfer(struct scsi_cmnd *const SCpnt, int phase)
5781da177e4SLinus Torvalds {
579ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
5801da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
5811da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
5821da177e4SLinus Torvalds char *buf = data->MsgBuffer;
5831da177e4SLinus Torvalds int len = min(MSGBUF_SIZE, data->MsgLen);
5841da177e4SLinus Torvalds int ptr;
5851da177e4SLinus Torvalds int ret;
5861da177e4SLinus Torvalds
5871da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
5881da177e4SLinus Torvalds for (ptr = 0; len > 0; len--, ptr++) {
5891da177e4SLinus Torvalds
5901da177e4SLinus Torvalds ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
5911da177e4SLinus Torvalds if (ret <= 0) {
5921da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
5931da177e4SLinus Torvalds return 0;
5941da177e4SLinus Torvalds }
5951da177e4SLinus Torvalds
5961da177e4SLinus Torvalds /* if last byte, negate ATN */
597ea39700fSBart Van Assche if (len == 1 && scsi_pointer->phase == PH_MSG_OUT) {
5981da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
5991da177e4SLinus Torvalds }
6001da177e4SLinus Torvalds
6011da177e4SLinus Torvalds /* read & write message */
6021da177e4SLinus Torvalds if (phase & BUSMON_IO) {
6031da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
6041da177e4SLinus Torvalds buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
6051da177e4SLinus Torvalds } else {
6061da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
6071da177e4SLinus Torvalds nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
6081da177e4SLinus Torvalds }
6091da177e4SLinus Torvalds nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
6101da177e4SLinus Torvalds
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds return len;
6131da177e4SLinus Torvalds }
6141da177e4SLinus Torvalds
6151da177e4SLinus Torvalds /*
6161da177e4SLinus Torvalds * get extra SCSI data from fifo
6171da177e4SLinus Torvalds */
nsp_dataphase_bypass(struct scsi_cmnd * const SCpnt)618ea39700fSBart Van Assche static int nsp_dataphase_bypass(struct scsi_cmnd *const SCpnt)
6191da177e4SLinus Torvalds {
620ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
6211da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
6221da177e4SLinus Torvalds unsigned int count;
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "in");
6251da177e4SLinus Torvalds
626ea39700fSBart Van Assche if (scsi_pointer->have_data_in != IO_IN) {
6271da177e4SLinus Torvalds return 0;
6281da177e4SLinus Torvalds }
6291da177e4SLinus Torvalds
6301da177e4SLinus Torvalds count = nsp_fifo_count(SCpnt);
6311da177e4SLinus Torvalds if (data->FifoCount == count) {
6321da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
6331da177e4SLinus Torvalds return 0;
6341da177e4SLinus Torvalds }
6351da177e4SLinus Torvalds
6361da177e4SLinus Torvalds /*
6371da177e4SLinus Torvalds * XXX: NSP_QUIRK
6381da177e4SLinus Torvalds * data phase skip only occures in case of SCSI_LOW_READ
6391da177e4SLinus Torvalds */
6401da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
641ea39700fSBart Van Assche scsi_pointer->phase = PH_DATA;
6421da177e4SLinus Torvalds nsp_pio_read(SCpnt);
643dfab1e53SBart Van Assche nsp_setup_fifo(data, false);
6441da177e4SLinus Torvalds
6451da177e4SLinus Torvalds return 0;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds
6481da177e4SLinus Torvalds /*
6491da177e4SLinus Torvalds * accept reselection
6501da177e4SLinus Torvalds */
nsp_reselected(struct scsi_cmnd * SCpnt)65172961735SBart Van Assche static void nsp_reselected(struct scsi_cmnd *SCpnt)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
6541da177e4SLinus Torvalds unsigned int host_id = SCpnt->device->host->this_id;
6551da177e4SLinus Torvalds //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
6561da177e4SLinus Torvalds unsigned char bus_reg;
6571da177e4SLinus Torvalds unsigned char id_reg, tmp;
6581da177e4SLinus Torvalds int target;
6591da177e4SLinus Torvalds
6601da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_RESELECTION, "in");
6611da177e4SLinus Torvalds
6621da177e4SLinus Torvalds id_reg = nsp_index_read(base, RESELECTID);
6631da177e4SLinus Torvalds tmp = id_reg & (~BIT(host_id));
6641da177e4SLinus Torvalds target = 0;
6651da177e4SLinus Torvalds while(tmp != 0) {
6661da177e4SLinus Torvalds if (tmp & BIT(0)) {
6671da177e4SLinus Torvalds break;
6681da177e4SLinus Torvalds }
6691da177e4SLinus Torvalds tmp >>= 1;
6701da177e4SLinus Torvalds target++;
6711da177e4SLinus Torvalds }
6721da177e4SLinus Torvalds
673422c0d61SJeff Garzik if (scmd_id(SCpnt) != target) {
6741da177e4SLinus Torvalds nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
6781da177e4SLinus Torvalds
6791da177e4SLinus Torvalds nsp_nexus(SCpnt);
6801da177e4SLinus Torvalds bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
6811da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, bus_reg);
6821da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds
6851da177e4SLinus Torvalds /*
6861da177e4SLinus Torvalds * count how many data transferd
6871da177e4SLinus Torvalds */
nsp_fifo_count(struct scsi_cmnd * SCpnt)6880fc82d5eSHenrik Kretzschmar static int nsp_fifo_count(struct scsi_cmnd *SCpnt)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
6911da177e4SLinus Torvalds unsigned int count;
69297a33483SLee Jones unsigned int l, m, h;
6931da177e4SLinus Torvalds
6941da177e4SLinus Torvalds nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
6951da177e4SLinus Torvalds
6961da177e4SLinus Torvalds l = nsp_index_read(base, TRANSFERCOUNT);
6971da177e4SLinus Torvalds m = nsp_index_read(base, TRANSFERCOUNT);
6981da177e4SLinus Torvalds h = nsp_index_read(base, TRANSFERCOUNT);
69997a33483SLee Jones nsp_index_read(base, TRANSFERCOUNT); /* required this! */
7001da177e4SLinus Torvalds
7011da177e4SLinus Torvalds count = (h << 16) | (m << 8) | (l << 0);
7021da177e4SLinus Torvalds
7031da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
7041da177e4SLinus Torvalds
7051da177e4SLinus Torvalds return count;
7061da177e4SLinus Torvalds }
7071da177e4SLinus Torvalds
7081da177e4SLinus Torvalds /* fifo size */
7091da177e4SLinus Torvalds #define RFIFO_CRIT 64
7101da177e4SLinus Torvalds #define WFIFO_CRIT 64
7111da177e4SLinus Torvalds
7121da177e4SLinus Torvalds /*
7131da177e4SLinus Torvalds * read data in DATA IN phase
7141da177e4SLinus Torvalds */
nsp_pio_read(struct scsi_cmnd * const SCpnt)715ea39700fSBart Van Assche static void nsp_pio_read(struct scsi_cmnd *const SCpnt)
7161da177e4SLinus Torvalds {
717ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
7181da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
7191da177e4SLinus Torvalds unsigned long mmio_base = SCpnt->device->host->base;
7201da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
7211da177e4SLinus Torvalds long time_out;
7221da177e4SLinus Torvalds int ocount, res;
7231da177e4SLinus Torvalds unsigned char stat, fifo_stat;
7241da177e4SLinus Torvalds
7251da177e4SLinus Torvalds ocount = data->FifoCount;
7261da177e4SLinus Torvalds
7271da177e4SLinus Torvalds 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",
728ea39700fSBart Van Assche SCpnt, scsi_get_resid(SCpnt), ocount, scsi_pointer->ptr,
729ea39700fSBart Van Assche scsi_pointer->this_residual, scsi_pointer->buffer,
730ea39700fSBart Van Assche scsi_pointer->buffers_residual);
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds time_out = 1000;
7331da177e4SLinus Torvalds
7341da177e4SLinus Torvalds while ((time_out-- != 0) &&
735ea39700fSBart Van Assche (scsi_pointer->this_residual > 0 ||
736ea39700fSBart Van Assche scsi_pointer->buffers_residual > 0)) {
7371da177e4SLinus Torvalds
7381da177e4SLinus Torvalds stat = nsp_index_read(base, SCSIBUSMON);
7391da177e4SLinus Torvalds stat &= BUSMON_PHASE_MASK;
7401da177e4SLinus Torvalds
7411da177e4SLinus Torvalds
7421da177e4SLinus Torvalds res = nsp_fifo_count(SCpnt) - ocount;
743ea39700fSBart Van Assche //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, ocount, res);
74425985edcSLucas De Marchi if (res == 0) { /* if some data available ? */
7451da177e4SLinus Torvalds if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
746ea39700fSBart Van Assche //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", scsi_pointer->this_residual);
7471da177e4SLinus Torvalds continue;
7481da177e4SLinus Torvalds } else {
7491da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
7501da177e4SLinus Torvalds break;
7511da177e4SLinus Torvalds }
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds
7541da177e4SLinus Torvalds fifo_stat = nsp_read(base, FIFOSTATUS);
7551da177e4SLinus Torvalds if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
7561da177e4SLinus Torvalds stat == BUSPHASE_DATA_IN) {
7571da177e4SLinus Torvalds continue;
7581da177e4SLinus Torvalds }
7591da177e4SLinus Torvalds
760ea39700fSBart Van Assche res = min(res, scsi_pointer->this_residual);
7611da177e4SLinus Torvalds
7621da177e4SLinus Torvalds switch (data->TransferMode) {
7631da177e4SLinus Torvalds case MODE_IO32:
7641da177e4SLinus Torvalds res &= ~(BIT(1)|BIT(0)); /* align 4 */
765ea39700fSBart Van Assche nsp_fifo32_read(base, scsi_pointer->ptr, res >> 2);
7661da177e4SLinus Torvalds break;
7671da177e4SLinus Torvalds case MODE_IO8:
768ea39700fSBart Van Assche nsp_fifo8_read(base, scsi_pointer->ptr, res);
7691da177e4SLinus Torvalds break;
7701da177e4SLinus Torvalds
7711da177e4SLinus Torvalds case MODE_MEM32:
7721da177e4SLinus Torvalds res &= ~(BIT(1)|BIT(0)); /* align 4 */
773ea39700fSBart Van Assche nsp_mmio_fifo32_read(mmio_base, scsi_pointer->ptr,
774ea39700fSBart Van Assche res >> 2);
7751da177e4SLinus Torvalds break;
7761da177e4SLinus Torvalds
7771da177e4SLinus Torvalds default:
7781da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
7791da177e4SLinus Torvalds return;
7801da177e4SLinus Torvalds }
7811da177e4SLinus Torvalds
782040cd232SBoaz Harrosh nsp_inc_resid(SCpnt, -res);
783ea39700fSBart Van Assche scsi_pointer->ptr += res;
784ea39700fSBart Van Assche scsi_pointer->this_residual -= res;
7851da177e4SLinus Torvalds ocount += res;
786ea39700fSBart Van Assche //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, ocount);
7871da177e4SLinus Torvalds
7881da177e4SLinus Torvalds /* go to next scatter list if available */
789ea39700fSBart Van Assche if (scsi_pointer->this_residual == 0 &&
790ea39700fSBart Van Assche scsi_pointer->buffers_residual != 0 ) {
7911da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
792ea39700fSBart Van Assche scsi_pointer->buffers_residual--;
793ea39700fSBart Van Assche scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
794ea39700fSBart Van Assche scsi_pointer->ptr = BUFFER_ADDR(SCpnt);
795ea39700fSBart Van Assche scsi_pointer->this_residual =
796ea39700fSBart Van Assche scsi_pointer->buffer->length;
7971da177e4SLinus Torvalds time_out = 1000;
7981da177e4SLinus Torvalds
799ea39700fSBart Van Assche //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", scsi_pointer->buffer->page, scsi_pointer->buffer->offset);
8001da177e4SLinus Torvalds }
8011da177e4SLinus Torvalds }
8021da177e4SLinus Torvalds
8031da177e4SLinus Torvalds data->FifoCount = ocount;
8041da177e4SLinus Torvalds
8050454c740SRoel Kluin if (time_out < 0) {
8061da177e4SLinus Torvalds nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
807ea39700fSBart Van Assche scsi_get_resid(SCpnt), scsi_pointer->this_residual,
808ea39700fSBart Van Assche scsi_pointer->buffers_residual);
8091da177e4SLinus Torvalds }
8101da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
811040cd232SBoaz Harrosh nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
812040cd232SBoaz Harrosh scsi_get_resid(SCpnt));
8131da177e4SLinus Torvalds }
8141da177e4SLinus Torvalds
8151da177e4SLinus Torvalds /*
8161da177e4SLinus Torvalds * write data in DATA OUT phase
8171da177e4SLinus Torvalds */
nsp_pio_write(struct scsi_cmnd * SCpnt)8180fc82d5eSHenrik Kretzschmar static void nsp_pio_write(struct scsi_cmnd *SCpnt)
8191da177e4SLinus Torvalds {
820ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt);
8211da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
8221da177e4SLinus Torvalds unsigned long mmio_base = SCpnt->device->host->base;
8231da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
8241da177e4SLinus Torvalds int time_out;
8251da177e4SLinus Torvalds int ocount, res;
8261da177e4SLinus Torvalds unsigned char stat;
8271da177e4SLinus Torvalds
8281da177e4SLinus Torvalds ocount = data->FifoCount;
8291da177e4SLinus Torvalds
8301da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
831ea39700fSBart Van Assche data->FifoCount, scsi_pointer->ptr, scsi_pointer->this_residual,
832ea39700fSBart Van Assche scsi_pointer->buffer, scsi_pointer->buffers_residual,
833040cd232SBoaz Harrosh scsi_get_resid(SCpnt));
8341da177e4SLinus Torvalds
8351da177e4SLinus Torvalds time_out = 1000;
8361da177e4SLinus Torvalds
8371da177e4SLinus Torvalds while ((time_out-- != 0) &&
838ea39700fSBart Van Assche (scsi_pointer->this_residual > 0 ||
839ea39700fSBart Van Assche scsi_pointer->buffers_residual > 0)) {
8401da177e4SLinus Torvalds stat = nsp_index_read(base, SCSIBUSMON);
8411da177e4SLinus Torvalds stat &= BUSMON_PHASE_MASK;
8421da177e4SLinus Torvalds
8431da177e4SLinus Torvalds if (stat != BUSPHASE_DATA_OUT) {
8441da177e4SLinus Torvalds res = ocount - nsp_fifo_count(SCpnt);
8451da177e4SLinus Torvalds
8461da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
8471da177e4SLinus Torvalds /* Put back pointer */
848040cd232SBoaz Harrosh nsp_inc_resid(SCpnt, res);
849ea39700fSBart Van Assche scsi_pointer->ptr -= res;
850ea39700fSBart Van Assche scsi_pointer->this_residual += res;
8511da177e4SLinus Torvalds ocount -= res;
8521da177e4SLinus Torvalds
8531da177e4SLinus Torvalds break;
8541da177e4SLinus Torvalds }
8551da177e4SLinus Torvalds
8561da177e4SLinus Torvalds res = ocount - nsp_fifo_count(SCpnt);
8571da177e4SLinus Torvalds if (res > 0) { /* write all data? */
8581da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
8591da177e4SLinus Torvalds continue;
8601da177e4SLinus Torvalds }
8611da177e4SLinus Torvalds
862ea39700fSBart Van Assche res = min(scsi_pointer->this_residual, WFIFO_CRIT);
8631da177e4SLinus Torvalds
864ea39700fSBart Van Assche //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", scsi_pointer->ptr, scsi_pointer->this_residual, res);
8651da177e4SLinus Torvalds switch (data->TransferMode) {
8661da177e4SLinus Torvalds case MODE_IO32:
8671da177e4SLinus Torvalds res &= ~(BIT(1)|BIT(0)); /* align 4 */
868ea39700fSBart Van Assche nsp_fifo32_write(base, scsi_pointer->ptr, res >> 2);
8691da177e4SLinus Torvalds break;
8701da177e4SLinus Torvalds case MODE_IO8:
871ea39700fSBart Van Assche nsp_fifo8_write(base, scsi_pointer->ptr, res);
8721da177e4SLinus Torvalds break;
8731da177e4SLinus Torvalds
8741da177e4SLinus Torvalds case MODE_MEM32:
8751da177e4SLinus Torvalds res &= ~(BIT(1)|BIT(0)); /* align 4 */
876ea39700fSBart Van Assche nsp_mmio_fifo32_write(mmio_base, scsi_pointer->ptr,
877ea39700fSBart Van Assche res >> 2);
8781da177e4SLinus Torvalds break;
8791da177e4SLinus Torvalds
8801da177e4SLinus Torvalds default:
8811da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
8821da177e4SLinus Torvalds break;
8831da177e4SLinus Torvalds }
8841da177e4SLinus Torvalds
885040cd232SBoaz Harrosh nsp_inc_resid(SCpnt, -res);
886ea39700fSBart Van Assche scsi_pointer->ptr += res;
887ea39700fSBart Van Assche scsi_pointer->this_residual -= res;
8881da177e4SLinus Torvalds ocount += res;
8891da177e4SLinus Torvalds
8901da177e4SLinus Torvalds /* go to next scatter list if available */
891ea39700fSBart Van Assche if (scsi_pointer->this_residual == 0 &&
892ea39700fSBart Van Assche scsi_pointer->buffers_residual != 0 ) {
8931da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
894ea39700fSBart Van Assche scsi_pointer->buffers_residual--;
895ea39700fSBart Van Assche scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
896ea39700fSBart Van Assche scsi_pointer->ptr = BUFFER_ADDR(SCpnt);
897ea39700fSBart Van Assche scsi_pointer->this_residual =
898ea39700fSBart Van Assche scsi_pointer->buffer->length;
8991da177e4SLinus Torvalds time_out = 1000;
9001da177e4SLinus Torvalds }
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds
9031da177e4SLinus Torvalds data->FifoCount = ocount;
9041da177e4SLinus Torvalds
9050454c740SRoel Kluin if (time_out < 0) {
906040cd232SBoaz Harrosh nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
907040cd232SBoaz Harrosh scsi_get_resid(SCpnt));
9081da177e4SLinus Torvalds }
9091da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
910040cd232SBoaz Harrosh nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
911040cd232SBoaz Harrosh scsi_get_resid(SCpnt));
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds #undef RFIFO_CRIT
9141da177e4SLinus Torvalds #undef WFIFO_CRIT
9151da177e4SLinus Torvalds
9161da177e4SLinus Torvalds /*
9171da177e4SLinus Torvalds * setup synchronous/asynchronous data transfer mode
9181da177e4SLinus Torvalds */
nsp_nexus(struct scsi_cmnd * SCpnt)9190fc82d5eSHenrik Kretzschmar static int nsp_nexus(struct scsi_cmnd *SCpnt)
9201da177e4SLinus Torvalds {
9211da177e4SLinus Torvalds unsigned int base = SCpnt->device->host->io_port;
922422c0d61SJeff Garzik unsigned char target = scmd_id(SCpnt);
9231da177e4SLinus Torvalds // unsigned char lun = SCpnt->device->lun;
9241da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
9251da177e4SLinus Torvalds sync_data *sync = &(data->Sync[target]);
9261da177e4SLinus Torvalds
9271da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
9281da177e4SLinus Torvalds
9291da177e4SLinus Torvalds /* setup synch transfer registers */
9301da177e4SLinus Torvalds nsp_index_write(base, SYNCREG, sync->SyncRegister);
9311da177e4SLinus Torvalds nsp_index_write(base, ACKWIDTH, sync->AckWidth);
9321da177e4SLinus Torvalds
933040cd232SBoaz Harrosh if (scsi_get_resid(SCpnt) % 4 != 0 ||
934040cd232SBoaz Harrosh scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
9351da177e4SLinus Torvalds data->TransferMode = MODE_IO8;
9361da177e4SLinus Torvalds } else if (nsp_burst_mode == BURST_MEM32) {
9371da177e4SLinus Torvalds data->TransferMode = MODE_MEM32;
9381da177e4SLinus Torvalds } else if (nsp_burst_mode == BURST_IO32) {
9391da177e4SLinus Torvalds data->TransferMode = MODE_IO32;
9401da177e4SLinus Torvalds } else {
9411da177e4SLinus Torvalds data->TransferMode = MODE_IO8;
9421da177e4SLinus Torvalds }
9431da177e4SLinus Torvalds
9441da177e4SLinus Torvalds /* setup pdma fifo */
945dfab1e53SBart Van Assche nsp_setup_fifo(data, true);
9461da177e4SLinus Torvalds
9471da177e4SLinus Torvalds /* clear ack counter */
9481da177e4SLinus Torvalds data->FifoCount = 0;
9491da177e4SLinus Torvalds nsp_index_write(base, POINTERCLR, POINTER_CLEAR |
9501da177e4SLinus Torvalds ACK_COUNTER_CLEAR |
9511da177e4SLinus Torvalds REQ_COUNTER_CLEAR |
9521da177e4SLinus Torvalds HOST_COUNTER_CLEAR);
9531da177e4SLinus Torvalds
9541da177e4SLinus Torvalds return 0;
9551da177e4SLinus Torvalds }
9561da177e4SLinus Torvalds
9571da177e4SLinus Torvalds #include "nsp_message.c"
9581da177e4SLinus Torvalds /*
9591da177e4SLinus Torvalds * interrupt handler
9601da177e4SLinus Torvalds */
nspintr(int irq,void * dev_id)9617d12e780SDavid Howells static irqreturn_t nspintr(int irq, void *dev_id)
9621da177e4SLinus Torvalds {
9631da177e4SLinus Torvalds unsigned int base;
9641da177e4SLinus Torvalds unsigned char irq_status, irq_phase, phase;
9650fc82d5eSHenrik Kretzschmar struct scsi_cmnd *tmpSC;
966ea39700fSBart Van Assche struct scsi_pointer *scsi_pointer;
9671da177e4SLinus Torvalds unsigned char target, lun;
9681da177e4SLinus Torvalds unsigned int *sync_neg;
9691da177e4SLinus Torvalds int i, tmp;
9701da177e4SLinus Torvalds nsp_hw_data *data;
9711da177e4SLinus Torvalds
9721da177e4SLinus Torvalds
9731da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
9741da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
9751da177e4SLinus Torvalds
9761da177e4SLinus Torvalds if ( dev_id != NULL &&
9771da177e4SLinus Torvalds ((scsi_info_t *)dev_id)->host != NULL ) {
9781da177e4SLinus Torvalds scsi_info_t *info = (scsi_info_t *)dev_id;
9791da177e4SLinus Torvalds
9801da177e4SLinus Torvalds data = (nsp_hw_data *)info->host->hostdata;
9811da177e4SLinus Torvalds } else {
9821da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
9831da177e4SLinus Torvalds return IRQ_NONE;
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds
9861da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
9871da177e4SLinus Torvalds
9881da177e4SLinus Torvalds base = data->BaseAddress;
9891da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
9901da177e4SLinus Torvalds
9911da177e4SLinus Torvalds /*
9921da177e4SLinus Torvalds * interrupt check
9931da177e4SLinus Torvalds */
9941da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
9951da177e4SLinus Torvalds irq_status = nsp_read(base, IRQSTATUS);
9961da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
9971da177e4SLinus Torvalds if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
9981da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, 0);
9991da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
10001da177e4SLinus Torvalds return IRQ_NONE;
10011da177e4SLinus Torvalds }
10021da177e4SLinus Torvalds
10031da177e4SLinus Torvalds /* XXX: IMPORTANT
10041da177e4SLinus Torvalds * Do not read an irq_phase register if no scsi phase interrupt.
10051da177e4SLinus Torvalds * Unless, you should lose a scsi phase interrupt.
10061da177e4SLinus Torvalds */
10071da177e4SLinus Torvalds phase = nsp_index_read(base, SCSIBUSMON);
10081da177e4SLinus Torvalds if((irq_status & IRQSTATUS_SCSI) != 0) {
10091da177e4SLinus Torvalds irq_phase = nsp_index_read(base, IRQPHASESENCE);
10101da177e4SLinus Torvalds } else {
10111da177e4SLinus Torvalds irq_phase = 0;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds
10141da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
10151da177e4SLinus Torvalds
10161da177e4SLinus Torvalds /*
10171da177e4SLinus Torvalds * timer interrupt handler (scsi vs timer interrupts)
10181da177e4SLinus Torvalds */
10191da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
10201da177e4SLinus Torvalds if (data->TimerCount != 0) {
10211da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "stop timer");
10221da177e4SLinus Torvalds nsp_index_write(base, TIMERCOUNT, 0);
10231da177e4SLinus Torvalds nsp_index_write(base, TIMERCOUNT, 0);
10241da177e4SLinus Torvalds data->TimerCount = 0;
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds
10271da177e4SLinus Torvalds if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
10281da177e4SLinus Torvalds data->SelectionTimeOut == 0) {
10291da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "timer start");
10301da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
10311da177e4SLinus Torvalds return IRQ_HANDLED;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds
10341da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
10351da177e4SLinus Torvalds
10361da177e4SLinus Torvalds if ((irq_status & IRQSTATUS_SCSI) &&
10371da177e4SLinus Torvalds (irq_phase & SCSI_RESET_IRQ)) {
10381da177e4SLinus Torvalds nsp_msg(KERN_ERR, "bus reset (power off?)");
10391da177e4SLinus Torvalds
10401da177e4SLinus Torvalds nsphw_init(data);
10411da177e4SLinus Torvalds nsp_bus_reset(data);
10421da177e4SLinus Torvalds
10431da177e4SLinus Torvalds if(data->CurrentSC != NULL) {
10441da177e4SLinus Torvalds tmpSC = data->CurrentSC;
1045ea39700fSBart Van Assche scsi_pointer = nsp_priv(tmpSC);
10461da177e4SLinus Torvalds tmpSC->result = (DID_RESET << 16) |
1047ea39700fSBart Van Assche ((scsi_pointer->Message & 0xff) << 8) |
1048ea39700fSBart Van Assche ((scsi_pointer->Status & 0xff) << 0);
10491da177e4SLinus Torvalds nsp_scsi_done(tmpSC);
10501da177e4SLinus Torvalds }
10511da177e4SLinus Torvalds return IRQ_HANDLED;
10521da177e4SLinus Torvalds }
10531da177e4SLinus Torvalds
10541da177e4SLinus Torvalds if (data->CurrentSC == NULL) {
10551da177e4SLinus Torvalds 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);
10561da177e4SLinus Torvalds nsphw_init(data);
10571da177e4SLinus Torvalds nsp_bus_reset(data);
10581da177e4SLinus Torvalds return IRQ_HANDLED;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds
10611da177e4SLinus Torvalds tmpSC = data->CurrentSC;
1062ea39700fSBart Van Assche scsi_pointer = nsp_priv(tmpSC);
10631da177e4SLinus Torvalds target = tmpSC->device->id;
10641da177e4SLinus Torvalds lun = tmpSC->device->lun;
10651da177e4SLinus Torvalds sync_neg = &(data->Sync[target].SyncNegotiation);
10661da177e4SLinus Torvalds
10671da177e4SLinus Torvalds /*
10681da177e4SLinus Torvalds * parse hardware SCSI irq reasons register
10691da177e4SLinus Torvalds */
10701da177e4SLinus Torvalds if (irq_status & IRQSTATUS_SCSI) {
10711da177e4SLinus Torvalds if (irq_phase & RESELECT_IRQ) {
10721da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "reselect");
10731da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
107472961735SBart Van Assche nsp_reselected(tmpSC);
10751da177e4SLinus Torvalds return IRQ_HANDLED;
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds
10781da177e4SLinus Torvalds if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
10791da177e4SLinus Torvalds return IRQ_HANDLED;
10801da177e4SLinus Torvalds }
10811da177e4SLinus Torvalds }
10821da177e4SLinus Torvalds
10831da177e4SLinus Torvalds //show_phase(tmpSC);
10841da177e4SLinus Torvalds
1085ea39700fSBart Van Assche switch (scsi_pointer->phase) {
10861da177e4SLinus Torvalds case PH_SELSTART:
10871da177e4SLinus Torvalds // *sync_neg = SYNC_NOT_YET;
10881da177e4SLinus Torvalds if ((phase & BUSMON_BSY) == 0) {
10891da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
10901da177e4SLinus Torvalds if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
10911da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "selection time out");
10921da177e4SLinus Torvalds data->SelectionTimeOut = 0;
10931da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, 0);
10941da177e4SLinus Torvalds
10951da177e4SLinus Torvalds tmpSC->result = DID_TIME_OUT << 16;
10961da177e4SLinus Torvalds nsp_scsi_done(tmpSC);
10971da177e4SLinus Torvalds
10981da177e4SLinus Torvalds return IRQ_HANDLED;
10991da177e4SLinus Torvalds }
11001da177e4SLinus Torvalds data->SelectionTimeOut += 1;
11011da177e4SLinus Torvalds nsp_start_timer(tmpSC, 1000/51);
11021da177e4SLinus Torvalds return IRQ_HANDLED;
11031da177e4SLinus Torvalds }
11041da177e4SLinus Torvalds
11051da177e4SLinus Torvalds /* attention assert */
11061da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "attention assert");
11071da177e4SLinus Torvalds data->SelectionTimeOut = 0;
1108ea39700fSBart Van Assche scsi_pointer->phase = PH_SELECTED;
11091da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
11101da177e4SLinus Torvalds udelay(1);
11111da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
11121da177e4SLinus Torvalds return IRQ_HANDLED;
11131da177e4SLinus Torvalds
11141da177e4SLinus Torvalds case PH_RESELECT:
11151da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
11161da177e4SLinus Torvalds // *sync_neg = SYNC_NOT_YET;
11171da177e4SLinus Torvalds if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
11181da177e4SLinus Torvalds
11191da177e4SLinus Torvalds tmpSC->result = DID_ABORT << 16;
11201da177e4SLinus Torvalds nsp_scsi_done(tmpSC);
11211da177e4SLinus Torvalds return IRQ_HANDLED;
11221da177e4SLinus Torvalds }
1123df561f66SGustavo A. R. Silva fallthrough;
11241da177e4SLinus Torvalds default:
11251da177e4SLinus Torvalds if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
11261da177e4SLinus Torvalds return IRQ_HANDLED;
11271da177e4SLinus Torvalds }
11281da177e4SLinus Torvalds break;
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds
11311da177e4SLinus Torvalds /*
11321da177e4SLinus Torvalds * SCSI sequencer
11331da177e4SLinus Torvalds */
11341da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
11351da177e4SLinus Torvalds
11361da177e4SLinus Torvalds /* normal disconnect */
1137ea39700fSBart Van Assche if ((scsi_pointer->phase == PH_MSG_IN ||
1138ea39700fSBart Van Assche scsi_pointer->phase == PH_MSG_OUT) &&
11391da177e4SLinus Torvalds (irq_phase & LATCHED_BUS_FREE) != 0) {
11401da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
11411da177e4SLinus Torvalds
11421da177e4SLinus Torvalds //*sync_neg = SYNC_NOT_YET;
11431da177e4SLinus Torvalds
11447e1c99e5SNathan Chancellor /* all command complete and return status */
1145ea39700fSBart Van Assche if (scsi_pointer->Message == COMMAND_COMPLETE) {
11461da177e4SLinus Torvalds tmpSC->result = (DID_OK << 16) |
1147ea39700fSBart Van Assche ((scsi_pointer->Message & 0xff) << 8) |
1148ea39700fSBart Van Assche ((scsi_pointer->Status & 0xff) << 0);
11491da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
11501da177e4SLinus Torvalds nsp_scsi_done(tmpSC);
11511da177e4SLinus Torvalds
11521da177e4SLinus Torvalds return IRQ_HANDLED;
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds
11551da177e4SLinus Torvalds return IRQ_HANDLED;
11561da177e4SLinus Torvalds }
11571da177e4SLinus Torvalds
11581da177e4SLinus Torvalds
11591da177e4SLinus Torvalds /* check unexpected bus free state */
11601da177e4SLinus Torvalds if (phase == 0) {
11611da177e4SLinus Torvalds nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
11621da177e4SLinus Torvalds
11631da177e4SLinus Torvalds *sync_neg = SYNC_NG;
11641da177e4SLinus Torvalds tmpSC->result = DID_ERROR << 16;
11651da177e4SLinus Torvalds nsp_scsi_done(tmpSC);
11661da177e4SLinus Torvalds return IRQ_HANDLED;
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds
11691da177e4SLinus Torvalds switch (phase & BUSMON_PHASE_MASK) {
11701da177e4SLinus Torvalds case BUSPHASE_COMMAND:
11711da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
11721da177e4SLinus Torvalds if ((phase & BUSMON_REQ) == 0) {
11731da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
11741da177e4SLinus Torvalds return IRQ_HANDLED;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds
1177ea39700fSBart Van Assche scsi_pointer->phase = PH_COMMAND;
11781da177e4SLinus Torvalds
11791da177e4SLinus Torvalds nsp_nexus(tmpSC);
11801da177e4SLinus Torvalds
11811da177e4SLinus Torvalds /* write scsi command */
11821da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
11831da177e4SLinus Torvalds nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
11841da177e4SLinus Torvalds for (i = 0; i < tmpSC->cmd_len; i++) {
11851da177e4SLinus Torvalds nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
11861da177e4SLinus Torvalds }
11871da177e4SLinus Torvalds nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
11881da177e4SLinus Torvalds break;
11891da177e4SLinus Torvalds
11901da177e4SLinus Torvalds case BUSPHASE_DATA_OUT:
11911da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
11921da177e4SLinus Torvalds
1193ea39700fSBart Van Assche scsi_pointer->phase = PH_DATA;
1194ea39700fSBart Van Assche scsi_pointer->have_data_in = IO_OUT;
11951da177e4SLinus Torvalds
11961da177e4SLinus Torvalds nsp_pio_write(tmpSC);
11971da177e4SLinus Torvalds
11981da177e4SLinus Torvalds break;
11991da177e4SLinus Torvalds
12001da177e4SLinus Torvalds case BUSPHASE_DATA_IN:
12011da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
12021da177e4SLinus Torvalds
1203ea39700fSBart Van Assche scsi_pointer->phase = PH_DATA;
1204ea39700fSBart Van Assche scsi_pointer->have_data_in = IO_IN;
12051da177e4SLinus Torvalds
12061da177e4SLinus Torvalds nsp_pio_read(tmpSC);
12071da177e4SLinus Torvalds
12081da177e4SLinus Torvalds break;
12091da177e4SLinus Torvalds
12101da177e4SLinus Torvalds case BUSPHASE_STATUS:
12111da177e4SLinus Torvalds nsp_dataphase_bypass(tmpSC);
12121da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
12131da177e4SLinus Torvalds
1214ea39700fSBart Van Assche scsi_pointer->phase = PH_STATUS;
12151da177e4SLinus Torvalds
1216ea39700fSBart Van Assche scsi_pointer->Status = nsp_index_read(base, SCSIDATAWITHACK);
1217ea39700fSBart Van Assche nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x",
1218ea39700fSBart Van Assche scsi_pointer->Message, scsi_pointer->Status);
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds break;
12211da177e4SLinus Torvalds
12221da177e4SLinus Torvalds case BUSPHASE_MESSAGE_OUT:
12231da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
12241da177e4SLinus Torvalds if ((phase & BUSMON_REQ) == 0) {
12251da177e4SLinus Torvalds goto timer_out;
12261da177e4SLinus Torvalds }
12271da177e4SLinus Torvalds
1228ea39700fSBart Van Assche scsi_pointer->phase = PH_MSG_OUT;
12291da177e4SLinus Torvalds
12301da177e4SLinus Torvalds //*sync_neg = SYNC_NOT_YET;
12311da177e4SLinus Torvalds
12321da177e4SLinus Torvalds data->MsgLen = i = 0;
1233dfab1e53SBart Van Assche data->MsgBuffer[i] = IDENTIFY(true, lun); i++;
12341da177e4SLinus Torvalds
12351da177e4SLinus Torvalds if (*sync_neg == SYNC_NOT_YET) {
12361da177e4SLinus Torvalds data->Sync[target].SyncPeriod = 0;
12371da177e4SLinus Torvalds data->Sync[target].SyncOffset = 0;
12381da177e4SLinus Torvalds
12391da177e4SLinus Torvalds /**/
12401c9eb798SHannes Reinecke data->MsgBuffer[i] = EXTENDED_MESSAGE; i++;
12411da177e4SLinus Torvalds data->MsgBuffer[i] = 3; i++;
12421c9eb798SHannes Reinecke data->MsgBuffer[i] = EXTENDED_SDTR; i++;
12431da177e4SLinus Torvalds data->MsgBuffer[i] = 0x0c; i++;
12441da177e4SLinus Torvalds data->MsgBuffer[i] = 15; i++;
12451da177e4SLinus Torvalds /**/
12461da177e4SLinus Torvalds }
12471da177e4SLinus Torvalds data->MsgLen = i;
12481da177e4SLinus Torvalds
12491da177e4SLinus Torvalds nsp_analyze_sdtr(tmpSC);
12501da177e4SLinus Torvalds show_message(data);
12511da177e4SLinus Torvalds nsp_message_out(tmpSC);
12521da177e4SLinus Torvalds break;
12531da177e4SLinus Torvalds
12541da177e4SLinus Torvalds case BUSPHASE_MESSAGE_IN:
12551da177e4SLinus Torvalds nsp_dataphase_bypass(tmpSC);
12561da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
12571da177e4SLinus Torvalds if ((phase & BUSMON_REQ) == 0) {
12581da177e4SLinus Torvalds goto timer_out;
12591da177e4SLinus Torvalds }
12601da177e4SLinus Torvalds
1261ea39700fSBart Van Assche scsi_pointer->phase = PH_MSG_IN;
12621da177e4SLinus Torvalds nsp_message_in(tmpSC);
12631da177e4SLinus Torvalds
12641da177e4SLinus Torvalds /**/
12651da177e4SLinus Torvalds if (*sync_neg == SYNC_NOT_YET) {
12661da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
12671da177e4SLinus Torvalds
12681da177e4SLinus Torvalds if (data->MsgLen >= 5 &&
12691c9eb798SHannes Reinecke data->MsgBuffer[0] == EXTENDED_MESSAGE &&
12701da177e4SLinus Torvalds data->MsgBuffer[1] == 3 &&
12711c9eb798SHannes Reinecke data->MsgBuffer[2] == EXTENDED_SDTR ) {
12721da177e4SLinus Torvalds data->Sync[target].SyncPeriod = data->MsgBuffer[3];
12731da177e4SLinus Torvalds data->Sync[target].SyncOffset = data->MsgBuffer[4];
12741da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
12751da177e4SLinus Torvalds *sync_neg = SYNC_OK;
12761da177e4SLinus Torvalds } else {
12771da177e4SLinus Torvalds data->Sync[target].SyncPeriod = 0;
12781da177e4SLinus Torvalds data->Sync[target].SyncOffset = 0;
12791da177e4SLinus Torvalds *sync_neg = SYNC_NG;
12801da177e4SLinus Torvalds }
12811da177e4SLinus Torvalds nsp_analyze_sdtr(tmpSC);
12821da177e4SLinus Torvalds }
12831da177e4SLinus Torvalds /**/
12841da177e4SLinus Torvalds
12851da177e4SLinus Torvalds /* search last messeage byte */
12861da177e4SLinus Torvalds tmp = -1;
12871da177e4SLinus Torvalds for (i = 0; i < data->MsgLen; i++) {
12881da177e4SLinus Torvalds tmp = data->MsgBuffer[i];
12891c9eb798SHannes Reinecke if (data->MsgBuffer[i] == EXTENDED_MESSAGE) {
12901da177e4SLinus Torvalds i += (1 + data->MsgBuffer[i+1]);
12911da177e4SLinus Torvalds }
12921da177e4SLinus Torvalds }
1293ea39700fSBart Van Assche scsi_pointer->Message = tmp;
12941da177e4SLinus Torvalds
1295ea39700fSBart Van Assche nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d",
1296ea39700fSBart Van Assche scsi_pointer->Message, data->MsgLen);
12971da177e4SLinus Torvalds show_message(data);
12981da177e4SLinus Torvalds
12991da177e4SLinus Torvalds break;
13001da177e4SLinus Torvalds
13011da177e4SLinus Torvalds case BUSPHASE_SELECT:
13021da177e4SLinus Torvalds default:
13031da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
13041da177e4SLinus Torvalds
13051da177e4SLinus Torvalds break;
13061da177e4SLinus Torvalds }
13071da177e4SLinus Torvalds
13081da177e4SLinus Torvalds //nsp_dbg(NSP_DEBUG_INTR, "out");
13091da177e4SLinus Torvalds return IRQ_HANDLED;
13101da177e4SLinus Torvalds
13111da177e4SLinus Torvalds timer_out:
13121da177e4SLinus Torvalds nsp_start_timer(tmpSC, 1000/102);
13131da177e4SLinus Torvalds return IRQ_HANDLED;
13141da177e4SLinus Torvalds }
13151da177e4SLinus Torvalds
13161da177e4SLinus Torvalds #ifdef NSP_DEBUG
13171da177e4SLinus Torvalds #include "nsp_debug.c"
13181da177e4SLinus Torvalds #endif /* NSP_DEBUG */
13191da177e4SLinus Torvalds
13201da177e4SLinus Torvalds /*----------------------------------------------------------------*/
13211da177e4SLinus Torvalds /* look for ninja3 card and init if found */
13221da177e4SLinus Torvalds /*----------------------------------------------------------------*/
nsp_detect(struct scsi_host_template * sht)1323d0be4a7dSChristoph Hellwig static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
13241da177e4SLinus Torvalds {
13251da177e4SLinus Torvalds struct Scsi_Host *host; /* registered host structure */
13261da177e4SLinus Torvalds nsp_hw_data *data_b = &nsp_data_base, *data;
13271da177e4SLinus Torvalds
13281da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
13291da177e4SLinus Torvalds host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
13301da177e4SLinus Torvalds if (host == NULL) {
13311da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "host failed");
13321da177e4SLinus Torvalds return NULL;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds
13351da177e4SLinus Torvalds memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
13361da177e4SLinus Torvalds data = (nsp_hw_data *)host->hostdata;
13371da177e4SLinus Torvalds data->ScsiInfo->host = host;
13381da177e4SLinus Torvalds #ifdef NSP_DEBUG
13391da177e4SLinus Torvalds data->CmdId = 0;
13401da177e4SLinus Torvalds #endif
13411da177e4SLinus Torvalds
13421da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
13431da177e4SLinus Torvalds
13441da177e4SLinus Torvalds host->unique_id = data->BaseAddress;
13451da177e4SLinus Torvalds host->io_port = data->BaseAddress;
13461da177e4SLinus Torvalds host->n_io_port = data->NumAddress;
13471da177e4SLinus Torvalds host->irq = data->IrqNumber;
13481da177e4SLinus Torvalds host->base = data->MmioAddress;
13491da177e4SLinus Torvalds
13501da177e4SLinus Torvalds spin_lock_init(&(data->Lock));
13511da177e4SLinus Torvalds
13521da177e4SLinus Torvalds snprintf(data->nspinfo,
13531da177e4SLinus Torvalds sizeof(data->nspinfo),
13541da177e4SLinus Torvalds "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
13551da177e4SLinus Torvalds host->io_port, host->io_port + host->n_io_port - 1,
13561da177e4SLinus Torvalds host->base,
13571da177e4SLinus Torvalds host->irq);
13581da177e4SLinus Torvalds sht->name = data->nspinfo;
13591da177e4SLinus Torvalds
13601da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "end");
13611da177e4SLinus Torvalds
13621da177e4SLinus Torvalds
13631da177e4SLinus Torvalds return host; /* detect done. */
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds
13661da177e4SLinus Torvalds /*----------------------------------------------------------------*/
13671da177e4SLinus Torvalds /* return info string */
13681da177e4SLinus Torvalds /*----------------------------------------------------------------*/
nsp_info(struct Scsi_Host * shpnt)13691da177e4SLinus Torvalds static const char *nsp_info(struct Scsi_Host *shpnt)
13701da177e4SLinus Torvalds {
13711da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
13721da177e4SLinus Torvalds
13731da177e4SLinus Torvalds return data->nspinfo;
13741da177e4SLinus Torvalds }
13751da177e4SLinus Torvalds
nsp_show_info(struct seq_file * m,struct Scsi_Host * host)137663fd57cbSAl Viro static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
13771da177e4SLinus Torvalds {
13781da177e4SLinus Torvalds int id;
13791da177e4SLinus Torvalds int speed;
13801da177e4SLinus Torvalds unsigned long flags;
13811da177e4SLinus Torvalds nsp_hw_data *data;
13821da177e4SLinus Torvalds int hostno;
1383774251efSAdrian Bunk
13841da177e4SLinus Torvalds hostno = host->host_no;
13851da177e4SLinus Torvalds data = (nsp_hw_data *)host->hostdata;
13861da177e4SLinus Torvalds
13873d30079cSRasmus Villemoes seq_puts(m, "NinjaSCSI status\n\n"
13883d30079cSRasmus Villemoes "Driver version: $Revision: 1.23 $\n");
13890c3de38fSRasmus Villemoes seq_printf(m, "SCSI host No.: %d\n", hostno);
13900c3de38fSRasmus Villemoes seq_printf(m, "IRQ: %d\n", host->irq);
13910c3de38fSRasmus Villemoes seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
13920c3de38fSRasmus Villemoes seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
13930c3de38fSRasmus Villemoes seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize);
13941da177e4SLinus Torvalds
139591c40f24SRasmus Villemoes seq_puts(m, "burst transfer mode: ");
13961da177e4SLinus Torvalds switch (nsp_burst_mode) {
13971da177e4SLinus Torvalds case BURST_IO8:
139891c40f24SRasmus Villemoes seq_puts(m, "io8");
13991da177e4SLinus Torvalds break;
14001da177e4SLinus Torvalds case BURST_IO32:
140191c40f24SRasmus Villemoes seq_puts(m, "io32");
14021da177e4SLinus Torvalds break;
14031da177e4SLinus Torvalds case BURST_MEM32:
140491c40f24SRasmus Villemoes seq_puts(m, "mem32");
14051da177e4SLinus Torvalds break;
14061da177e4SLinus Torvalds default:
140791c40f24SRasmus Villemoes seq_puts(m, "???");
14081da177e4SLinus Torvalds break;
14091da177e4SLinus Torvalds }
1410f50332ffSRasmus Villemoes seq_putc(m, '\n');
14111da177e4SLinus Torvalds
14121da177e4SLinus Torvalds
14131da177e4SLinus Torvalds spin_lock_irqsave(&(data->Lock), flags);
14140c3de38fSRasmus Villemoes seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC);
14151da177e4SLinus Torvalds spin_unlock_irqrestore(&(data->Lock), flags);
14161da177e4SLinus Torvalds
141791c40f24SRasmus Villemoes seq_puts(m, "SDTR status\n");
14181da177e4SLinus Torvalds for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
14191da177e4SLinus Torvalds
14200c3de38fSRasmus Villemoes seq_printf(m, "id %d: ", id);
14211da177e4SLinus Torvalds
14221da177e4SLinus Torvalds if (id == host->this_id) {
142391c40f24SRasmus Villemoes seq_puts(m, "----- NinjaSCSI-3 host adapter\n");
14241da177e4SLinus Torvalds continue;
14251da177e4SLinus Torvalds }
14261da177e4SLinus Torvalds
14271da177e4SLinus Torvalds switch(data->Sync[id].SyncNegotiation) {
14281da177e4SLinus Torvalds case SYNC_OK:
142991c40f24SRasmus Villemoes seq_puts(m, " sync");
14301da177e4SLinus Torvalds break;
14311da177e4SLinus Torvalds case SYNC_NG:
143291c40f24SRasmus Villemoes seq_puts(m, "async");
14331da177e4SLinus Torvalds break;
14341da177e4SLinus Torvalds case SYNC_NOT_YET:
143591c40f24SRasmus Villemoes seq_puts(m, " none");
14361da177e4SLinus Torvalds break;
14371da177e4SLinus Torvalds default:
143891c40f24SRasmus Villemoes seq_puts(m, "?????");
14391da177e4SLinus Torvalds break;
14401da177e4SLinus Torvalds }
14411da177e4SLinus Torvalds
14421da177e4SLinus Torvalds if (data->Sync[id].SyncPeriod != 0) {
14431da177e4SLinus Torvalds speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
14441da177e4SLinus Torvalds
14450c3de38fSRasmus Villemoes seq_printf(m, " transfer %d.%dMB/s, offset %d",
14461da177e4SLinus Torvalds speed / 1000,
14471da177e4SLinus Torvalds speed % 1000,
14481da177e4SLinus Torvalds data->Sync[id].SyncOffset
14491da177e4SLinus Torvalds );
14501da177e4SLinus Torvalds }
1451f50332ffSRasmus Villemoes seq_putc(m, '\n');
14521da177e4SLinus Torvalds }
14531da177e4SLinus Torvalds return 0;
14541da177e4SLinus Torvalds }
14551da177e4SLinus Torvalds
14561da177e4SLinus Torvalds /*---------------------------------------------------------------*/
14571da177e4SLinus Torvalds /* error handler */
14581da177e4SLinus Torvalds /*---------------------------------------------------------------*/
14591da177e4SLinus Torvalds
14601da177e4SLinus Torvalds /*
14610fc82d5eSHenrik Kretzschmar static int nsp_eh_abort(struct scsi_cmnd *SCpnt)
14621da177e4SLinus Torvalds {
14631da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
14641da177e4SLinus Torvalds
14651da177e4SLinus Torvalds return nsp_eh_bus_reset(SCpnt);
14661da177e4SLinus Torvalds }*/
14671da177e4SLinus Torvalds
nsp_bus_reset(nsp_hw_data * data)14681da177e4SLinus Torvalds static int nsp_bus_reset(nsp_hw_data *data)
14691da177e4SLinus Torvalds {
14701da177e4SLinus Torvalds unsigned int base = data->BaseAddress;
14711da177e4SLinus Torvalds int i;
14721da177e4SLinus Torvalds
14731da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
14741da177e4SLinus Torvalds
14751da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
14761da177e4SLinus Torvalds mdelay(100); /* 100ms */
14771da177e4SLinus Torvalds nsp_index_write(base, SCSIBUSCTRL, 0);
14781da177e4SLinus Torvalds for(i = 0; i < 5; i++) {
14791da177e4SLinus Torvalds nsp_index_read(base, IRQPHASESENCE); /* dummy read */
14801da177e4SLinus Torvalds }
14811da177e4SLinus Torvalds
14821da177e4SLinus Torvalds nsphw_init_sync(data);
14831da177e4SLinus Torvalds
14841da177e4SLinus Torvalds nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
14851da177e4SLinus Torvalds
14861da177e4SLinus Torvalds return SUCCESS;
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds
nsp_eh_bus_reset(struct scsi_cmnd * SCpnt)14890fc82d5eSHenrik Kretzschmar static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt)
14901da177e4SLinus Torvalds {
14911da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
14921da177e4SLinus Torvalds
14931da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
14941da177e4SLinus Torvalds
14951da177e4SLinus Torvalds return nsp_bus_reset(data);
14961da177e4SLinus Torvalds }
14971da177e4SLinus Torvalds
nsp_eh_host_reset(struct scsi_cmnd * SCpnt)14980fc82d5eSHenrik Kretzschmar static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
14991da177e4SLinus Torvalds {
15001da177e4SLinus Torvalds nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
15011da177e4SLinus Torvalds
15021da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_BUSRESET, "in");
15031da177e4SLinus Torvalds
15041da177e4SLinus Torvalds nsphw_init(data);
15051da177e4SLinus Torvalds
15061da177e4SLinus Torvalds return SUCCESS;
15071da177e4SLinus Torvalds }
15081da177e4SLinus Torvalds
15091da177e4SLinus Torvalds
15101da177e4SLinus Torvalds /**********************************************************************
15111da177e4SLinus Torvalds PCMCIA functions
15121da177e4SLinus Torvalds **********************************************************************/
15131da177e4SLinus Torvalds
nsp_cs_probe(struct pcmcia_device * link)151415b99ac1SDominik Brodowski static int nsp_cs_probe(struct pcmcia_device *link)
15151da177e4SLinus Torvalds {
15161da177e4SLinus Torvalds scsi_info_t *info;
15171da177e4SLinus Torvalds nsp_hw_data *data = &nsp_data_base;
151815b99ac1SDominik Brodowski int ret;
15191da177e4SLinus Torvalds
15201da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "in");
15211da177e4SLinus Torvalds
15221da177e4SLinus Torvalds /* Create new SCSI device */
1523dd00cc48SYoann Padioleau info = kzalloc(sizeof(*info), GFP_KERNEL);
1524f8cfa618SDominik Brodowski if (info == NULL) { return -ENOMEM; }
1525fba395eeSDominik Brodowski info->p_dev = link;
15261da177e4SLinus Torvalds link->priv = info;
15271da177e4SLinus Torvalds data->ScsiInfo = info;
15281da177e4SLinus Torvalds
15291da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
15301da177e4SLinus Torvalds
153115b99ac1SDominik Brodowski ret = nsp_cs_config(link);
15321da177e4SLinus Torvalds
15331da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
153415b99ac1SDominik Brodowski return ret;
15351da177e4SLinus Torvalds } /* nsp_cs_attach */
15361da177e4SLinus Torvalds
15371da177e4SLinus Torvalds
nsp_cs_detach(struct pcmcia_device * link)1538fba395eeSDominik Brodowski static void nsp_cs_detach(struct pcmcia_device *link)
15391da177e4SLinus Torvalds {
15401da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
15411da177e4SLinus Torvalds
1542cc3b4866SDominik Brodowski ((scsi_info_t *)link->priv)->stop = 1;
15431da177e4SLinus Torvalds nsp_cs_release(link);
15441da177e4SLinus Torvalds
15451da177e4SLinus Torvalds kfree(link->priv);
15461da177e4SLinus Torvalds link->priv = NULL;
15471da177e4SLinus Torvalds } /* nsp_cs_detach */
15481da177e4SLinus Torvalds
15491da177e4SLinus Torvalds
nsp_cs_config_check(struct pcmcia_device * p_dev,void * priv_data)155000990e7cSDominik Brodowski static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
15510e6f9d27SDominik Brodowski {
1552cdb13808SDominik Brodowski nsp_hw_data *data = priv_data;
15531da177e4SLinus Torvalds
155400990e7cSDominik Brodowski if (p_dev->config_index == 0)
15550e6f9d27SDominik Brodowski return -ENODEV;
15561da177e4SLinus Torvalds
15571da177e4SLinus Torvalds /* This reserves IO space but doesn't actually enable it */
155890abdc3bSDominik Brodowski if (pcmcia_request_io(p_dev) != 0)
15591da177e4SLinus Torvalds goto next_entry;
15601da177e4SLinus Torvalds
156100990e7cSDominik Brodowski if (resource_size(p_dev->resource[2])) {
1562cdb13808SDominik Brodowski p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
1563cdb13808SDominik Brodowski WIN_MEMORY_TYPE_CM |
1564cdb13808SDominik Brodowski WIN_ENABLE);
1565cdb13808SDominik Brodowski if (p_dev->resource[2]->end < 0x1000)
1566cdb13808SDominik Brodowski p_dev->resource[2]->end = 0x1000;
1567440eed43SDominik Brodowski if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
15681da177e4SLinus Torvalds goto next_entry;
1569cdb13808SDominik Brodowski if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
157000990e7cSDominik Brodowski p_dev->card_addr) != 0)
15711da177e4SLinus Torvalds goto next_entry;
15721da177e4SLinus Torvalds
1573cdb13808SDominik Brodowski data->MmioAddress = (unsigned long)
15744bdc0d67SChristoph Hellwig ioremap(p_dev->resource[2]->start,
1575cdb13808SDominik Brodowski resource_size(p_dev->resource[2]));
15762576e153SJiasheng Jiang if (!data->MmioAddress)
15772576e153SJiasheng Jiang goto next_entry;
15782576e153SJiasheng Jiang
1579cdb13808SDominik Brodowski data->MmioLength = resource_size(p_dev->resource[2]);
15801da177e4SLinus Torvalds }
15811da177e4SLinus Torvalds /* If we got this far, we're cool! */
15820e6f9d27SDominik Brodowski return 0;
15831da177e4SLinus Torvalds
15841da177e4SLinus Torvalds next_entry:
15851da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "next");
15860e6f9d27SDominik Brodowski pcmcia_disable_device(p_dev);
15870e6f9d27SDominik Brodowski return -ENODEV;
15881da177e4SLinus Torvalds }
15891da177e4SLinus Torvalds
nsp_cs_config(struct pcmcia_device * link)15900e6f9d27SDominik Brodowski static int nsp_cs_config(struct pcmcia_device *link)
15910e6f9d27SDominik Brodowski {
15920e6f9d27SDominik Brodowski int ret;
15930e6f9d27SDominik Brodowski scsi_info_t *info = link->priv;
15940e6f9d27SDominik Brodowski struct Scsi_Host *host;
15950e6f9d27SDominik Brodowski nsp_hw_data *data = &nsp_data_base;
15960e6f9d27SDominik Brodowski
15970e6f9d27SDominik Brodowski nsp_dbg(NSP_DEBUG_INIT, "in");
15980e6f9d27SDominik Brodowski
1599440eed43SDominik Brodowski link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
160000990e7cSDominik Brodowski CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM |
160100990e7cSDominik Brodowski CONF_AUTO_SET_IO;
1602440eed43SDominik Brodowski
1603cdb13808SDominik Brodowski ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
1604e794c01bSDan Carpenter if (ret)
16050e6f9d27SDominik Brodowski goto cs_failed;
16060e6f9d27SDominik Brodowski
1607eb14120fSDominik Brodowski if (pcmcia_request_irq(link, nspintr))
16080e6f9d27SDominik Brodowski goto cs_failed;
16090e6f9d27SDominik Brodowski
16101ac71e5aSDominik Brodowski ret = pcmcia_enable_device(link);
16110e6f9d27SDominik Brodowski if (ret)
16120e6f9d27SDominik Brodowski goto cs_failed;
16131da177e4SLinus Torvalds
16141da177e4SLinus Torvalds if (free_ports) {
16159a017a91SDominik Brodowski if (link->resource[0]) {
16169a017a91SDominik Brodowski release_region(link->resource[0]->start,
16179a017a91SDominik Brodowski resource_size(link->resource[0]));
16181da177e4SLinus Torvalds }
16199a017a91SDominik Brodowski if (link->resource[1]) {
16209a017a91SDominik Brodowski release_region(link->resource[1]->start,
16219a017a91SDominik Brodowski resource_size(link->resource[1]));
16221da177e4SLinus Torvalds }
16231da177e4SLinus Torvalds }
16241da177e4SLinus Torvalds
16251da177e4SLinus Torvalds /* Set port and IRQ */
16269a017a91SDominik Brodowski data->BaseAddress = link->resource[0]->start;
16279a017a91SDominik Brodowski data->NumAddress = resource_size(link->resource[0]);
1628eb14120fSDominik Brodowski data->IrqNumber = link->irq;
16291da177e4SLinus Torvalds
16301da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
16311da177e4SLinus Torvalds data->BaseAddress, data->NumAddress, data->IrqNumber);
16321da177e4SLinus Torvalds
163372961735SBart Van Assche nsphw_init(data);
16341da177e4SLinus Torvalds
16351da177e4SLinus Torvalds host = nsp_detect(&nsp_driver_template);
16361da177e4SLinus Torvalds
16371da177e4SLinus Torvalds if (host == NULL) {
16381da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "detect failed");
16391da177e4SLinus Torvalds goto cs_failed;
16401da177e4SLinus Torvalds }
16411da177e4SLinus Torvalds
16421da177e4SLinus Torvalds
164315b99ac1SDominik Brodowski ret = scsi_add_host (host, NULL);
164415b99ac1SDominik Brodowski if (ret)
164515b99ac1SDominik Brodowski goto cs_failed;
164615b99ac1SDominik Brodowski
16471da177e4SLinus Torvalds scsi_scan_host(host);
16481da177e4SLinus Torvalds
16491da177e4SLinus Torvalds info->host = host;
16501da177e4SLinus Torvalds
165115b99ac1SDominik Brodowski return 0;
16521da177e4SLinus Torvalds
16531da177e4SLinus Torvalds cs_failed:
16541da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "config fail");
16551da177e4SLinus Torvalds nsp_cs_release(link);
16561da177e4SLinus Torvalds
165715b99ac1SDominik Brodowski return -ENODEV;
16581da177e4SLinus Torvalds } /* nsp_cs_config */
16591da177e4SLinus Torvalds
16601da177e4SLinus Torvalds
nsp_cs_release(struct pcmcia_device * link)1661fba395eeSDominik Brodowski static void nsp_cs_release(struct pcmcia_device *link)
16621da177e4SLinus Torvalds {
16631da177e4SLinus Torvalds scsi_info_t *info = link->priv;
16641da177e4SLinus Torvalds nsp_hw_data *data = NULL;
16651da177e4SLinus Torvalds
16661da177e4SLinus Torvalds if (info->host == NULL) {
16671da177e4SLinus Torvalds nsp_msg(KERN_DEBUG, "unexpected card release call.");
16681da177e4SLinus Torvalds } else {
16691da177e4SLinus Torvalds data = (nsp_hw_data *)info->host->hostdata;
16701da177e4SLinus Torvalds }
16711da177e4SLinus Torvalds
16721da177e4SLinus Torvalds nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
16731da177e4SLinus Torvalds
16741da177e4SLinus Torvalds /* Unlink the device chain */
16751da177e4SLinus Torvalds if (info->host != NULL) {
16761da177e4SLinus Torvalds scsi_remove_host(info->host);
16771da177e4SLinus Torvalds }
16781da177e4SLinus Torvalds
1679cdb13808SDominik Brodowski if (resource_size(link->resource[2])) {
16801da177e4SLinus Torvalds if (data != NULL) {
16811da177e4SLinus Torvalds iounmap((void *)(data->MmioAddress));
16821da177e4SLinus Torvalds }
16831da177e4SLinus Torvalds }
1684fba395eeSDominik Brodowski pcmcia_disable_device(link);
16855f2a71fcSDominik Brodowski
16861da177e4SLinus Torvalds if (info->host != NULL) {
16871da177e4SLinus Torvalds scsi_host_put(info->host);
16881da177e4SLinus Torvalds }
16891da177e4SLinus Torvalds } /* nsp_cs_release */
16901da177e4SLinus Torvalds
nsp_cs_suspend(struct pcmcia_device * link)1691fba395eeSDominik Brodowski static int nsp_cs_suspend(struct pcmcia_device *link)
169298e4c28bSDominik Brodowski {
169398e4c28bSDominik Brodowski scsi_info_t *info = link->priv;
169498e4c28bSDominik Brodowski nsp_hw_data *data;
169598e4c28bSDominik Brodowski
169698e4c28bSDominik Brodowski nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
169798e4c28bSDominik Brodowski
169898e4c28bSDominik Brodowski if (info->host != NULL) {
169998e4c28bSDominik Brodowski nsp_msg(KERN_INFO, "clear SDTR status");
170098e4c28bSDominik Brodowski
170198e4c28bSDominik Brodowski data = (nsp_hw_data *)info->host->hostdata;
170298e4c28bSDominik Brodowski
170398e4c28bSDominik Brodowski nsphw_init_sync(data);
170498e4c28bSDominik Brodowski }
170598e4c28bSDominik Brodowski
170698e4c28bSDominik Brodowski info->stop = 1;
170798e4c28bSDominik Brodowski
170898e4c28bSDominik Brodowski return 0;
170998e4c28bSDominik Brodowski }
171098e4c28bSDominik Brodowski
nsp_cs_resume(struct pcmcia_device * link)1711fba395eeSDominik Brodowski static int nsp_cs_resume(struct pcmcia_device *link)
171298e4c28bSDominik Brodowski {
171398e4c28bSDominik Brodowski scsi_info_t *info = link->priv;
171498e4c28bSDominik Brodowski nsp_hw_data *data;
171598e4c28bSDominik Brodowski
171698e4c28bSDominik Brodowski nsp_dbg(NSP_DEBUG_INIT, "event: resume");
171798e4c28bSDominik Brodowski
171898e4c28bSDominik Brodowski info->stop = 0;
171998e4c28bSDominik Brodowski
172098e4c28bSDominik Brodowski if (info->host != NULL) {
172198e4c28bSDominik Brodowski nsp_msg(KERN_INFO, "reset host and bus");
172298e4c28bSDominik Brodowski
172398e4c28bSDominik Brodowski data = (nsp_hw_data *)info->host->hostdata;
172498e4c28bSDominik Brodowski
172598e4c28bSDominik Brodowski nsphw_init (data);
172698e4c28bSDominik Brodowski nsp_bus_reset(data);
172798e4c28bSDominik Brodowski }
172898e4c28bSDominik Brodowski
172998e4c28bSDominik Brodowski return 0;
173098e4c28bSDominik Brodowski }
173198e4c28bSDominik Brodowski
17321da177e4SLinus Torvalds /*======================================================================*
17331da177e4SLinus Torvalds * module entry point
17341da177e4SLinus Torvalds *====================================================================*/
173525f8f54fSJoe Perches static const struct pcmcia_device_id nsp_cs_ids[] = {
1736aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
1737aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
1738aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
1739aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
1740aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
1741aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
1742aba14100SDominik Brodowski PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
1743aba14100SDominik Brodowski PCMCIA_DEVICE_NULL
1744aba14100SDominik Brodowski };
1745aba14100SDominik Brodowski MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
1746aba14100SDominik Brodowski
17471da177e4SLinus Torvalds static struct pcmcia_driver nsp_driver = {
17481da177e4SLinus Torvalds .owner = THIS_MODULE,
17491da177e4SLinus Torvalds .name = "nsp_cs",
175015b99ac1SDominik Brodowski .probe = nsp_cs_probe,
1751cc3b4866SDominik Brodowski .remove = nsp_cs_detach,
1752aba14100SDominik Brodowski .id_table = nsp_cs_ids,
175398e4c28bSDominik Brodowski .suspend = nsp_cs_suspend,
175498e4c28bSDominik Brodowski .resume = nsp_cs_resume,
17551da177e4SLinus Torvalds };
1756dc245cfaSVaishali Thakkar module_pcmcia_driver(nsp_driver);
17571da177e4SLinus Torvalds
17581da177e4SLinus Torvalds /* end */
1759