18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci* sym53c500_cs.c Bob Tracy (rct@frus.com) 48c2ecf20Sopenharmony_ci* 58c2ecf20Sopenharmony_ci* A rewrite of the pcmcia-cs add-on driver for newer (circa 1997) 68c2ecf20Sopenharmony_ci* New Media Bus Toaster PCMCIA SCSI cards using the Symbios Logic 78c2ecf20Sopenharmony_ci* 53c500 controller: intended for use with 2.6 and later kernels. 88c2ecf20Sopenharmony_ci* The pcmcia-cs add-on version of this driver is not supported 98c2ecf20Sopenharmony_ci* beyond 2.4. It consisted of three files with history/copyright 108c2ecf20Sopenharmony_ci* information as follows: 118c2ecf20Sopenharmony_ci* 128c2ecf20Sopenharmony_ci* SYM53C500.h 138c2ecf20Sopenharmony_ci* Bob Tracy (rct@frus.com) 148c2ecf20Sopenharmony_ci* Original by Tom Corner (tcorner@via.at). 158c2ecf20Sopenharmony_ci* Adapted from NCR53c406a.h which is Copyrighted (C) 1994 168c2ecf20Sopenharmony_ci* Normunds Saumanis (normunds@rx.tech.swh.lv) 178c2ecf20Sopenharmony_ci* 188c2ecf20Sopenharmony_ci* SYM53C500.c 198c2ecf20Sopenharmony_ci* Bob Tracy (rct@frus.com) 208c2ecf20Sopenharmony_ci* Original driver by Tom Corner (tcorner@via.at) was adapted 218c2ecf20Sopenharmony_ci* from NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996 228c2ecf20Sopenharmony_ci* Normunds Saumanis (normunds@fi.ibm.com) 238c2ecf20Sopenharmony_ci* 248c2ecf20Sopenharmony_ci* sym53c500.c 258c2ecf20Sopenharmony_ci* Bob Tracy (rct@frus.com) 268c2ecf20Sopenharmony_ci* Original by Tom Corner (tcorner@via.at) was adapted from a 278c2ecf20Sopenharmony_ci* driver for the Qlogic SCSI card written by 288c2ecf20Sopenharmony_ci* David Hinds (dhinds@allegro.stanford.edu). 298c2ecf20Sopenharmony_ci*/ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SYM53C500_DEBUG 0 328c2ecf20Sopenharmony_ci#define VERBOSE_SYM53C500_DEBUG 0 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci* Set this to 0 if you encounter kernel lockups while transferring 368c2ecf20Sopenharmony_ci* data in PIO mode. Note this can be changed via "sysfs". 378c2ecf20Sopenharmony_ci*/ 388c2ecf20Sopenharmony_ci#define USE_FAST_PIO 1 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* =============== End of user configurable parameters ============== */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <linux/module.h> 438c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 448c2ecf20Sopenharmony_ci#include <linux/errno.h> 458c2ecf20Sopenharmony_ci#include <linux/init.h> 468c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 478c2ecf20Sopenharmony_ci#include <linux/kernel.h> 488c2ecf20Sopenharmony_ci#include <linux/slab.h> 498c2ecf20Sopenharmony_ci#include <linux/string.h> 508c2ecf20Sopenharmony_ci#include <linux/ioport.h> 518c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 528c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 538c2ecf20Sopenharmony_ci#include <linux/bitops.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <asm/io.h> 568c2ecf20Sopenharmony_ci#include <asm/dma.h> 578c2ecf20Sopenharmony_ci#include <asm/irq.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> 608c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 618c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 628c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 638c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h> 668c2ecf20Sopenharmony_ci#include <pcmcia/ds.h> 678c2ecf20Sopenharmony_ci#include <pcmcia/ciscode.h> 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* ================================================================== */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define SYNC_MODE 0 /* Synchronous transfer mode */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Default configuration */ 758c2ecf20Sopenharmony_ci#define C1_IMG 0x07 /* ID=7 */ 768c2ecf20Sopenharmony_ci#define C2_IMG 0x48 /* FE SCSI2 */ 778c2ecf20Sopenharmony_ci#define C3_IMG 0x20 /* CDB */ 788c2ecf20Sopenharmony_ci#define C4_IMG 0x04 /* ANE */ 798c2ecf20Sopenharmony_ci#define C5_IMG 0xa4 /* ? changed from b6= AA PI SIE POL */ 808c2ecf20Sopenharmony_ci#define C7_IMG 0x80 /* added for SYM53C500 t. corner */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Hardware Registers: offsets from io_port (base) */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Control Register Set 0 */ 858c2ecf20Sopenharmony_ci#define TC_LSB 0x00 /* transfer counter lsb */ 868c2ecf20Sopenharmony_ci#define TC_MSB 0x01 /* transfer counter msb */ 878c2ecf20Sopenharmony_ci#define SCSI_FIFO 0x02 /* scsi fifo register */ 888c2ecf20Sopenharmony_ci#define CMD_REG 0x03 /* command register */ 898c2ecf20Sopenharmony_ci#define STAT_REG 0x04 /* status register */ 908c2ecf20Sopenharmony_ci#define DEST_ID 0x04 /* selection/reselection bus id */ 918c2ecf20Sopenharmony_ci#define INT_REG 0x05 /* interrupt status register */ 928c2ecf20Sopenharmony_ci#define SRTIMOUT 0x05 /* select/reselect timeout reg */ 938c2ecf20Sopenharmony_ci#define SEQ_REG 0x06 /* sequence step register */ 948c2ecf20Sopenharmony_ci#define SYNCPRD 0x06 /* synchronous transfer period */ 958c2ecf20Sopenharmony_ci#define FIFO_FLAGS 0x07 /* indicates # of bytes in fifo */ 968c2ecf20Sopenharmony_ci#define SYNCOFF 0x07 /* synchronous offset register */ 978c2ecf20Sopenharmony_ci#define CONFIG1 0x08 /* configuration register */ 988c2ecf20Sopenharmony_ci#define CLKCONV 0x09 /* clock conversion register */ 998c2ecf20Sopenharmony_ci/* #define TESTREG 0x0A */ /* test mode register */ 1008c2ecf20Sopenharmony_ci#define CONFIG2 0x0B /* configuration 2 register */ 1018c2ecf20Sopenharmony_ci#define CONFIG3 0x0C /* configuration 3 register */ 1028c2ecf20Sopenharmony_ci#define CONFIG4 0x0D /* configuration 4 register */ 1038c2ecf20Sopenharmony_ci#define TC_HIGH 0x0E /* transfer counter high */ 1048c2ecf20Sopenharmony_ci/* #define FIFO_BOTTOM 0x0F */ /* reserve FIFO byte register */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Control Register Set 1 */ 1078c2ecf20Sopenharmony_ci/* #define JUMPER_SENSE 0x00 */ /* jumper sense port reg (r/w) */ 1088c2ecf20Sopenharmony_ci/* #define SRAM_PTR 0x01 */ /* SRAM address pointer reg (r/w) */ 1098c2ecf20Sopenharmony_ci/* #define SRAM_DATA 0x02 */ /* SRAM data register (r/w) */ 1108c2ecf20Sopenharmony_ci#define PIO_FIFO 0x04 /* PIO FIFO registers (r/w) */ 1118c2ecf20Sopenharmony_ci/* #define PIO_FIFO1 0x05 */ /* */ 1128c2ecf20Sopenharmony_ci/* #define PIO_FIFO2 0x06 */ /* */ 1138c2ecf20Sopenharmony_ci/* #define PIO_FIFO3 0x07 */ /* */ 1148c2ecf20Sopenharmony_ci#define PIO_STATUS 0x08 /* PIO status (r/w) */ 1158c2ecf20Sopenharmony_ci/* #define ATA_CMD 0x09 */ /* ATA command/status reg (r/w) */ 1168c2ecf20Sopenharmony_ci/* #define ATA_ERR 0x0A */ /* ATA features/error reg (r/w) */ 1178c2ecf20Sopenharmony_ci#define PIO_FLAG 0x0B /* PIO flag interrupt enable (r/w) */ 1188c2ecf20Sopenharmony_ci#define CONFIG5 0x09 /* configuration 5 register */ 1198c2ecf20Sopenharmony_ci/* #define SIGNATURE 0x0E */ /* signature register (r) */ 1208c2ecf20Sopenharmony_ci/* #define CONFIG6 0x0F */ /* configuration 6 register (r) */ 1218c2ecf20Sopenharmony_ci#define CONFIG7 0x0d 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* select register set 0 */ 1248c2ecf20Sopenharmony_ci#define REG0(x) (outb(C4_IMG, (x) + CONFIG4)) 1258c2ecf20Sopenharmony_ci/* select register set 1 */ 1268c2ecf20Sopenharmony_ci#define REG1(x) outb(C7_IMG, (x) + CONFIG7); outb(C5_IMG, (x) + CONFIG5) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#if SYM53C500_DEBUG 1298c2ecf20Sopenharmony_ci#define DEB(x) x 1308c2ecf20Sopenharmony_ci#else 1318c2ecf20Sopenharmony_ci#define DEB(x) 1328c2ecf20Sopenharmony_ci#endif 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#if VERBOSE_SYM53C500_DEBUG 1358c2ecf20Sopenharmony_ci#define VDEB(x) x 1368c2ecf20Sopenharmony_ci#else 1378c2ecf20Sopenharmony_ci#define VDEB(x) 1388c2ecf20Sopenharmony_ci#endif 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define LOAD_DMA_COUNT(x, count) \ 1418c2ecf20Sopenharmony_ci outb(count & 0xff, (x) + TC_LSB); \ 1428c2ecf20Sopenharmony_ci outb((count >> 8) & 0xff, (x) + TC_MSB); \ 1438c2ecf20Sopenharmony_ci outb((count >> 16) & 0xff, (x) + TC_HIGH); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* Chip commands */ 1468c2ecf20Sopenharmony_ci#define DMA_OP 0x80 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define SCSI_NOP 0x00 1498c2ecf20Sopenharmony_ci#define FLUSH_FIFO 0x01 1508c2ecf20Sopenharmony_ci#define CHIP_RESET 0x02 1518c2ecf20Sopenharmony_ci#define SCSI_RESET 0x03 1528c2ecf20Sopenharmony_ci#define RESELECT 0x40 1538c2ecf20Sopenharmony_ci#define SELECT_NO_ATN 0x41 1548c2ecf20Sopenharmony_ci#define SELECT_ATN 0x42 1558c2ecf20Sopenharmony_ci#define SELECT_ATN_STOP 0x43 1568c2ecf20Sopenharmony_ci#define ENABLE_SEL 0x44 1578c2ecf20Sopenharmony_ci#define DISABLE_SEL 0x45 1588c2ecf20Sopenharmony_ci#define SELECT_ATN3 0x46 1598c2ecf20Sopenharmony_ci#define RESELECT3 0x47 1608c2ecf20Sopenharmony_ci#define TRANSFER_INFO 0x10 1618c2ecf20Sopenharmony_ci#define INIT_CMD_COMPLETE 0x11 1628c2ecf20Sopenharmony_ci#define MSG_ACCEPT 0x12 1638c2ecf20Sopenharmony_ci#define TRANSFER_PAD 0x18 1648c2ecf20Sopenharmony_ci#define SET_ATN 0x1a 1658c2ecf20Sopenharmony_ci#define RESET_ATN 0x1b 1668c2ecf20Sopenharmony_ci#define SEND_MSG 0x20 1678c2ecf20Sopenharmony_ci#define SEND_STATUS 0x21 1688c2ecf20Sopenharmony_ci#define SEND_DATA 0x22 1698c2ecf20Sopenharmony_ci#define DISCONN_SEQ 0x23 1708c2ecf20Sopenharmony_ci#define TERMINATE_SEQ 0x24 1718c2ecf20Sopenharmony_ci#define TARG_CMD_COMPLETE 0x25 1728c2ecf20Sopenharmony_ci#define DISCONN 0x27 1738c2ecf20Sopenharmony_ci#define RECV_MSG 0x28 1748c2ecf20Sopenharmony_ci#define RECV_CMD 0x29 1758c2ecf20Sopenharmony_ci#define RECV_DATA 0x2a 1768c2ecf20Sopenharmony_ci#define RECV_CMD_SEQ 0x2b 1778c2ecf20Sopenharmony_ci#define TARGET_ABORT_DMA 0x04 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* ================================================================== */ 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct scsi_info_t { 1828c2ecf20Sopenharmony_ci struct pcmcia_device *p_dev; 1838c2ecf20Sopenharmony_ci struct Scsi_Host *host; 1848c2ecf20Sopenharmony_ci unsigned short manf_id; 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci* Repository for per-instance host data. 1898c2ecf20Sopenharmony_ci*/ 1908c2ecf20Sopenharmony_cistruct sym53c500_data { 1918c2ecf20Sopenharmony_ci struct scsi_cmnd *current_SC; 1928c2ecf20Sopenharmony_ci int fast_pio; 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cienum Phase { 1968c2ecf20Sopenharmony_ci idle, 1978c2ecf20Sopenharmony_ci data_out, 1988c2ecf20Sopenharmony_ci data_in, 1998c2ecf20Sopenharmony_ci command_ph, 2008c2ecf20Sopenharmony_ci status_ph, 2018c2ecf20Sopenharmony_ci message_out, 2028c2ecf20Sopenharmony_ci message_in 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* ================================================================== */ 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void 2088c2ecf20Sopenharmony_cichip_init(int io_port) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci REG1(io_port); 2118c2ecf20Sopenharmony_ci outb(0x01, io_port + PIO_STATUS); 2128c2ecf20Sopenharmony_ci outb(0x00, io_port + PIO_FLAG); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ 2158c2ecf20Sopenharmony_ci outb(C3_IMG, io_port + CONFIG3); 2168c2ecf20Sopenharmony_ci outb(C2_IMG, io_port + CONFIG2); 2178c2ecf20Sopenharmony_ci outb(C1_IMG, io_port + CONFIG1); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci outb(0x05, io_port + CLKCONV); /* clock conversion factor */ 2208c2ecf20Sopenharmony_ci outb(0x9C, io_port + SRTIMOUT); /* Selection timeout */ 2218c2ecf20Sopenharmony_ci outb(0x05, io_port + SYNCPRD); /* Synchronous transfer period */ 2228c2ecf20Sopenharmony_ci outb(SYNC_MODE, io_port + SYNCOFF); /* synchronous mode */ 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic void 2268c2ecf20Sopenharmony_ciSYM53C500_int_host_reset(int io_port) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ 2298c2ecf20Sopenharmony_ci outb(CHIP_RESET, io_port + CMD_REG); 2308c2ecf20Sopenharmony_ci outb(SCSI_NOP, io_port + CMD_REG); /* required after reset */ 2318c2ecf20Sopenharmony_ci outb(SCSI_RESET, io_port + CMD_REG); 2328c2ecf20Sopenharmony_ci chip_init(io_port); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic __inline__ int 2368c2ecf20Sopenharmony_ciSYM53C500_pio_read(int fast_pio, int base, unsigned char *request, unsigned int reqlen) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci int i; 2398c2ecf20Sopenharmony_ci int len; /* current scsi fifo size */ 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci REG1(base); 2428c2ecf20Sopenharmony_ci while (reqlen) { 2438c2ecf20Sopenharmony_ci i = inb(base + PIO_STATUS); 2448c2ecf20Sopenharmony_ci /* VDEB(printk("pio_status=%x\n", i)); */ 2458c2ecf20Sopenharmony_ci if (i & 0x80) 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (i & 0x1e) { 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci case 0x10: /* fifo empty */ 2518c2ecf20Sopenharmony_ci len = 0; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case 0x0: 2548c2ecf20Sopenharmony_ci len = 1; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 0x8: /* fifo 1/3 full */ 2578c2ecf20Sopenharmony_ci len = 42; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case 0xc: /* fifo 2/3 full */ 2608c2ecf20Sopenharmony_ci len = 84; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case 0xe: /* fifo full */ 2638c2ecf20Sopenharmony_ci len = 128; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (len) { 2728c2ecf20Sopenharmony_ci if (len > reqlen) 2738c2ecf20Sopenharmony_ci len = reqlen; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (fast_pio && len > 3) { 2768c2ecf20Sopenharmony_ci insl(base + PIO_FIFO, request, len >> 2); 2778c2ecf20Sopenharmony_ci request += len & 0xfc; 2788c2ecf20Sopenharmony_ci reqlen -= len & 0xfc; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci while (len--) { 2818c2ecf20Sopenharmony_ci *request++ = inb(base + PIO_FIFO); 2828c2ecf20Sopenharmony_ci reqlen--; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic __inline__ int 2918c2ecf20Sopenharmony_ciSYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int reqlen) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci int i = 0; 2948c2ecf20Sopenharmony_ci int len; /* current scsi fifo size */ 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci REG1(base); 2978c2ecf20Sopenharmony_ci while (reqlen && !(i & 0x40)) { 2988c2ecf20Sopenharmony_ci i = inb(base + PIO_STATUS); 2998c2ecf20Sopenharmony_ci /* VDEB(printk("pio_status=%x\n", i)); */ 3008c2ecf20Sopenharmony_ci if (i & 0x80) /* error */ 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci switch (i & 0x1e) { 3048c2ecf20Sopenharmony_ci case 0x10: 3058c2ecf20Sopenharmony_ci len = 128; 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci case 0x0: 3088c2ecf20Sopenharmony_ci len = 84; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case 0x8: 3118c2ecf20Sopenharmony_ci len = 42; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case 0xc: 3148c2ecf20Sopenharmony_ci len = 1; 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci default: 3178c2ecf20Sopenharmony_ci case 0xe: 3188c2ecf20Sopenharmony_ci len = 0; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (len) { 3238c2ecf20Sopenharmony_ci if (len > reqlen) 3248c2ecf20Sopenharmony_ci len = reqlen; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (fast_pio && len > 3) { 3278c2ecf20Sopenharmony_ci outsl(base + PIO_FIFO, request, len >> 2); 3288c2ecf20Sopenharmony_ci request += len & 0xfc; 3298c2ecf20Sopenharmony_ci reqlen -= len & 0xfc; 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci while (len--) { 3328c2ecf20Sopenharmony_ci outb(*request++, base + PIO_FIFO); 3338c2ecf20Sopenharmony_ci reqlen--; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic irqreturn_t 3428c2ecf20Sopenharmony_ciSYM53C500_intr(int irq, void *dev_id) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci unsigned long flags; 3458c2ecf20Sopenharmony_ci struct Scsi_Host *dev = dev_id; 3468c2ecf20Sopenharmony_ci DEB(unsigned char fifo_size;) 3478c2ecf20Sopenharmony_ci DEB(unsigned char seq_reg;) 3488c2ecf20Sopenharmony_ci unsigned char status, int_reg; 3498c2ecf20Sopenharmony_ci unsigned char pio_status; 3508c2ecf20Sopenharmony_ci int port_base = dev->io_port; 3518c2ecf20Sopenharmony_ci struct sym53c500_data *data = 3528c2ecf20Sopenharmony_ci (struct sym53c500_data *)dev->hostdata; 3538c2ecf20Sopenharmony_ci struct scsi_cmnd *curSC = data->current_SC; 3548c2ecf20Sopenharmony_ci int fast_pio = data->fast_pio; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci spin_lock_irqsave(dev->host_lock, flags); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500_intr called\n")); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci REG1(port_base); 3618c2ecf20Sopenharmony_ci pio_status = inb(port_base + PIO_STATUS); 3628c2ecf20Sopenharmony_ci REG0(port_base); 3638c2ecf20Sopenharmony_ci status = inb(port_base + STAT_REG); 3648c2ecf20Sopenharmony_ci DEB(seq_reg = inb(port_base + SEQ_REG)); 3658c2ecf20Sopenharmony_ci int_reg = inb(port_base + INT_REG); 3668c2ecf20Sopenharmony_ci DEB(fifo_size = inb(port_base + FIFO_FLAGS) & 0x1f); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci#if SYM53C500_DEBUG 3698c2ecf20Sopenharmony_ci printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", 3708c2ecf20Sopenharmony_ci status, seq_reg, int_reg, fifo_size); 3718c2ecf20Sopenharmony_ci printk(", pio=%02x\n", pio_status); 3728c2ecf20Sopenharmony_ci#endif /* SYM53C500_DEBUG */ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (int_reg & 0x80) { /* SCSI reset intr */ 3758c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: reset intr received\n")); 3768c2ecf20Sopenharmony_ci curSC->result = DID_RESET << 16; 3778c2ecf20Sopenharmony_ci goto idle_out; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (pio_status & 0x80) { 3818c2ecf20Sopenharmony_ci printk("SYM53C500: Warning: PIO error!\n"); 3828c2ecf20Sopenharmony_ci curSC->result = DID_ERROR << 16; 3838c2ecf20Sopenharmony_ci goto idle_out; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (status & 0x20) { /* Parity error */ 3878c2ecf20Sopenharmony_ci printk("SYM53C500: Warning: parity error!\n"); 3888c2ecf20Sopenharmony_ci curSC->result = DID_PARITY << 16; 3898c2ecf20Sopenharmony_ci goto idle_out; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (status & 0x40) { /* Gross error */ 3938c2ecf20Sopenharmony_ci printk("SYM53C500: Warning: gross error!\n"); 3948c2ecf20Sopenharmony_ci curSC->result = DID_ERROR << 16; 3958c2ecf20Sopenharmony_ci goto idle_out; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (int_reg & 0x20) { /* Disconnect */ 3998c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: disconnect intr received\n")); 4008c2ecf20Sopenharmony_ci if (curSC->SCp.phase != message_in) { /* Unexpected disconnect */ 4018c2ecf20Sopenharmony_ci curSC->result = DID_NO_CONNECT << 16; 4028c2ecf20Sopenharmony_ci } else { /* Command complete, return status and message */ 4038c2ecf20Sopenharmony_ci curSC->result = (curSC->SCp.Status & 0xff) 4048c2ecf20Sopenharmony_ci | ((curSC->SCp.Message & 0xff) << 8) | (DID_OK << 16); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci goto idle_out; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci switch (status & 0x07) { /* scsi phase */ 4108c2ecf20Sopenharmony_ci case 0x00: /* DATA-OUT */ 4118c2ecf20Sopenharmony_ci if (int_reg & 0x10) { /* Target requesting info transfer */ 4128c2ecf20Sopenharmony_ci struct scatterlist *sg; 4138c2ecf20Sopenharmony_ci int i; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci curSC->SCp.phase = data_out; 4168c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500: Data-Out phase\n")); 4178c2ecf20Sopenharmony_ci outb(FLUSH_FIFO, port_base + CMD_REG); 4188c2ecf20Sopenharmony_ci LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ 4198c2ecf20Sopenharmony_ci outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) { 4228c2ecf20Sopenharmony_ci SYM53C500_pio_write(fast_pio, port_base, 4238c2ecf20Sopenharmony_ci sg_virt(sg), sg->length); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci REG0(port_base); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci case 0x01: /* DATA-IN */ 4308c2ecf20Sopenharmony_ci if (int_reg & 0x10) { /* Target requesting info transfer */ 4318c2ecf20Sopenharmony_ci struct scatterlist *sg; 4328c2ecf20Sopenharmony_ci int i; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci curSC->SCp.phase = data_in; 4358c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500: Data-In phase\n")); 4368c2ecf20Sopenharmony_ci outb(FLUSH_FIFO, port_base + CMD_REG); 4378c2ecf20Sopenharmony_ci LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ 4388c2ecf20Sopenharmony_ci outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) { 4418c2ecf20Sopenharmony_ci SYM53C500_pio_read(fast_pio, port_base, 4428c2ecf20Sopenharmony_ci sg_virt(sg), sg->length); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci REG0(port_base); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci case 0x02: /* COMMAND */ 4498c2ecf20Sopenharmony_ci curSC->SCp.phase = command_ph; 4508c2ecf20Sopenharmony_ci printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n"); 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci case 0x03: /* STATUS */ 4548c2ecf20Sopenharmony_ci curSC->SCp.phase = status_ph; 4558c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500: Status phase\n")); 4568c2ecf20Sopenharmony_ci outb(FLUSH_FIFO, port_base + CMD_REG); 4578c2ecf20Sopenharmony_ci outb(INIT_CMD_COMPLETE, port_base + CMD_REG); 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci case 0x04: /* Reserved */ 4618c2ecf20Sopenharmony_ci case 0x05: /* Reserved */ 4628c2ecf20Sopenharmony_ci printk("SYM53C500: WARNING: Reserved phase!!!\n"); 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci case 0x06: /* MESSAGE-OUT */ 4668c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: Message-Out phase\n")); 4678c2ecf20Sopenharmony_ci curSC->SCp.phase = message_out; 4688c2ecf20Sopenharmony_ci outb(SET_ATN, port_base + CMD_REG); /* Reject the message */ 4698c2ecf20Sopenharmony_ci outb(MSG_ACCEPT, port_base + CMD_REG); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci case 0x07: /* MESSAGE-IN */ 4738c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500: Message-In phase\n")); 4748c2ecf20Sopenharmony_ci curSC->SCp.phase = message_in; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci curSC->SCp.Status = inb(port_base + SCSI_FIFO); 4778c2ecf20Sopenharmony_ci curSC->SCp.Message = inb(port_base + SCSI_FIFO); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); 4808c2ecf20Sopenharmony_ci DEB(printk("Status = %02x Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message)); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) { 4838c2ecf20Sopenharmony_ci outb(SET_ATN, port_base + CMD_REG); /* Reject message */ 4848c2ecf20Sopenharmony_ci DEB(printk("Discarding SAVE_POINTERS message\n")); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci outb(MSG_ACCEPT, port_base + CMD_REG); 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ciout: 4908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(dev->host_lock, flags); 4918c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ciidle_out: 4948c2ecf20Sopenharmony_ci curSC->SCp.phase = idle; 4958c2ecf20Sopenharmony_ci curSC->scsi_done(curSC); 4968c2ecf20Sopenharmony_ci goto out; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic void 5008c2ecf20Sopenharmony_ciSYM53C500_release(struct pcmcia_device *link) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct scsi_info_t *info = link->priv; 5038c2ecf20Sopenharmony_ci struct Scsi_Host *shost = info->host; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "SYM53C500_release\n"); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* 5088c2ecf20Sopenharmony_ci * Do this before releasing/freeing resources. 5098c2ecf20Sopenharmony_ci */ 5108c2ecf20Sopenharmony_ci scsi_remove_host(shost); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* 5138c2ecf20Sopenharmony_ci * Interrupts getting hosed on card removal. Try 5148c2ecf20Sopenharmony_ci * the following code, mostly from qlogicfas.c. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci if (shost->irq) 5178c2ecf20Sopenharmony_ci free_irq(shost->irq, shost); 5188c2ecf20Sopenharmony_ci if (shost->io_port && shost->n_io_port) 5198c2ecf20Sopenharmony_ci release_region(shost->io_port, shost->n_io_port); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci pcmcia_disable_device(link); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci scsi_host_put(shost); 5248c2ecf20Sopenharmony_ci} /* SYM53C500_release */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic const char* 5278c2ecf20Sopenharmony_ciSYM53C500_info(struct Scsi_Host *SChost) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci static char info_msg[256]; 5308c2ecf20Sopenharmony_ci struct sym53c500_data *data = 5318c2ecf20Sopenharmony_ci (struct sym53c500_data *)SChost->hostdata; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci DEB(printk("SYM53C500_info called\n")); 5348c2ecf20Sopenharmony_ci (void)snprintf(info_msg, sizeof(info_msg), 5358c2ecf20Sopenharmony_ci "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", 5368c2ecf20Sopenharmony_ci SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow"); 5378c2ecf20Sopenharmony_ci return (info_msg); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int 5418c2ecf20Sopenharmony_ciSYM53C500_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci int i; 5448c2ecf20Sopenharmony_ci int port_base = SCpnt->device->host->io_port; 5458c2ecf20Sopenharmony_ci struct sym53c500_data *data = 5468c2ecf20Sopenharmony_ci (struct sym53c500_data *)SCpnt->device->host->hostdata; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci VDEB(printk("SYM53C500_queue called\n")); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", 5518c2ecf20Sopenharmony_ci SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, 5528c2ecf20Sopenharmony_ci (u8)SCpnt->device->lun, scsi_bufflen(SCpnt))); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci VDEB(for (i = 0; i < SCpnt->cmd_len; i++) 5558c2ecf20Sopenharmony_ci printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); 5568c2ecf20Sopenharmony_ci VDEB(printk("\n")); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci data->current_SC = SCpnt; 5598c2ecf20Sopenharmony_ci data->current_SC->scsi_done = done; 5608c2ecf20Sopenharmony_ci data->current_SC->SCp.phase = command_ph; 5618c2ecf20Sopenharmony_ci data->current_SC->SCp.Status = 0; 5628c2ecf20Sopenharmony_ci data->current_SC->SCp.Message = 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* We are locked here already by the mid layer */ 5658c2ecf20Sopenharmony_ci REG0(port_base); 5668c2ecf20Sopenharmony_ci outb(scmd_id(SCpnt), port_base + DEST_ID); /* set destination */ 5678c2ecf20Sopenharmony_ci outb(FLUSH_FIFO, port_base + CMD_REG); /* reset the fifos */ 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci for (i = 0; i < SCpnt->cmd_len; i++) { 5708c2ecf20Sopenharmony_ci outb(SCpnt->cmnd[i], port_base + SCSI_FIFO); 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci outb(SELECT_NO_ATN, port_base + CMD_REG); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(SYM53C500_queue) 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic int 5808c2ecf20Sopenharmony_ciSYM53C500_host_reset(struct scsi_cmnd *SCpnt) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci int port_base = SCpnt->device->host->io_port; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci DEB(printk("SYM53C500_host_reset called\n")); 5858c2ecf20Sopenharmony_ci spin_lock_irq(SCpnt->device->host->host_lock); 5868c2ecf20Sopenharmony_ci SYM53C500_int_host_reset(port_base); 5878c2ecf20Sopenharmony_ci spin_unlock_irq(SCpnt->device->host->host_lock); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return SUCCESS; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int 5938c2ecf20Sopenharmony_ciSYM53C500_biosparm(struct scsi_device *disk, 5948c2ecf20Sopenharmony_ci struct block_device *dev, 5958c2ecf20Sopenharmony_ci sector_t capacity, int *info_array) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci int size; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci DEB(printk("SYM53C500_biosparm called\n")); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci size = capacity; 6028c2ecf20Sopenharmony_ci info_array[0] = 64; /* heads */ 6038c2ecf20Sopenharmony_ci info_array[1] = 32; /* sectors */ 6048c2ecf20Sopenharmony_ci info_array[2] = size >> 11; /* cylinders */ 6058c2ecf20Sopenharmony_ci if (info_array[2] > 1024) { /* big disk */ 6068c2ecf20Sopenharmony_ci info_array[0] = 255; 6078c2ecf20Sopenharmony_ci info_array[1] = 63; 6088c2ecf20Sopenharmony_ci info_array[2] = size / (255 * 63); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic ssize_t 6148c2ecf20Sopenharmony_ciSYM53C500_show_pio(struct device *dev, struct device_attribute *attr, 6158c2ecf20Sopenharmony_ci char *buf) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct Scsi_Host *SHp = class_to_shost(dev); 6188c2ecf20Sopenharmony_ci struct sym53c500_data *data = 6198c2ecf20Sopenharmony_ci (struct sym53c500_data *)SHp->hostdata; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return snprintf(buf, 4, "%d\n", data->fast_pio); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic ssize_t 6258c2ecf20Sopenharmony_ciSYM53C500_store_pio(struct device *dev, struct device_attribute *attr, 6268c2ecf20Sopenharmony_ci const char *buf, size_t count) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci int pio; 6298c2ecf20Sopenharmony_ci struct Scsi_Host *SHp = class_to_shost(dev); 6308c2ecf20Sopenharmony_ci struct sym53c500_data *data = 6318c2ecf20Sopenharmony_ci (struct sym53c500_data *)SHp->hostdata; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci pio = simple_strtoul(buf, NULL, 0); 6348c2ecf20Sopenharmony_ci if (pio == 0 || pio == 1) { 6358c2ecf20Sopenharmony_ci data->fast_pio = pio; 6368c2ecf20Sopenharmony_ci return count; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci else 6398c2ecf20Sopenharmony_ci return -EINVAL; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci/* 6438c2ecf20Sopenharmony_ci* SCSI HBA device attributes we want to 6448c2ecf20Sopenharmony_ci* make available via sysfs. 6458c2ecf20Sopenharmony_ci*/ 6468c2ecf20Sopenharmony_cistatic struct device_attribute SYM53C500_pio_attr = { 6478c2ecf20Sopenharmony_ci .attr = { 6488c2ecf20Sopenharmony_ci .name = "fast_pio", 6498c2ecf20Sopenharmony_ci .mode = (S_IRUGO | S_IWUSR), 6508c2ecf20Sopenharmony_ci }, 6518c2ecf20Sopenharmony_ci .show = SYM53C500_show_pio, 6528c2ecf20Sopenharmony_ci .store = SYM53C500_store_pio, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic struct device_attribute *SYM53C500_shost_attrs[] = { 6568c2ecf20Sopenharmony_ci &SYM53C500_pio_attr, 6578c2ecf20Sopenharmony_ci NULL, 6588c2ecf20Sopenharmony_ci}; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* 6618c2ecf20Sopenharmony_ci* scsi_host_template initializer 6628c2ecf20Sopenharmony_ci*/ 6638c2ecf20Sopenharmony_cistatic struct scsi_host_template sym53c500_driver_template = { 6648c2ecf20Sopenharmony_ci .module = THIS_MODULE, 6658c2ecf20Sopenharmony_ci .name = "SYM53C500", 6668c2ecf20Sopenharmony_ci .info = SYM53C500_info, 6678c2ecf20Sopenharmony_ci .queuecommand = SYM53C500_queue, 6688c2ecf20Sopenharmony_ci .eh_host_reset_handler = SYM53C500_host_reset, 6698c2ecf20Sopenharmony_ci .bios_param = SYM53C500_biosparm, 6708c2ecf20Sopenharmony_ci .proc_name = "SYM53C500", 6718c2ecf20Sopenharmony_ci .can_queue = 1, 6728c2ecf20Sopenharmony_ci .this_id = 7, 6738c2ecf20Sopenharmony_ci .sg_tablesize = 32, 6748c2ecf20Sopenharmony_ci .shost_attrs = SYM53C500_shost_attrs 6758c2ecf20Sopenharmony_ci}; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci p_dev->io_lines = 10; 6808c2ecf20Sopenharmony_ci p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 6818c2ecf20Sopenharmony_ci p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (p_dev->resource[0]->start == 0) 6848c2ecf20Sopenharmony_ci return -ENODEV; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return pcmcia_request_io(p_dev); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int 6908c2ecf20Sopenharmony_ciSYM53C500_config(struct pcmcia_device *link) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct scsi_info_t *info = link->priv; 6938c2ecf20Sopenharmony_ci int ret; 6948c2ecf20Sopenharmony_ci int irq_level, port_base; 6958c2ecf20Sopenharmony_ci struct Scsi_Host *host; 6968c2ecf20Sopenharmony_ci struct scsi_host_template *tpnt = &sym53c500_driver_template; 6978c2ecf20Sopenharmony_ci struct sym53c500_data *data; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "SYM53C500_config\n"); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci info->manf_id = link->manf_id; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL); 7048c2ecf20Sopenharmony_ci if (ret) 7058c2ecf20Sopenharmony_ci goto failed; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (!link->irq) 7088c2ecf20Sopenharmony_ci goto failed; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci ret = pcmcia_enable_device(link); 7118c2ecf20Sopenharmony_ci if (ret) 7128c2ecf20Sopenharmony_ci goto failed; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * That's the trouble with copying liberally from another driver. 7168c2ecf20Sopenharmony_ci * Some things probably aren't relevant, and I suspect this entire 7178c2ecf20Sopenharmony_ci * section dealing with manufacturer IDs can be scrapped. --rct 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci if ((info->manf_id == MANFID_MACNICA) || 7208c2ecf20Sopenharmony_ci (info->manf_id == MANFID_PIONEER) || 7218c2ecf20Sopenharmony_ci (info->manf_id == 0x0098)) { 7228c2ecf20Sopenharmony_ci /* set ATAcmd */ 7238c2ecf20Sopenharmony_ci outb(0xb4, link->resource[0]->start + 0xd); 7248c2ecf20Sopenharmony_ci outb(0x24, link->resource[0]->start + 0x9); 7258c2ecf20Sopenharmony_ci outb(0x04, link->resource[0]->start + 0xd); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* 7298c2ecf20Sopenharmony_ci * irq_level == 0 implies tpnt->can_queue == 0, which 7308c2ecf20Sopenharmony_ci * is not supported in 2.6. Thus, only irq_level > 0 7318c2ecf20Sopenharmony_ci * will be allowed. 7328c2ecf20Sopenharmony_ci * 7338c2ecf20Sopenharmony_ci * Possible port_base values are as follows: 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * 0x130, 0x230, 0x280, 0x290, 7368c2ecf20Sopenharmony_ci * 0x320, 0x330, 0x340, 0x350 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci port_base = link->resource[0]->start; 7398c2ecf20Sopenharmony_ci irq_level = link->irq; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n", 7428c2ecf20Sopenharmony_ci port_base, irq_level, USE_FAST_PIO);) 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci chip_init(port_base); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data)); 7478c2ecf20Sopenharmony_ci if (!host) { 7488c2ecf20Sopenharmony_ci printk("SYM53C500: Unable to register host, giving up.\n"); 7498c2ecf20Sopenharmony_ci goto err_release; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci data = (struct sym53c500_data *)host->hostdata; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (irq_level > 0) { 7558c2ecf20Sopenharmony_ci if (request_irq(irq_level, SYM53C500_intr, IRQF_SHARED, "SYM53C500", host)) { 7568c2ecf20Sopenharmony_ci printk("SYM53C500: unable to allocate IRQ %d\n", irq_level); 7578c2ecf20Sopenharmony_ci goto err_free_scsi; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level)); 7608c2ecf20Sopenharmony_ci } else if (irq_level == 0) { 7618c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: No interrupts detected\n")); 7628c2ecf20Sopenharmony_ci goto err_free_scsi; 7638c2ecf20Sopenharmony_ci } else { 7648c2ecf20Sopenharmony_ci DEB(printk("SYM53C500: Shouldn't get here!\n")); 7658c2ecf20Sopenharmony_ci goto err_free_scsi; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci host->unique_id = port_base; 7698c2ecf20Sopenharmony_ci host->irq = irq_level; 7708c2ecf20Sopenharmony_ci host->io_port = port_base; 7718c2ecf20Sopenharmony_ci host->n_io_port = 0x10; 7728c2ecf20Sopenharmony_ci host->dma_channel = -1; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* 7758c2ecf20Sopenharmony_ci * Note fast_pio is set to USE_FAST_PIO by 7768c2ecf20Sopenharmony_ci * default, but can be changed via "sysfs". 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci data->fast_pio = USE_FAST_PIO; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci info->host = host; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (scsi_add_host(host, NULL)) 7838c2ecf20Sopenharmony_ci goto err_free_irq; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci scsi_scan_host(host); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cierr_free_irq: 7908c2ecf20Sopenharmony_ci free_irq(irq_level, host); 7918c2ecf20Sopenharmony_cierr_free_scsi: 7928c2ecf20Sopenharmony_ci scsi_host_put(host); 7938c2ecf20Sopenharmony_cierr_release: 7948c2ecf20Sopenharmony_ci release_region(port_base, 0x10); 7958c2ecf20Sopenharmony_ci printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); 7968c2ecf20Sopenharmony_ci return -ENODEV; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cifailed: 7998c2ecf20Sopenharmony_ci SYM53C500_release(link); 8008c2ecf20Sopenharmony_ci return -ENODEV; 8018c2ecf20Sopenharmony_ci} /* SYM53C500_config */ 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic int sym53c500_resume(struct pcmcia_device *link) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct scsi_info_t *info = link->priv; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* See earlier comment about manufacturer IDs. */ 8088c2ecf20Sopenharmony_ci if ((info->manf_id == MANFID_MACNICA) || 8098c2ecf20Sopenharmony_ci (info->manf_id == MANFID_PIONEER) || 8108c2ecf20Sopenharmony_ci (info->manf_id == 0x0098)) { 8118c2ecf20Sopenharmony_ci outb(0x80, link->resource[0]->start + 0xd); 8128c2ecf20Sopenharmony_ci outb(0x24, link->resource[0]->start + 0x9); 8138c2ecf20Sopenharmony_ci outb(0x04, link->resource[0]->start + 0xd); 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci /* 8168c2ecf20Sopenharmony_ci * If things don't work after a "resume", 8178c2ecf20Sopenharmony_ci * this is a good place to start looking. 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_ci SYM53C500_int_host_reset(link->resource[0]->start); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return 0; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic void 8258c2ecf20Sopenharmony_ciSYM53C500_detach(struct pcmcia_device *link) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "SYM53C500_detach\n"); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci SYM53C500_release(link); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci kfree(link->priv); 8328c2ecf20Sopenharmony_ci link->priv = NULL; 8338c2ecf20Sopenharmony_ci} /* SYM53C500_detach */ 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int 8368c2ecf20Sopenharmony_ciSYM53C500_probe(struct pcmcia_device *link) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct scsi_info_t *info; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci dev_dbg(&link->dev, "SYM53C500_attach()\n"); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Create new SCSI device */ 8438c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 8448c2ecf20Sopenharmony_ci if (!info) 8458c2ecf20Sopenharmony_ci return -ENOMEM; 8468c2ecf20Sopenharmony_ci info->p_dev = link; 8478c2ecf20Sopenharmony_ci link->priv = info; 8488c2ecf20Sopenharmony_ci link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return SYM53C500_config(link); 8518c2ecf20Sopenharmony_ci} /* SYM53C500_attach */ 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bob Tracy <rct@frus.com>"); 8548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver"); 8558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic const struct pcmcia_device_id sym53c500_ids[] = { 8588c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7), 8598c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8), 8608c2ecf20Sopenharmony_ci PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44), 8618c2ecf20Sopenharmony_ci PCMCIA_DEVICE_NULL, 8628c2ecf20Sopenharmony_ci}; 8638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, sym53c500_ids); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic struct pcmcia_driver sym53c500_cs_driver = { 8668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8678c2ecf20Sopenharmony_ci .name = "sym53c500_cs", 8688c2ecf20Sopenharmony_ci .probe = SYM53C500_probe, 8698c2ecf20Sopenharmony_ci .remove = SYM53C500_detach, 8708c2ecf20Sopenharmony_ci .id_table = sym53c500_ids, 8718c2ecf20Sopenharmony_ci .resume = sym53c500_resume, 8728c2ecf20Sopenharmony_ci}; 8738c2ecf20Sopenharmony_cimodule_pcmcia_driver(sym53c500_cs_driver); 874