11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* $Id$ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1993/03/31 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/kernel/aha1740.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based loosely on aha1542.c which is 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1992 Tommy Thorn and 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modified by Eric Youngdale 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is aha1740.c, written and 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1992,1993 Brad McLean 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * brad@saturn.gaylord.com or brad@bradpc.gaylord.com. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Modifications to makecode and queuecommand 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for proper handling of multiple devices courteously 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided by Michael Weller, March, 1993 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Multiple adapter support, extended translation detection, 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * update to current scsi subsystem changes, proc fs support, 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * working (!) module support based on patches from Andreas Arens, 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aha1740_makecode may still need even more work 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if it doesn't work for your devices, take a look. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 25fa195afe4ad3f6d85a9b7cc236ae85c05ca8db03Alan Cox * Reworked for new_eh and new locking by Alan Cox <alan@lxorguk.ukuu.org.uk> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Converted to EISA and generic DMA APIs by Marc Zyngier 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * <maz@wild-wind.fr.eu.org>, 4/2003. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Shared interrupt support added by Rask Ingemann Lambertsen 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * <rask@sygehus.dk>, 10/2003 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For the avoidance of doubt the "preferred form" of this code is one which 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is in an open non patent encumbered format. Where cryptographic key signing 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * forms part of the process of creating an executable the information 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including keys needed to generate an equivalently functional executable 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are deemed to be part of the source code. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stat.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/eisa.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 535a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "scsi.h" 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aha1740.h" 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IT WORK, THEN: 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEB(x) x 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEB(x) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aha1740_hostdata { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct eisa_device *edev; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int translation; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int last_ecb_used; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t ecb_dma_addr; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecb ecb[AHA1740_ECBS]; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aha1740_sg { 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_chain sg_chain[AHA1740_SCATTER]; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t sg_dma_addr; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t buf_dma_addr; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dma) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *hdata = HOSTDATA (host); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t offset; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = dma - hdata->ecb_dma_addr; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *hdata = HOSTDATA (host); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t offset; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = (char *) cpu - (char *) hdata->ecb; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return hdata->ecb_dma_addr + offset; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer, 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char **start, off_t offset, 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int length, int inout) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *host; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inout) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return-ENOSYS; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = HOSTDATA(shpnt); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n" 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Extended translation %sabled.\n", 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->io_port, shpnt->irq, host->edev->slot, 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->translation ? "en" : "dis"); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset > len) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *start = buffer; 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *start = buffer + offset; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= offset; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > length) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = length; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_makecode(unchar *sense, unchar *status) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct statusword 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort don:1, /* Command Done - No Error */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds du:1, /* Data underrun */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds :1, qf:1, /* Queue full */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc:1, /* Specification Check */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dor:1, /* Data overrun */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ch:1, /* Chaining Halted */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr:1, /* Interrupt issued */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds asa:1, /* Additional Status Available */ 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sns:1, /* Sense information Stored */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds :1, ini:1, /* Initialization Required */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds me:1, /* Major error or exception */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds :1, eca:1, /* Extended Contingent alliance */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds :1; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } status_word; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval = DID_OK; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status_word = * (struct statusword *) status; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("makecode from %x,%x,%x,%x %x,%x,%x,%x", 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status[0], status[1], status[2], status[3], 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sense[0], sense[1], sense[2], sense[3]); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!status_word.don) { /* Anything abnormal was detected */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (status[1]&0x18) || status_word.sc ) { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*Additional info available*/ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Use the supplied info for further diagnostics */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ( status[2] ) { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x12: 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( status_word.dor ) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval=DID_ERROR; /* It's an Overrun */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If not overrun, assume underrun and 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ignore it! */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x00: /* No info, assume no error, should 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not occur */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x11: 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x21: 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval=DID_TIME_OUT; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0a: 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval=DID_BAD_TARGET; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x04: 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x05: 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval=DID_ABORT; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Either by this driver or the 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AHA1740 itself */ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval=DID_ERROR; /* No further 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * diagnostics 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * possible */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Michael suggests, and Brad concurs: */ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( status_word.qf ) { 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = DID_TIME_OUT; /* forces a redo */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* I think this specific one should 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not happen -Brad */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740.c: WARNING: AHA1740 queue overflow!\n"); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( status[0]&0x60 ) { 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Didn't find a better error */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = DID_ERROR; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* In any other case return DID_OK so for example 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CONDITION_CHECKS make it through to the appropriate 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device driver */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Under all circumstances supply the target status -Michael */ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return status[3] | retval << 16; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_test_port(unsigned int base) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( inb(PORTADR(base)) & PORTADDR_ENH ) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; /* Okay, we're all set */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n"); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A "high" level interrupt handler */ 2267d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t aha1740_intr_handle(int irq, void *dev_id) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *host = (struct Scsi_Host *) dev_id; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*my_done)(Scsi_Cmnd *); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int errstatus, adapstat; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int number_serviced; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ecb *ecbptr; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Scsi_Cmnd *SCtmp; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int base; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_sg *sgptr; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct eisa_device *edev; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("aha1740.c: Irq from unknown host!\n"); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(host->host_lock, flags); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = host->io_port; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds number_serviced = 0; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds edev = HOSTDATA(host)->edev; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(inb(G2STAT(base)) & G2STAT_INTPEND) { 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = 1; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740_intr top of loop.\n")); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapstat = inb(G2INTST(base)); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base))); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ( adapstat & G2INTST_MASK ) { 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_CCBRETRY: 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_CCBERROR: 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_CCBGOOD: 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Host Ready -> Mailbox in complete */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(G2CNTRL_HRDY,G2CNTRL(base)); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ecbptr) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n", 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(G2STAT(base)),adapstat, 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(G2INTST(base)), number_serviced++); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCtmp = ecbptr->SCpnt; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SCtmp) { 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n", 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(G2STAT(base)),adapstat, 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(G2INTST(base)), number_serviced++); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = (struct aha1740_sg *) SCtmp->host_scribble; 274c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori scsi_dma_unmap(SCtmp); 275c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the sg block */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_free_coherent (&edev->dev, 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (struct aha1740_sg), 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCtmp->host_scribble, 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr->sg_dma_addr); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fetch the sense data, and tuck it away, in 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the required slot. The Adaptec 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds automatically fetches it, and there is no 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds guarantee that we will still have it in the 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdb when we come back */ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(SCtmp->sense_buffer, ecbptr->sense, 289b80ca4f7ee36c26d300c5a8f429e73372d153379FUJITA Tomonori SCSI_SENSE_BUFFERSIZE); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds errstatus = 0; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(if (errstatus) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740_intr_handle: returning %6x\n", 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds errstatus)); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCtmp->result = errstatus; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_done = ecbptr->done; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ecbptr,0,sizeof(struct ecb)); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( my_done ) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds my_done(SCtmp); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_HARDFAIL: 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ALERT "aha1740 hardware failure!\n"); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("aha1740.c"); /* Goodbye */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_ASNEVENT: 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n", 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds adapstat, 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(MBOXIN0(base)), 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(MBOXIN1(base)), 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(MBOXIN2(base)), 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(MBOXIN3(base))); /* Say What? */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Host Ready -> Mailbox in complete */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(G2CNTRL_HRDY,G2CNTRL(base)); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_CMDGOOD: 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set immediate command success flag here: */ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case G2INTST_CMDERROR: 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set immediate command failure flag here: */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds number_serviced++; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(host->host_lock, flags); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 333f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unchar direction; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unchar *cmd = (unchar *) SCpnt->cmnd; 337422c0d61d591cbfb70f029e13505fb437e169d68Jeff Garzik unchar target = scmd_id(SCpnt); 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t sg_dma; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_sg *sgptr; 342c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori int ecbno, nseg; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(int i); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(*cmd == REQUEST_SENSE) { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->result = 0; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done(SCpnt); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*cmd == READ_10 || *cmd == WRITE_10) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = xscsi2int(cmd+2); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (*cmd == READ_6 || *cmd == WRITE_6) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = scsi2int(cmd+2); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = -1; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target, *cmd, i, bufflen); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("scsi cmd:"); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* locate an available ecb */ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(SCpnt->device->host->host_lock, flags); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecbno = host->last_ecb_used + 1; /* An optimization */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecbno >= AHA1740_ECBS) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecbno = 0; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->ecb[ecbno].cmdw) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecbno++; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecbno >= AHA1740_ECBS) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecbno = 0; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (ecbno != host->last_ecb_used); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host->ecb[ecbno].cmdw) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("Unable to find empty ecb for aha1740.\n"); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds doubles as reserved flag */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->last_ecb_used = ecbno; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Sending command (%d %x)...", ecbno, done); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Descriptor Block 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Length */ 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds direction = 0; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*cmd == READ_10 || *cmd == READ_6) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds direction = 1; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (*cmd == WRITE_10 || *cmd == WRITE_6) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds direction = 0; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev, 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (struct aha1740_sg), 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &sg_dma, GFP_ATOMIC); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(SCpnt->host_scribble == NULL) { 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n"); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr = (struct aha1740_sg *) SCpnt->host_scribble; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sgptr->sg_dma_addr = sg_dma; 412c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori 413c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori nseg = scsi_dma_map(SCpnt); 414c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori BUG_ON(nseg < 0); 415c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori if (nseg) { 416c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori struct scatterlist *sg; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_chain * cptr; 418c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori int i; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(unsigned char * ptr); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].sg = 1; /* SCSI Initiator Command 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * w/scatter-gather*/ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cptr = sgptr->sg_chain; 424c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori scsi_for_each_sg(SCpnt, sg, nseg, i) { 425c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori cptr[i].datalen = sg_dma_len (sg); 426c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori cptr[i].dataptr = sg_dma_address (sg); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 428c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].dataptr = sg_dma; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("cptr %x: ",cptr); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr = (unsigned char *) cptr; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=0;i<24;i++) printk("%02x ", ptr[i]); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 436c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori host->ecb[ecbno].datalen = 0; 437c66cc13c16377d177d8887f15a3cc42ab3866f57FUJITA Tomonori host->ecb[ecbno].dataptr = 0; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].lun = SCpnt->device->lun; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].ses = 1; /* Suppress underrun errors */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].dir = direction; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].senselen = 12; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host, 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].sense); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host, 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].status); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].done = done; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb[ecbno].SCpnt = SCpnt; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740_command: sending.. "); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (done) { 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The Adaptec Spec says the card is so fast that the loops 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds will only be executed once in the code below. Even if this 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was true with the fastest processors when the spec was 46325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi written, it doesn't seem to be true with today's fast 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds processors. We print a warning if the code is executed more 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds often than LOOPCNT_WARN. If this happens, it should be 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds investigated. If the count reaches LOOPCNT_MAX, we assume 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds something is broken; since there is no way to return an 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error (the return value is ignored by the mid-level scsi 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds layer) we have to panic (and maybe that's the best thing we 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds can do then anyhow). */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPCNT_WARN 10 /* excessive mbxout wait -> syslog-msg */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPCNT_MAX 1000000 /* mbxout deadlock -> panic() after ~ 2 sec. */ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loopcnt; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int base = SCpnt->device->host->io_port; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740[%d] critical section\n",ecbno)); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(SCpnt->device->host->host_lock, flags); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (loopcnt = 0; ; loopcnt++) { 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(G2STAT(base)) & G2STAT_MBXOUT) break; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loopcnt == LOOPCNT_WARN) { 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740[%d]_mbxout wait!\n",ecbno); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loopcnt == LOOPCNT_MAX) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("aha1740.c: mbxout busy!\n"); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno), 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MBOXOUT0(base)); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (loopcnt = 0; ; loopcnt++) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loopcnt == LOOPCNT_WARN) { 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("aha1740[%d]_attn wait!\n",ecbno); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loopcnt == LOOPCNT_MAX) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("aha1740.c: attn wait failed!\n"); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */ 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740[%d] request queued.\n",ecbno)); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n"); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 505f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzikstatic DEF_SCSI_QCMD(aha1740_queuecommand) 506f281233d3eba15fb225d21ae2e228fd4553d824aJeff Garzik 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Query the board for its irq_level and irq_type. Nothing else matters 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in enhanced mode on an EISA bus. */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void aha1740_getconfig(unsigned int base, unsigned int *irq_level, 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int *irq_type, 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int *translation) 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 }; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *irq_level = intab[inb(INTDEF(base)) & 0x7]; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *irq_type = (inb(INTDEF(base)) & 0x8) >> 3; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *translation = inb(RESV1(base)) & 0x1; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(inb(INTDEF(base)) | 0x10, INTDEF(base)); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_biosparam(struct scsi_device *sdev, 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct block_device *dev, 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sector_t capacity, int* ip) 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size = capacity; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int extended = HOSTDATA(sdev->host)->translation; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740_biosparam\n")); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (extended && (ip[2] > 1024)) { 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 255; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 63; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = size / (255 * 63); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[0] = 64; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[1] = 32; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ip[2] = size >> 11; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_eh_abort_handler (Scsi_Cmnd *dummy) 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From Alan Cox : 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The AHA1740 has firmware handled abort/reset handling. The "head in 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sand" kernel code is correct for once 8) 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So we define a dummy handler just to keep the kernel SCSI code as 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * quiet as possible... 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 556d0be4a7d29ad0bd3ce2209dd9e46d410b632db59Christoph Hellwigstatic struct scsi_host_template aha1740_template = { 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .module = THIS_MODULE, 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_name = "aha1740", 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_info = aha1740_proc_info, 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "Adaptec 174x (EISA)", 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .queuecommand = aha1740_queuecommand, 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bios_param = aha1740_biosparam, 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .can_queue = AHA1740_ECBS, 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .this_id = 7, 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .sg_tablesize = AHA1740_SCATTER, 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .cmd_per_lun = AHA1740_CMDLUN, 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .eh_abort_handler = aha1740_eh_abort_handler, 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int aha1740_probe (struct device *dev) 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 57308157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik int slotbase, rc; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int irq_level, irq_type, translation; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Scsi_Host *shpnt; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *host; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct eisa_device *edev = to_eisa_device (dev); 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740_probe: \n")); 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!aha1740_test_port(slotbase)) 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_release_region; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((inb(G2STAT(slotbase)) & 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) { 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the card isn't ready, hard reset it */ 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(G2CNTRL_HRST, G2CNTRL(slotbase)); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, G2CNTRL(slotbase)); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n", 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds edev->slot, slotbase, irq_level, irq_type ? "edge" : "level"); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "aha174x: Extended translation %sabled.\n", 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds translation ? "en" : "dis"); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt = scsi_host_alloc(&aha1740_template, 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(struct aha1740_hostdata)); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(shpnt == NULL) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_release_region; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->base = 0; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->io_port = slotbase; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->n_io_port = SLOTSIZE; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->irq = irq_level; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shpnt->dma_channel = 0xff; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host = HOSTDATA(shpnt); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->edev = edev; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->translation = translation; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb, 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (host->ecb), 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA_BIDIRECTIONAL); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!host->ecb_dma_addr) { 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n"); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_unregister (shpnt); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_host_put; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level)); 6201d6f359a2e06296418481239f8054a878f36e819Thomas Gleixner if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED, 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "aha1740",shpnt)) { 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n", 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_level); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_unmap; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eisa_set_drvdata (edev, shpnt); 62808157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik 62908157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik rc = scsi_add_host (shpnt, dev); 63008157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik if (rc) 63108157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik goto err_irq; 63208157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_scan_host (shpnt); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63608157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik err_irq: 63708157cd0787004e2ebf9ee8cc92257244da53848Jeff Garzik free_irq(irq_level, shpnt); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_unmap: 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_unmap_single (&edev->dev, host->ecb_dma_addr, 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (host->ecb), DMA_BIDIRECTIONAL); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_host_put: 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put (shpnt); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err_release_region: 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(slotbase, SLOTSIZE); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __devexit int aha1740_remove (struct device *dev) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 65178c55d76b84628862079351f77aa0f4aa3b65f58Greg Kroah-Hartman struct Scsi_Host *shpnt = dev_get_drvdata(dev); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct aha1740_hostdata *host = HOSTDATA (shpnt); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_remove_host(shpnt); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq (shpnt->irq, shpnt); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_unmap_single (dev, host->ecb_dma_addr, 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof (host->ecb), DMA_BIDIRECTIONAL); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region (shpnt->io_port, SLOTSIZE); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scsi_host_put (shpnt); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct eisa_device_id aha1740_ids[] = { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ADP0000" }, /* 1740 */ 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ADP0001" }, /* 1740A */ 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ADP0002" }, /* 1742A */ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ADP0400" }, /* 1744 */ 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "" } 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 67307563c711fbc25389e58ab9c9f0b9de2fce56760Michael TokarevMODULE_DEVICE_TABLE(eisa, aha1740_ids); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct eisa_driver aha1740_driver = { 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = aha1740_ids, 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "aha1740", 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = aha1740_probe, 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p (aha1740_remove), 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __init int aha1740_init (void) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eisa_driver_register (&aha1740_driver); 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __exit void aha1740_exit (void) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eisa_driver_unregister (&aha1740_driver); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (aha1740_init); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (aha1740_exit); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 698