18c2ecf20Sopenharmony_ci/*====================================================================== 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver 48c2ecf20Sopenharmony_ci By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci Ver.2.8 Support 32bit MMIO mode 78c2ecf20Sopenharmony_ci Support Synchronous Data Transfer Request (SDTR) mode 88c2ecf20Sopenharmony_ci Ver.2.0 Support 32bit PIO mode 98c2ecf20Sopenharmony_ci Ver.1.1.2 Fix for scatter list buffer exceeds 108c2ecf20Sopenharmony_ci Ver.1.1 Support scatter list 118c2ecf20Sopenharmony_ci Ver.0.1 Initial version 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci This software may be used and distributed according to the terms of 148c2ecf20Sopenharmony_ci the GNU General Public License. 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci======================================================================*/ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/*********************************************************************** 198c2ecf20Sopenharmony_ci This driver is for these PCcards. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci I-O DATA PCSC-F (Workbit NinjaSCSI-3) 228c2ecf20Sopenharmony_ci "WBT", "NinjaSCSI-3", "R1.0" 238c2ecf20Sopenharmony_ci I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) 248c2ecf20Sopenharmony_ci "IO DATA", "CBSC16 ", "1" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci***********************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/kernel.h> 308c2ecf20Sopenharmony_ci#include <linux/init.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci#include <linux/string.h> 338c2ecf20Sopenharmony_ci#include <linux/timer.h> 348c2ecf20Sopenharmony_ci#include <linux/ioport.h> 358c2ecf20Sopenharmony_ci#include <linux/delay.h> 368c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 378c2ecf20Sopenharmony_ci#include <linux/major.h> 388c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 398c2ecf20Sopenharmony_ci#include <linux/stat.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <asm/io.h> 428c2ecf20Sopenharmony_ci#include <asm/irq.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <../drivers/scsi/scsi.h> 458c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 488c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h> 518c2ecf20Sopenharmony_ci#include <pcmcia/cisreg.h> 528c2ecf20Sopenharmony_ci#include <pcmcia/ds.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include "nsp_cs.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciMODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>"); 578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); 588c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); 598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include "nsp_io.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/*====================================================================*/ 648c2ecf20Sopenharmony_ci/* Parameters that can be set with 'insmod' */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int nsp_burst_mode = BURST_MEM32; 678c2ecf20Sopenharmony_cimodule_param(nsp_burst_mode, int, 0); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Release IO ports after configuration? */ 718c2ecf20Sopenharmony_cistatic bool free_ports = 0; 728c2ecf20Sopenharmony_cimodule_param(free_ports, bool, 0); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct scsi_host_template nsp_driver_template = { 768c2ecf20Sopenharmony_ci .proc_name = "nsp_cs", 778c2ecf20Sopenharmony_ci .show_info = nsp_show_info, 788c2ecf20Sopenharmony_ci .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", 798c2ecf20Sopenharmony_ci .info = nsp_info, 808c2ecf20Sopenharmony_ci .queuecommand = nsp_queuecommand, 818c2ecf20Sopenharmony_ci/* .eh_abort_handler = nsp_eh_abort,*/ 828c2ecf20Sopenharmony_ci .eh_bus_reset_handler = nsp_eh_bus_reset, 838c2ecf20Sopenharmony_ci .eh_host_reset_handler = nsp_eh_host_reset, 848c2ecf20Sopenharmony_ci .can_queue = 1, 858c2ecf20Sopenharmony_ci .this_id = NSP_INITIATOR_ID, 868c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 878c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic nsp_hw_data nsp_data_base; /* attach <-> detect glue */ 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* 958c2ecf20Sopenharmony_ci * debug, error print 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci#ifndef NSP_DEBUG 988c2ecf20Sopenharmony_ci# define NSP_DEBUG_MASK 0x000000 998c2ecf20Sopenharmony_ci# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args) 1008c2ecf20Sopenharmony_ci# define nsp_dbg(mask, args...) /* */ 1018c2ecf20Sopenharmony_ci#else 1028c2ecf20Sopenharmony_ci# define NSP_DEBUG_MASK 0xffffff 1038c2ecf20Sopenharmony_ci# define nsp_msg(type, args...) \ 1048c2ecf20Sopenharmony_ci nsp_cs_message (__func__, __LINE__, (type), args) 1058c2ecf20Sopenharmony_ci# define nsp_dbg(mask, args...) \ 1068c2ecf20Sopenharmony_ci nsp_cs_dmessage(__func__, __LINE__, (mask), args) 1078c2ecf20Sopenharmony_ci#endif 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define NSP_DEBUG_QUEUECOMMAND BIT(0) 1108c2ecf20Sopenharmony_ci#define NSP_DEBUG_REGISTER BIT(1) 1118c2ecf20Sopenharmony_ci#define NSP_DEBUG_AUTOSCSI BIT(2) 1128c2ecf20Sopenharmony_ci#define NSP_DEBUG_INTR BIT(3) 1138c2ecf20Sopenharmony_ci#define NSP_DEBUG_SGLIST BIT(4) 1148c2ecf20Sopenharmony_ci#define NSP_DEBUG_BUSFREE BIT(5) 1158c2ecf20Sopenharmony_ci#define NSP_DEBUG_CDB_CONTENTS BIT(6) 1168c2ecf20Sopenharmony_ci#define NSP_DEBUG_RESELECTION BIT(7) 1178c2ecf20Sopenharmony_ci#define NSP_DEBUG_MSGINOCCUR BIT(8) 1188c2ecf20Sopenharmony_ci#define NSP_DEBUG_EEPROM BIT(9) 1198c2ecf20Sopenharmony_ci#define NSP_DEBUG_MSGOUTOCCUR BIT(10) 1208c2ecf20Sopenharmony_ci#define NSP_DEBUG_BUSRESET BIT(11) 1218c2ecf20Sopenharmony_ci#define NSP_DEBUG_RESTART BIT(12) 1228c2ecf20Sopenharmony_ci#define NSP_DEBUG_SYNC BIT(13) 1238c2ecf20Sopenharmony_ci#define NSP_DEBUG_WAIT BIT(14) 1248c2ecf20Sopenharmony_ci#define NSP_DEBUG_TARGETFLAG BIT(15) 1258c2ecf20Sopenharmony_ci#define NSP_DEBUG_PROC BIT(16) 1268c2ecf20Sopenharmony_ci#define NSP_DEBUG_INIT BIT(17) 1278c2ecf20Sopenharmony_ci#define NSP_DEBUG_DATA_IO BIT(18) 1288c2ecf20Sopenharmony_ci#define NSP_SPECIAL_PRINT_REGISTER BIT(20) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define NSP_DEBUG_BUF_LEN 150 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci__printf(4, 5) 1388c2ecf20Sopenharmony_cistatic void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci va_list args; 1418c2ecf20Sopenharmony_ci char buf[NSP_DEBUG_BUF_LEN]; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci va_start(args, fmt); 1448c2ecf20Sopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, args); 1458c2ecf20Sopenharmony_ci va_end(args); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#ifndef NSP_DEBUG 1488c2ecf20Sopenharmony_ci printk("%snsp_cs: %s\n", type, buf); 1498c2ecf20Sopenharmony_ci#else 1508c2ecf20Sopenharmony_ci printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf); 1518c2ecf20Sopenharmony_ci#endif 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#ifdef NSP_DEBUG 1558c2ecf20Sopenharmony_cistatic void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci va_list args; 1588c2ecf20Sopenharmony_ci char buf[NSP_DEBUG_BUF_LEN]; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci va_start(args, fmt); 1618c2ecf20Sopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, args); 1628c2ecf20Sopenharmony_ci va_end(args); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (mask & NSP_DEBUG_MASK) { 1658c2ecf20Sopenharmony_ci printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci#endif 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/***********************************************************/ 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/*==================================================== 1738c2ecf20Sopenharmony_ci * Clenaup parameters and call done() functions. 1748c2ecf20Sopenharmony_ci * You must be set SCpnt->result before call this function. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_cistatic void nsp_scsi_done(struct scsi_cmnd *SCpnt) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci data->CurrentSC = NULL; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci SCpnt->scsi_done(SCpnt); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt, 1868c2ecf20Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci#ifdef NSP_DEBUG 1898c2ecf20Sopenharmony_ci /*unsigned int host_id = SCpnt->device->host->this_id;*/ 1908c2ecf20Sopenharmony_ci /*unsigned int base = SCpnt->device->host->io_port;*/ 1918c2ecf20Sopenharmony_ci unsigned char target = scmd_id(SCpnt); 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_QUEUECOMMAND, 1968c2ecf20Sopenharmony_ci "SCpnt=0x%p target=%d lun=%llu sglist=0x%p bufflen=%d sg_count=%d", 1978c2ecf20Sopenharmony_ci SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt), 1988c2ecf20Sopenharmony_ci scsi_bufflen(SCpnt), scsi_sg_count(SCpnt)); 1998c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci SCpnt->scsi_done = done; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (data->CurrentSC != NULL) { 2048c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen"); 2058c2ecf20Sopenharmony_ci SCpnt->result = DID_BAD_TARGET << 16; 2068c2ecf20Sopenharmony_ci nsp_scsi_done(SCpnt); 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#if 0 2118c2ecf20Sopenharmony_ci /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility. 2128c2ecf20Sopenharmony_ci This makes kernel crash when suspending... */ 2138c2ecf20Sopenharmony_ci if (data->ScsiInfo->stop != 0) { 2148c2ecf20Sopenharmony_ci nsp_msg(KERN_INFO, "suspending device. reject command."); 2158c2ecf20Sopenharmony_ci SCpnt->result = DID_BAD_TARGET << 16; 2168c2ecf20Sopenharmony_ci nsp_scsi_done(SCpnt); 2178c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci#endif 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci show_command(SCpnt); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci data->CurrentSC = SCpnt; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci SCpnt->SCp.Status = CHECK_CONDITION; 2268c2ecf20Sopenharmony_ci SCpnt->SCp.Message = 0; 2278c2ecf20Sopenharmony_ci SCpnt->SCp.have_data_in = IO_UNKNOWN; 2288c2ecf20Sopenharmony_ci SCpnt->SCp.sent_command = 0; 2298c2ecf20Sopenharmony_ci SCpnt->SCp.phase = PH_UNDETERMINED; 2308c2ecf20Sopenharmony_ci scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* setup scratch area 2338c2ecf20Sopenharmony_ci SCp.ptr : buffer pointer 2348c2ecf20Sopenharmony_ci SCp.this_residual : buffer length 2358c2ecf20Sopenharmony_ci SCp.buffer : next buffer 2368c2ecf20Sopenharmony_ci SCp.buffers_residual : left buffers in list 2378c2ecf20Sopenharmony_ci SCp.phase : current state of the command */ 2388c2ecf20Sopenharmony_ci if (scsi_bufflen(SCpnt)) { 2398c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = scsi_sglist(SCpnt); 2408c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = BUFFER_ADDR; 2418c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 2428c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; 2438c2ecf20Sopenharmony_ci } else { 2448c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = NULL; 2458c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = 0; 2468c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = NULL; 2478c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual = 0; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (nsphw_start_selection(SCpnt) == FALSE) { 2518c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail"); 2528c2ecf20Sopenharmony_ci SCpnt->result = DID_BUS_BUSY << 16; 2538c2ecf20Sopenharmony_ci nsp_scsi_done(SCpnt); 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out"); 2598c2ecf20Sopenharmony_ci#ifdef NSP_DEBUG 2608c2ecf20Sopenharmony_ci data->CmdId++; 2618c2ecf20Sopenharmony_ci#endif 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(nsp_queuecommand) 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * setup PIO FIFO transfer mode and enable/disable to data out 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistatic void nsp_setup_fifo(nsp_hw_data *data, int enabled) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci unsigned int base = data->BaseAddress; 2738c2ecf20Sopenharmony_ci unsigned char transfer_mode_reg; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (enabled != FALSE) { 2788c2ecf20Sopenharmony_ci transfer_mode_reg = TRANSFER_GO | BRAIND; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci transfer_mode_reg = 0; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci transfer_mode_reg |= data->TransferMode; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void nsphw_init_sync(nsp_hw_data *data) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET, 2918c2ecf20Sopenharmony_ci .SyncPeriod = 0, 2928c2ecf20Sopenharmony_ci .SyncOffset = 0 2938c2ecf20Sopenharmony_ci }; 2948c2ecf20Sopenharmony_ci int i; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* setup sync data */ 2978c2ecf20Sopenharmony_ci for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) { 2988c2ecf20Sopenharmony_ci data->Sync[i] = tmp_sync; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci/* 3038c2ecf20Sopenharmony_ci * Initialize Ninja hardware 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_cistatic int nsphw_init(nsp_hw_data *data) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci unsigned int base = data->BaseAddress; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci data->ScsiClockDiv = CLOCK_40M | FAST_20; 3128c2ecf20Sopenharmony_ci data->CurrentSC = NULL; 3138c2ecf20Sopenharmony_ci data->FifoCount = 0; 3148c2ecf20Sopenharmony_ci data->TransferMode = MODE_IO8; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci nsphw_init_sync(data); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* block all interrupts */ 3198c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* setup SCSI interface */ 3228c2ecf20Sopenharmony_ci nsp_write(base, IFSELECT, IF_IFSEL); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIIRQMODE, 0); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci nsp_index_write(base, TRANSFERMODE, MODE_IO8); 3278c2ecf20Sopenharmony_ci nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci nsp_index_write(base, PARITYCTRL, 0); 3308c2ecf20Sopenharmony_ci nsp_index_write(base, POINTERCLR, POINTER_CLEAR | 3318c2ecf20Sopenharmony_ci ACK_COUNTER_CLEAR | 3328c2ecf20Sopenharmony_ci REQ_COUNTER_CLEAR | 3338c2ecf20Sopenharmony_ci HOST_COUNTER_CLEAR); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* setup fifo asic */ 3368c2ecf20Sopenharmony_ci nsp_write(base, IFSELECT, IF_REGSEL); 3378c2ecf20Sopenharmony_ci nsp_index_write(base, TERMPWRCTRL, 0); 3388c2ecf20Sopenharmony_ci if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { 3398c2ecf20Sopenharmony_ci nsp_msg(KERN_INFO, "terminator power on"); 3408c2ecf20Sopenharmony_ci nsp_index_write(base, TERMPWRCTRL, POWER_ON); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci nsp_index_write(base, TIMERCOUNT, 0); 3448c2ecf20Sopenharmony_ci nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci nsp_index_write(base, SYNCREG, 0); 3478c2ecf20Sopenharmony_ci nsp_index_write(base, ACKWIDTH, 0); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* enable interrupts and ack them */ 3508c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | 3518c2ecf20Sopenharmony_ci RESELECT_EI | 3528c2ecf20Sopenharmony_ci SCSI_RESET_IRQ_EI ); 3538c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci nsp_setup_fifo(data, FALSE); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return TRUE; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* 3618c2ecf20Sopenharmony_ci * Start selection phase 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_cistatic int nsphw_start_selection(struct scsi_cmnd *SCpnt) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci unsigned int host_id = SCpnt->device->host->this_id; 3668c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 3678c2ecf20Sopenharmony_ci unsigned char target = scmd_id(SCpnt); 3688c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 3698c2ecf20Sopenharmony_ci int time_out; 3708c2ecf20Sopenharmony_ci unsigned char phase, arbit; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "in"); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci phase = nsp_index_read(base, SCSIBUSMON); 3758c2ecf20Sopenharmony_ci if(phase != BUSMON_BUS_FREE) { 3768c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy"); 3778c2ecf20Sopenharmony_ci return FALSE; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* start arbitration */ 3818c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit"); 3828c2ecf20Sopenharmony_ci SCpnt->SCp.phase = PH_ARBSTART; 3838c2ecf20Sopenharmony_ci nsp_index_write(base, SETARBIT, ARBIT_GO); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci time_out = 1000; 3868c2ecf20Sopenharmony_ci do { 3878c2ecf20Sopenharmony_ci /* XXX: what a stupid chip! */ 3888c2ecf20Sopenharmony_ci arbit = nsp_index_read(base, ARBITSTATUS); 3898c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count); 3908c2ecf20Sopenharmony_ci udelay(1); /* hold 1.2us */ 3918c2ecf20Sopenharmony_ci } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && 3928c2ecf20Sopenharmony_ci (time_out-- != 0)); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!(arbit & ARBIT_WIN)) { 3958c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail"); 3968c2ecf20Sopenharmony_ci nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); 3978c2ecf20Sopenharmony_ci return FALSE; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* assert select line */ 4018c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line"); 4028c2ecf20Sopenharmony_ci SCpnt->SCp.phase = PH_SELSTART; 4038c2ecf20Sopenharmony_ci udelay(3); /* wait 2.4us */ 4048c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target)); 4058c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); 4068c2ecf20Sopenharmony_ci udelay(2); /* wait >1.2us */ 4078c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); 4088c2ecf20Sopenharmony_ci nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); 4098c2ecf20Sopenharmony_ci /*udelay(1);*/ /* wait >90ns */ 4108c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* check selection timeout */ 4138c2ecf20Sopenharmony_ci nsp_start_timer(SCpnt, 1000/51); 4148c2ecf20Sopenharmony_ci data->SelectionTimeOut = 1; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return TRUE; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistruct nsp_sync_table { 4208c2ecf20Sopenharmony_ci unsigned int min_period; 4218c2ecf20Sopenharmony_ci unsigned int max_period; 4228c2ecf20Sopenharmony_ci unsigned int chip_period; 4238c2ecf20Sopenharmony_ci unsigned int ack_width; 4248c2ecf20Sopenharmony_ci}; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic struct nsp_sync_table nsp_sync_table_40M[] = { 4278c2ecf20Sopenharmony_ci {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/ 4288c2ecf20Sopenharmony_ci {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/ 4298c2ecf20Sopenharmony_ci {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/ 4308c2ecf20Sopenharmony_ci {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/ 4318c2ecf20Sopenharmony_ci { 0, 0, 0, 0}, 4328c2ecf20Sopenharmony_ci}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic struct nsp_sync_table nsp_sync_table_20M[] = { 4358c2ecf20Sopenharmony_ci {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/ 4368c2ecf20Sopenharmony_ci {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/ 4378c2ecf20Sopenharmony_ci {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/ 4388c2ecf20Sopenharmony_ci { 0, 0, 0, 0}, 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci/* 4428c2ecf20Sopenharmony_ci * setup synchronous data transfer mode 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_cistatic int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci unsigned char target = scmd_id(SCpnt); 4478c2ecf20Sopenharmony_ci// unsigned char lun = SCpnt->device->lun; 4488c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 4498c2ecf20Sopenharmony_ci sync_data *sync = &(data->Sync[target]); 4508c2ecf20Sopenharmony_ci struct nsp_sync_table *sync_table; 4518c2ecf20Sopenharmony_ci unsigned int period, offset; 4528c2ecf20Sopenharmony_ci int i; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_SYNC, "in"); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci period = sync->SyncPeriod; 4588c2ecf20Sopenharmony_ci offset = sync->SyncOffset; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) { 4638c2ecf20Sopenharmony_ci sync_table = nsp_sync_table_20M; 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci sync_table = nsp_sync_table_40M; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { 4698c2ecf20Sopenharmony_ci if ( period >= sync_table->min_period && 4708c2ecf20Sopenharmony_ci period <= sync_table->max_period ) { 4718c2ecf20Sopenharmony_ci break; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (period != 0 && sync_table->max_period == 0) { 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * No proper period/offset found 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset"); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci sync->SyncPeriod = 0; 4828c2ecf20Sopenharmony_ci sync->SyncOffset = 0; 4838c2ecf20Sopenharmony_ci sync->SyncRegister = 0; 4848c2ecf20Sopenharmony_ci sync->AckWidth = 0; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return FALSE; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | 4908c2ecf20Sopenharmony_ci (offset & SYNCREG_OFFSET_MASK); 4918c2ecf20Sopenharmony_ci sync->AckWidth = sync_table->ack_width; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return TRUE; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/* 5008c2ecf20Sopenharmony_ci * start ninja hardware timer 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_cistatic void nsp_start_timer(struct scsi_cmnd *SCpnt, int time) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 5058c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time); 5088c2ecf20Sopenharmony_ci data->TimerCount = time; 5098c2ecf20Sopenharmony_ci nsp_index_write(base, TIMERCOUNT, time); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* 5138c2ecf20Sopenharmony_ci * wait for bus phase change 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistatic int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask, 5168c2ecf20Sopenharmony_ci char *str) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 5198c2ecf20Sopenharmony_ci unsigned char reg; 5208c2ecf20Sopenharmony_ci int time_out; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "in"); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci time_out = 100; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci do { 5278c2ecf20Sopenharmony_ci reg = nsp_index_read(base, SCSIBUSMON); 5288c2ecf20Sopenharmony_ci if (reg == 0xff) { 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci } while ((--time_out != 0) && (reg & mask) != 0); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (time_out == 0) { 5348c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, " %s signal off timeout", str); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* 5418c2ecf20Sopenharmony_ci * expect Ninja Irq 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cistatic int nsp_expect_signal(struct scsi_cmnd *SCpnt, 5448c2ecf20Sopenharmony_ci unsigned char current_phase, 5458c2ecf20Sopenharmony_ci unsigned char mask) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 5488c2ecf20Sopenharmony_ci int time_out; 5498c2ecf20Sopenharmony_ci unsigned char phase, i_src; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci time_out = 100; 5548c2ecf20Sopenharmony_ci do { 5558c2ecf20Sopenharmony_ci phase = nsp_index_read(base, SCSIBUSMON); 5568c2ecf20Sopenharmony_ci if (phase == 0xff) { 5578c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "ret -1"); 5588c2ecf20Sopenharmony_ci return -1; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci i_src = nsp_read(base, IRQSTATUS); 5618c2ecf20Sopenharmony_ci if (i_src & IRQSTATUS_SCSI) { 5628c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal"); 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { 5668c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase); 5678c2ecf20Sopenharmony_ci return 1; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } while(time_out-- != 0); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "timeout"); 5728c2ecf20Sopenharmony_ci return -1; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci/* 5768c2ecf20Sopenharmony_ci * transfer SCSI message 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic int nsp_xfer(struct scsi_cmnd *SCpnt, int phase) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 5818c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 5828c2ecf20Sopenharmony_ci char *buf = data->MsgBuffer; 5838c2ecf20Sopenharmony_ci int len = min(MSGBUF_SIZE, data->MsgLen); 5848c2ecf20Sopenharmony_ci int ptr; 5858c2ecf20Sopenharmony_ci int ret; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); 5888c2ecf20Sopenharmony_ci for (ptr = 0; len > 0; len--, ptr++) { 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); 5918c2ecf20Sopenharmony_ci if (ret <= 0) { 5928c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit"); 5938c2ecf20Sopenharmony_ci return 0; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* if last byte, negate ATN */ 5978c2ecf20Sopenharmony_ci if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { 5988c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* read & write message */ 6028c2ecf20Sopenharmony_ci if (phase & BUSMON_IO) { 6038c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "read msg"); 6048c2ecf20Sopenharmony_ci buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "write msg"); 6078c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>"); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci return len; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci/* 6168c2ecf20Sopenharmony_ci * get extra SCSI data from fifo 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_cistatic int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 6218c2ecf20Sopenharmony_ci unsigned int count; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (SCpnt->SCp.have_data_in != IO_IN) { 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci count = nsp_fifo_count(SCpnt); 6308c2ecf20Sopenharmony_ci if (data->FifoCount == count) { 6318c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk"); 6328c2ecf20Sopenharmony_ci return 0; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* 6368c2ecf20Sopenharmony_ci * XXX: NSP_QUIRK 6378c2ecf20Sopenharmony_ci * data phase skip only occures in case of SCSI_LOW_READ 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk"); 6408c2ecf20Sopenharmony_ci SCpnt->SCp.phase = PH_DATA; 6418c2ecf20Sopenharmony_ci nsp_pio_read(SCpnt); 6428c2ecf20Sopenharmony_ci nsp_setup_fifo(data, FALSE); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* 6488c2ecf20Sopenharmony_ci * accept reselection 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_cistatic int nsp_reselected(struct scsi_cmnd *SCpnt) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 6538c2ecf20Sopenharmony_ci unsigned int host_id = SCpnt->device->host->this_id; 6548c2ecf20Sopenharmony_ci //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 6558c2ecf20Sopenharmony_ci unsigned char bus_reg; 6568c2ecf20Sopenharmony_ci unsigned char id_reg, tmp; 6578c2ecf20Sopenharmony_ci int target; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_RESELECTION, "in"); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci id_reg = nsp_index_read(base, RESELECTID); 6628c2ecf20Sopenharmony_ci tmp = id_reg & (~BIT(host_id)); 6638c2ecf20Sopenharmony_ci target = 0; 6648c2ecf20Sopenharmony_ci while(tmp != 0) { 6658c2ecf20Sopenharmony_ci if (tmp & BIT(0)) { 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci tmp >>= 1; 6698c2ecf20Sopenharmony_ci target++; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (scmd_id(SCpnt) != target) { 6738c2ecf20Sopenharmony_ci nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci nsp_nexus(SCpnt); 6798c2ecf20Sopenharmony_ci bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); 6808c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, bus_reg); 6818c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return TRUE; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/* 6878c2ecf20Sopenharmony_ci * count how many data transferd 6888c2ecf20Sopenharmony_ci */ 6898c2ecf20Sopenharmony_cistatic int nsp_fifo_count(struct scsi_cmnd *SCpnt) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 6928c2ecf20Sopenharmony_ci unsigned int count; 6938c2ecf20Sopenharmony_ci unsigned int l, m, h; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci l = nsp_index_read(base, TRANSFERCOUNT); 6988c2ecf20Sopenharmony_ci m = nsp_index_read(base, TRANSFERCOUNT); 6998c2ecf20Sopenharmony_ci h = nsp_index_read(base, TRANSFERCOUNT); 7008c2ecf20Sopenharmony_ci nsp_index_read(base, TRANSFERCOUNT); /* required this! */ 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci count = (h << 16) | (m << 8) | (l << 0); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return count; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci/* fifo size */ 7108c2ecf20Sopenharmony_ci#define RFIFO_CRIT 64 7118c2ecf20Sopenharmony_ci#define WFIFO_CRIT 64 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci/* 7148c2ecf20Sopenharmony_ci * read data in DATA IN phase 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_cistatic void nsp_pio_read(struct scsi_cmnd *SCpnt) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 7198c2ecf20Sopenharmony_ci unsigned long mmio_base = SCpnt->device->host->base; 7208c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 7218c2ecf20Sopenharmony_ci long time_out; 7228c2ecf20Sopenharmony_ci int ocount, res; 7238c2ecf20Sopenharmony_ci unsigned char stat, fifo_stat; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ocount = data->FifoCount; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci 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", 7288c2ecf20Sopenharmony_ci SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr, 7298c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual, SCpnt->SCp.buffer, 7308c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci time_out = 1000; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci while ((time_out-- != 0) && 7358c2ecf20Sopenharmony_ci (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci stat = nsp_index_read(base, SCSIBUSMON); 7388c2ecf20Sopenharmony_ci stat &= BUSMON_PHASE_MASK; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci res = nsp_fifo_count(SCpnt) - ocount; 7428c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); 7438c2ecf20Sopenharmony_ci if (res == 0) { /* if some data available ? */ 7448c2ecf20Sopenharmony_ci if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ 7458c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual); 7468c2ecf20Sopenharmony_ci continue; 7478c2ecf20Sopenharmony_ci } else { 7488c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat); 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci fifo_stat = nsp_read(base, FIFOSTATUS); 7548c2ecf20Sopenharmony_ci if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && 7558c2ecf20Sopenharmony_ci stat == BUSPHASE_DATA_IN) { 7568c2ecf20Sopenharmony_ci continue; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci res = min(res, SCpnt->SCp.this_residual); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci switch (data->TransferMode) { 7628c2ecf20Sopenharmony_ci case MODE_IO32: 7638c2ecf20Sopenharmony_ci res &= ~(BIT(1)|BIT(0)); /* align 4 */ 7648c2ecf20Sopenharmony_ci nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci case MODE_IO8: 7678c2ecf20Sopenharmony_ci nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci case MODE_MEM32: 7718c2ecf20Sopenharmony_ci res &= ~(BIT(1)|BIT(0)); /* align 4 */ 7728c2ecf20Sopenharmony_ci nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode"); 7778c2ecf20Sopenharmony_ci return; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci nsp_inc_resid(SCpnt, -res); 7818c2ecf20Sopenharmony_ci SCpnt->SCp.ptr += res; 7828c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual -= res; 7838c2ecf20Sopenharmony_ci ocount += res; 7848c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* go to next scatter list if available */ 7878c2ecf20Sopenharmony_ci if (SCpnt->SCp.this_residual == 0 && 7888c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual != 0 ) { 7898c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); 7908c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual--; 7918c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); 7928c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = BUFFER_ADDR; 7938c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 7948c2ecf20Sopenharmony_ci time_out = 1000; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci data->FifoCount = ocount; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (time_out < 0) { 8038c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", 8048c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt), SCpnt->SCp.this_residual, 8058c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual); 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); 8088c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, 8098c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt)); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/* 8138c2ecf20Sopenharmony_ci * write data in DATA OUT phase 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_cistatic void nsp_pio_write(struct scsi_cmnd *SCpnt) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 8188c2ecf20Sopenharmony_ci unsigned long mmio_base = SCpnt->device->host->base; 8198c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 8208c2ecf20Sopenharmony_ci int time_out; 8218c2ecf20Sopenharmony_ci int ocount, res; 8228c2ecf20Sopenharmony_ci unsigned char stat; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci ocount = data->FifoCount; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", 8278c2ecf20Sopenharmony_ci data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, 8288c2ecf20Sopenharmony_ci SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, 8298c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt)); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci time_out = 1000; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci while ((time_out-- != 0) && 8348c2ecf20Sopenharmony_ci (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { 8358c2ecf20Sopenharmony_ci stat = nsp_index_read(base, SCSIBUSMON); 8368c2ecf20Sopenharmony_ci stat &= BUSMON_PHASE_MASK; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (stat != BUSPHASE_DATA_OUT) { 8398c2ecf20Sopenharmony_ci res = ocount - nsp_fifo_count(SCpnt); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); 8428c2ecf20Sopenharmony_ci /* Put back pointer */ 8438c2ecf20Sopenharmony_ci nsp_inc_resid(SCpnt, res); 8448c2ecf20Sopenharmony_ci SCpnt->SCp.ptr -= res; 8458c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual += res; 8468c2ecf20Sopenharmony_ci ocount -= res; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci res = ocount - nsp_fifo_count(SCpnt); 8528c2ecf20Sopenharmony_ci if (res > 0) { /* write all data? */ 8538c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res); 8548c2ecf20Sopenharmony_ci continue; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci res = min(SCpnt->SCp.this_residual, WFIFO_CRIT); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); 8608c2ecf20Sopenharmony_ci switch (data->TransferMode) { 8618c2ecf20Sopenharmony_ci case MODE_IO32: 8628c2ecf20Sopenharmony_ci res &= ~(BIT(1)|BIT(0)); /* align 4 */ 8638c2ecf20Sopenharmony_ci nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci case MODE_IO8: 8668c2ecf20Sopenharmony_ci nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci case MODE_MEM32: 8708c2ecf20Sopenharmony_ci res &= ~(BIT(1)|BIT(0)); /* align 4 */ 8718c2ecf20Sopenharmony_ci nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci default: 8758c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode"); 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci nsp_inc_resid(SCpnt, -res); 8808c2ecf20Sopenharmony_ci SCpnt->SCp.ptr += res; 8818c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual -= res; 8828c2ecf20Sopenharmony_ci ocount += res; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* go to next scatter list if available */ 8858c2ecf20Sopenharmony_ci if (SCpnt->SCp.this_residual == 0 && 8868c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual != 0 ) { 8878c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); 8888c2ecf20Sopenharmony_ci SCpnt->SCp.buffers_residual--; 8898c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); 8908c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = BUFFER_ADDR; 8918c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 8928c2ecf20Sopenharmony_ci time_out = 1000; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci data->FifoCount = ocount; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (time_out < 0) { 8998c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", 9008c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt)); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); 9038c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, 9048c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt)); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci#undef RFIFO_CRIT 9078c2ecf20Sopenharmony_ci#undef WFIFO_CRIT 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* 9108c2ecf20Sopenharmony_ci * setup synchronous/asynchronous data transfer mode 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_cistatic int nsp_nexus(struct scsi_cmnd *SCpnt) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci unsigned int base = SCpnt->device->host->io_port; 9158c2ecf20Sopenharmony_ci unsigned char target = scmd_id(SCpnt); 9168c2ecf20Sopenharmony_ci// unsigned char lun = SCpnt->device->lun; 9178c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 9188c2ecf20Sopenharmony_ci sync_data *sync = &(data->Sync[target]); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* setup synch transfer registers */ 9238c2ecf20Sopenharmony_ci nsp_index_write(base, SYNCREG, sync->SyncRegister); 9248c2ecf20Sopenharmony_ci nsp_index_write(base, ACKWIDTH, sync->AckWidth); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (scsi_get_resid(SCpnt) % 4 != 0 || 9278c2ecf20Sopenharmony_ci scsi_get_resid(SCpnt) <= PAGE_SIZE ) { 9288c2ecf20Sopenharmony_ci data->TransferMode = MODE_IO8; 9298c2ecf20Sopenharmony_ci } else if (nsp_burst_mode == BURST_MEM32) { 9308c2ecf20Sopenharmony_ci data->TransferMode = MODE_MEM32; 9318c2ecf20Sopenharmony_ci } else if (nsp_burst_mode == BURST_IO32) { 9328c2ecf20Sopenharmony_ci data->TransferMode = MODE_IO32; 9338c2ecf20Sopenharmony_ci } else { 9348c2ecf20Sopenharmony_ci data->TransferMode = MODE_IO8; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* setup pdma fifo */ 9388c2ecf20Sopenharmony_ci nsp_setup_fifo(data, TRUE); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* clear ack counter */ 9418c2ecf20Sopenharmony_ci data->FifoCount = 0; 9428c2ecf20Sopenharmony_ci nsp_index_write(base, POINTERCLR, POINTER_CLEAR | 9438c2ecf20Sopenharmony_ci ACK_COUNTER_CLEAR | 9448c2ecf20Sopenharmony_ci REQ_COUNTER_CLEAR | 9458c2ecf20Sopenharmony_ci HOST_COUNTER_CLEAR); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci#include "nsp_message.c" 9518c2ecf20Sopenharmony_ci/* 9528c2ecf20Sopenharmony_ci * interrupt handler 9538c2ecf20Sopenharmony_ci */ 9548c2ecf20Sopenharmony_cistatic irqreturn_t nspintr(int irq, void *dev_id) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci unsigned int base; 9578c2ecf20Sopenharmony_ci unsigned char irq_status, irq_phase, phase; 9588c2ecf20Sopenharmony_ci struct scsi_cmnd *tmpSC; 9598c2ecf20Sopenharmony_ci unsigned char target, lun; 9608c2ecf20Sopenharmony_ci unsigned int *sync_neg; 9618c2ecf20Sopenharmony_ci int i, tmp; 9628c2ecf20Sopenharmony_ci nsp_hw_data *data; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id); 9668c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if ( dev_id != NULL && 9698c2ecf20Sopenharmony_ci ((scsi_info_t *)dev_id)->host != NULL ) { 9708c2ecf20Sopenharmony_ci scsi_info_t *info = (scsi_info_t *)dev_id; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci data = (nsp_hw_data *)info->host->hostdata; 9738c2ecf20Sopenharmony_ci } else { 9748c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "host data wrong"); 9758c2ecf20Sopenharmony_ci return IRQ_NONE; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci base = data->BaseAddress; 9818c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* 9848c2ecf20Sopenharmony_ci * interrupt check 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); 9878c2ecf20Sopenharmony_ci irq_status = nsp_read(base, IRQSTATUS); 9888c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status); 9898c2ecf20Sopenharmony_ci if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) { 9908c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, 0); 9918c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq"); 9928c2ecf20Sopenharmony_ci return IRQ_NONE; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* XXX: IMPORTANT 9968c2ecf20Sopenharmony_ci * Do not read an irq_phase register if no scsi phase interrupt. 9978c2ecf20Sopenharmony_ci * Unless, you should lose a scsi phase interrupt. 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci phase = nsp_index_read(base, SCSIBUSMON); 10008c2ecf20Sopenharmony_ci if((irq_status & IRQSTATUS_SCSI) != 0) { 10018c2ecf20Sopenharmony_ci irq_phase = nsp_index_read(base, IRQPHASESENCE); 10028c2ecf20Sopenharmony_ci } else { 10038c2ecf20Sopenharmony_ci irq_phase = 0; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* 10098c2ecf20Sopenharmony_ci * timer interrupt handler (scsi vs timer interrupts) 10108c2ecf20Sopenharmony_ci */ 10118c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount); 10128c2ecf20Sopenharmony_ci if (data->TimerCount != 0) { 10138c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "stop timer"); 10148c2ecf20Sopenharmony_ci nsp_index_write(base, TIMERCOUNT, 0); 10158c2ecf20Sopenharmony_ci nsp_index_write(base, TIMERCOUNT, 0); 10168c2ecf20Sopenharmony_ci data->TimerCount = 0; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER && 10208c2ecf20Sopenharmony_ci data->SelectionTimeOut == 0) { 10218c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "timer start"); 10228c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); 10238c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if ((irq_status & IRQSTATUS_SCSI) && 10298c2ecf20Sopenharmony_ci (irq_phase & SCSI_RESET_IRQ)) { 10308c2ecf20Sopenharmony_ci nsp_msg(KERN_ERR, "bus reset (power off?)"); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci nsphw_init(data); 10338c2ecf20Sopenharmony_ci nsp_bus_reset(data); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if(data->CurrentSC != NULL) { 10368c2ecf20Sopenharmony_ci tmpSC = data->CurrentSC; 10378c2ecf20Sopenharmony_ci tmpSC->result = (DID_RESET << 16) | 10388c2ecf20Sopenharmony_ci ((tmpSC->SCp.Message & 0xff) << 8) | 10398c2ecf20Sopenharmony_ci ((tmpSC->SCp.Status & 0xff) << 0); 10408c2ecf20Sopenharmony_ci nsp_scsi_done(tmpSC); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (data->CurrentSC == NULL) { 10468c2ecf20Sopenharmony_ci 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); 10478c2ecf20Sopenharmony_ci nsphw_init(data); 10488c2ecf20Sopenharmony_ci nsp_bus_reset(data); 10498c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci tmpSC = data->CurrentSC; 10538c2ecf20Sopenharmony_ci target = tmpSC->device->id; 10548c2ecf20Sopenharmony_ci lun = tmpSC->device->lun; 10558c2ecf20Sopenharmony_ci sync_neg = &(data->Sync[target].SyncNegotiation); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* 10588c2ecf20Sopenharmony_ci * parse hardware SCSI irq reasons register 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_ci if (irq_status & IRQSTATUS_SCSI) { 10618c2ecf20Sopenharmony_ci if (irq_phase & RESELECT_IRQ) { 10628c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "reselect"); 10638c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); 10648c2ecf20Sopenharmony_ci if (nsp_reselected(tmpSC) != FALSE) { 10658c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { 10708c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci //show_phase(tmpSC); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci switch(tmpSC->SCp.phase) { 10778c2ecf20Sopenharmony_ci case PH_SELSTART: 10788c2ecf20Sopenharmony_ci // *sync_neg = SYNC_NOT_YET; 10798c2ecf20Sopenharmony_ci if ((phase & BUSMON_BSY) == 0) { 10808c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut); 10818c2ecf20Sopenharmony_ci if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { 10828c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "selection time out"); 10838c2ecf20Sopenharmony_ci data->SelectionTimeOut = 0; 10848c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, 0); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci tmpSC->result = DID_TIME_OUT << 16; 10878c2ecf20Sopenharmony_ci nsp_scsi_done(tmpSC); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci data->SelectionTimeOut += 1; 10928c2ecf20Sopenharmony_ci nsp_start_timer(tmpSC, 1000/51); 10938c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* attention assert */ 10978c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "attention assert"); 10988c2ecf20Sopenharmony_ci data->SelectionTimeOut = 0; 10998c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_SELECTED; 11008c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); 11018c2ecf20Sopenharmony_ci udelay(1); 11028c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); 11038c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci case PH_RESELECT: 11088c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "phase reselect"); 11098c2ecf20Sopenharmony_ci // *sync_neg = SYNC_NOT_YET; 11108c2ecf20Sopenharmony_ci if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci tmpSC->result = DID_ABORT << 16; 11138c2ecf20Sopenharmony_ci nsp_scsi_done(tmpSC); 11148c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci fallthrough; 11178c2ecf20Sopenharmony_ci default: 11188c2ecf20Sopenharmony_ci if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { 11198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci break; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* 11258c2ecf20Sopenharmony_ci * SCSI sequencer 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq"); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* normal disconnect */ 11308c2ecf20Sopenharmony_ci if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && 11318c2ecf20Sopenharmony_ci (irq_phase & LATCHED_BUS_FREE) != 0 ) { 11328c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci //*sync_neg = SYNC_NOT_YET; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* all command complete and return status */ 11378c2ecf20Sopenharmony_ci if (tmpSC->SCp.Message == MSG_COMMAND_COMPLETE) { 11388c2ecf20Sopenharmony_ci tmpSC->result = (DID_OK << 16) | 11398c2ecf20Sopenharmony_ci ((tmpSC->SCp.Message & 0xff) << 8) | 11408c2ecf20Sopenharmony_ci ((tmpSC->SCp.Status & 0xff) << 0); 11418c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result); 11428c2ecf20Sopenharmony_ci nsp_scsi_done(tmpSC); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* check unexpected bus free state */ 11528c2ecf20Sopenharmony_ci if (phase == 0) { 11538c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci *sync_neg = SYNC_NG; 11568c2ecf20Sopenharmony_ci tmpSC->result = DID_ERROR << 16; 11578c2ecf20Sopenharmony_ci nsp_scsi_done(tmpSC); 11588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci switch (phase & BUSMON_PHASE_MASK) { 11628c2ecf20Sopenharmony_ci case BUSPHASE_COMMAND: 11638c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND"); 11648c2ecf20Sopenharmony_ci if ((phase & BUSMON_REQ) == 0) { 11658c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "REQ == 0"); 11668c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_COMMAND; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci nsp_nexus(tmpSC); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* write scsi command */ 11748c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len); 11758c2ecf20Sopenharmony_ci nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); 11768c2ecf20Sopenharmony_ci for (i = 0; i < tmpSC->cmd_len; i++) { 11778c2ecf20Sopenharmony_ci nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci case BUSPHASE_DATA_OUT: 11838c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT"); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_DATA; 11868c2ecf20Sopenharmony_ci tmpSC->SCp.have_data_in = IO_OUT; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci nsp_pio_write(tmpSC); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci break; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci case BUSPHASE_DATA_IN: 11938c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN"); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_DATA; 11968c2ecf20Sopenharmony_ci tmpSC->SCp.have_data_in = IO_IN; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci nsp_pio_read(tmpSC); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci break; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci case BUSPHASE_STATUS: 12038c2ecf20Sopenharmony_ci nsp_dataphase_bypass(tmpSC); 12048c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS"); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_STATUS; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); 12098c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci break; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci case BUSPHASE_MESSAGE_OUT: 12148c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT"); 12158c2ecf20Sopenharmony_ci if ((phase & BUSMON_REQ) == 0) { 12168c2ecf20Sopenharmony_ci goto timer_out; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_MSG_OUT; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci //*sync_neg = SYNC_NOT_YET; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci data->MsgLen = i = 0; 12248c2ecf20Sopenharmony_ci data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (*sync_neg == SYNC_NOT_YET) { 12278c2ecf20Sopenharmony_ci data->Sync[target].SyncPeriod = 0; 12288c2ecf20Sopenharmony_ci data->Sync[target].SyncOffset = 0; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /**/ 12318c2ecf20Sopenharmony_ci data->MsgBuffer[i] = MSG_EXTENDED; i++; 12328c2ecf20Sopenharmony_ci data->MsgBuffer[i] = 3; i++; 12338c2ecf20Sopenharmony_ci data->MsgBuffer[i] = MSG_EXT_SDTR; i++; 12348c2ecf20Sopenharmony_ci data->MsgBuffer[i] = 0x0c; i++; 12358c2ecf20Sopenharmony_ci data->MsgBuffer[i] = 15; i++; 12368c2ecf20Sopenharmony_ci /**/ 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci data->MsgLen = i; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci nsp_analyze_sdtr(tmpSC); 12418c2ecf20Sopenharmony_ci show_message(data); 12428c2ecf20Sopenharmony_ci nsp_message_out(tmpSC); 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci case BUSPHASE_MESSAGE_IN: 12468c2ecf20Sopenharmony_ci nsp_dataphase_bypass(tmpSC); 12478c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN"); 12488c2ecf20Sopenharmony_ci if ((phase & BUSMON_REQ) == 0) { 12498c2ecf20Sopenharmony_ci goto timer_out; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci tmpSC->SCp.phase = PH_MSG_IN; 12538c2ecf20Sopenharmony_ci nsp_message_in(tmpSC); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /**/ 12568c2ecf20Sopenharmony_ci if (*sync_neg == SYNC_NOT_YET) { 12578c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (data->MsgLen >= 5 && 12608c2ecf20Sopenharmony_ci data->MsgBuffer[0] == MSG_EXTENDED && 12618c2ecf20Sopenharmony_ci data->MsgBuffer[1] == 3 && 12628c2ecf20Sopenharmony_ci data->MsgBuffer[2] == MSG_EXT_SDTR ) { 12638c2ecf20Sopenharmony_ci data->Sync[target].SyncPeriod = data->MsgBuffer[3]; 12648c2ecf20Sopenharmony_ci data->Sync[target].SyncOffset = data->MsgBuffer[4]; 12658c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]); 12668c2ecf20Sopenharmony_ci *sync_neg = SYNC_OK; 12678c2ecf20Sopenharmony_ci } else { 12688c2ecf20Sopenharmony_ci data->Sync[target].SyncPeriod = 0; 12698c2ecf20Sopenharmony_ci data->Sync[target].SyncOffset = 0; 12708c2ecf20Sopenharmony_ci *sync_neg = SYNC_NG; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci nsp_analyze_sdtr(tmpSC); 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci /**/ 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* search last messeage byte */ 12778c2ecf20Sopenharmony_ci tmp = -1; 12788c2ecf20Sopenharmony_ci for (i = 0; i < data->MsgLen; i++) { 12798c2ecf20Sopenharmony_ci tmp = data->MsgBuffer[i]; 12808c2ecf20Sopenharmony_ci if (data->MsgBuffer[i] == MSG_EXTENDED) { 12818c2ecf20Sopenharmony_ci i += (1 + data->MsgBuffer[i+1]); 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci tmpSC->SCp.Message = tmp; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen); 12878c2ecf20Sopenharmony_ci show_message(data); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci break; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci case BUSPHASE_SELECT: 12928c2ecf20Sopenharmony_ci default: 12938c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other"); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci //nsp_dbg(NSP_DEBUG_INTR, "out"); 12998c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_citimer_out: 13028c2ecf20Sopenharmony_ci nsp_start_timer(tmpSC, 1000/102); 13038c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci#ifdef NSP_DEBUG 13078c2ecf20Sopenharmony_ci#include "nsp_debug.c" 13088c2ecf20Sopenharmony_ci#endif /* NSP_DEBUG */ 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 13118c2ecf20Sopenharmony_ci/* look for ninja3 card and init if found */ 13128c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 13138c2ecf20Sopenharmony_cistatic struct Scsi_Host *nsp_detect(struct scsi_host_template *sht) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci struct Scsi_Host *host; /* registered host structure */ 13168c2ecf20Sopenharmony_ci nsp_hw_data *data_b = &nsp_data_base, *data; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id); 13198c2ecf20Sopenharmony_ci host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data)); 13208c2ecf20Sopenharmony_ci if (host == NULL) { 13218c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "host failed"); 13228c2ecf20Sopenharmony_ci return NULL; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci memcpy(host->hostdata, data_b, sizeof(nsp_hw_data)); 13268c2ecf20Sopenharmony_ci data = (nsp_hw_data *)host->hostdata; 13278c2ecf20Sopenharmony_ci data->ScsiInfo->host = host; 13288c2ecf20Sopenharmony_ci#ifdef NSP_DEBUG 13298c2ecf20Sopenharmony_ci data->CmdId = 0; 13308c2ecf20Sopenharmony_ci#endif 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci host->unique_id = data->BaseAddress; 13358c2ecf20Sopenharmony_ci host->io_port = data->BaseAddress; 13368c2ecf20Sopenharmony_ci host->n_io_port = data->NumAddress; 13378c2ecf20Sopenharmony_ci host->irq = data->IrqNumber; 13388c2ecf20Sopenharmony_ci host->base = data->MmioAddress; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci spin_lock_init(&(data->Lock)); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci snprintf(data->nspinfo, 13438c2ecf20Sopenharmony_ci sizeof(data->nspinfo), 13448c2ecf20Sopenharmony_ci "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", 13458c2ecf20Sopenharmony_ci host->io_port, host->io_port + host->n_io_port - 1, 13468c2ecf20Sopenharmony_ci host->base, 13478c2ecf20Sopenharmony_ci host->irq); 13488c2ecf20Sopenharmony_ci sht->name = data->nspinfo; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "end"); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci return host; /* detect done. */ 13548c2ecf20Sopenharmony_ci} 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 13578c2ecf20Sopenharmony_ci/* return info string */ 13588c2ecf20Sopenharmony_ci/*----------------------------------------------------------------*/ 13598c2ecf20Sopenharmony_cistatic const char *nsp_info(struct Scsi_Host *shpnt) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return data->nspinfo; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic int nsp_show_info(struct seq_file *m, struct Scsi_Host *host) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci int id; 13698c2ecf20Sopenharmony_ci int speed; 13708c2ecf20Sopenharmony_ci unsigned long flags; 13718c2ecf20Sopenharmony_ci nsp_hw_data *data; 13728c2ecf20Sopenharmony_ci int hostno; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci hostno = host->host_no; 13758c2ecf20Sopenharmony_ci data = (nsp_hw_data *)host->hostdata; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci seq_puts(m, "NinjaSCSI status\n\n" 13788c2ecf20Sopenharmony_ci "Driver version: $Revision: 1.23 $\n"); 13798c2ecf20Sopenharmony_ci seq_printf(m, "SCSI host No.: %d\n", hostno); 13808c2ecf20Sopenharmony_ci seq_printf(m, "IRQ: %d\n", host->irq); 13818c2ecf20Sopenharmony_ci seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); 13828c2ecf20Sopenharmony_ci seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); 13838c2ecf20Sopenharmony_ci seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci seq_puts(m, "burst transfer mode: "); 13868c2ecf20Sopenharmony_ci switch (nsp_burst_mode) { 13878c2ecf20Sopenharmony_ci case BURST_IO8: 13888c2ecf20Sopenharmony_ci seq_puts(m, "io8"); 13898c2ecf20Sopenharmony_ci break; 13908c2ecf20Sopenharmony_ci case BURST_IO32: 13918c2ecf20Sopenharmony_ci seq_puts(m, "io32"); 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci case BURST_MEM32: 13948c2ecf20Sopenharmony_ci seq_puts(m, "mem32"); 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci default: 13978c2ecf20Sopenharmony_ci seq_puts(m, "???"); 13988c2ecf20Sopenharmony_ci break; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci spin_lock_irqsave(&(data->Lock), flags); 14048c2ecf20Sopenharmony_ci seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC); 14058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&(data->Lock), flags); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci seq_puts(m, "SDTR status\n"); 14088c2ecf20Sopenharmony_ci for(id = 0; id < ARRAY_SIZE(data->Sync); id++) { 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci seq_printf(m, "id %d: ", id); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (id == host->this_id) { 14138c2ecf20Sopenharmony_ci seq_puts(m, "----- NinjaSCSI-3 host adapter\n"); 14148c2ecf20Sopenharmony_ci continue; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci switch(data->Sync[id].SyncNegotiation) { 14188c2ecf20Sopenharmony_ci case SYNC_OK: 14198c2ecf20Sopenharmony_ci seq_puts(m, " sync"); 14208c2ecf20Sopenharmony_ci break; 14218c2ecf20Sopenharmony_ci case SYNC_NG: 14228c2ecf20Sopenharmony_ci seq_puts(m, "async"); 14238c2ecf20Sopenharmony_ci break; 14248c2ecf20Sopenharmony_ci case SYNC_NOT_YET: 14258c2ecf20Sopenharmony_ci seq_puts(m, " none"); 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci default: 14288c2ecf20Sopenharmony_ci seq_puts(m, "?????"); 14298c2ecf20Sopenharmony_ci break; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (data->Sync[id].SyncPeriod != 0) { 14338c2ecf20Sopenharmony_ci speed = 1000000 / (data->Sync[id].SyncPeriod * 4); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci seq_printf(m, " transfer %d.%dMB/s, offset %d", 14368c2ecf20Sopenharmony_ci speed / 1000, 14378c2ecf20Sopenharmony_ci speed % 1000, 14388c2ecf20Sopenharmony_ci data->Sync[id].SyncOffset 14398c2ecf20Sopenharmony_ci ); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci return 0; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci/*---------------------------------------------------------------*/ 14478c2ecf20Sopenharmony_ci/* error handler */ 14488c2ecf20Sopenharmony_ci/*---------------------------------------------------------------*/ 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci/* 14518c2ecf20Sopenharmony_cistatic int nsp_eh_abort(struct scsi_cmnd *SCpnt) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci return nsp_eh_bus_reset(SCpnt); 14568c2ecf20Sopenharmony_ci}*/ 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic int nsp_bus_reset(nsp_hw_data *data) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci unsigned int base = data->BaseAddress; 14618c2ecf20Sopenharmony_ci int i; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); 14668c2ecf20Sopenharmony_ci mdelay(100); /* 100ms */ 14678c2ecf20Sopenharmony_ci nsp_index_write(base, SCSIBUSCTRL, 0); 14688c2ecf20Sopenharmony_ci for(i = 0; i < 5; i++) { 14698c2ecf20Sopenharmony_ci nsp_index_read(base, IRQPHASESENCE); /* dummy read */ 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci nsphw_init_sync(data); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci return SUCCESS; 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci return nsp_bus_reset(data); 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic int nsp_eh_host_reset(struct scsi_cmnd *SCpnt) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_BUSRESET, "in"); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci nsphw_init(data); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci return SUCCESS; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/********************************************************************** 15018c2ecf20Sopenharmony_ci PCMCIA functions 15028c2ecf20Sopenharmony_ci**********************************************************************/ 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic int nsp_cs_probe(struct pcmcia_device *link) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci scsi_info_t *info; 15078c2ecf20Sopenharmony_ci nsp_hw_data *data = &nsp_data_base; 15088c2ecf20Sopenharmony_ci int ret; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "in"); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* Create new SCSI device */ 15138c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 15148c2ecf20Sopenharmony_ci if (info == NULL) { return -ENOMEM; } 15158c2ecf20Sopenharmony_ci info->p_dev = link; 15168c2ecf20Sopenharmony_ci link->priv = info; 15178c2ecf20Sopenharmony_ci data->ScsiInfo = info; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci ret = nsp_cs_config(link); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); 15248c2ecf20Sopenharmony_ci return ret; 15258c2ecf20Sopenharmony_ci} /* nsp_cs_attach */ 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic void nsp_cs_detach(struct pcmcia_device *link) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci ((scsi_info_t *)link->priv)->stop = 1; 15338c2ecf20Sopenharmony_ci nsp_cs_release(link); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci kfree(link->priv); 15368c2ecf20Sopenharmony_ci link->priv = NULL; 15378c2ecf20Sopenharmony_ci} /* nsp_cs_detach */ 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cistatic int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) 15418c2ecf20Sopenharmony_ci{ 15428c2ecf20Sopenharmony_ci nsp_hw_data *data = priv_data; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci if (p_dev->config_index == 0) 15458c2ecf20Sopenharmony_ci return -ENODEV; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci /* This reserves IO space but doesn't actually enable it */ 15488c2ecf20Sopenharmony_ci if (pcmcia_request_io(p_dev) != 0) 15498c2ecf20Sopenharmony_ci goto next_entry; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (resource_size(p_dev->resource[2])) { 15528c2ecf20Sopenharmony_ci p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 | 15538c2ecf20Sopenharmony_ci WIN_MEMORY_TYPE_CM | 15548c2ecf20Sopenharmony_ci WIN_ENABLE); 15558c2ecf20Sopenharmony_ci if (p_dev->resource[2]->end < 0x1000) 15568c2ecf20Sopenharmony_ci p_dev->resource[2]->end = 0x1000; 15578c2ecf20Sopenharmony_ci if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0) 15588c2ecf20Sopenharmony_ci goto next_entry; 15598c2ecf20Sopenharmony_ci if (pcmcia_map_mem_page(p_dev, p_dev->resource[2], 15608c2ecf20Sopenharmony_ci p_dev->card_addr) != 0) 15618c2ecf20Sopenharmony_ci goto next_entry; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci data->MmioAddress = (unsigned long) 15648c2ecf20Sopenharmony_ci ioremap(p_dev->resource[2]->start, 15658c2ecf20Sopenharmony_ci resource_size(p_dev->resource[2])); 15668c2ecf20Sopenharmony_ci data->MmioLength = resource_size(p_dev->resource[2]); 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci /* If we got this far, we're cool! */ 15698c2ecf20Sopenharmony_ci return 0; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_cinext_entry: 15728c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "next"); 15738c2ecf20Sopenharmony_ci pcmcia_disable_device(p_dev); 15748c2ecf20Sopenharmony_ci return -ENODEV; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int nsp_cs_config(struct pcmcia_device *link) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci int ret; 15808c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 15818c2ecf20Sopenharmony_ci struct Scsi_Host *host; 15828c2ecf20Sopenharmony_ci nsp_hw_data *data = &nsp_data_base; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "in"); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | 15878c2ecf20Sopenharmony_ci CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM | 15888c2ecf20Sopenharmony_ci CONF_AUTO_SET_IO; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci ret = pcmcia_loop_config(link, nsp_cs_config_check, data); 15918c2ecf20Sopenharmony_ci if (ret) 15928c2ecf20Sopenharmony_ci goto cs_failed; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci if (pcmcia_request_irq(link, nspintr)) 15958c2ecf20Sopenharmony_ci goto cs_failed; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci ret = pcmcia_enable_device(link); 15988c2ecf20Sopenharmony_ci if (ret) 15998c2ecf20Sopenharmony_ci goto cs_failed; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (free_ports) { 16028c2ecf20Sopenharmony_ci if (link->resource[0]) { 16038c2ecf20Sopenharmony_ci release_region(link->resource[0]->start, 16048c2ecf20Sopenharmony_ci resource_size(link->resource[0])); 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci if (link->resource[1]) { 16078c2ecf20Sopenharmony_ci release_region(link->resource[1]->start, 16088c2ecf20Sopenharmony_ci resource_size(link->resource[1])); 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Set port and IRQ */ 16138c2ecf20Sopenharmony_ci data->BaseAddress = link->resource[0]->start; 16148c2ecf20Sopenharmony_ci data->NumAddress = resource_size(link->resource[0]); 16158c2ecf20Sopenharmony_ci data->IrqNumber = link->irq; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d", 16188c2ecf20Sopenharmony_ci data->BaseAddress, data->NumAddress, data->IrqNumber); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if(nsphw_init(data) == FALSE) { 16218c2ecf20Sopenharmony_ci goto cs_failed; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci host = nsp_detect(&nsp_driver_template); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (host == NULL) { 16278c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "detect failed"); 16288c2ecf20Sopenharmony_ci goto cs_failed; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci ret = scsi_add_host (host, NULL); 16338c2ecf20Sopenharmony_ci if (ret) 16348c2ecf20Sopenharmony_ci goto cs_failed; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci scsi_scan_host(host); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci info->host = host; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci cs_failed: 16438c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "config fail"); 16448c2ecf20Sopenharmony_ci nsp_cs_release(link); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci return -ENODEV; 16478c2ecf20Sopenharmony_ci} /* nsp_cs_config */ 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic void nsp_cs_release(struct pcmcia_device *link) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 16538c2ecf20Sopenharmony_ci nsp_hw_data *data = NULL; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci if (info->host == NULL) { 16568c2ecf20Sopenharmony_ci nsp_msg(KERN_DEBUG, "unexpected card release call."); 16578c2ecf20Sopenharmony_ci } else { 16588c2ecf20Sopenharmony_ci data = (nsp_hw_data *)info->host->hostdata; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* Unlink the device chain */ 16648c2ecf20Sopenharmony_ci if (info->host != NULL) { 16658c2ecf20Sopenharmony_ci scsi_remove_host(info->host); 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (resource_size(link->resource[2])) { 16698c2ecf20Sopenharmony_ci if (data != NULL) { 16708c2ecf20Sopenharmony_ci iounmap((void *)(data->MmioAddress)); 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci pcmcia_disable_device(link); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (info->host != NULL) { 16768c2ecf20Sopenharmony_ci scsi_host_put(info->host); 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci} /* nsp_cs_release */ 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_cistatic int nsp_cs_suspend(struct pcmcia_device *link) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 16838c2ecf20Sopenharmony_ci nsp_hw_data *data; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (info->host != NULL) { 16888c2ecf20Sopenharmony_ci nsp_msg(KERN_INFO, "clear SDTR status"); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci data = (nsp_hw_data *)info->host->hostdata; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci nsphw_init_sync(data); 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci info->stop = 1; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci return 0; 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cistatic int nsp_cs_resume(struct pcmcia_device *link) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci scsi_info_t *info = link->priv; 17038c2ecf20Sopenharmony_ci nsp_hw_data *data; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci nsp_dbg(NSP_DEBUG_INIT, "event: resume"); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci info->stop = 0; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (info->host != NULL) { 17108c2ecf20Sopenharmony_ci nsp_msg(KERN_INFO, "reset host and bus"); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci data = (nsp_hw_data *)info->host->hostdata; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci nsphw_init (data); 17158c2ecf20Sopenharmony_ci nsp_bus_reset(data); 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci return 0; 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci/*======================================================================* 17228c2ecf20Sopenharmony_ci * module entry point 17238c2ecf20Sopenharmony_ci *====================================================================*/ 17248c2ecf20Sopenharmony_cistatic const struct pcmcia_device_id nsp_cs_ids[] = { 17258c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a), 17268c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a), 17278c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a), 17288c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a), 17298c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a), 17308c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e), 17318c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a), 17328c2ecf20Sopenharmony_ci PCMCIA_DEVICE_NULL 17338c2ecf20Sopenharmony_ci}; 17348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic struct pcmcia_driver nsp_driver = { 17378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 17388c2ecf20Sopenharmony_ci .name = "nsp_cs", 17398c2ecf20Sopenharmony_ci .probe = nsp_cs_probe, 17408c2ecf20Sopenharmony_ci .remove = nsp_cs_detach, 17418c2ecf20Sopenharmony_ci .id_table = nsp_cs_ids, 17428c2ecf20Sopenharmony_ci .suspend = nsp_cs_suspend, 17438c2ecf20Sopenharmony_ci .resume = nsp_cs_resume, 17448c2ecf20Sopenharmony_ci}; 17458c2ecf20Sopenharmony_cimodule_pcmcia_driver(nsp_driver); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci/* end */ 1748