11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ppa.c -- low level driver for the IOMEGA PPA3 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parallel port SCSI host adapter. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (The PPA3 is the embedded controller in the ZIP drive.) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) 1995,1996 Grant R. Guenther, grant@torque.net, 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 135a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 1868b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik#include <linux/delay.h> 1960c904ae5bded8bb71f7bff7d63f2a6959d2a8e4Marcelo Feitoza Parisi#include <linux/jiffies.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_reset_pulse(unsigned int base); 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct { 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pardevice *dev; /* Parport device entry */ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int base; /* Actual port address */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mode; /* Transfer mode */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cur_cmd; /* Current queued command */ 35c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct delayed_work ppa_tq; /* Polling interrupt stuff */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long jstart; /* Jiffies at start */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int failed:1; /* Failure flag */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned wanted:1; /* Parport sharing busy flag */ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t *waiting; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *host; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head list; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} ppa_struct; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ppa.h" 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline ppa_struct *ppa_dev(struct Scsi_Host *host) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return *(ppa_struct **)&host->hostdata; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(arbitration_lock); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void got_it(ppa_struct *dev) 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base = dev->dev->port->base; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->cur_cmd) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd->SCp.phase = 1; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(dev->waiting); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_wakeup(void *ref) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = (ppa_struct *) ref; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&arbitration_lock, flags); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->wanted) { 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_claim(dev->dev); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds got_it(dev); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wanted = 0; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&arbitration_lock, flags); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_pb_claim(ppa_struct *dev) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = 1; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&arbitration_lock, flags); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (parport_claim(dev->dev) == 0) { 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds got_it(dev); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wanted = res; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&arbitration_lock, flags); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_pb_dismiss(ppa_struct *dev) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int wanted; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&arbitration_lock, flags); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wanted = dev->wanted; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->wanted = 0; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&arbitration_lock, flags); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!wanted) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_release(dev->dev); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_pb_release(ppa_struct *dev) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_release(dev->dev); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start of Chipset kludges 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This is to give the ppa driver a way to modify the timings (and other 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parameters) by writing to the /proc/scsi/ppa/0 file. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Very simple method really... (To simple, no error checking :( ) 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reason: Kernel hackers HATE having to unload and reload modules for 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * testing... 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also gives a method to use a script to obtain optimum timings (TODO) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Virostatic inline int ppa_write_info(struct Scsi_Host *host, char *buffer, int length) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 123b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro ppa_struct *dev = ppa_dev(host); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long x; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = simple_strtoul(buffer + 5, NULL, 0); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = x; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return length; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = simple_strtoul(buffer + 10, NULL, 0); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->recon_tmo = x; 134cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_INFO "ppa: recon_tmo set to %ld\n", x); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return length; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 137cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_WARNING "ppa /proc: invalid variable\n"); 138cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox return -EINVAL; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Virostatic int ppa_show_info(struct seq_file *m, struct Scsi_Host *host) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(host); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro seq_printf(m, "Version : %s\n", PPA_VERSION); 146b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro seq_printf(m, "Parport : %s\n", dev->dev->port->name); 147b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro seq_printf(m, "Mode : %s\n", PPA_MODE_STRING[dev->mode]); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PPA_DEBUG > 0 149b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro seq_printf(m, "recon_tmo : %lu\n", dev->recon_tmo); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 151b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro return 0; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int device_check(ppa_struct *dev); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PPA_DEBUG > 0 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ 158cadbd4a5e36dde7e6c49b587b2c419103c0b7218Harvey Harrison y, __func__, __LINE__); ppa_fail_func(x,y); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_fail_func(ppa_struct *dev, int error_code) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_fail(ppa_struct *dev, int error_code) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we fail a device then we trash status / message bytes */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->cur_cmd) { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd->result = error_code << 16; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->failed = 1; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the high bit to be set. 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In principle, this could be tied to an interrupt, but the adapter 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * doesn't appear to be designed to support interrupts. We spin on 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the 0x80 ready bit. 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char ppa_wait(ppa_struct *dev) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int k; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char r; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = PPA_SPIN_TMO; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for bit 6 and 7 - PJC */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (r = r_str(ppb); ((r & 0xc0) != 0xc0) && (k); k--) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = r_str(ppb); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return some status information. 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Semantics: 0xc0 = ZIP wants more data 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xd0 = ZIP wants to send more data 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xe0 = ZIP is expecting SCSI command data 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0xf0 = end of transfer, ZIP is sending status 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (k) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (r & 0xf0); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Counter expired - Time out occurred */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_TIME_OUT); 203cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_WARNING "ppa timeout in ppa_wait\n"); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; /* command timed out */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear EPP Timeout Bit 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void epp_reset(unsigned short ppb) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = r_str(ppb); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_str(ppb, i); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_str(ppb, i & 0xfe); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for empty ECP fifo (if we are in ECP fifo mode only) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ecp_sync(ppa_struct *dev) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, ppb_hi = dev->dev->port->base_hi; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppb_hi == 0) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 100; i++) { 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r_ecr(ppb_hi) & 0x01) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(5); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 235cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n"); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_byte_out(unsigned short base, const char *buffer, int len) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = len; i; i--) { 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(base, *buffer++); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0xe); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0xc); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* All went well - we hope! */ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_byte_in(unsigned short base, char *buffer, int len) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = len; i; i--) { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buffer++ = r_dtr(base); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0x27); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0x25); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* All went well - we hope! */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_nibble_in(unsigned short base, char *buffer, int len) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; len; len--) { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char h; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0x4); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds h = r_str(base) & 0xf0; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0x6); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buffer++ = h | ((r_str(base) & 0xf0) >> 4); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* All went well - we hope! */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_out(ppa_struct *dev, char *buffer, int len) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = ppa_wait(dev); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r & 0x50) != 0x40) { 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_ERROR); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dev->mode) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_NIBBLE: 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_PS2: 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8 bit output, with a loop */ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = ppa_byte_out(ppb, buffer, len); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_32: 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_16: 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_8: 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epp_reset(ppb); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x4); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SCSI_IZIP_EPP16 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(((long) buffer | len) & 0x01)) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsw(ppb + 4, buffer, len >> 1); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(((long) buffer | len) & 0x03)) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsl(ppb + 4, buffer, len >> 2); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsb(ppb + 4, buffer, len); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = !(r_str(ppb) & 0x01); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecp_sync(dev); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 315cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "PPA: bug in ppa_out()\n"); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = 0; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_in(ppa_struct *dev, char *buffer, int len) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = ppa_wait(dev); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r & 0x50) != 0x50) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_ERROR); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dev->mode) { 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_NIBBLE: 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4 bit input, with a loop */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = ppa_nibble_in(ppb, buffer, len); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_PS2: 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8 bit input, with a loop */ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x25); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = ppa_byte_in(ppb, buffer, len); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x4); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_32: 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_16: 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPA_EPP_8: 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds epp_reset(ppb); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x24); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SCSI_IZIP_EPP16 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(((long) buffer | len) & 0x01)) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insw(ppb + 4, buffer, len >> 1); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(((long) buffer | len) & 0x03)) 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insl(ppb + 4, buffer, len >> 2); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insb(ppb + 4, buffer, len); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x2c); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = !(r_str(ppb) & 0x01); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x2c); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecp_sync(dev); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 368cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "PPA: bug in ppa_ins()\n"); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = 0; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* end of ppa_io.h */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_d_pulse(unsigned short ppb, unsigned char b) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(ppb, b); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xe); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x4); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_disconnect(ppa_struct *dev) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_d_pulse(ppb, 0); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_d_pulse(ppb, 0x3c); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_d_pulse(ppb, 0x20); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_d_pulse(ppb, 0xf); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_c_pulse(unsigned short ppb, unsigned char b) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(ppb, b); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x4); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x6); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x4); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void ppa_connect(ppa_struct *dev, int flag) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_c_pulse(ppb, 0); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_c_pulse(ppb, 0x3c); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_c_pulse(ppb, 0x20); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((flag == CONNECT_EPP_MAYBE) && IN_EPP_MODE(dev->mode)) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_c_pulse(ppb, 0xcf); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_c_pulse(ppb, 0x8f); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_select(ppa_struct *dev, int target) 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int k; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bit 6 (0x40) is the device selected bit. 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First we must wait till the current device goes off line... 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = PPA_SELECT_TMO; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k--; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((r_str(ppb) & 0x40) && (k)); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!k) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(ppb, (1 << target)); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xe); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(ppb, 0x80); /* This is NOT the initator */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x8); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = PPA_SELECT_TMO; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k--; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!(r_str(ppb) & 0x40) && (k)); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!k) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is based on a trace of what the Iomega DOS 'guest' driver does. 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I've tried several different kinds of parallel ports with guest and 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * coded this to react in the same ways that it does. 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The return value from this function is just a hint about where the 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handshaking failed. 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_init(ppa_struct *dev) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retv; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_NORMAL); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv = 2; /* Failed */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xe); 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r_str(ppb) & 0x08) == 0x08) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv--; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r_str(ppb) & 0x08) == 0x00) 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv--; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!retv) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_reset_pulse(ppb); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); /* Allow devices to settle down */ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); /* Another delay to allow devices to settle */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retv) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return device_check(dev); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int ppa_send_command(struct scsi_cmnd *cmd) 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(cmd->device->host); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int k; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(dev->base, 0x0c); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = 0; k < cmd->cmd_len; k++) 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ppa_out(dev, &cmd->cmnd[k], 1)) 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The bulk flag enables some optimisations in the data transfer loops, 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it should be true for any command that transfers data in integral 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * numbers of sectors. 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver appears to remain stable if we speed up the parallel port 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i/o in this function, but not elsewhere. 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_completion(struct scsi_cmnd *cmd) 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Return codes: 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -1 Error 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 Told to schedule 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 Finished data transfer 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(cmd->device->host); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long start_jiffies = jiffies; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char r, v; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fast, bulk, status; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = cmd->cmnd[0]; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bulk = ((v == READ_6) || 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (v == READ_10) || (v == WRITE_6) || (v == WRITE_10)); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We only get here if the drive is ready to comunicate, 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hence no need for a full ppa_wait. 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = (r_str(ppb) & 0xf0); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (r != (unsigned char) 0xf0) { 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have been running for more than a full timer tick 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then take a rest. 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, start_jiffies + 1)) 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd->SCp.this_residual <= 0)) { 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_ERROR); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; /* ERROR_RETURN */ 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* On some hardware we have SCSI disconnected (6th bit low) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for about 100usecs. It is too expensive to wait a 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tick on every loop so we busy wait for no more than 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 500usecs to give the drive a chance first. We do not 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * change things for "normal" hardware since generally 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the 6th bit is always high. 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This makes the CPU load higher on some hardware 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but otherwise we can not get more than 50K/secs 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on this problem hardware. 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r & 0xc0) != 0xc0) { 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for reconnection should be no more than 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * jiffy/2 = 5ms = 5000 loops 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long k = dev->recon_tmo; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k--) 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!k) 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* determine if we should use burst I/O */ 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? PPA_BURST_SIZE : 1; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r == (unsigned char) 0xc0) 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ppa_out(dev, cmd->SCp.ptr, fast); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ppa_in(dev, cmd->SCp.ptr, fast); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.ptr += fast; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.this_residual -= fast; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!status) { 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_BUS_BUSY); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; /* ERROR_RETURN */ 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->SCp.buffer && !cmd->SCp.this_residual) { 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* if scatter/gather, advance to the next segment */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->SCp.buffers_residual--) { 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.buffer++; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.this_residual = 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.buffer->length; 59545711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now check to see if the drive is ready to comunicate */ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = (r_str(ppb) & 0xf0); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If not, drop back down to the scheduler and wait a timer tick */ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(r & 0x80)) 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* FINISH_RETURN */ 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since the PPA itself doesn't generate interrupts, we use 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the scheduler's task queue to generate a stream of call-backs and 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * complete the request when the drive is ready. 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 612c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void ppa_interrupt(struct work_struct *work) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 614c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd = dev->cur_cmd; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cmd) { 618cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "PPA: bug in ppa_interrupt\n"); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppa_engine(dev, cmd)) { 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_delayed_work(&dev->ppa_tq, 1); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Command must of completed hence it is safe to let go... */ 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PPA_DEBUG > 0 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ((cmd->result >> 16) & 0xff) { 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_OK: 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_NO_CONNECT: 631cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", cmd->device->target); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_BUS_BUSY: 634cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n"); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_TIME_OUT: 637cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: unknown timeout\n"); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_ABORT: 640cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: told to abort\n"); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_PARITY: 643cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: parity error (???)\n"); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_ERROR: 646cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: internal driver error\n"); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_RESET: 649cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_DEBUG "ppa: told to reset device\n"); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DID_BAD_INTR: 652cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_WARNING "ppa: bad interrupt (???)\n"); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 655cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_WARNING "ppa: bad return code (%02x)\n", 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cmd->result >> 16) & 0xff); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->SCp.phase > 1) 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_pb_dismiss(dev); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd = NULL; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->scsi_done(cmd); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short ppb = dev->base; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char l = 0, h = 0; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retv; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First check for any errors that may of occurred 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Here we check for internal errors 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->failed) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd->SCp.phase) { 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* Phase 0 - Waiting for parport */ 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, dev->jstart + HZ)) { 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We waited more than a second 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for parport to call us 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_BUS_BUSY); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* wait until ppa_wakeup claims parport */ 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: /* Phase 1 - Connected */ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { /* Perform a sanity check for cable unplugged */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retv = 2; /* Failed */ 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_EPP_MAYBE); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xe); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r_str(ppb) & 0x08) == 0x08) 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv--; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0xc); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((r_str(ppb) & 0x08) == 0x00) 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv--; 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retv) { 70860c904ae5bded8bb71f7bff7d63f2a6959d2a8e4Marcelo Feitoza Parisi if (time_after(jiffies, dev->jstart + (1 * HZ))) { 709cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n"); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_BUS_BUSY); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* Try again in a jiffy */ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase++; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: /* Phase 2 - We are now talking to the scsi bus */ 721422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik if (!ppa_select(dev, scmd_id(cmd))) { 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_NO_CONNECT); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase++; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: /* Phase 3 - Ready to accept a command */ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(r_str(ppb) & 0x80)) 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ppa_send_command(cmd)) 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase++; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 4: /* Phase 4 - Setup scatter/gather buffers */ 73757643c711c3759623e7ac651a4a418858cdaeae5Boaz Harrosh if (scsi_bufflen(cmd)) { 73857643c711c3759623e7ac651a4a418858cdaeae5Boaz Harrosh cmd->SCp.buffer = scsi_sglist(cmd); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 74045711f1af6eff1a6d010703b4862e0d2b9afd056Jens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.buffer = NULL; 74357643c711c3759623e7ac651a4a418858cdaeae5Boaz Harrosh cmd->SCp.this_residual = 0; 74457643c711c3759623e7ac651a4a418858cdaeae5Boaz Harrosh cmd->SCp.ptr = NULL; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 74657643c711c3759623e7ac651a4a418858cdaeae5Boaz Harrosh cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase++; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: /* Phase 5 - Data transfer stage */ 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(r_str(ppb) & 0x80)) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv = ppa_completion(cmd); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retv == -1) 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retv == 0) 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase++; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 6: /* Phase 6 - Read status/message */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->result = DID_OK << 16; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for data overrun */ 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppa_wait(dev) != (unsigned char) 0xf0) { 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_fail(dev, DID_ERROR); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppa_in(dev, &l, 1)) { /* read status byte */ 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for optional message byte */ 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppa_wait(dev) == (unsigned char) 0xf0) 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_in(dev, &h, 1); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->result = 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (DID_OK << 16) + (h << 8) + (l & STATUS_MASK); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; /* Finished */ 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 779cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "ppa: Invalid scsi phase\n"); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 784f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic int ppa_queuecommand_lck(struct scsi_cmnd *cmd, 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*done) (struct scsi_cmnd *)) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(cmd->device->host); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->cur_cmd) { 790cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_ERR "PPA: bug in ppa_queuecommand\n"); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->failed = 0; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->jstart = jiffies; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd = cmd; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->scsi_done = done; 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->result = DID_ERROR << 16; /* default return code */ 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd->SCp.phase = 0; /* bus free */ 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 800c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells schedule_delayed_work(&dev->ppa_tq, 0); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_pb_claim(dev); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 807f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic DEF_SCSI_QCMD(ppa_queuecommand) 808f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzik 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Apparently the disk->capacity attribute is off by 1 sector 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for all disk drives. We add the one here, but it should really 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be done in sd.c. Even if it gets fixed there, this will still 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * work. 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev, 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t capacity, int ip[]) 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 0x40; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 0x20; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ip[2] > 1024) { 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 0xff; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 0x3f; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ip[2] > 1023) 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = 1023; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_abort(struct scsi_cmnd *cmd) 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(cmd->device->host); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is no method for aborting commands since Iomega 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have tied the SCSI_MESSAGE line high in the interface 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd->SCp.phase) { 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: /* Do not have access to parport */ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: /* Have not connected to interface */ 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd = NULL; /* Forget the problem */ 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SUCCESS; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* SCSI command sent, can not abort */ 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return FAILED; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_reset_pulse(unsigned int base) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(base, 0x40); 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0x8); 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(30); 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(base, 0xc); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ppa_reset(struct scsi_cmnd *cmd) 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev = ppa_dev(cmd->device->host); 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd->SCp.phase) 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->cur_cmd = NULL; /* Forget the problem */ 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_NORMAL); 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_reset_pulse(dev->base); 86968b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik mdelay(1); /* device settle delay */ 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 87168b3aa7c9805aee9005a8ca53c5e99177961fbb9Jeff Garzik mdelay(1); /* device settle delay */ 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SUCCESS; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int device_check(ppa_struct *dev) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This routine looks for a device and then attempts to use EPP 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to send a command. If all goes as planned then EPP is available. */ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 880cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox static u8 cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loop, old_mode, status, k, ppb = dev->base; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char l; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_mode = dev->mode; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (loop = 0; loop < 8; loop++) { 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Attempt to use EPP for Test Unit Ready */ 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ppb & 0x0007) == 0x0000) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = PPA_EPP_32; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 890cebadc5c97547aa8567ee2d628b187a34869b389Alan Coxsecond_pass: 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_EPP_MAYBE); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select SCSI device */ 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ppa_select(dev, loop)) { 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 897cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n", 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loop, PPA_MODE_STRING[dev->mode]); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send SCSI command */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = 1; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (l = 0; (l < 6) && (status); l++) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ppa_out(dev, cmd, 1); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!status) { 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_EPP_MAYBE); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_dtr(ppb, 0x40); 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x08); 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(30); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->mode == PPA_EPP_32) { 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = old_mode; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto second_pass; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = 1000000; /* 1 Second */ 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l = r_str(ppb); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k--; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1); 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (!(l & 0x80) && (k)); 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds l &= 0xf0; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (l != 0xf0) { 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_EPP_MAYBE); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_reset_pulse(ppb); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->mode == PPA_EPP_32) { 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = old_mode; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto second_pass; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 946cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_INFO "ppa: Communication established with ID %i using %s\n", 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loop, PPA_MODE_STRING[dev->mode]); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_connect(dev, CONNECT_EPP_MAYBE); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_reset_pulse(ppb); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_disconnect(dev); 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95878a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlapstatic int ppa_adjust_queue(struct scsi_device *device) 95978a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap{ 96078a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); 96178a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap return 0; 96278a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap} 96378a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct scsi_host_template ppa_template = { 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .module = THIS_MODULE, 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_name = "ppa", 967b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro .show_info = ppa_show_info, 968b7654914bb8059a9817f32f4c4d0e7f75a08b78aAl Viro .write_info = ppa_write_info, 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "Iomega VPI0 (ppa) interface", 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queuecommand = ppa_queuecommand, 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .eh_abort_handler = ppa_abort, 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .eh_bus_reset_handler = ppa_reset, 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .eh_host_reset_handler = ppa_reset, 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bios_param = ppa_biosparam, 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .this_id = -1, 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .sg_tablesize = SG_ALL, 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cmd_per_lun = 1, 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .can_queue = 1, 98078a904b65420e02bf964af6a83c1fd7a85e0b59dRandy.Dunlap .slave_alloc = ppa_adjust_queue, 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*************************************************************************** 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parallel port probing routines * 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ***************************************************************************/ 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(ppa_hosts); 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __ppa_attach(struct parport *pb) 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *host; 9927259f0d05d595b73ef312a082e628627c6414969Peter Zijlstra DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEFINE_WAIT(wait); 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ports; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int modes, ppb, ppb_hi; 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOMEM; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 999dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL); 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base = -1; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = PPA_AUTODETECT; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->recon_tmo = PPA_RECON_TMO; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&waiting); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, 0, dev); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev->dev) 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Claim the bus so it remembers what we do to the control 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registers. [ CTR and ECP ] 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->waiting = &waiting; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ppa_pb_claim(dev)) 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_timeout(3 * HZ); 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->wanted) { 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ppa%d: failed to claim parport because " 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "a pardevice is owning the port for too long " 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "time!\n", pb->number); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_pb_dismiss(dev); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->waiting = NULL; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finish_wait(&waiting, &wait); 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->waiting = NULL; 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finish_wait(&waiting, &wait); 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppb = dev->base = dev->dev->port->base; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppb_hi = dev->dev->port->base_hi; 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ctr(ppb, 0x0c); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds modes = dev->dev->port->modes; 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mode detection works up the chain of speed 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This avoids a nasty if-then-else-if-... tree 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = PPA_NIBBLE; 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (modes & PARPORT_MODE_TRISTATE) 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = PPA_PS2; 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (modes & PARPORT_MODE_ECP) { 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ecr(ppb_hi, 0x20); 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mode = PPA_PS2; 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_ecr(ppb_hi, 0x80); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Done configuration */ 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = ppa_init(dev); 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_pb_release(dev); 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now the glue ... */ 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->mode == PPA_NIBBLE || dev->mode == PPA_PS2) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports = 3; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ports = 8; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1065c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt); 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host) 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->io_port = pb->base; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->n_io_port = ports; 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->dma_channel = -1; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->unique_id = pb->number; 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(ppa_struct **)&host->hostdata = dev; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->host = host; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&dev->list, &ppa_hosts); 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = scsi_add_host(host, NULL); 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out2; 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_scan_host(host); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout2: 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init(&dev->list); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put(host); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1: 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_unregister_device(dev->dev); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dev); 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_attach(struct parport *pb) 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __ppa_attach(pb); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ppa_detach(struct parport *pb) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppa_struct *dev; 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(dev, &ppa_hosts, list) { 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->dev->port == pb) { 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del_init(&dev->list); 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_remove_host(dev->host); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put(dev->host); 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_unregister_device(dev->dev); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dev); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct parport_driver ppa_driver = { 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "ppa", 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .attach = ppa_attach, 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .detach = ppa_detach, 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ppa_driver_init(void) 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1121cebadc5c97547aa8567ee2d628b187a34869b389Alan Cox printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return parport_register_driver(&ppa_driver); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ppa_driver_exit(void) 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parport_unregister_driver(&ppa_driver); 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ppa_driver_init); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ppa_driver_exit); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1133