18c2ecf20Sopenharmony_ci/* ppa.c -- low level driver for the IOMEGA PPA3 28c2ecf20Sopenharmony_ci * parallel port SCSI host adapter. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * (The PPA3 is the embedded controller in the ZIP drive.) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (c) 1995,1996 Grant R. Guenther, grant@torque.net, 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 168c2ecf20Sopenharmony_ci#include <linux/parport.h> 178c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 208c2ecf20Sopenharmony_ci#include <asm/io.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 238c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 248c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 258c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void ppa_reset_pulse(unsigned int base); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_citypedef struct { 318c2ecf20Sopenharmony_ci struct pardevice *dev; /* Parport device entry */ 328c2ecf20Sopenharmony_ci int base; /* Actual port address */ 338c2ecf20Sopenharmony_ci int mode; /* Transfer mode */ 348c2ecf20Sopenharmony_ci struct scsi_cmnd *cur_cmd; /* Current queued command */ 358c2ecf20Sopenharmony_ci struct delayed_work ppa_tq; /* Polling interrupt stuff */ 368c2ecf20Sopenharmony_ci unsigned long jstart; /* Jiffies at start */ 378c2ecf20Sopenharmony_ci unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ 388c2ecf20Sopenharmony_ci unsigned int failed:1; /* Failure flag */ 398c2ecf20Sopenharmony_ci unsigned wanted:1; /* Parport sharing busy flag */ 408c2ecf20Sopenharmony_ci unsigned int dev_no; /* Device number */ 418c2ecf20Sopenharmony_ci wait_queue_head_t *waiting; 428c2ecf20Sopenharmony_ci struct Scsi_Host *host; 438c2ecf20Sopenharmony_ci struct list_head list; 448c2ecf20Sopenharmony_ci} ppa_struct; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include "ppa.h" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline ppa_struct *ppa_dev(struct Scsi_Host *host) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return *(ppa_struct **)&host->hostdata; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(arbitration_lock); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void got_it(ppa_struct *dev) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci dev->base = dev->dev->port->base; 588c2ecf20Sopenharmony_ci if (dev->cur_cmd) 598c2ecf20Sopenharmony_ci dev->cur_cmd->SCp.phase = 1; 608c2ecf20Sopenharmony_ci else 618c2ecf20Sopenharmony_ci wake_up(dev->waiting); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void ppa_wakeup(void *ref) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci ppa_struct *dev = (ppa_struct *) ref; 678c2ecf20Sopenharmony_ci unsigned long flags; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci spin_lock_irqsave(&arbitration_lock, flags); 708c2ecf20Sopenharmony_ci if (dev->wanted) { 718c2ecf20Sopenharmony_ci parport_claim(dev->dev); 728c2ecf20Sopenharmony_ci got_it(dev); 738c2ecf20Sopenharmony_ci dev->wanted = 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&arbitration_lock, flags); 768c2ecf20Sopenharmony_ci return; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int ppa_pb_claim(ppa_struct *dev) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned long flags; 828c2ecf20Sopenharmony_ci int res = 1; 838c2ecf20Sopenharmony_ci spin_lock_irqsave(&arbitration_lock, flags); 848c2ecf20Sopenharmony_ci if (parport_claim(dev->dev) == 0) { 858c2ecf20Sopenharmony_ci got_it(dev); 868c2ecf20Sopenharmony_ci res = 0; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci dev->wanted = res; 898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&arbitration_lock, flags); 908c2ecf20Sopenharmony_ci return res; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void ppa_pb_dismiss(ppa_struct *dev) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci unsigned long flags; 968c2ecf20Sopenharmony_ci int wanted; 978c2ecf20Sopenharmony_ci spin_lock_irqsave(&arbitration_lock, flags); 988c2ecf20Sopenharmony_ci wanted = dev->wanted; 998c2ecf20Sopenharmony_ci dev->wanted = 0; 1008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&arbitration_lock, flags); 1018c2ecf20Sopenharmony_ci if (!wanted) 1028c2ecf20Sopenharmony_ci parport_release(dev->dev); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic inline void ppa_pb_release(ppa_struct *dev) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci parport_release(dev->dev); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * Start of Chipset kludges 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* This is to give the ppa driver a way to modify the timings (and other 1158c2ecf20Sopenharmony_ci * parameters) by writing to the /proc/scsi/ppa/0 file. 1168c2ecf20Sopenharmony_ci * Very simple method really... (To simple, no error checking :( ) 1178c2ecf20Sopenharmony_ci * Reason: Kernel hackers HATE having to unload and reload modules for 1188c2ecf20Sopenharmony_ci * testing... 1198c2ecf20Sopenharmony_ci * Also gives a method to use a script to obtain optimum timings (TODO) 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic inline int ppa_write_info(struct Scsi_Host *host, char *buffer, int length) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(host); 1258c2ecf20Sopenharmony_ci unsigned long x; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) { 1288c2ecf20Sopenharmony_ci x = simple_strtoul(buffer + 5, NULL, 0); 1298c2ecf20Sopenharmony_ci dev->mode = x; 1308c2ecf20Sopenharmony_ci return length; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) { 1338c2ecf20Sopenharmony_ci x = simple_strtoul(buffer + 10, NULL, 0); 1348c2ecf20Sopenharmony_ci dev->recon_tmo = x; 1358c2ecf20Sopenharmony_ci printk(KERN_INFO "ppa: recon_tmo set to %ld\n", x); 1368c2ecf20Sopenharmony_ci return length; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci printk(KERN_WARNING "ppa /proc: invalid variable\n"); 1398c2ecf20Sopenharmony_ci return -EINVAL; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int ppa_show_info(struct seq_file *m, struct Scsi_Host *host) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(host); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci seq_printf(m, "Version : %s\n", PPA_VERSION); 1478c2ecf20Sopenharmony_ci seq_printf(m, "Parport : %s\n", dev->dev->port->name); 1488c2ecf20Sopenharmony_ci seq_printf(m, "Mode : %s\n", PPA_MODE_STRING[dev->mode]); 1498c2ecf20Sopenharmony_ci#if PPA_DEBUG > 0 1508c2ecf20Sopenharmony_ci seq_printf(m, "recon_tmo : %lu\n", dev->recon_tmo); 1518c2ecf20Sopenharmony_ci#endif 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int device_check(ppa_struct *dev); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#if PPA_DEBUG > 0 1588c2ecf20Sopenharmony_ci#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ 1598c2ecf20Sopenharmony_ci y, __func__, __LINE__); ppa_fail_func(x,y); 1608c2ecf20Sopenharmony_cistatic inline void ppa_fail_func(ppa_struct *dev, int error_code) 1618c2ecf20Sopenharmony_ci#else 1628c2ecf20Sopenharmony_cistatic inline void ppa_fail(ppa_struct *dev, int error_code) 1638c2ecf20Sopenharmony_ci#endif 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci /* If we fail a device then we trash status / message bytes */ 1668c2ecf20Sopenharmony_ci if (dev->cur_cmd) { 1678c2ecf20Sopenharmony_ci dev->cur_cmd->result = error_code << 16; 1688c2ecf20Sopenharmony_ci dev->failed = 1; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Wait for the high bit to be set. 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * In principle, this could be tied to an interrupt, but the adapter 1768c2ecf20Sopenharmony_ci * doesn't appear to be designed to support interrupts. We spin on 1778c2ecf20Sopenharmony_ci * the 0x80 ready bit. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic unsigned char ppa_wait(ppa_struct *dev) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int k; 1828c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 1838c2ecf20Sopenharmony_ci unsigned char r; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci k = PPA_SPIN_TMO; 1868c2ecf20Sopenharmony_ci /* Wait for bit 6 and 7 - PJC */ 1878c2ecf20Sopenharmony_ci for (r = r_str(ppb); ((r & 0xc0) != 0xc0) && (k); k--) { 1888c2ecf20Sopenharmony_ci udelay(1); 1898c2ecf20Sopenharmony_ci r = r_str(ppb); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * return some status information. 1948c2ecf20Sopenharmony_ci * Semantics: 0xc0 = ZIP wants more data 1958c2ecf20Sopenharmony_ci * 0xd0 = ZIP wants to send more data 1968c2ecf20Sopenharmony_ci * 0xe0 = ZIP is expecting SCSI command data 1978c2ecf20Sopenharmony_ci * 0xf0 = end of transfer, ZIP is sending status 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci if (k) 2008c2ecf20Sopenharmony_ci return (r & 0xf0); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Counter expired - Time out occurred */ 2038c2ecf20Sopenharmony_ci ppa_fail(dev, DID_TIME_OUT); 2048c2ecf20Sopenharmony_ci printk(KERN_WARNING "ppa timeout in ppa_wait\n"); 2058c2ecf20Sopenharmony_ci return 0; /* command timed out */ 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* 2098c2ecf20Sopenharmony_ci * Clear EPP Timeout Bit 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic inline void epp_reset(unsigned short ppb) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci int i; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci i = r_str(ppb); 2168c2ecf20Sopenharmony_ci w_str(ppb, i); 2178c2ecf20Sopenharmony_ci w_str(ppb, i & 0xfe); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * Wait for empty ECP fifo (if we are in ECP fifo mode only) 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_cistatic inline void ecp_sync(ppa_struct *dev) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int i, ppb_hi = dev->dev->port->base_hi; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (ppb_hi == 0) 2288c2ecf20Sopenharmony_ci return; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */ 2318c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 2328c2ecf20Sopenharmony_ci if (r_ecr(ppb_hi) & 0x01) 2338c2ecf20Sopenharmony_ci return; 2348c2ecf20Sopenharmony_ci udelay(5); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci printk(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n"); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int ppa_byte_out(unsigned short base, const char *buffer, int len) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int i; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci for (i = len; i; i--) { 2458c2ecf20Sopenharmony_ci w_dtr(base, *buffer++); 2468c2ecf20Sopenharmony_ci w_ctr(base, 0xe); 2478c2ecf20Sopenharmony_ci w_ctr(base, 0xc); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci return 1; /* All went well - we hope! */ 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int ppa_byte_in(unsigned short base, char *buffer, int len) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci int i; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (i = len; i; i--) { 2578c2ecf20Sopenharmony_ci *buffer++ = r_dtr(base); 2588c2ecf20Sopenharmony_ci w_ctr(base, 0x27); 2598c2ecf20Sopenharmony_ci w_ctr(base, 0x25); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci return 1; /* All went well - we hope! */ 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int ppa_nibble_in(unsigned short base, char *buffer, int len) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci for (; len; len--) { 2678c2ecf20Sopenharmony_ci unsigned char h; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci w_ctr(base, 0x4); 2708c2ecf20Sopenharmony_ci h = r_str(base) & 0xf0; 2718c2ecf20Sopenharmony_ci w_ctr(base, 0x6); 2728c2ecf20Sopenharmony_ci *buffer++ = h | ((r_str(base) & 0xf0) >> 4); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci return 1; /* All went well - we hope! */ 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int ppa_out(ppa_struct *dev, char *buffer, int len) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int r; 2808c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci r = ppa_wait(dev); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if ((r & 0x50) != 0x40) { 2858c2ecf20Sopenharmony_ci ppa_fail(dev, DID_ERROR); 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci switch (dev->mode) { 2898c2ecf20Sopenharmony_ci case PPA_NIBBLE: 2908c2ecf20Sopenharmony_ci case PPA_PS2: 2918c2ecf20Sopenharmony_ci /* 8 bit output, with a loop */ 2928c2ecf20Sopenharmony_ci r = ppa_byte_out(ppb, buffer, len); 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci case PPA_EPP_32: 2968c2ecf20Sopenharmony_ci case PPA_EPP_16: 2978c2ecf20Sopenharmony_ci case PPA_EPP_8: 2988c2ecf20Sopenharmony_ci epp_reset(ppb); 2998c2ecf20Sopenharmony_ci w_ctr(ppb, 0x4); 3008c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_IZIP_EPP16 3018c2ecf20Sopenharmony_ci if (!(((long) buffer | len) & 0x01)) 3028c2ecf20Sopenharmony_ci outsw(ppb + 4, buffer, len >> 1); 3038c2ecf20Sopenharmony_ci#else 3048c2ecf20Sopenharmony_ci if (!(((long) buffer | len) & 0x03)) 3058c2ecf20Sopenharmony_ci outsl(ppb + 4, buffer, len >> 2); 3068c2ecf20Sopenharmony_ci#endif 3078c2ecf20Sopenharmony_ci else 3088c2ecf20Sopenharmony_ci outsb(ppb + 4, buffer, len); 3098c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3108c2ecf20Sopenharmony_ci r = !(r_str(ppb) & 0x01); 3118c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3128c2ecf20Sopenharmony_ci ecp_sync(dev); 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci default: 3168c2ecf20Sopenharmony_ci printk(KERN_ERR "PPA: bug in ppa_out()\n"); 3178c2ecf20Sopenharmony_ci r = 0; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci return r; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int ppa_in(ppa_struct *dev, char *buffer, int len) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci int r; 3258c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci r = ppa_wait(dev); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if ((r & 0x50) != 0x50) { 3308c2ecf20Sopenharmony_ci ppa_fail(dev, DID_ERROR); 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci switch (dev->mode) { 3348c2ecf20Sopenharmony_ci case PPA_NIBBLE: 3358c2ecf20Sopenharmony_ci /* 4 bit input, with a loop */ 3368c2ecf20Sopenharmony_ci r = ppa_nibble_in(ppb, buffer, len); 3378c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case PPA_PS2: 3418c2ecf20Sopenharmony_ci /* 8 bit input, with a loop */ 3428c2ecf20Sopenharmony_ci w_ctr(ppb, 0x25); 3438c2ecf20Sopenharmony_ci r = ppa_byte_in(ppb, buffer, len); 3448c2ecf20Sopenharmony_ci w_ctr(ppb, 0x4); 3458c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci case PPA_EPP_32: 3498c2ecf20Sopenharmony_ci case PPA_EPP_16: 3508c2ecf20Sopenharmony_ci case PPA_EPP_8: 3518c2ecf20Sopenharmony_ci epp_reset(ppb); 3528c2ecf20Sopenharmony_ci w_ctr(ppb, 0x24); 3538c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_IZIP_EPP16 3548c2ecf20Sopenharmony_ci if (!(((long) buffer | len) & 0x01)) 3558c2ecf20Sopenharmony_ci insw(ppb + 4, buffer, len >> 1); 3568c2ecf20Sopenharmony_ci#else 3578c2ecf20Sopenharmony_ci if (!(((long) buffer | len) & 0x03)) 3588c2ecf20Sopenharmony_ci insl(ppb + 4, buffer, len >> 2); 3598c2ecf20Sopenharmony_ci#endif 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci insb(ppb + 4, buffer, len); 3628c2ecf20Sopenharmony_ci w_ctr(ppb, 0x2c); 3638c2ecf20Sopenharmony_ci r = !(r_str(ppb) & 0x01); 3648c2ecf20Sopenharmony_ci w_ctr(ppb, 0x2c); 3658c2ecf20Sopenharmony_ci ecp_sync(dev); 3668c2ecf20Sopenharmony_ci break; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci default: 3698c2ecf20Sopenharmony_ci printk(KERN_ERR "PPA: bug in ppa_ins()\n"); 3708c2ecf20Sopenharmony_ci r = 0; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci return r; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* end of ppa_io.h */ 3778c2ecf20Sopenharmony_cistatic inline void ppa_d_pulse(unsigned short ppb, unsigned char b) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci w_dtr(ppb, b); 3808c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3818c2ecf20Sopenharmony_ci w_ctr(ppb, 0xe); 3828c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3838c2ecf20Sopenharmony_ci w_ctr(ppb, 0x4); 3848c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void ppa_disconnect(ppa_struct *dev) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ppa_d_pulse(ppb, 0); 3928c2ecf20Sopenharmony_ci ppa_d_pulse(ppb, 0x3c); 3938c2ecf20Sopenharmony_ci ppa_d_pulse(ppb, 0x20); 3948c2ecf20Sopenharmony_ci ppa_d_pulse(ppb, 0xf); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic inline void ppa_c_pulse(unsigned short ppb, unsigned char b) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci w_dtr(ppb, b); 4008c2ecf20Sopenharmony_ci w_ctr(ppb, 0x4); 4018c2ecf20Sopenharmony_ci w_ctr(ppb, 0x6); 4028c2ecf20Sopenharmony_ci w_ctr(ppb, 0x4); 4038c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic inline void ppa_connect(ppa_struct *dev, int flag) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ppa_c_pulse(ppb, 0); 4118c2ecf20Sopenharmony_ci ppa_c_pulse(ppb, 0x3c); 4128c2ecf20Sopenharmony_ci ppa_c_pulse(ppb, 0x20); 4138c2ecf20Sopenharmony_ci if ((flag == CONNECT_EPP_MAYBE) && IN_EPP_MODE(dev->mode)) 4148c2ecf20Sopenharmony_ci ppa_c_pulse(ppb, 0xcf); 4158c2ecf20Sopenharmony_ci else 4168c2ecf20Sopenharmony_ci ppa_c_pulse(ppb, 0x8f); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int ppa_select(ppa_struct *dev, int target) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci int k; 4228c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * Bit 6 (0x40) is the device selected bit. 4268c2ecf20Sopenharmony_ci * First we must wait till the current device goes off line... 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci k = PPA_SELECT_TMO; 4298c2ecf20Sopenharmony_ci do { 4308c2ecf20Sopenharmony_ci k--; 4318c2ecf20Sopenharmony_ci udelay(1); 4328c2ecf20Sopenharmony_ci } while ((r_str(ppb) & 0x40) && (k)); 4338c2ecf20Sopenharmony_ci if (!k) 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci w_dtr(ppb, (1 << target)); 4378c2ecf20Sopenharmony_ci w_ctr(ppb, 0xe); 4388c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 4398c2ecf20Sopenharmony_ci w_dtr(ppb, 0x80); /* This is NOT the initator */ 4408c2ecf20Sopenharmony_ci w_ctr(ppb, 0x8); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci k = PPA_SELECT_TMO; 4438c2ecf20Sopenharmony_ci do { 4448c2ecf20Sopenharmony_ci k--; 4458c2ecf20Sopenharmony_ci udelay(1); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci while (!(r_str(ppb) & 0x40) && (k)); 4488c2ecf20Sopenharmony_ci if (!k) 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return 1; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* 4558c2ecf20Sopenharmony_ci * This is based on a trace of what the Iomega DOS 'guest' driver does. 4568c2ecf20Sopenharmony_ci * I've tried several different kinds of parallel ports with guest and 4578c2ecf20Sopenharmony_ci * coded this to react in the same ways that it does. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * The return value from this function is just a hint about where the 4608c2ecf20Sopenharmony_ci * handshaking failed. 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_cistatic int ppa_init(ppa_struct *dev) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int retv; 4668c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ppa_disconnect(dev); 4698c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_NORMAL); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci retv = 2; /* Failed */ 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci w_ctr(ppb, 0xe); 4748c2ecf20Sopenharmony_ci if ((r_str(ppb) & 0x08) == 0x08) 4758c2ecf20Sopenharmony_ci retv--; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 4788c2ecf20Sopenharmony_ci if ((r_str(ppb) & 0x08) == 0x00) 4798c2ecf20Sopenharmony_ci retv--; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!retv) 4828c2ecf20Sopenharmony_ci ppa_reset_pulse(ppb); 4838c2ecf20Sopenharmony_ci udelay(1000); /* Allow devices to settle down */ 4848c2ecf20Sopenharmony_ci ppa_disconnect(dev); 4858c2ecf20Sopenharmony_ci udelay(1000); /* Another delay to allow devices to settle */ 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (retv) 4888c2ecf20Sopenharmony_ci return -EIO; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return device_check(dev); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic inline int ppa_send_command(struct scsi_cmnd *cmd) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(cmd->device->host); 4968c2ecf20Sopenharmony_ci int k; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci w_ctr(dev->base, 0x0c); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci for (k = 0; k < cmd->cmd_len; k++) 5018c2ecf20Sopenharmony_ci if (!ppa_out(dev, &cmd->cmnd[k], 1)) 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci return 1; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/* 5078c2ecf20Sopenharmony_ci * The bulk flag enables some optimisations in the data transfer loops, 5088c2ecf20Sopenharmony_ci * it should be true for any command that transfers data in integral 5098c2ecf20Sopenharmony_ci * numbers of sectors. 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * The driver appears to remain stable if we speed up the parallel port 5128c2ecf20Sopenharmony_ci * i/o in this function, but not elsewhere. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic int ppa_completion(struct scsi_cmnd *cmd) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci /* Return codes: 5178c2ecf20Sopenharmony_ci * -1 Error 5188c2ecf20Sopenharmony_ci * 0 Told to schedule 5198c2ecf20Sopenharmony_ci * 1 Finished data transfer 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(cmd->device->host); 5228c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 5238c2ecf20Sopenharmony_ci unsigned long start_jiffies = jiffies; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci unsigned char r, v; 5268c2ecf20Sopenharmony_ci int fast, bulk, status; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci v = cmd->cmnd[0]; 5298c2ecf20Sopenharmony_ci bulk = ((v == READ_6) || 5308c2ecf20Sopenharmony_ci (v == READ_10) || (v == WRITE_6) || (v == WRITE_10)); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * We only get here if the drive is ready to comunicate, 5348c2ecf20Sopenharmony_ci * hence no need for a full ppa_wait. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci r = (r_str(ppb) & 0xf0); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci while (r != (unsigned char) 0xf0) { 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * If we have been running for more than a full timer tick 5418c2ecf20Sopenharmony_ci * then take a rest. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci if (time_after(jiffies, start_jiffies + 1)) 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if ((cmd->SCp.this_residual <= 0)) { 5478c2ecf20Sopenharmony_ci ppa_fail(dev, DID_ERROR); 5488c2ecf20Sopenharmony_ci return -1; /* ERROR_RETURN */ 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* On some hardware we have SCSI disconnected (6th bit low) 5528c2ecf20Sopenharmony_ci * for about 100usecs. It is too expensive to wait a 5538c2ecf20Sopenharmony_ci * tick on every loop so we busy wait for no more than 5548c2ecf20Sopenharmony_ci * 500usecs to give the drive a chance first. We do not 5558c2ecf20Sopenharmony_ci * change things for "normal" hardware since generally 5568c2ecf20Sopenharmony_ci * the 6th bit is always high. 5578c2ecf20Sopenharmony_ci * This makes the CPU load higher on some hardware 5588c2ecf20Sopenharmony_ci * but otherwise we can not get more than 50K/secs 5598c2ecf20Sopenharmony_ci * on this problem hardware. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci if ((r & 0xc0) != 0xc0) { 5628c2ecf20Sopenharmony_ci /* Wait for reconnection should be no more than 5638c2ecf20Sopenharmony_ci * jiffy/2 = 5ms = 5000 loops 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci unsigned long k = dev->recon_tmo; 5668c2ecf20Sopenharmony_ci for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; 5678c2ecf20Sopenharmony_ci k--) 5688c2ecf20Sopenharmony_ci udelay(1); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!k) 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* determine if we should use burst I/O */ 5758c2ecf20Sopenharmony_ci fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) 5768c2ecf20Sopenharmony_ci ? PPA_BURST_SIZE : 1; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (r == (unsigned char) 0xc0) 5798c2ecf20Sopenharmony_ci status = ppa_out(dev, cmd->SCp.ptr, fast); 5808c2ecf20Sopenharmony_ci else 5818c2ecf20Sopenharmony_ci status = ppa_in(dev, cmd->SCp.ptr, fast); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci cmd->SCp.ptr += fast; 5848c2ecf20Sopenharmony_ci cmd->SCp.this_residual -= fast; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!status) { 5878c2ecf20Sopenharmony_ci ppa_fail(dev, DID_BUS_BUSY); 5888c2ecf20Sopenharmony_ci return -1; /* ERROR_RETURN */ 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci if (cmd->SCp.buffer && !cmd->SCp.this_residual) { 5918c2ecf20Sopenharmony_ci /* if scatter/gather, advance to the next segment */ 5928c2ecf20Sopenharmony_ci if (cmd->SCp.buffers_residual--) { 5938c2ecf20Sopenharmony_ci cmd->SCp.buffer = sg_next(cmd->SCp.buffer); 5948c2ecf20Sopenharmony_ci cmd->SCp.this_residual = 5958c2ecf20Sopenharmony_ci cmd->SCp.buffer->length; 5968c2ecf20Sopenharmony_ci cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci /* Now check to see if the drive is ready to comunicate */ 6008c2ecf20Sopenharmony_ci r = (r_str(ppb) & 0xf0); 6018c2ecf20Sopenharmony_ci /* If not, drop back down to the scheduler and wait a timer tick */ 6028c2ecf20Sopenharmony_ci if (!(r & 0x80)) 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci return 1; /* FINISH_RETURN */ 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/* 6098c2ecf20Sopenharmony_ci * Since the PPA itself doesn't generate interrupts, we use 6108c2ecf20Sopenharmony_ci * the scheduler's task queue to generate a stream of call-backs and 6118c2ecf20Sopenharmony_ci * complete the request when the drive is ready. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_cistatic void ppa_interrupt(struct work_struct *work) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work); 6168c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = dev->cur_cmd; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (!cmd) { 6198c2ecf20Sopenharmony_ci printk(KERN_ERR "PPA: bug in ppa_interrupt\n"); 6208c2ecf20Sopenharmony_ci return; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci if (ppa_engine(dev, cmd)) { 6238c2ecf20Sopenharmony_ci schedule_delayed_work(&dev->ppa_tq, 1); 6248c2ecf20Sopenharmony_ci return; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci /* Command must of completed hence it is safe to let go... */ 6278c2ecf20Sopenharmony_ci#if PPA_DEBUG > 0 6288c2ecf20Sopenharmony_ci switch ((cmd->result >> 16) & 0xff) { 6298c2ecf20Sopenharmony_ci case DID_OK: 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci case DID_NO_CONNECT: 6328c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", cmd->device->target); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case DID_BUS_BUSY: 6358c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n"); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case DID_TIME_OUT: 6388c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: unknown timeout\n"); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case DID_ABORT: 6418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: told to abort\n"); 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci case DID_PARITY: 6448c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: parity error (???)\n"); 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci case DID_ERROR: 6478c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: internal driver error\n"); 6488c2ecf20Sopenharmony_ci break; 6498c2ecf20Sopenharmony_ci case DID_RESET: 6508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ppa: told to reset device\n"); 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case DID_BAD_INTR: 6538c2ecf20Sopenharmony_ci printk(KERN_WARNING "ppa: bad interrupt (???)\n"); 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci default: 6568c2ecf20Sopenharmony_ci printk(KERN_WARNING "ppa: bad return code (%02x)\n", 6578c2ecf20Sopenharmony_ci (cmd->result >> 16) & 0xff); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci#endif 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (cmd->SCp.phase > 1) 6628c2ecf20Sopenharmony_ci ppa_disconnect(dev); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ppa_pb_dismiss(dev); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci dev->cur_cmd = NULL; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci unsigned short ppb = dev->base; 6748c2ecf20Sopenharmony_ci unsigned char l = 0, h = 0; 6758c2ecf20Sopenharmony_ci int retv; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* First check for any errors that may of occurred 6788c2ecf20Sopenharmony_ci * Here we check for internal errors 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci if (dev->failed) 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci switch (cmd->SCp.phase) { 6848c2ecf20Sopenharmony_ci case 0: /* Phase 0 - Waiting for parport */ 6858c2ecf20Sopenharmony_ci if (time_after(jiffies, dev->jstart + HZ)) { 6868c2ecf20Sopenharmony_ci /* 6878c2ecf20Sopenharmony_ci * We waited more than a second 6888c2ecf20Sopenharmony_ci * for parport to call us 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci ppa_fail(dev, DID_BUS_BUSY); 6918c2ecf20Sopenharmony_ci return 0; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci return 1; /* wait until ppa_wakeup claims parport */ 6948c2ecf20Sopenharmony_ci case 1: /* Phase 1 - Connected */ 6958c2ecf20Sopenharmony_ci { /* Perform a sanity check for cable unplugged */ 6968c2ecf20Sopenharmony_ci int retv = 2; /* Failed */ 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_EPP_MAYBE); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci w_ctr(ppb, 0xe); 7018c2ecf20Sopenharmony_ci if ((r_str(ppb) & 0x08) == 0x08) 7028c2ecf20Sopenharmony_ci retv--; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci w_ctr(ppb, 0xc); 7058c2ecf20Sopenharmony_ci if ((r_str(ppb) & 0x08) == 0x00) 7068c2ecf20Sopenharmony_ci retv--; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (retv) { 7098c2ecf20Sopenharmony_ci if (time_after(jiffies, dev->jstart + (1 * HZ))) { 7108c2ecf20Sopenharmony_ci printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n"); 7118c2ecf20Sopenharmony_ci ppa_fail(dev, DID_BUS_BUSY); 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci } else { 7148c2ecf20Sopenharmony_ci ppa_disconnect(dev); 7158c2ecf20Sopenharmony_ci return 1; /* Try again in a jiffy */ 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci cmd->SCp.phase++; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci fallthrough; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci case 2: /* Phase 2 - We are now talking to the scsi bus */ 7238c2ecf20Sopenharmony_ci if (!ppa_select(dev, scmd_id(cmd))) { 7248c2ecf20Sopenharmony_ci ppa_fail(dev, DID_NO_CONNECT); 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci cmd->SCp.phase++; 7288c2ecf20Sopenharmony_ci fallthrough; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci case 3: /* Phase 3 - Ready to accept a command */ 7318c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 7328c2ecf20Sopenharmony_ci if (!(r_str(ppb) & 0x80)) 7338c2ecf20Sopenharmony_ci return 1; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (!ppa_send_command(cmd)) 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci cmd->SCp.phase++; 7388c2ecf20Sopenharmony_ci fallthrough; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci case 4: /* Phase 4 - Setup scatter/gather buffers */ 7418c2ecf20Sopenharmony_ci if (scsi_bufflen(cmd)) { 7428c2ecf20Sopenharmony_ci cmd->SCp.buffer = scsi_sglist(cmd); 7438c2ecf20Sopenharmony_ci cmd->SCp.this_residual = cmd->SCp.buffer->length; 7448c2ecf20Sopenharmony_ci cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 7458c2ecf20Sopenharmony_ci } else { 7468c2ecf20Sopenharmony_ci cmd->SCp.buffer = NULL; 7478c2ecf20Sopenharmony_ci cmd->SCp.this_residual = 0; 7488c2ecf20Sopenharmony_ci cmd->SCp.ptr = NULL; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; 7518c2ecf20Sopenharmony_ci cmd->SCp.phase++; 7528c2ecf20Sopenharmony_ci fallthrough; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci case 5: /* Phase 5 - Data transfer stage */ 7558c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 7568c2ecf20Sopenharmony_ci if (!(r_str(ppb) & 0x80)) 7578c2ecf20Sopenharmony_ci return 1; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci retv = ppa_completion(cmd); 7608c2ecf20Sopenharmony_ci if (retv == -1) 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci if (retv == 0) 7638c2ecf20Sopenharmony_ci return 1; 7648c2ecf20Sopenharmony_ci cmd->SCp.phase++; 7658c2ecf20Sopenharmony_ci fallthrough; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci case 6: /* Phase 6 - Read status/message */ 7688c2ecf20Sopenharmony_ci cmd->result = DID_OK << 16; 7698c2ecf20Sopenharmony_ci /* Check for data overrun */ 7708c2ecf20Sopenharmony_ci if (ppa_wait(dev) != (unsigned char) 0xf0) { 7718c2ecf20Sopenharmony_ci ppa_fail(dev, DID_ERROR); 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci if (ppa_in(dev, &l, 1)) { /* read status byte */ 7758c2ecf20Sopenharmony_ci /* Check for optional message byte */ 7768c2ecf20Sopenharmony_ci if (ppa_wait(dev) == (unsigned char) 0xf0) 7778c2ecf20Sopenharmony_ci ppa_in(dev, &h, 1); 7788c2ecf20Sopenharmony_ci cmd->result = 7798c2ecf20Sopenharmony_ci (DID_OK << 16) + (h << 8) + (l & STATUS_MASK); 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci return 0; /* Finished */ 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci default: 7848c2ecf20Sopenharmony_ci printk(KERN_ERR "ppa: Invalid scsi phase\n"); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci return 0; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int ppa_queuecommand_lck(struct scsi_cmnd *cmd, 7908c2ecf20Sopenharmony_ci void (*done) (struct scsi_cmnd *)) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(cmd->device->host); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (dev->cur_cmd) { 7958c2ecf20Sopenharmony_ci printk(KERN_ERR "PPA: bug in ppa_queuecommand\n"); 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci dev->failed = 0; 7998c2ecf20Sopenharmony_ci dev->jstart = jiffies; 8008c2ecf20Sopenharmony_ci dev->cur_cmd = cmd; 8018c2ecf20Sopenharmony_ci cmd->scsi_done = done; 8028c2ecf20Sopenharmony_ci cmd->result = DID_ERROR << 16; /* default return code */ 8038c2ecf20Sopenharmony_ci cmd->SCp.phase = 0; /* bus free */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci schedule_delayed_work(&dev->ppa_tq, 0); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci ppa_pb_claim(dev); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return 0; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(ppa_queuecommand) 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci/* 8158c2ecf20Sopenharmony_ci * Apparently the disk->capacity attribute is off by 1 sector 8168c2ecf20Sopenharmony_ci * for all disk drives. We add the one here, but it should really 8178c2ecf20Sopenharmony_ci * be done in sd.c. Even if it gets fixed there, this will still 8188c2ecf20Sopenharmony_ci * work. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_cistatic int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev, 8218c2ecf20Sopenharmony_ci sector_t capacity, int ip[]) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci ip[0] = 0x40; 8248c2ecf20Sopenharmony_ci ip[1] = 0x20; 8258c2ecf20Sopenharmony_ci ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); 8268c2ecf20Sopenharmony_ci if (ip[2] > 1024) { 8278c2ecf20Sopenharmony_ci ip[0] = 0xff; 8288c2ecf20Sopenharmony_ci ip[1] = 0x3f; 8298c2ecf20Sopenharmony_ci ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); 8308c2ecf20Sopenharmony_ci if (ip[2] > 1023) 8318c2ecf20Sopenharmony_ci ip[2] = 1023; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int ppa_abort(struct scsi_cmnd *cmd) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(cmd->device->host); 8398c2ecf20Sopenharmony_ci /* 8408c2ecf20Sopenharmony_ci * There is no method for aborting commands since Iomega 8418c2ecf20Sopenharmony_ci * have tied the SCSI_MESSAGE line high in the interface 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci switch (cmd->SCp.phase) { 8458c2ecf20Sopenharmony_ci case 0: /* Do not have access to parport */ 8468c2ecf20Sopenharmony_ci case 1: /* Have not connected to interface */ 8478c2ecf20Sopenharmony_ci dev->cur_cmd = NULL; /* Forget the problem */ 8488c2ecf20Sopenharmony_ci return SUCCESS; 8498c2ecf20Sopenharmony_ci default: /* SCSI command sent, can not abort */ 8508c2ecf20Sopenharmony_ci return FAILED; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic void ppa_reset_pulse(unsigned int base) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci w_dtr(base, 0x40); 8578c2ecf20Sopenharmony_ci w_ctr(base, 0x8); 8588c2ecf20Sopenharmony_ci udelay(30); 8598c2ecf20Sopenharmony_ci w_ctr(base, 0xc); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int ppa_reset(struct scsi_cmnd *cmd) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci ppa_struct *dev = ppa_dev(cmd->device->host); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (cmd->SCp.phase) 8678c2ecf20Sopenharmony_ci ppa_disconnect(dev); 8688c2ecf20Sopenharmony_ci dev->cur_cmd = NULL; /* Forget the problem */ 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_NORMAL); 8718c2ecf20Sopenharmony_ci ppa_reset_pulse(dev->base); 8728c2ecf20Sopenharmony_ci mdelay(1); /* device settle delay */ 8738c2ecf20Sopenharmony_ci ppa_disconnect(dev); 8748c2ecf20Sopenharmony_ci mdelay(1); /* device settle delay */ 8758c2ecf20Sopenharmony_ci return SUCCESS; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int device_check(ppa_struct *dev) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci /* This routine looks for a device and then attempts to use EPP 8818c2ecf20Sopenharmony_ci to send a command. If all goes as planned then EPP is available. */ 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci static u8 cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 8848c2ecf20Sopenharmony_ci int loop, old_mode, status, k, ppb = dev->base; 8858c2ecf20Sopenharmony_ci unsigned char l; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci old_mode = dev->mode; 8888c2ecf20Sopenharmony_ci for (loop = 0; loop < 8; loop++) { 8898c2ecf20Sopenharmony_ci /* Attempt to use EPP for Test Unit Ready */ 8908c2ecf20Sopenharmony_ci if ((ppb & 0x0007) == 0x0000) 8918c2ecf20Sopenharmony_ci dev->mode = PPA_EPP_32; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cisecond_pass: 8948c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_EPP_MAYBE); 8958c2ecf20Sopenharmony_ci /* Select SCSI device */ 8968c2ecf20Sopenharmony_ci if (!ppa_select(dev, loop)) { 8978c2ecf20Sopenharmony_ci ppa_disconnect(dev); 8988c2ecf20Sopenharmony_ci continue; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n", 9018c2ecf20Sopenharmony_ci loop, PPA_MODE_STRING[dev->mode]); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* Send SCSI command */ 9048c2ecf20Sopenharmony_ci status = 1; 9058c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 9068c2ecf20Sopenharmony_ci for (l = 0; (l < 6) && (status); l++) 9078c2ecf20Sopenharmony_ci status = ppa_out(dev, cmd, 1); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (!status) { 9108c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9118c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_EPP_MAYBE); 9128c2ecf20Sopenharmony_ci w_dtr(ppb, 0x40); 9138c2ecf20Sopenharmony_ci w_ctr(ppb, 0x08); 9148c2ecf20Sopenharmony_ci udelay(30); 9158c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 9168c2ecf20Sopenharmony_ci udelay(1000); 9178c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9188c2ecf20Sopenharmony_ci udelay(1000); 9198c2ecf20Sopenharmony_ci if (dev->mode == PPA_EPP_32) { 9208c2ecf20Sopenharmony_ci dev->mode = old_mode; 9218c2ecf20Sopenharmony_ci goto second_pass; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci return -EIO; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 9268c2ecf20Sopenharmony_ci k = 1000000; /* 1 Second */ 9278c2ecf20Sopenharmony_ci do { 9288c2ecf20Sopenharmony_ci l = r_str(ppb); 9298c2ecf20Sopenharmony_ci k--; 9308c2ecf20Sopenharmony_ci udelay(1); 9318c2ecf20Sopenharmony_ci } while (!(l & 0x80) && (k)); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci l &= 0xf0; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (l != 0xf0) { 9368c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9378c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_EPP_MAYBE); 9388c2ecf20Sopenharmony_ci ppa_reset_pulse(ppb); 9398c2ecf20Sopenharmony_ci udelay(1000); 9408c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9418c2ecf20Sopenharmony_ci udelay(1000); 9428c2ecf20Sopenharmony_ci if (dev->mode == PPA_EPP_32) { 9438c2ecf20Sopenharmony_ci dev->mode = old_mode; 9448c2ecf20Sopenharmony_ci goto second_pass; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci return -EIO; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9498c2ecf20Sopenharmony_ci printk(KERN_INFO "ppa: Communication established with ID %i using %s\n", 9508c2ecf20Sopenharmony_ci loop, PPA_MODE_STRING[dev->mode]); 9518c2ecf20Sopenharmony_ci ppa_connect(dev, CONNECT_EPP_MAYBE); 9528c2ecf20Sopenharmony_ci ppa_reset_pulse(ppb); 9538c2ecf20Sopenharmony_ci udelay(1000); 9548c2ecf20Sopenharmony_ci ppa_disconnect(dev); 9558c2ecf20Sopenharmony_ci udelay(1000); 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci return -ENODEV; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic int ppa_adjust_queue(struct scsi_device *device) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); 9648c2ecf20Sopenharmony_ci return 0; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic struct scsi_host_template ppa_template = { 9688c2ecf20Sopenharmony_ci .module = THIS_MODULE, 9698c2ecf20Sopenharmony_ci .proc_name = "ppa", 9708c2ecf20Sopenharmony_ci .show_info = ppa_show_info, 9718c2ecf20Sopenharmony_ci .write_info = ppa_write_info, 9728c2ecf20Sopenharmony_ci .name = "Iomega VPI0 (ppa) interface", 9738c2ecf20Sopenharmony_ci .queuecommand = ppa_queuecommand, 9748c2ecf20Sopenharmony_ci .eh_abort_handler = ppa_abort, 9758c2ecf20Sopenharmony_ci .eh_host_reset_handler = ppa_reset, 9768c2ecf20Sopenharmony_ci .bios_param = ppa_biosparam, 9778c2ecf20Sopenharmony_ci .this_id = -1, 9788c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 9798c2ecf20Sopenharmony_ci .can_queue = 1, 9808c2ecf20Sopenharmony_ci .slave_alloc = ppa_adjust_queue, 9818c2ecf20Sopenharmony_ci}; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/*************************************************************************** 9848c2ecf20Sopenharmony_ci * Parallel port probing routines * 9858c2ecf20Sopenharmony_ci ***************************************************************************/ 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic LIST_HEAD(ppa_hosts); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/* 9908c2ecf20Sopenharmony_ci * Finds the first available device number that can be alloted to the 9918c2ecf20Sopenharmony_ci * new ppa device and returns the address of the previous node so that 9928c2ecf20Sopenharmony_ci * we can add to the tail and have a list in the ascending order. 9938c2ecf20Sopenharmony_ci */ 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic inline ppa_struct *find_parent(void) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci ppa_struct *dev, *par = NULL; 9988c2ecf20Sopenharmony_ci unsigned int cnt = 0; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (list_empty(&ppa_hosts)) 10018c2ecf20Sopenharmony_ci return NULL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci list_for_each_entry(dev, &ppa_hosts, list) { 10048c2ecf20Sopenharmony_ci if (dev->dev_no != cnt) 10058c2ecf20Sopenharmony_ci return par; 10068c2ecf20Sopenharmony_ci cnt++; 10078c2ecf20Sopenharmony_ci par = dev; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return par; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic int __ppa_attach(struct parport *pb) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct Scsi_Host *host; 10168c2ecf20Sopenharmony_ci DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); 10178c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 10188c2ecf20Sopenharmony_ci ppa_struct *dev, *temp; 10198c2ecf20Sopenharmony_ci int ports; 10208c2ecf20Sopenharmony_ci int modes, ppb, ppb_hi; 10218c2ecf20Sopenharmony_ci int err = -ENOMEM; 10228c2ecf20Sopenharmony_ci struct pardev_cb ppa_cb; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL); 10258c2ecf20Sopenharmony_ci if (!dev) 10268c2ecf20Sopenharmony_ci return -ENOMEM; 10278c2ecf20Sopenharmony_ci dev->base = -1; 10288c2ecf20Sopenharmony_ci dev->mode = PPA_AUTODETECT; 10298c2ecf20Sopenharmony_ci dev->recon_tmo = PPA_RECON_TMO; 10308c2ecf20Sopenharmony_ci init_waitqueue_head(&waiting); 10318c2ecf20Sopenharmony_ci temp = find_parent(); 10328c2ecf20Sopenharmony_ci if (temp) 10338c2ecf20Sopenharmony_ci dev->dev_no = temp->dev_no + 1; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci memset(&ppa_cb, 0, sizeof(ppa_cb)); 10368c2ecf20Sopenharmony_ci ppa_cb.private = dev; 10378c2ecf20Sopenharmony_ci ppa_cb.wakeup = ppa_wakeup; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci dev->dev = parport_register_dev_model(pb, "ppa", &ppa_cb, dev->dev_no); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (!dev->dev) 10428c2ecf20Sopenharmony_ci goto out; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* Claim the bus so it remembers what we do to the control 10458c2ecf20Sopenharmony_ci * registers. [ CTR and ECP ] 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_ci err = -EBUSY; 10488c2ecf20Sopenharmony_ci dev->waiting = &waiting; 10498c2ecf20Sopenharmony_ci prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); 10508c2ecf20Sopenharmony_ci if (ppa_pb_claim(dev)) 10518c2ecf20Sopenharmony_ci schedule_timeout(3 * HZ); 10528c2ecf20Sopenharmony_ci if (dev->wanted) { 10538c2ecf20Sopenharmony_ci printk(KERN_ERR "ppa%d: failed to claim parport because " 10548c2ecf20Sopenharmony_ci "a pardevice is owning the port for too long " 10558c2ecf20Sopenharmony_ci "time!\n", pb->number); 10568c2ecf20Sopenharmony_ci ppa_pb_dismiss(dev); 10578c2ecf20Sopenharmony_ci dev->waiting = NULL; 10588c2ecf20Sopenharmony_ci finish_wait(&waiting, &wait); 10598c2ecf20Sopenharmony_ci goto out1; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci dev->waiting = NULL; 10628c2ecf20Sopenharmony_ci finish_wait(&waiting, &wait); 10638c2ecf20Sopenharmony_ci ppb = dev->base = dev->dev->port->base; 10648c2ecf20Sopenharmony_ci ppb_hi = dev->dev->port->base_hi; 10658c2ecf20Sopenharmony_ci w_ctr(ppb, 0x0c); 10668c2ecf20Sopenharmony_ci modes = dev->dev->port->modes; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* Mode detection works up the chain of speed 10698c2ecf20Sopenharmony_ci * This avoids a nasty if-then-else-if-... tree 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_ci dev->mode = PPA_NIBBLE; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (modes & PARPORT_MODE_TRISTATE) 10748c2ecf20Sopenharmony_ci dev->mode = PPA_PS2; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (modes & PARPORT_MODE_ECP) { 10778c2ecf20Sopenharmony_ci w_ecr(ppb_hi, 0x20); 10788c2ecf20Sopenharmony_ci dev->mode = PPA_PS2; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) 10818c2ecf20Sopenharmony_ci w_ecr(ppb_hi, 0x80); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* Done configuration */ 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci err = ppa_init(dev); 10868c2ecf20Sopenharmony_ci ppa_pb_release(dev); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (err) 10898c2ecf20Sopenharmony_ci goto out1; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* now the glue ... */ 10928c2ecf20Sopenharmony_ci if (dev->mode == PPA_NIBBLE || dev->mode == PPA_PS2) 10938c2ecf20Sopenharmony_ci ports = 3; 10948c2ecf20Sopenharmony_ci else 10958c2ecf20Sopenharmony_ci ports = 8; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci err = -ENOMEM; 11008c2ecf20Sopenharmony_ci host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); 11018c2ecf20Sopenharmony_ci if (!host) 11028c2ecf20Sopenharmony_ci goto out1; 11038c2ecf20Sopenharmony_ci host->io_port = pb->base; 11048c2ecf20Sopenharmony_ci host->n_io_port = ports; 11058c2ecf20Sopenharmony_ci host->dma_channel = -1; 11068c2ecf20Sopenharmony_ci host->unique_id = pb->number; 11078c2ecf20Sopenharmony_ci *(ppa_struct **)&host->hostdata = dev; 11088c2ecf20Sopenharmony_ci dev->host = host; 11098c2ecf20Sopenharmony_ci list_add_tail(&dev->list, &ppa_hosts); 11108c2ecf20Sopenharmony_ci err = scsi_add_host(host, NULL); 11118c2ecf20Sopenharmony_ci if (err) 11128c2ecf20Sopenharmony_ci goto out2; 11138c2ecf20Sopenharmony_ci scsi_scan_host(host); 11148c2ecf20Sopenharmony_ci return 0; 11158c2ecf20Sopenharmony_ciout2: 11168c2ecf20Sopenharmony_ci list_del_init(&dev->list); 11178c2ecf20Sopenharmony_ci scsi_host_put(host); 11188c2ecf20Sopenharmony_ciout1: 11198c2ecf20Sopenharmony_ci parport_unregister_device(dev->dev); 11208c2ecf20Sopenharmony_ciout: 11218c2ecf20Sopenharmony_ci kfree(dev); 11228c2ecf20Sopenharmony_ci return err; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_cistatic void ppa_attach(struct parport *pb) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci __ppa_attach(pb); 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic void ppa_detach(struct parport *pb) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci ppa_struct *dev; 11338c2ecf20Sopenharmony_ci list_for_each_entry(dev, &ppa_hosts, list) { 11348c2ecf20Sopenharmony_ci if (dev->dev->port == pb) { 11358c2ecf20Sopenharmony_ci list_del_init(&dev->list); 11368c2ecf20Sopenharmony_ci scsi_remove_host(dev->host); 11378c2ecf20Sopenharmony_ci scsi_host_put(dev->host); 11388c2ecf20Sopenharmony_ci parport_unregister_device(dev->dev); 11398c2ecf20Sopenharmony_ci kfree(dev); 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic struct parport_driver ppa_driver = { 11468c2ecf20Sopenharmony_ci .name = "ppa", 11478c2ecf20Sopenharmony_ci .match_port = ppa_attach, 11488c2ecf20Sopenharmony_ci .detach = ppa_detach, 11498c2ecf20Sopenharmony_ci .devmodel = true, 11508c2ecf20Sopenharmony_ci}; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic int __init ppa_driver_init(void) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION); 11558c2ecf20Sopenharmony_ci return parport_register_driver(&ppa_driver); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic void __exit ppa_driver_exit(void) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci parport_unregister_driver(&ppa_driver); 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cimodule_init(ppa_driver_init); 11648c2ecf20Sopenharmony_cimodule_exit(ppa_driver_exit); 11658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1166