18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* aha152x.c -- Adaptec AHA-152x driver 38c2ecf20Sopenharmony_ci * Author: Jürgen E. Fischer, fischer@norbit.de 48c2ecf20Sopenharmony_ci * Copyright 1993-2004 Jürgen E. Fischer 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $ 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * $Log: aha152x.c,v $ 98c2ecf20Sopenharmony_ci * Revision 2.7 2004/01/24 11:42:59 fischer 108c2ecf20Sopenharmony_ci * - gather code that is not used by PCMCIA at the end 118c2ecf20Sopenharmony_ci * - move request_region for !PCMCIA case to detection 128c2ecf20Sopenharmony_ci * - migration to new scsi host api (remove legacy code) 138c2ecf20Sopenharmony_ci * - free host scribble before scsi_done 148c2ecf20Sopenharmony_ci * - fix error handling 158c2ecf20Sopenharmony_ci * - one isapnp device added to id_table 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Revision 2.6 2003/10/30 20:52:47 fischer 188c2ecf20Sopenharmony_ci * - interfaces changes for kernel 2.6 198c2ecf20Sopenharmony_ci * - aha152x_probe_one introduced for pcmcia stub 208c2ecf20Sopenharmony_ci * - fixed pnpdev handling 218c2ecf20Sopenharmony_ci * - instead of allocation a new one, reuse command for request sense after check condition and reset 228c2ecf20Sopenharmony_ci * - fixes race in is_complete 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Revision 2.5 2002/04/14 11:24:53 fischer 258c2ecf20Sopenharmony_ci * - isapnp support 268c2ecf20Sopenharmony_ci * - abort fixed 278c2ecf20Sopenharmony_ci * - 2.5 support 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Revision 2.4 2000/12/16 12:53:56 fischer 308c2ecf20Sopenharmony_ci * - allow REQUEST SENSE to be queued 318c2ecf20Sopenharmony_ci * - handle shared PCI interrupts 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Revision 2.3 2000/11/04 16:40:26 fischer 348c2ecf20Sopenharmony_ci * - handle data overruns 358c2ecf20Sopenharmony_ci * - extend timeout for data phases 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Revision 2.2 2000/08/08 19:54:53 fischer 388c2ecf20Sopenharmony_ci * - minor changes 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Revision 2.1 2000/05/17 16:23:17 fischer 418c2ecf20Sopenharmony_ci * - signature update 428c2ecf20Sopenharmony_ci * - fix for data out w/o scatter gather 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Revision 2.0 1999/12/25 15:07:32 fischer 458c2ecf20Sopenharmony_ci * - interrupt routine completly reworked 468c2ecf20Sopenharmony_ci * - basic support for new eh code 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Revision 1.21 1999/11/10 23:46:36 fischer 498c2ecf20Sopenharmony_ci * - default to synchronous operation 508c2ecf20Sopenharmony_ci * - synchronous negotiation fixed 518c2ecf20Sopenharmony_ci * - added timeout to loops 528c2ecf20Sopenharmony_ci * - debugging output can be controlled through procfs 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Revision 1.20 1999/11/07 18:37:31 fischer 558c2ecf20Sopenharmony_ci * - synchronous operation works 568c2ecf20Sopenharmony_ci * - resid support for sg driver 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * Revision 1.19 1999/11/02 22:39:59 fischer 598c2ecf20Sopenharmony_ci * - moved leading comments to README.aha152x 608c2ecf20Sopenharmony_ci * - new additional module parameters 618c2ecf20Sopenharmony_ci * - updates for 2.3 628c2ecf20Sopenharmony_ci * - support for the Tripace TC1550 controller 638c2ecf20Sopenharmony_ci * - interrupt handling changed 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * Revision 1.18 1996/09/07 20:10:40 fischer 668c2ecf20Sopenharmony_ci * - fixed can_queue handling (multiple outstanding commands working again) 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Revision 1.17 1996/08/17 16:05:14 fischer 698c2ecf20Sopenharmony_ci * - biosparam improved 708c2ecf20Sopenharmony_ci * - interrupt verification 718c2ecf20Sopenharmony_ci * - updated documentation 728c2ecf20Sopenharmony_ci * - cleanups 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Revision 1.16 1996/06/09 00:04:56 root 758c2ecf20Sopenharmony_ci * - added configuration symbols for insmod (aha152x/aha152x1) 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Revision 1.15 1996/04/30 14:52:06 fischer 788c2ecf20Sopenharmony_ci * - proc info fixed 798c2ecf20Sopenharmony_ci * - support for extended translation for >1GB disks 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Revision 1.14 1996/01/17 15:11:20 fischer 828c2ecf20Sopenharmony_ci * - fixed lockup in MESSAGE IN phase after reconnection 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Revision 1.13 1996/01/09 02:15:53 fischer 858c2ecf20Sopenharmony_ci * - some cleanups 868c2ecf20Sopenharmony_ci * - moved request_irq behind controller initialization 878c2ecf20Sopenharmony_ci * (to avoid spurious interrupts) 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * Revision 1.12 1995/12/16 12:26:07 fischer 908c2ecf20Sopenharmony_ci * - barrier()s added 918c2ecf20Sopenharmony_ci * - configurable RESET delay added 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * Revision 1.11 1995/12/06 21:18:35 fischer 948c2ecf20Sopenharmony_ci * - some minor updates 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Revision 1.10 1995/07/22 19:18:45 fischer 978c2ecf20Sopenharmony_ci * - support for 2 controllers 988c2ecf20Sopenharmony_ci * - started synchronous data transfers (not working yet) 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Revision 1.9 1995/03/18 09:20:24 root 1018c2ecf20Sopenharmony_ci * - patches for PCMCIA and modules 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Revision 1.8 1995/01/21 22:07:19 root 1048c2ecf20Sopenharmony_ci * - snarf_region => request_region 1058c2ecf20Sopenharmony_ci * - aha152x_intr interface change 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * Revision 1.7 1995/01/02 23:19:36 root 1088c2ecf20Sopenharmony_ci * - updated COMMAND_SIZE to cmd_len 1098c2ecf20Sopenharmony_ci * - changed sti() to restore_flags() 1108c2ecf20Sopenharmony_ci * - fixed some #ifdef which generated warnings 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Revision 1.6 1994/11/24 20:35:27 root 1138c2ecf20Sopenharmony_ci * - problem with odd number of bytes in fifo fixed 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Revision 1.5 1994/10/30 14:39:56 root 1168c2ecf20Sopenharmony_ci * - abort code fixed 1178c2ecf20Sopenharmony_ci * - debugging improved 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Revision 1.4 1994/09/12 11:33:01 root 1208c2ecf20Sopenharmony_ci * - irqaction to request_irq 1218c2ecf20Sopenharmony_ci * - abortion updated 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * Revision 1.3 1994/08/04 13:53:05 root 1248c2ecf20Sopenharmony_ci * - updates for mid-level-driver changes 1258c2ecf20Sopenharmony_ci * - accept unexpected BUSFREE phase as error condition 1268c2ecf20Sopenharmony_ci * - parity check now configurable 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Revision 1.2 1994/07/03 12:56:36 root 1298c2ecf20Sopenharmony_ci * - cleaned up debugging code 1308c2ecf20Sopenharmony_ci * - more tweaking on reset delays 1318c2ecf20Sopenharmony_ci * - updated abort/reset code (pretty untested...) 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * Revision 1.1 1994/05/28 21:18:49 root 1348c2ecf20Sopenharmony_ci * - update for mid-level interface change (abort-reset) 1358c2ecf20Sopenharmony_ci * - delays after resets adjusted for some slow devices 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * Revision 1.0 1994/03/25 12:52:00 root 1388c2ecf20Sopenharmony_ci * - Fixed "more data than expected" problem 1398c2ecf20Sopenharmony_ci * - added new BIOS signatures 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * Revision 0.102 1994/01/31 20:44:12 root 1428c2ecf20Sopenharmony_ci * - minor changes in insw/outsw handling 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * Revision 0.101 1993/12/13 01:16:27 root 1458c2ecf20Sopenharmony_ci * - fixed STATUS phase (non-GOOD stati were dropped sometimes; 1468c2ecf20Sopenharmony_ci * fixes problems with CD-ROM sector size detection & media change) 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Revision 0.100 1993/12/10 16:58:47 root 1498c2ecf20Sopenharmony_ci * - fix for unsuccessful selections in case of non-continuous id assignments 1508c2ecf20Sopenharmony_ci * on the scsi bus. 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * Revision 0.99 1993/10/24 16:19:59 root 1538c2ecf20Sopenharmony_ci * - fixed DATA IN (rare read errors gone) 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Revision 0.98 1993/10/17 12:54:44 root 1568c2ecf20Sopenharmony_ci * - fixed some recent fixes (shame on me) 1578c2ecf20Sopenharmony_ci * - moved initialization of scratch area to aha152x_queue 1588c2ecf20Sopenharmony_ci * 1598c2ecf20Sopenharmony_ci * Revision 0.97 1993/10/09 18:53:53 root 1608c2ecf20Sopenharmony_ci * - DATA IN fixed. Rarely left data in the fifo. 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci * Revision 0.96 1993/10/03 00:53:59 root 1638c2ecf20Sopenharmony_ci * - minor changes on DATA IN 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Revision 0.95 1993/09/24 10:36:01 root 1668c2ecf20Sopenharmony_ci * - change handling of MSGI after reselection 1678c2ecf20Sopenharmony_ci * - fixed sti/cli 1688c2ecf20Sopenharmony_ci * - minor changes 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Revision 0.94 1993/09/18 14:08:22 root 1718c2ecf20Sopenharmony_ci * - fixed bug in multiple outstanding command code 1728c2ecf20Sopenharmony_ci * - changed detection 1738c2ecf20Sopenharmony_ci * - support for kernel command line configuration 1748c2ecf20Sopenharmony_ci * - reset corrected 1758c2ecf20Sopenharmony_ci * - changed message handling 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Revision 0.93 1993/09/15 20:41:19 root 1788c2ecf20Sopenharmony_ci * - fixed bugs with multiple outstanding commands 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * Revision 0.92 1993/09/13 02:46:33 root 1818c2ecf20Sopenharmony_ci * - multiple outstanding commands work (no problems with IBM drive) 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * Revision 0.91 1993/09/12 20:51:46 root 1848c2ecf20Sopenharmony_ci * added multiple outstanding commands 1858c2ecf20Sopenharmony_ci * (some problem with this $%&? IBM device remain) 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Revision 0.9 1993/09/12 11:11:22 root 1888c2ecf20Sopenharmony_ci * - corrected auto-configuration 1898c2ecf20Sopenharmony_ci * - changed the auto-configuration (added some '#define's) 1908c2ecf20Sopenharmony_ci * - added support for dis-/reconnection 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Revision 0.8 1993/09/06 23:09:39 root 1938c2ecf20Sopenharmony_ci * - added support for the drive activity light 1948c2ecf20Sopenharmony_ci * - minor changes 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * Revision 0.7 1993/09/05 14:30:15 root 1978c2ecf20Sopenharmony_ci * - improved phase detection 1988c2ecf20Sopenharmony_ci * - now using the new snarf_region code of 0.99pl13 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * Revision 0.6 1993/09/02 11:01:38 root 2018c2ecf20Sopenharmony_ci * first public release; added some signatures and biosparam() 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * Revision 0.5 1993/08/30 10:23:30 root 2048c2ecf20Sopenharmony_ci * fixed timing problems with my IBM drive 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * Revision 0.4 1993/08/29 14:06:52 root 2078c2ecf20Sopenharmony_ci * fixed some problems with timeouts due incomplete commands 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * Revision 0.3 1993/08/28 15:55:03 root 2108c2ecf20Sopenharmony_ci * writing data works too. mounted and worked on a dos partition 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * Revision 0.2 1993/08/27 22:42:07 root 2138c2ecf20Sopenharmony_ci * reading data works. Mounted a msdos partition. 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * Revision 0.1 1993/08/25 13:38:30 root 2168c2ecf20Sopenharmony_ci * first "damn thing doesn't work" version 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * Revision 0.0 1993/08/14 19:54:25 root 2198c2ecf20Sopenharmony_ci * empty function bodies; detect() works. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci ************************************************************************** 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci see Documentation/scsi/aha152x.rst for configuration details 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci **************************************************************************/ 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#include <linux/module.h> 2288c2ecf20Sopenharmony_ci#include <asm/irq.h> 2298c2ecf20Sopenharmony_ci#include <linux/io.h> 2308c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 2318c2ecf20Sopenharmony_ci#include <linux/completion.h> 2328c2ecf20Sopenharmony_ci#include <linux/errno.h> 2338c2ecf20Sopenharmony_ci#include <linux/string.h> 2348c2ecf20Sopenharmony_ci#include <linux/wait.h> 2358c2ecf20Sopenharmony_ci#include <linux/ioport.h> 2368c2ecf20Sopenharmony_ci#include <linux/delay.h> 2378c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 2388c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 2398c2ecf20Sopenharmony_ci#include <linux/init.h> 2408c2ecf20Sopenharmony_ci#include <linux/kernel.h> 2418c2ecf20Sopenharmony_ci#include <linux/isapnp.h> 2428c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 2438c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 2448c2ecf20Sopenharmony_ci#include <linux/list.h> 2458c2ecf20Sopenharmony_ci#include <linux/slab.h> 2468c2ecf20Sopenharmony_ci#include <scsi/scsicam.h> 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci#include "scsi.h" 2498c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 2508c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 2518c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_spi.h> 2528c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 2538c2ecf20Sopenharmony_ci#include "aha152x.h" 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic LIST_HEAD(aha152x_host_list); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* DEFINES */ 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* For PCMCIA cards, always use AUTOCONF */ 2618c2ecf20Sopenharmony_ci#if defined(AHA152X_PCMCIA) || defined(MODULE) 2628c2ecf20Sopenharmony_ci#if !defined(AUTOCONF) 2638c2ecf20Sopenharmony_ci#define AUTOCONF 2648c2ecf20Sopenharmony_ci#endif 2658c2ecf20Sopenharmony_ci#endif 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#if !defined(AUTOCONF) && !defined(SETUP0) 2688c2ecf20Sopenharmony_ci#error define AUTOCONF or SETUP0 2698c2ecf20Sopenharmony_ci#endif 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) 2728c2ecf20Sopenharmony_ci#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define LEAD "(scsi%d:%d:%d) " 2758c2ecf20Sopenharmony_ci#define INFO_LEAD KERN_INFO LEAD 2768c2ecf20Sopenharmony_ci#define CMDINFO(cmd) \ 2778c2ecf20Sopenharmony_ci (cmd) ? ((cmd)->device->host->host_no) : -1, \ 2788c2ecf20Sopenharmony_ci (cmd) ? ((cmd)->device->id & 0x0f) : -1, \ 2798c2ecf20Sopenharmony_ci (cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic inline void 2828c2ecf20Sopenharmony_ciCMD_INC_RESID(struct scsi_cmnd *cmd, int inc) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci scsi_set_resid(cmd, scsi_get_resid(cmd) + inc); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define DELAY_DEFAULT 1000 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#if defined(AHA152X_PCMCIA) 2908c2ecf20Sopenharmony_ci#define IRQ_MIN 0 2918c2ecf20Sopenharmony_ci#define IRQ_MAX 16 2928c2ecf20Sopenharmony_ci#else 2938c2ecf20Sopenharmony_ci#define IRQ_MIN 9 2948c2ecf20Sopenharmony_ci#if defined(__PPC) 2958c2ecf20Sopenharmony_ci#define IRQ_MAX (nr_irqs-1) 2968c2ecf20Sopenharmony_ci#else 2978c2ecf20Sopenharmony_ci#define IRQ_MAX 12 2988c2ecf20Sopenharmony_ci#endif 2998c2ecf20Sopenharmony_ci#endif 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cienum { 3028c2ecf20Sopenharmony_ci not_issued = 0x0001, /* command not yet issued */ 3038c2ecf20Sopenharmony_ci selecting = 0x0002, /* target is being selected */ 3048c2ecf20Sopenharmony_ci identified = 0x0004, /* IDENTIFY was sent */ 3058c2ecf20Sopenharmony_ci disconnected = 0x0008, /* target disconnected */ 3068c2ecf20Sopenharmony_ci completed = 0x0010, /* target sent COMMAND COMPLETE */ 3078c2ecf20Sopenharmony_ci aborted = 0x0020, /* ABORT was sent */ 3088c2ecf20Sopenharmony_ci resetted = 0x0040, /* BUS DEVICE RESET was sent */ 3098c2ecf20Sopenharmony_ci spiordy = 0x0080, /* waiting for SPIORDY to raise */ 3108c2ecf20Sopenharmony_ci syncneg = 0x0100, /* synchronous negotiation in progress */ 3118c2ecf20Sopenharmony_ci aborting = 0x0200, /* ABORT is pending */ 3128c2ecf20Sopenharmony_ci resetting = 0x0400, /* BUS DEVICE RESET is pending */ 3138c2ecf20Sopenharmony_ci check_condition = 0x0800, /* requesting sense after CHECK CONDITION */ 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jürgen Fischer"); 3178c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(AHA152X_REVID); 3188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 3218c2ecf20Sopenharmony_ci#if defined(MODULE) 3228c2ecf20Sopenharmony_cistatic int io[] = {0, 0}; 3238c2ecf20Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0); 3248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(io,"base io address of controller"); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int irq[] = {0, 0}; 3278c2ecf20Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0); 3288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq,"interrupt for controller"); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int scsiid[] = {7, 7}; 3318c2ecf20Sopenharmony_cimodule_param_array(scsiid, int, NULL, 0); 3328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(scsiid,"scsi id of controller"); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int reconnect[] = {1, 1}; 3358c2ecf20Sopenharmony_cimodule_param_array(reconnect, int, NULL, 0); 3368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reconnect,"allow targets to disconnect"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int parity[] = {1, 1}; 3398c2ecf20Sopenharmony_cimodule_param_array(parity, int, NULL, 0); 3408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(parity,"use scsi parity"); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int sync[] = {1, 1}; 3438c2ecf20Sopenharmony_cimodule_param_array(sync, int, NULL, 0); 3448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sync,"use synchronous transfers"); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; 3478c2ecf20Sopenharmony_cimodule_param_array(delay, int, NULL, 0); 3488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(delay,"scsi reset delay"); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int exttrans[] = {0, 0}; 3518c2ecf20Sopenharmony_cimodule_param_array(exttrans, int, NULL, 0); 3528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(exttrans,"use extended translation"); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 3558c2ecf20Sopenharmony_cimodule_param_array(aha152x, int, NULL, 0); 3568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aha152x, "parameters for first controller"); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 3598c2ecf20Sopenharmony_cimodule_param_array(aha152x1, int, NULL, 0); 3608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aha152x1, "parameters for second controller"); 3618c2ecf20Sopenharmony_ci#endif /* MODULE */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci#ifdef __ISAPNP__ 3648c2ecf20Sopenharmony_cistatic struct isapnp_device_id id_table[] = { 3658c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, 3668c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, 3678c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, 3688c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, 3698c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, 3708c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, 3718c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, 3728c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, 3738c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, 3748c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, 3758c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, 3768c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, 3778c2ecf20Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, 3788c2ecf20Sopenharmony_ci { ISAPNP_DEVICE_SINGLE_END, } 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, id_table); 3818c2ecf20Sopenharmony_ci#endif /* ISAPNP */ 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci#endif /* !AHA152X_PCMCIA */ 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic struct scsi_host_template aha152x_driver_template; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/* 3888c2ecf20Sopenharmony_ci * internal states of the host 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_cienum aha152x_state { 3928c2ecf20Sopenharmony_ci idle=0, 3938c2ecf20Sopenharmony_ci unknown, 3948c2ecf20Sopenharmony_ci seldo, 3958c2ecf20Sopenharmony_ci seldi, 3968c2ecf20Sopenharmony_ci selto, 3978c2ecf20Sopenharmony_ci busfree, 3988c2ecf20Sopenharmony_ci msgo, 3998c2ecf20Sopenharmony_ci cmd, 4008c2ecf20Sopenharmony_ci msgi, 4018c2ecf20Sopenharmony_ci status, 4028c2ecf20Sopenharmony_ci datai, 4038c2ecf20Sopenharmony_ci datao, 4048c2ecf20Sopenharmony_ci parerr, 4058c2ecf20Sopenharmony_ci rsti, 4068c2ecf20Sopenharmony_ci maxstate 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * current state information of the host 4118c2ecf20Sopenharmony_ci * 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_cistruct aha152x_hostdata { 4148c2ecf20Sopenharmony_ci struct scsi_cmnd *issue_SC; 4158c2ecf20Sopenharmony_ci /* pending commands to issue */ 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci struct scsi_cmnd *current_SC; 4188c2ecf20Sopenharmony_ci /* current command on the bus */ 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci struct scsi_cmnd *disconnected_SC; 4218c2ecf20Sopenharmony_ci /* commands that disconnected */ 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci struct scsi_cmnd *done_SC; 4248c2ecf20Sopenharmony_ci /* command that was completed */ 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci spinlock_t lock; 4278c2ecf20Sopenharmony_ci /* host lock */ 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 4308c2ecf20Sopenharmony_ci int total_commands; 4318c2ecf20Sopenharmony_ci int disconnections; 4328c2ecf20Sopenharmony_ci int busfree_without_any_action; 4338c2ecf20Sopenharmony_ci int busfree_without_old_command; 4348c2ecf20Sopenharmony_ci int busfree_without_new_command; 4358c2ecf20Sopenharmony_ci int busfree_without_done_command; 4368c2ecf20Sopenharmony_ci int busfree_with_check_condition; 4378c2ecf20Sopenharmony_ci int count[maxstate]; 4388c2ecf20Sopenharmony_ci int count_trans[maxstate]; 4398c2ecf20Sopenharmony_ci unsigned long time[maxstate]; 4408c2ecf20Sopenharmony_ci#endif 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci int commands; /* current number of commands */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci int reconnect; /* disconnection allowed */ 4458c2ecf20Sopenharmony_ci int parity; /* parity checking enabled */ 4468c2ecf20Sopenharmony_ci int synchronous; /* synchronous transferes enabled */ 4478c2ecf20Sopenharmony_ci int delay; /* reset out delay */ 4488c2ecf20Sopenharmony_ci int ext_trans; /* extended translation enabled */ 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci int swint; /* software-interrupt was fired during detect() */ 4518c2ecf20Sopenharmony_ci int service; /* bh needs to be run */ 4528c2ecf20Sopenharmony_ci int in_intr; /* bh is running */ 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* current state, 4558c2ecf20Sopenharmony_ci previous state, 4568c2ecf20Sopenharmony_ci last state different from current state */ 4578c2ecf20Sopenharmony_ci enum aha152x_state state, prevstate, laststate; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci int target; 4608c2ecf20Sopenharmony_ci /* reconnecting target */ 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci unsigned char syncrate[8]; 4638c2ecf20Sopenharmony_ci /* current synchronous transfer agreements */ 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci unsigned char syncneg[8]; 4668c2ecf20Sopenharmony_ci /* 0: no negotiation; 4678c2ecf20Sopenharmony_ci * 1: negotiation in progress; 4688c2ecf20Sopenharmony_ci * 2: negotiation completed 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci int cmd_i; 4728c2ecf20Sopenharmony_ci /* number of sent bytes of current command */ 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci int msgi_len; 4758c2ecf20Sopenharmony_ci /* number of received message bytes */ 4768c2ecf20Sopenharmony_ci unsigned char msgi[256]; 4778c2ecf20Sopenharmony_ci /* received message bytes */ 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci int msgo_i, msgo_len; 4808c2ecf20Sopenharmony_ci /* number of sent bytes and length of current messages */ 4818c2ecf20Sopenharmony_ci unsigned char msgo[256]; 4828c2ecf20Sopenharmony_ci /* pending messages */ 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci int data_len; 4858c2ecf20Sopenharmony_ci /* number of sent/received bytes in dataphase */ 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci unsigned long io_port0; 4888c2ecf20Sopenharmony_ci unsigned long io_port1; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci#ifdef __ISAPNP__ 4918c2ecf20Sopenharmony_ci struct pnp_dev *pnpdev; 4928c2ecf20Sopenharmony_ci#endif 4938c2ecf20Sopenharmony_ci struct list_head host_list; 4948c2ecf20Sopenharmony_ci}; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* 4988c2ecf20Sopenharmony_ci * host specific command extension 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_cistruct aha152x_scdata { 5028c2ecf20Sopenharmony_ci struct scsi_cmnd *next; /* next sc in queue */ 5038c2ecf20Sopenharmony_ci struct completion *done;/* semaphore to block on */ 5048c2ecf20Sopenharmony_ci struct scsi_eh_save ses; 5058c2ecf20Sopenharmony_ci}; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* access macros for hostdata */ 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#define HOSTNO ((shpnt)->host_no) 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) 5148c2ecf20Sopenharmony_ci#define DONE_SC (HOSTDATA(shpnt)->done_SC) 5158c2ecf20Sopenharmony_ci#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) 5168c2ecf20Sopenharmony_ci#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) 5178c2ecf20Sopenharmony_ci#define QLOCK (HOSTDATA(shpnt)->lock) 5188c2ecf20Sopenharmony_ci#define QLOCKER (HOSTDATA(shpnt)->locker) 5198c2ecf20Sopenharmony_ci#define QLOCKERL (HOSTDATA(shpnt)->lockerl) 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci#define STATE (HOSTDATA(shpnt)->state) 5228c2ecf20Sopenharmony_ci#define PREVSTATE (HOSTDATA(shpnt)->prevstate) 5238c2ecf20Sopenharmony_ci#define LASTSTATE (HOSTDATA(shpnt)->laststate) 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci#define RECONN_TARGET (HOSTDATA(shpnt)->target) 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci#define CMD_I (HOSTDATA(shpnt)->cmd_i) 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci#define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) 5308c2ecf20Sopenharmony_ci#define MSGO_I (HOSTDATA(shpnt)->msgo_i) 5318c2ecf20Sopenharmony_ci#define MSGOLEN (HOSTDATA(shpnt)->msgo_len) 5328c2ecf20Sopenharmony_ci#define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow")) 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci#define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) 5358c2ecf20Sopenharmony_ci#define MSGILEN (HOSTDATA(shpnt)->msgi_len) 5368c2ecf20Sopenharmony_ci#define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow")) 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci#define DATA_LEN (HOSTDATA(shpnt)->data_len) 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id]) 5418c2ecf20Sopenharmony_ci#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id]) 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci#define DELAY (HOSTDATA(shpnt)->delay) 5448c2ecf20Sopenharmony_ci#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) 5458c2ecf20Sopenharmony_ci#define TC1550 (HOSTDATA(shpnt)->tc1550) 5468c2ecf20Sopenharmony_ci#define RECONNECT (HOSTDATA(shpnt)->reconnect) 5478c2ecf20Sopenharmony_ci#define PARITY (HOSTDATA(shpnt)->parity) 5488c2ecf20Sopenharmony_ci#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) 5518c2ecf20Sopenharmony_ci#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) 5548c2ecf20Sopenharmony_ci#define SCNEXT(SCpnt) SCDATA(SCpnt)->next 5558c2ecf20Sopenharmony_ci#define SCSEM(SCpnt) SCDATA(SCpnt)->done 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/* state handling */ 5608c2ecf20Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt); 5618c2ecf20Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt); 5628c2ecf20Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt); 5638c2ecf20Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt); 5668c2ecf20Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt); 5678c2ecf20Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt); 5708c2ecf20Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt); 5718c2ecf20Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt); 5748c2ecf20Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt); 5758c2ecf20Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt); 5788c2ecf20Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt); 5798c2ecf20Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt); 5848c2ecf20Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt); 5878c2ecf20Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/* 5928c2ecf20Sopenharmony_ci * driver states 5938c2ecf20Sopenharmony_ci * 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_cistatic struct { 5968c2ecf20Sopenharmony_ci char *name; 5978c2ecf20Sopenharmony_ci void (*init)(struct Scsi_Host *); 5988c2ecf20Sopenharmony_ci void (*run)(struct Scsi_Host *); 5998c2ecf20Sopenharmony_ci void (*end)(struct Scsi_Host *); 6008c2ecf20Sopenharmony_ci int spio; 6018c2ecf20Sopenharmony_ci} states[] = { 6028c2ecf20Sopenharmony_ci { "idle", NULL, NULL, NULL, 0}, 6038c2ecf20Sopenharmony_ci { "unknown", NULL, NULL, NULL, 0}, 6048c2ecf20Sopenharmony_ci { "seldo", NULL, seldo_run, NULL, 0}, 6058c2ecf20Sopenharmony_ci { "seldi", NULL, seldi_run, NULL, 0}, 6068c2ecf20Sopenharmony_ci { "selto", NULL, selto_run, NULL, 0}, 6078c2ecf20Sopenharmony_ci { "busfree", NULL, busfree_run, NULL, 0}, 6088c2ecf20Sopenharmony_ci { "msgo", msgo_init, msgo_run, msgo_end, 1}, 6098c2ecf20Sopenharmony_ci { "cmd", cmd_init, cmd_run, cmd_end, 1}, 6108c2ecf20Sopenharmony_ci { "msgi", NULL, msgi_run, msgi_end, 1}, 6118c2ecf20Sopenharmony_ci { "status", NULL, status_run, NULL, 1}, 6128c2ecf20Sopenharmony_ci { "datai", datai_init, datai_run, datai_end, 0}, 6138c2ecf20Sopenharmony_ci { "datao", datao_init, datao_run, datao_end, 0}, 6148c2ecf20Sopenharmony_ci { "parerr", NULL, parerr_run, NULL, 0}, 6158c2ecf20Sopenharmony_ci { "rsti", NULL, rsti_run, NULL, 0}, 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* setup & interrupt */ 6198c2ecf20Sopenharmony_cistatic irqreturn_t intr(int irq, void *dev_id); 6208c2ecf20Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt); 6218c2ecf20Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg); 6228c2ecf20Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, int error); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/* diagnostics */ 6258c2ecf20Sopenharmony_cistatic void show_command(struct scsi_cmnd * ptr); 6268c2ecf20Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt); 6278c2ecf20Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/* 6318c2ecf20Sopenharmony_ci * queue services: 6328c2ecf20Sopenharmony_ci * 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_cistatic inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct scsi_cmnd *end; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci SCNEXT(new_SC) = NULL; 6398c2ecf20Sopenharmony_ci if (!*SC) 6408c2ecf20Sopenharmony_ci *SC = new_SC; 6418c2ecf20Sopenharmony_ci else { 6428c2ecf20Sopenharmony_ci for (end = *SC; SCNEXT(end); end = SCNEXT(end)) 6438c2ecf20Sopenharmony_ci ; 6448c2ecf20Sopenharmony_ci SCNEXT(end) = new_SC; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ptr = *SC; 6538c2ecf20Sopenharmony_ci if (ptr) { 6548c2ecf20Sopenharmony_ci *SC = SCNEXT(*SC); 6558c2ecf20Sopenharmony_ci SCNEXT(ptr)=NULL; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci return ptr; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC, 6618c2ecf20Sopenharmony_ci int target, int lun) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr, *prev; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci for (ptr = *SC, prev = NULL; 6668c2ecf20Sopenharmony_ci ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); 6678c2ecf20Sopenharmony_ci prev = ptr, ptr = SCNEXT(ptr)) 6688c2ecf20Sopenharmony_ci ; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (ptr) { 6718c2ecf20Sopenharmony_ci if (prev) 6728c2ecf20Sopenharmony_ci SCNEXT(prev) = SCNEXT(ptr); 6738c2ecf20Sopenharmony_ci else 6748c2ecf20Sopenharmony_ci *SC = SCNEXT(ptr); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci SCNEXT(ptr)=NULL; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return ptr; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, 6838c2ecf20Sopenharmony_ci struct scsi_cmnd *SCp) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr, *prev; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci for (ptr = *SC, prev = NULL; 6888c2ecf20Sopenharmony_ci ptr && SCp!=ptr; 6898c2ecf20Sopenharmony_ci prev = ptr, ptr = SCNEXT(ptr)) 6908c2ecf20Sopenharmony_ci ; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (ptr) { 6938c2ecf20Sopenharmony_ci if (prev) 6948c2ecf20Sopenharmony_ci SCNEXT(prev) = SCNEXT(ptr); 6958c2ecf20Sopenharmony_ci else 6968c2ecf20Sopenharmony_ci *SC = SCNEXT(ptr); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci SCNEXT(ptr)=NULL; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci return ptr; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic irqreturn_t swintr(int irqno, void *dev_id) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = dev_id; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->swint++; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, INTEN); 7118c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistruct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata)); 7198c2ecf20Sopenharmony_ci if (!shpnt) { 7208c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: scsi_host_alloc failed\n"); 7218c2ecf20Sopenharmony_ci return NULL; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt)); 7258c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* need to have host registered before triggering any interrupt */ 7288c2ecf20Sopenharmony_ci list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci shpnt->io_port = setup->io_port; 7318c2ecf20Sopenharmony_ci shpnt->n_io_port = IO_RANGE; 7328c2ecf20Sopenharmony_ci shpnt->irq = setup->irq; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (!setup->tc1550) { 7358c2ecf20Sopenharmony_ci HOSTIOPORT0 = setup->io_port; 7368c2ecf20Sopenharmony_ci HOSTIOPORT1 = setup->io_port; 7378c2ecf20Sopenharmony_ci } else { 7388c2ecf20Sopenharmony_ci HOSTIOPORT0 = setup->io_port+0x10; 7398c2ecf20Sopenharmony_ci HOSTIOPORT1 = setup->io_port-0x10; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci spin_lock_init(&QLOCK); 7438c2ecf20Sopenharmony_ci RECONNECT = setup->reconnect; 7448c2ecf20Sopenharmony_ci SYNCHRONOUS = setup->synchronous; 7458c2ecf20Sopenharmony_ci PARITY = setup->parity; 7468c2ecf20Sopenharmony_ci DELAY = setup->delay; 7478c2ecf20Sopenharmony_ci EXT_TRANS = setup->ext_trans; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci SETPORT(SCSIID, setup->scsiid << 4); 7508c2ecf20Sopenharmony_ci shpnt->this_id = setup->scsiid; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (setup->reconnect) 7538c2ecf20Sopenharmony_ci shpnt->can_queue = AHA152X_MAXQUEUE; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* RESET OUT */ 7568c2ecf20Sopenharmony_ci printk("aha152x: resetting bus...\n"); 7578c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, SCSIRSTO); 7588c2ecf20Sopenharmony_ci mdelay(256); 7598c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 7608c2ecf20Sopenharmony_ci mdelay(DELAY); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci reset_ports(shpnt); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci printk(KERN_INFO 7658c2ecf20Sopenharmony_ci "aha152x%d%s: " 7668c2ecf20Sopenharmony_ci "vital data: rev=%x, " 7678c2ecf20Sopenharmony_ci "io=0x%03lx (0x%03lx/0x%03lx), " 7688c2ecf20Sopenharmony_ci "irq=%d, " 7698c2ecf20Sopenharmony_ci "scsiid=%d, " 7708c2ecf20Sopenharmony_ci "reconnect=%s, " 7718c2ecf20Sopenharmony_ci "parity=%s, " 7728c2ecf20Sopenharmony_ci "synchronous=%s, " 7738c2ecf20Sopenharmony_ci "delay=%d, " 7748c2ecf20Sopenharmony_ci "extended translation=%s\n", 7758c2ecf20Sopenharmony_ci shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "", 7768c2ecf20Sopenharmony_ci GETPORT(REV) & 0x7, 7778c2ecf20Sopenharmony_ci shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, 7788c2ecf20Sopenharmony_ci shpnt->irq, 7798c2ecf20Sopenharmony_ci shpnt->this_id, 7808c2ecf20Sopenharmony_ci RECONNECT ? "enabled" : "disabled", 7818c2ecf20Sopenharmony_ci PARITY ? "enabled" : "disabled", 7828c2ecf20Sopenharmony_ci SYNCHRONOUS ? "enabled" : "disabled", 7838c2ecf20Sopenharmony_ci DELAY, 7848c2ecf20Sopenharmony_ci EXT_TRANS ? "enabled" : "disabled"); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci /* not expecting any interrupts */ 7878c2ecf20Sopenharmony_ci SETPORT(SIMODE0, 0); 7888c2ecf20Sopenharmony_ci SETPORT(SIMODE1, 0); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) { 7918c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq); 7928c2ecf20Sopenharmony_ci goto out_host_put; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->swint = 0; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci mb(); 8008c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, SWINT|INTEN); 8018c2ecf20Sopenharmony_ci mdelay(1000); 8028c2ecf20Sopenharmony_ci free_irq(shpnt->irq, shpnt); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->swint) { 8058c2ecf20Sopenharmony_ci if (TESTHI(DMASTAT, INTSTAT)) { 8068c2ecf20Sopenharmony_ci printk("lost.\n"); 8078c2ecf20Sopenharmony_ci } else { 8088c2ecf20Sopenharmony_ci printk("failed.\n"); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, INTEN); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x%d: irq %d possibly wrong. " 8148c2ecf20Sopenharmony_ci "Please verify.\n", shpnt->host_no, shpnt->irq); 8158c2ecf20Sopenharmony_ci goto out_host_put; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci printk("ok.\n"); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci /* clear interrupts */ 8218c2ecf20Sopenharmony_ci SETPORT(SSTAT0, 0x7f); 8228c2ecf20Sopenharmony_ci SETPORT(SSTAT1, 0xef); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) { 8258c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq); 8268c2ecf20Sopenharmony_ci goto out_host_put; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if( scsi_add_host(shpnt, NULL) ) { 8308c2ecf20Sopenharmony_ci free_irq(shpnt->irq, shpnt); 8318c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no); 8328c2ecf20Sopenharmony_ci goto out_host_put; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci scsi_scan_host(shpnt); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return shpnt; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciout_host_put: 8408c2ecf20Sopenharmony_ci list_del(&HOSTDATA(shpnt)->host_list); 8418c2ecf20Sopenharmony_ci scsi_host_put(shpnt); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return NULL; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_civoid aha152x_release(struct Scsi_Host *shpnt) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci if (!shpnt) 8498c2ecf20Sopenharmony_ci return; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci scsi_remove_host(shpnt); 8528c2ecf20Sopenharmony_ci if (shpnt->irq) 8538c2ecf20Sopenharmony_ci free_irq(shpnt->irq, shpnt); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 8568c2ecf20Sopenharmony_ci if (shpnt->io_port) 8578c2ecf20Sopenharmony_ci release_region(shpnt->io_port, IO_RANGE); 8588c2ecf20Sopenharmony_ci#endif 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci#ifdef __ISAPNP__ 8618c2ecf20Sopenharmony_ci if (HOSTDATA(shpnt)->pnpdev) 8628c2ecf20Sopenharmony_ci pnp_device_detach(HOSTDATA(shpnt)->pnpdev); 8638c2ecf20Sopenharmony_ci#endif 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci list_del(&HOSTDATA(shpnt)->host_list); 8668c2ecf20Sopenharmony_ci scsi_host_put(shpnt); 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci/* 8718c2ecf20Sopenharmony_ci * setup controller to generate interrupts depending 8728c2ecf20Sopenharmony_ci * on current state (lock has to be acquired) 8738c2ecf20Sopenharmony_ci * 8748c2ecf20Sopenharmony_ci */ 8758c2ecf20Sopenharmony_cistatic int setup_expected_interrupts(struct Scsi_Host *shpnt) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci if(CURRENT_SC) { 8788c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= 1 << 16; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if(CURRENT_SC->SCp.phase & selecting) { 8818c2ecf20Sopenharmony_ci SETPORT(SSTAT1, SELTO); 8828c2ecf20Sopenharmony_ci SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); 8838c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENSELTIMO); 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); 8868c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci } else if(STATE==seldi) { 8898c2ecf20Sopenharmony_ci SETPORT(SIMODE0, 0); 8908c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); 8938c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if(!HOSTDATA(shpnt)->in_intr) 8978c2ecf20Sopenharmony_ci SETBITS(DMACNTRL0, INTEN); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return TESTHI(DMASTAT, INTSTAT); 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci/* 9048c2ecf20Sopenharmony_ci * Queue a command and setup interrupts for a free bus. 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_cistatic int aha152x_internal_queue(struct scsi_cmnd *SCpnt, 9078c2ecf20Sopenharmony_ci struct completion *complete, 9088c2ecf20Sopenharmony_ci int phase, void (*done)(struct scsi_cmnd *)) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 9118c2ecf20Sopenharmony_ci unsigned long flags; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci SCpnt->scsi_done = done; 9148c2ecf20Sopenharmony_ci SCpnt->SCp.phase = not_issued | phase; 9158c2ecf20Sopenharmony_ci SCpnt->SCp.Status = 0x1; /* Ilegal status by SCSI standard */ 9168c2ecf20Sopenharmony_ci SCpnt->SCp.Message = 0; 9178c2ecf20Sopenharmony_ci SCpnt->SCp.have_data_in = 0; 9188c2ecf20Sopenharmony_ci SCpnt->SCp.sent_command = 0; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if(SCpnt->SCp.phase & (resetting|check_condition)) { 9218c2ecf20Sopenharmony_ci if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { 9228c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); 9238c2ecf20Sopenharmony_ci return FAILED; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci } else { 9268c2ecf20Sopenharmony_ci SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); 9278c2ecf20Sopenharmony_ci if(!SCpnt->host_scribble) { 9288c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); 9298c2ecf20Sopenharmony_ci return FAILED; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci SCNEXT(SCpnt) = NULL; 9348c2ecf20Sopenharmony_ci SCSEM(SCpnt) = complete; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* setup scratch area 9378c2ecf20Sopenharmony_ci SCp.ptr : buffer pointer 9388c2ecf20Sopenharmony_ci SCp.this_residual : buffer length 9398c2ecf20Sopenharmony_ci SCp.buffer : next buffer 9408c2ecf20Sopenharmony_ci SCp.phase : current state of the command */ 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if ((phase & resetting) || !scsi_sglist(SCpnt)) { 9438c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = NULL; 9448c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = 0; 9458c2ecf20Sopenharmony_ci scsi_set_resid(SCpnt, 0); 9468c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = NULL; 9478c2ecf20Sopenharmony_ci } else { 9488c2ecf20Sopenharmony_ci scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 9498c2ecf20Sopenharmony_ci SCpnt->SCp.buffer = scsi_sglist(SCpnt); 9508c2ecf20Sopenharmony_ci SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); 9518c2ecf20Sopenharmony_ci SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci DO_LOCK(flags); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 9578c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->total_commands++; 9588c2ecf20Sopenharmony_ci#endif 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Turn led on, when this is the first command. */ 9618c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands++; 9628c2ecf20Sopenharmony_ci if (HOSTDATA(shpnt)->commands==1) 9638c2ecf20Sopenharmony_ci SETPORT(PORTA, 1); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci append_SC(&ISSUE_SC, SCpnt); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if(!HOSTDATA(shpnt)->in_intr) 9688c2ecf20Sopenharmony_ci setup_expected_interrupts(shpnt); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return 0; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci/* 9768c2ecf20Sopenharmony_ci * queue a command 9778c2ecf20Sopenharmony_ci * 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_cistatic int aha152x_queue_lck(struct scsi_cmnd *SCpnt, 9808c2ecf20Sopenharmony_ci void (*done)(struct scsi_cmnd *)) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci return aha152x_internal_queue(SCpnt, NULL, 0, done); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(aha152x_queue) 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci/* 9898c2ecf20Sopenharmony_ci * 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_cistatic void reset_done(struct scsi_cmnd *SCpnt) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci if(SCSEM(SCpnt)) { 9948c2ecf20Sopenharmony_ci complete(SCSEM(SCpnt)); 9958c2ecf20Sopenharmony_ci } else { 9968c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: reset_done w/o completion\n"); 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci/* 10018c2ecf20Sopenharmony_ci * Abort a command 10028c2ecf20Sopenharmony_ci * 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_cistatic int aha152x_abort(struct scsi_cmnd *SCpnt) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 10078c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 10088c2ecf20Sopenharmony_ci unsigned long flags; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci DO_LOCK(flags); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci ptr=remove_SC(&ISSUE_SC, SCpnt); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if(ptr) { 10158c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands--; 10168c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 10178c2ecf20Sopenharmony_ci SETPORT(PORTA, 0); 10188c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci kfree(SCpnt->host_scribble); 10218c2ecf20Sopenharmony_ci SCpnt->host_scribble=NULL; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci return SUCCESS; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* 10298c2ecf20Sopenharmony_ci * FIXME: 10308c2ecf20Sopenharmony_ci * for current command: queue ABORT for message out and raise ATN 10318c2ecf20Sopenharmony_ci * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? 10328c2ecf20Sopenharmony_ci * 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, 10368c2ecf20Sopenharmony_ci "cannot abort running or disconnected command\n"); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci return FAILED; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci/* 10428c2ecf20Sopenharmony_ci * Reset a device 10438c2ecf20Sopenharmony_ci * 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_cistatic int aha152x_device_reset(struct scsi_cmnd * SCpnt) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 10488c2ecf20Sopenharmony_ci DECLARE_COMPLETION(done); 10498c2ecf20Sopenharmony_ci int ret, issued, disconnected; 10508c2ecf20Sopenharmony_ci unsigned char old_cmd_len = SCpnt->cmd_len; 10518c2ecf20Sopenharmony_ci unsigned long flags; 10528c2ecf20Sopenharmony_ci unsigned long timeleft; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if(CURRENT_SC==SCpnt) { 10558c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n"); 10568c2ecf20Sopenharmony_ci return FAILED; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci DO_LOCK(flags); 10608c2ecf20Sopenharmony_ci issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; 10618c2ecf20Sopenharmony_ci disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); 10628c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci SCpnt->cmd_len = 0; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci aha152x_internal_queue(SCpnt, &done, resetting, reset_done); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&done, 100*HZ); 10698c2ecf20Sopenharmony_ci if (!timeleft) { 10708c2ecf20Sopenharmony_ci /* remove command from issue queue */ 10718c2ecf20Sopenharmony_ci DO_LOCK(flags); 10728c2ecf20Sopenharmony_ci remove_SC(&ISSUE_SC, SCpnt); 10738c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci SCpnt->cmd_len = old_cmd_len; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci DO_LOCK(flags); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if(SCpnt->SCp.phase & resetted) { 10818c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands--; 10828c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 10838c2ecf20Sopenharmony_ci SETPORT(PORTA, 0); 10848c2ecf20Sopenharmony_ci kfree(SCpnt->host_scribble); 10858c2ecf20Sopenharmony_ci SCpnt->host_scribble=NULL; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci ret = SUCCESS; 10888c2ecf20Sopenharmony_ci } else { 10898c2ecf20Sopenharmony_ci /* requeue */ 10908c2ecf20Sopenharmony_ci if(!issued) { 10918c2ecf20Sopenharmony_ci append_SC(&ISSUE_SC, SCpnt); 10928c2ecf20Sopenharmony_ci } else if(disconnected) { 10938c2ecf20Sopenharmony_ci append_SC(&DISCONNECTED_SC, SCpnt); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci ret = FAILED; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 11008c2ecf20Sopenharmony_ci return ret; 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic void free_hard_reset_SCs(struct Scsi_Host *shpnt, 11048c2ecf20Sopenharmony_ci struct scsi_cmnd **SCs) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci ptr=*SCs; 11098c2ecf20Sopenharmony_ci while(ptr) { 11108c2ecf20Sopenharmony_ci struct scsi_cmnd *next; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if(SCDATA(ptr)) { 11138c2ecf20Sopenharmony_ci next = SCNEXT(ptr); 11148c2ecf20Sopenharmony_ci } else { 11158c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, ptr, 11168c2ecf20Sopenharmony_ci "queue corrupted at %p\n", ptr); 11178c2ecf20Sopenharmony_ci next = NULL; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (!ptr->device->soft_reset) { 11218c2ecf20Sopenharmony_ci remove_SC(SCs, ptr); 11228c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands--; 11238c2ecf20Sopenharmony_ci kfree(ptr->host_scribble); 11248c2ecf20Sopenharmony_ci ptr->host_scribble=NULL; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci ptr = next; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci/* 11328c2ecf20Sopenharmony_ci * Reset the bus 11338c2ecf20Sopenharmony_ci * 11348c2ecf20Sopenharmony_ci * AIC-6260 has a hard reset (MRST signal), but apparently 11358c2ecf20Sopenharmony_ci * one cannot trigger it via software. So live with 11368c2ecf20Sopenharmony_ci * a soft reset; no-one seemed to have cared. 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_cistatic int aha152x_bus_reset_host(struct Scsi_Host *shpnt) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci unsigned long flags; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci DO_LOCK(flags); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci free_hard_reset_SCs(shpnt, &ISSUE_SC); 11458c2ecf20Sopenharmony_ci free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, SCSIRSTO); 11488c2ecf20Sopenharmony_ci mdelay(256); 11498c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 11508c2ecf20Sopenharmony_ci mdelay(DELAY); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci setup_expected_interrupts(shpnt); 11538c2ecf20Sopenharmony_ci if(HOSTDATA(shpnt)->commands==0) 11548c2ecf20Sopenharmony_ci SETPORT(PORTA, 0); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci return SUCCESS; 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci/* 11628c2ecf20Sopenharmony_ci * Reset the bus 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_cistatic int aha152x_bus_reset(struct scsi_cmnd *SCpnt) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci return aha152x_bus_reset_host(SCpnt->device->host); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* 11718c2ecf20Sopenharmony_ci * Restore default values to the AIC-6260 registers and reset the fifos 11728c2ecf20Sopenharmony_ci * 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci unsigned long flags; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* disable interrupts */ 11798c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci SETPORT(SXFRCTL1, 0); 11848c2ecf20Sopenharmony_ci SETPORT(SCSISIG, 0); 11858c2ecf20Sopenharmony_ci SETRATE(0); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* clear all interrupt conditions */ 11888c2ecf20Sopenharmony_ci SETPORT(SSTAT0, 0x7f); 11898c2ecf20Sopenharmony_ci SETPORT(SSTAT1, 0xef); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, 0); 11948c2ecf20Sopenharmony_ci SETPORT(DMACNTRL1, 0); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci SETPORT(BRSTCNTRL, 0xf1); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* clear SCSI fifos and transfer count */ 11998c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 12008c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci DO_LOCK(flags); 12038c2ecf20Sopenharmony_ci setup_expected_interrupts(shpnt); 12048c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci/* 12088c2ecf20Sopenharmony_ci * Reset the host (bus and controller) 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_ciint aha152x_host_reset_host(struct Scsi_Host *shpnt) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci aha152x_bus_reset_host(shpnt); 12148c2ecf20Sopenharmony_ci reset_ports(shpnt); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci return SUCCESS; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci/* 12208c2ecf20Sopenharmony_ci * Return the "logical geometry" 12218c2ecf20Sopenharmony_ci * 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_cistatic int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, 12248c2ecf20Sopenharmony_ci sector_t capacity, int *info_array) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = sdev->host; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* try default translation */ 12298c2ecf20Sopenharmony_ci info_array[0] = 64; 12308c2ecf20Sopenharmony_ci info_array[1] = 32; 12318c2ecf20Sopenharmony_ci info_array[2] = (unsigned long)capacity / (64 * 32); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* for disks >1GB do some guessing */ 12348c2ecf20Sopenharmony_ci if (info_array[2] >= 1024) { 12358c2ecf20Sopenharmony_ci int info[3]; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* try to figure out the geometry from the partition table */ 12388c2ecf20Sopenharmony_ci if (scsicam_bios_param(bdev, capacity, info) < 0 || 12398c2ecf20Sopenharmony_ci !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { 12408c2ecf20Sopenharmony_ci if (EXT_TRANS) { 12418c2ecf20Sopenharmony_ci printk(KERN_NOTICE 12428c2ecf20Sopenharmony_ci "aha152x: unable to verify geometry for disk with >1GB.\n" 12438c2ecf20Sopenharmony_ci " using extended translation.\n"); 12448c2ecf20Sopenharmony_ci info_array[0] = 255; 12458c2ecf20Sopenharmony_ci info_array[1] = 63; 12468c2ecf20Sopenharmony_ci info_array[2] = (unsigned long)capacity / (255 * 63); 12478c2ecf20Sopenharmony_ci } else { 12488c2ecf20Sopenharmony_ci printk(KERN_NOTICE 12498c2ecf20Sopenharmony_ci "aha152x: unable to verify geometry for disk with >1GB.\n" 12508c2ecf20Sopenharmony_ci " Using default translation. Please verify yourself.\n" 12518c2ecf20Sopenharmony_ci " Perhaps you need to enable extended translation in the driver.\n" 12528c2ecf20Sopenharmony_ci " See Documentation/scsi/aha152x.rst for details.\n"); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci } else { 12558c2ecf20Sopenharmony_ci info_array[0] = info[0]; 12568c2ecf20Sopenharmony_ci info_array[1] = info[1]; 12578c2ecf20Sopenharmony_ci info_array[2] = info[2]; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (info[0] == 255 && !EXT_TRANS) { 12608c2ecf20Sopenharmony_ci printk(KERN_NOTICE 12618c2ecf20Sopenharmony_ci "aha152x: current partition table is using extended translation.\n" 12628c2ecf20Sopenharmony_ci " using it also, although it's not explicitly enabled.\n"); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci return 0; 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci/* 12718c2ecf20Sopenharmony_ci * Internal done function 12728c2ecf20Sopenharmony_ci * 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, int error) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci if (CURRENT_SC) { 12778c2ecf20Sopenharmony_ci if(DONE_SC) 12788c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 12798c2ecf20Sopenharmony_ci "there's already a completed command %p " 12808c2ecf20Sopenharmony_ci "- will cause abort\n", DONE_SC); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci DONE_SC = CURRENT_SC; 12838c2ecf20Sopenharmony_ci CURRENT_SC = NULL; 12848c2ecf20Sopenharmony_ci DONE_SC->result = error; 12858c2ecf20Sopenharmony_ci } else 12868c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: done() called outside of command\n"); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic struct work_struct aha152x_tq; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci/* 12928c2ecf20Sopenharmony_ci * Run service completions on the card with interrupts enabled. 12938c2ecf20Sopenharmony_ci * 12948c2ecf20Sopenharmony_ci */ 12958c2ecf20Sopenharmony_cistatic void run(struct work_struct *work) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci struct aha152x_hostdata *hd; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci list_for_each_entry(hd, &aha152x_host_list, host_list) { 13008c2ecf20Sopenharmony_ci struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci is_complete(shost); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci/* 13078c2ecf20Sopenharmony_ci * Interrupt handler 13088c2ecf20Sopenharmony_ci * 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_cistatic irqreturn_t intr(int irqno, void *dev_id) 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = dev_id; 13138c2ecf20Sopenharmony_ci unsigned long flags; 13148c2ecf20Sopenharmony_ci unsigned char rev, dmacntrl0; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* 13178c2ecf20Sopenharmony_ci * Read a couple of registers that are known to not be all 1's. If 13188c2ecf20Sopenharmony_ci * we read all 1's (-1), that means that either: 13198c2ecf20Sopenharmony_ci * 13208c2ecf20Sopenharmony_ci * a. The host adapter chip has gone bad, and we cannot control it, 13218c2ecf20Sopenharmony_ci * OR 13228c2ecf20Sopenharmony_ci * b. The host adapter is a PCMCIA card that has been ejected 13238c2ecf20Sopenharmony_ci * 13248c2ecf20Sopenharmony_ci * In either case, we cannot do anything with the host adapter at 13258c2ecf20Sopenharmony_ci * this point in time. So just ignore the interrupt and return. 13268c2ecf20Sopenharmony_ci * In the latter case, the interrupt might actually be meant for 13278c2ecf20Sopenharmony_ci * someone else sharing this IRQ, and that driver will handle it. 13288c2ecf20Sopenharmony_ci */ 13298c2ecf20Sopenharmony_ci rev = GETPORT(REV); 13308c2ecf20Sopenharmony_ci dmacntrl0 = GETPORT(DMACNTRL0); 13318c2ecf20Sopenharmony_ci if ((rev == 0xFF) && (dmacntrl0 == 0xFF)) 13328c2ecf20Sopenharmony_ci return IRQ_NONE; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if( TESTLO(DMASTAT, INTSTAT) ) 13358c2ecf20Sopenharmony_ci return IRQ_NONE; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* no more interrupts from the controller, while we're busy. 13388c2ecf20Sopenharmony_ci INTEN is restored by the BH handler */ 13398c2ecf20Sopenharmony_ci CLRBITS(DMACNTRL0, INTEN); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci DO_LOCK(flags); 13428c2ecf20Sopenharmony_ci if( HOSTDATA(shpnt)->service==0 ) { 13438c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->service=1; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Poke the BH handler */ 13468c2ecf20Sopenharmony_ci INIT_WORK(&aha152x_tq, run); 13478c2ecf20Sopenharmony_ci schedule_work(&aha152x_tq); 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci/* 13558c2ecf20Sopenharmony_ci * busfree phase 13568c2ecf20Sopenharmony_ci * - handle completition/disconnection/error of current command 13578c2ecf20Sopenharmony_ci * - start selection for next command (if any) 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci unsigned long flags; 13628c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 13638c2ecf20Sopenharmony_ci int action=0; 13648c2ecf20Sopenharmony_ci#endif 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 13678c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if(CURRENT_SC) { 13728c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 13738c2ecf20Sopenharmony_ci action++; 13748c2ecf20Sopenharmony_ci#endif 13758c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase &= ~syncneg; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if(CURRENT_SC->SCp.phase & completed) { 13788c2ecf20Sopenharmony_ci /* target sent COMMAND COMPLETE */ 13798c2ecf20Sopenharmony_ci done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci } else if(CURRENT_SC->SCp.phase & aborted) { 13828c2ecf20Sopenharmony_ci done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci } else if(CURRENT_SC->SCp.phase & resetted) { 13858c2ecf20Sopenharmony_ci done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci } else if(CURRENT_SC->SCp.phase & disconnected) { 13888c2ecf20Sopenharmony_ci /* target sent DISCONNECT */ 13898c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 13908c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->disconnections++; 13918c2ecf20Sopenharmony_ci#endif 13928c2ecf20Sopenharmony_ci append_SC(&DISCONNECTED_SC, CURRENT_SC); 13938c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= 1 << 16; 13948c2ecf20Sopenharmony_ci CURRENT_SC = NULL; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci } else { 13978c2ecf20Sopenharmony_ci done(shpnt, DID_ERROR << 16); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14008c2ecf20Sopenharmony_ci } else { 14018c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command++; 14028c2ecf20Sopenharmony_ci#endif 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci DO_LOCK(flags); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if(DONE_SC) { 14088c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14098c2ecf20Sopenharmony_ci action++; 14108c2ecf20Sopenharmony_ci#endif 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if(DONE_SC->SCp.phase & check_condition) { 14138c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; 14148c2ecf20Sopenharmony_ci struct aha152x_scdata *sc = SCDATA(cmd); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci scsi_eh_restore_cmnd(cmd, &sc->ses); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci cmd->SCp.Status = SAM_STAT_CHECK_CONDITION; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands--; 14218c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 14228c2ecf20Sopenharmony_ci SETPORT(PORTA, 0); /* turn led off */ 14238c2ecf20Sopenharmony_ci } else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) { 14248c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14258c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition++; 14268c2ecf20Sopenharmony_ci#endif 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if(!(DONE_SC->SCp.phase & not_issued)) { 14298c2ecf20Sopenharmony_ci struct aha152x_scdata *sc; 14308c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr = DONE_SC; 14318c2ecf20Sopenharmony_ci DONE_SC=NULL; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci sc = SCDATA(ptr); 14348c2ecf20Sopenharmony_ci /* It was allocated in aha152x_internal_queue? */ 14358c2ecf20Sopenharmony_ci BUG_ON(!sc); 14368c2ecf20Sopenharmony_ci scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 14398c2ecf20Sopenharmony_ci aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done); 14408c2ecf20Sopenharmony_ci DO_LOCK(flags); 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if(DONE_SC && DONE_SC->scsi_done) { 14458c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr = DONE_SC; 14468c2ecf20Sopenharmony_ci DONE_SC=NULL; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci /* turn led off, when no commands are in the driver */ 14498c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->commands--; 14508c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 14518c2ecf20Sopenharmony_ci SETPORT(PORTA, 0); /* turn led off */ 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci if(ptr->scsi_done != reset_done) { 14548c2ecf20Sopenharmony_ci kfree(ptr->host_scribble); 14558c2ecf20Sopenharmony_ci ptr->host_scribble=NULL; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 14598c2ecf20Sopenharmony_ci ptr->scsi_done(ptr); 14608c2ecf20Sopenharmony_ci DO_LOCK(flags); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci DONE_SC=NULL; 14648c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14658c2ecf20Sopenharmony_ci } else { 14668c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command++; 14678c2ecf20Sopenharmony_ci#endif 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if(ISSUE_SC) 14718c2ecf20Sopenharmony_ci CURRENT_SC = remove_first_SC(&ISSUE_SC); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if(CURRENT_SC) { 14768c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14778c2ecf20Sopenharmony_ci action++; 14788c2ecf20Sopenharmony_ci#endif 14798c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= selecting; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci /* clear selection timeout */ 14828c2ecf20Sopenharmony_ci SETPORT(SSTAT1, SELTO); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id); 14858c2ecf20Sopenharmony_ci SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); 14868c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); 14878c2ecf20Sopenharmony_ci } else { 14888c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14898c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command++; 14908c2ecf20Sopenharmony_ci#endif 14918c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 14958c2ecf20Sopenharmony_ci if(!action) 14968c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action++; 14978c2ecf20Sopenharmony_ci#endif 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/* 15018c2ecf20Sopenharmony_ci * Selection done (OUT) 15028c2ecf20Sopenharmony_ci * - queue IDENTIFY message and SDTR to selected target for message out 15038c2ecf20Sopenharmony_ci * (ATN asserted automagically via ENAUTOATNO in busfree()) 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci SETPORT(SCSISIG, 0); 15088c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 15098c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRPHASECHG); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase &= ~(selecting|not_issued); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci if (TESTLO(SSTAT0, SELDO)) { 15168c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 15178c2ecf20Sopenharmony_ci "aha152x: passing bus free condition\n"); 15188c2ecf20Sopenharmony_ci done(shpnt, DID_NO_CONNECT << 16); 15198c2ecf20Sopenharmony_ci return; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci SETPORT(SSTAT0, CLRSELDO); 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (CURRENT_SC->SCp.phase & aborting) { 15278c2ecf20Sopenharmony_ci ADDMSGO(ABORT); 15288c2ecf20Sopenharmony_ci } else if (CURRENT_SC->SCp.phase & resetting) { 15298c2ecf20Sopenharmony_ci ADDMSGO(BUS_DEVICE_RESET); 15308c2ecf20Sopenharmony_ci } else if (SYNCNEG==0 && SYNCHRONOUS) { 15318c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= syncneg; 15328c2ecf20Sopenharmony_ci MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8); 15338c2ecf20Sopenharmony_ci SYNCNEG=1; /* negotiation in progress */ 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci SETRATE(SYNCRATE); 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci/* 15408c2ecf20Sopenharmony_ci * Selection timeout 15418c2ecf20Sopenharmony_ci * - return command to mid-level with failure cause 15428c2ecf20Sopenharmony_ci * 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 15478c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRSELTIMO); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (!CURRENT_SC) 15508c2ecf20Sopenharmony_ci return; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase &= ~selecting; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (CURRENT_SC->SCp.phase & aborted) 15558c2ecf20Sopenharmony_ci done(shpnt, DID_ABORT << 16); 15568c2ecf20Sopenharmony_ci else if (TESTLO(SSTAT0, SELINGO)) 15578c2ecf20Sopenharmony_ci done(shpnt, DID_BUS_BUSY << 16); 15588c2ecf20Sopenharmony_ci else 15598c2ecf20Sopenharmony_ci /* ARBITRATION won, but SELECTION failed */ 15608c2ecf20Sopenharmony_ci done(shpnt, DID_NO_CONNECT << 16); 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci/* 15648c2ecf20Sopenharmony_ci * Selection in done 15658c2ecf20Sopenharmony_ci * - put current command back to issue queue 15668c2ecf20Sopenharmony_ci * (reconnection of a disconnected nexus instead 15678c2ecf20Sopenharmony_ci * of successful selection out) 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci int selid; 15738c2ecf20Sopenharmony_ci int target; 15748c2ecf20Sopenharmony_ci unsigned long flags; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci SETPORT(SCSISIG, 0); 15778c2ecf20Sopenharmony_ci SETPORT(SSTAT0, CLRSELDI); 15788c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 15798c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRPHASECHG); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci if(CURRENT_SC) { 15828c2ecf20Sopenharmony_ci if(!(CURRENT_SC->SCp.phase & not_issued)) 15838c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 15848c2ecf20Sopenharmony_ci "command should not have been issued yet\n"); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci DO_LOCK(flags); 15878c2ecf20Sopenharmony_ci append_SC(&ISSUE_SC, CURRENT_SC); 15888c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci CURRENT_SC = NULL; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (!DISCONNECTED_SC) 15948c2ecf20Sopenharmony_ci return; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci RECONN_TARGET=-1; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci selid = GETPORT(SELID) & ~(1 << shpnt->this_id); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (selid==0) { 16018c2ecf20Sopenharmony_ci shost_printk(KERN_INFO, shpnt, 16028c2ecf20Sopenharmony_ci "target id unknown (%02x)\n", selid); 16038c2ecf20Sopenharmony_ci return; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci for(target=7; !(selid & (1 << target)); target--) 16078c2ecf20Sopenharmony_ci ; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if(selid & ~(1 << target)) { 16108c2ecf20Sopenharmony_ci shost_printk(KERN_INFO, shpnt, 16118c2ecf20Sopenharmony_ci "multiple targets reconnected (%02x)\n", selid); 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci SETPORT(SCSIID, (shpnt->this_id << OID_) | target); 16168c2ecf20Sopenharmony_ci SETPORT(SCSISEQ, 0); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci SETRATE(HOSTDATA(shpnt)->syncrate[target]); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci RECONN_TARGET=target; 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci/* 16248c2ecf20Sopenharmony_ci * message in phase 16258c2ecf20Sopenharmony_ci * - handle initial message after reconnection to identify 16268c2ecf20Sopenharmony_ci * reconnecting nexus 16278c2ecf20Sopenharmony_ci * - queue command on DISCONNECTED_SC on DISCONNECT message 16288c2ecf20Sopenharmony_ci * - set completed flag on COMMAND COMPLETE 16298c2ecf20Sopenharmony_ci * (other completition code moved to busfree_run) 16308c2ecf20Sopenharmony_ci * - handle response to SDTR 16318c2ecf20Sopenharmony_ci * - clear synchronous transfer agreements on BUS RESET 16328c2ecf20Sopenharmony_ci * 16338c2ecf20Sopenharmony_ci * FIXME: what about SAVE POINTERS, RESTORE POINTERS? 16348c2ecf20Sopenharmony_ci * 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci for(;;) { 16398c2ecf20Sopenharmony_ci int sstat1 = GETPORT(SSTAT1); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) 16428c2ecf20Sopenharmony_ci return; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 16458c2ecf20Sopenharmony_ci return; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci ADDMSGI(GETPORT(SCSIDAT)); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if(!CURRENT_SC) { 16508c2ecf20Sopenharmony_ci if(LASTSTATE!=seldi) { 16518c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 16528c2ecf20Sopenharmony_ci "message in w/o current command" 16538c2ecf20Sopenharmony_ci " not after reselection\n"); 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* 16578c2ecf20Sopenharmony_ci * Handle reselection 16588c2ecf20Sopenharmony_ci */ 16598c2ecf20Sopenharmony_ci if(!(MSGI(0) & IDENTIFY_BASE)) { 16608c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 16618c2ecf20Sopenharmony_ci "target didn't identify after reselection\n"); 16628c2ecf20Sopenharmony_ci continue; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (!CURRENT_SC) { 16688c2ecf20Sopenharmony_ci show_queues(shpnt); 16698c2ecf20Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 16708c2ecf20Sopenharmony_ci "no disconnected command" 16718c2ecf20Sopenharmony_ci " for target %d/%d\n", 16728c2ecf20Sopenharmony_ci RECONN_TARGET, MSGI(0) & 0x3f); 16738c2ecf20Sopenharmony_ci continue; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci CURRENT_SC->SCp.Message = MSGI(0); 16778c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase &= ~disconnected; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci MSGILEN=0; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* next message if any */ 16828c2ecf20Sopenharmony_ci continue; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci CURRENT_SC->SCp.Message = MSGI(0); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci switch (MSGI(0)) { 16888c2ecf20Sopenharmony_ci case DISCONNECT: 16898c2ecf20Sopenharmony_ci if (!RECONNECT) 16908c2ecf20Sopenharmony_ci scmd_printk(KERN_WARNING, CURRENT_SC, 16918c2ecf20Sopenharmony_ci "target was not allowed to disconnect\n"); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= disconnected; 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci case COMMAND_COMPLETE: 16978c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= completed; 16988c2ecf20Sopenharmony_ci break; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci case MESSAGE_REJECT: 17018c2ecf20Sopenharmony_ci if (SYNCNEG==1) { 17028c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 17038c2ecf20Sopenharmony_ci "Synchronous Data Transfer Request" 17048c2ecf20Sopenharmony_ci " was rejected\n"); 17058c2ecf20Sopenharmony_ci SYNCNEG=2; /* negotiation completed */ 17068c2ecf20Sopenharmony_ci } else 17078c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 17088c2ecf20Sopenharmony_ci "inbound message (MESSAGE REJECT)\n"); 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci case SAVE_POINTERS: 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci case RESTORE_POINTERS: 17158c2ecf20Sopenharmony_ci break; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci case EXTENDED_MESSAGE: 17188c2ecf20Sopenharmony_ci if(MSGILEN<2 || MSGILEN<MSGI(1)+2) { 17198c2ecf20Sopenharmony_ci /* not yet completed */ 17208c2ecf20Sopenharmony_ci continue; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci switch (MSGI(2)) { 17248c2ecf20Sopenharmony_ci case EXTENDED_SDTR: 17258c2ecf20Sopenharmony_ci { 17268c2ecf20Sopenharmony_ci long ticks; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci if (MSGI(1) != 3) { 17298c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 17308c2ecf20Sopenharmony_ci "SDTR message length!=3\n"); 17318c2ecf20Sopenharmony_ci break; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (!HOSTDATA(shpnt)->synchronous) 17358c2ecf20Sopenharmony_ci break; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci printk(INFO_LEAD, CMDINFO(CURRENT_SC)); 17388c2ecf20Sopenharmony_ci spi_print_msg(&MSGI(0)); 17398c2ecf20Sopenharmony_ci printk("\n"); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci ticks = (MSGI(3) * 4 + 49) / 50; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci if (syncneg) { 17448c2ecf20Sopenharmony_ci /* negotiation in progress */ 17458c2ecf20Sopenharmony_ci if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { 17468c2ecf20Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 17478c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, 17488c2ecf20Sopenharmony_ci CURRENT_SC, 17498c2ecf20Sopenharmony_ci "received Synchronous Data Transfer Request invalid - rejected\n"); 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 17548c2ecf20Sopenharmony_ci } else if (ticks <= 9 && MSGI(4) >= 1) { 17558c2ecf20Sopenharmony_ci ADDMSGO(EXTENDED_MESSAGE); 17568c2ecf20Sopenharmony_ci ADDMSGO(3); 17578c2ecf20Sopenharmony_ci ADDMSGO(EXTENDED_SDTR); 17588c2ecf20Sopenharmony_ci if (ticks < 4) { 17598c2ecf20Sopenharmony_ci ticks = 4; 17608c2ecf20Sopenharmony_ci ADDMSGO(50); 17618c2ecf20Sopenharmony_ci } else 17628c2ecf20Sopenharmony_ci ADDMSGO(MSGI(3)); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (MSGI(4) > 8) 17658c2ecf20Sopenharmony_ci MSGI(4) = 8; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci ADDMSGO(MSGI(4)); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 17708c2ecf20Sopenharmony_ci } else { 17718c2ecf20Sopenharmony_ci /* requested SDTR is too slow, do it asynchronously */ 17728c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, 17738c2ecf20Sopenharmony_ci CURRENT_SC, 17748c2ecf20Sopenharmony_ci "Synchronous Data Transfer Request too slow - Rejecting\n"); 17758c2ecf20Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* negotiation completed */ 17798c2ecf20Sopenharmony_ci SYNCNEG=2; 17808c2ecf20Sopenharmony_ci SETRATE(SYNCRATE); 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci break; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci case BUS_DEVICE_RESET: 17858c2ecf20Sopenharmony_ci { 17868c2ecf20Sopenharmony_ci int i; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci for(i=0; i<8; i++) { 17898c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->syncrate[i]=0; 17908c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->syncneg[i]=0; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci break; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci case EXTENDED_MODIFY_DATA_POINTER: 17978c2ecf20Sopenharmony_ci case EXTENDED_EXTENDED_IDENTIFY: 17988c2ecf20Sopenharmony_ci case EXTENDED_WDTR: 17998c2ecf20Sopenharmony_ci default: 18008c2ecf20Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 18018c2ecf20Sopenharmony_ci break; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci break; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci MSGILEN=0; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci if(MSGILEN>0) 18138c2ecf20Sopenharmony_ci scmd_printk(KERN_WARNING, CURRENT_SC, 18148c2ecf20Sopenharmony_ci "target left before message completed (%d)\n", 18158c2ecf20Sopenharmony_ci MSGILEN); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) 18188c2ecf20Sopenharmony_ci SETPORT(SCSISIG, P_MSGI | SIG_ATNO); 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci/* 18228c2ecf20Sopenharmony_ci * message out phase 18238c2ecf20Sopenharmony_ci * 18248c2ecf20Sopenharmony_ci */ 18258c2ecf20Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci if(MSGOLEN==0) { 18288c2ecf20Sopenharmony_ci if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) { 18298c2ecf20Sopenharmony_ci ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 18308c2ecf20Sopenharmony_ci } else { 18318c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 18328c2ecf20Sopenharmony_ci "unexpected MESSAGE OUT phase; rejecting\n"); 18338c2ecf20Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci/* 18408c2ecf20Sopenharmony_ci * message out phase 18418c2ecf20Sopenharmony_ci * 18428c2ecf20Sopenharmony_ci */ 18438c2ecf20Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci while(MSGO_I<MSGOLEN) { 18468c2ecf20Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 18478c2ecf20Sopenharmony_ci return; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci if (MSGO_I==MSGOLEN-1) { 18508c2ecf20Sopenharmony_ci /* Leave MESSAGE OUT after transfer */ 18518c2ecf20Sopenharmony_ci SETPORT(SSTAT1, CLRATNO); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci if (MSGO(MSGO_I) & IDENTIFY_BASE) 18568c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= identified; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci if (MSGO(MSGO_I)==ABORT) 18598c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= aborted; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (MSGO(MSGO_I)==BUS_DEVICE_RESET) 18628c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= resetted; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci SETPORT(SCSIDAT, MSGO(MSGO_I++)); 18658c2ecf20Sopenharmony_ci } 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci if(MSGO_I<MSGOLEN) { 18718c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 18728c2ecf20Sopenharmony_ci "message sent incompletely (%d/%d)\n", 18738c2ecf20Sopenharmony_ci MSGO_I, MSGOLEN); 18748c2ecf20Sopenharmony_ci if(SYNCNEG==1) { 18758c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 18768c2ecf20Sopenharmony_ci "Synchronous Data Transfer Request was rejected\n"); 18778c2ecf20Sopenharmony_ci SYNCNEG=2; 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci MSGO_I = 0; 18828c2ecf20Sopenharmony_ci MSGOLEN = 0; 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci/* 18868c2ecf20Sopenharmony_ci * command phase 18878c2ecf20Sopenharmony_ci * 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci if (CURRENT_SC->SCp.sent_command) { 18928c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 18938c2ecf20Sopenharmony_ci "command already sent\n"); 18948c2ecf20Sopenharmony_ci done(shpnt, DID_ERROR << 16); 18958c2ecf20Sopenharmony_ci return; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci CMD_I=0; 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci/* 19028c2ecf20Sopenharmony_ci * command phase 19038c2ecf20Sopenharmony_ci * 19048c2ecf20Sopenharmony_ci */ 19058c2ecf20Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci while(CMD_I<CURRENT_SC->cmd_len) { 19088c2ecf20Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 19098c2ecf20Sopenharmony_ci return; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci} 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt) 19168c2ecf20Sopenharmony_ci{ 19178c2ecf20Sopenharmony_ci if(CMD_I<CURRENT_SC->cmd_len) 19188c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 19198c2ecf20Sopenharmony_ci "command sent incompletely (%d/%d)\n", 19208c2ecf20Sopenharmony_ci CMD_I, CURRENT_SC->cmd_len); 19218c2ecf20Sopenharmony_ci else 19228c2ecf20Sopenharmony_ci CURRENT_SC->SCp.sent_command++; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci/* 19268c2ecf20Sopenharmony_ci * status phase 19278c2ecf20Sopenharmony_ci * 19288c2ecf20Sopenharmony_ci */ 19298c2ecf20Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt) 19308c2ecf20Sopenharmony_ci{ 19318c2ecf20Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 19328c2ecf20Sopenharmony_ci return; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci/* 19398c2ecf20Sopenharmony_ci * data in phase 19408c2ecf20Sopenharmony_ci * 19418c2ecf20Sopenharmony_ci */ 19428c2ecf20Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO); 19458c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO|ENDMA); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 19488c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci SETPORT(SIMODE0, 0); 19518c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci DATA_LEN=0; 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci unsigned long the_time; 19598c2ecf20Sopenharmony_ci int fifodata, data_count; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* 19628c2ecf20Sopenharmony_ci * loop while the phase persists or the fifos are not empty 19638c2ecf20Sopenharmony_ci * 19648c2ecf20Sopenharmony_ci */ 19658c2ecf20Sopenharmony_ci while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { 19668c2ecf20Sopenharmony_ci /* FIXME: maybe this should be done by setting up 19678c2ecf20Sopenharmony_ci * STCNT to trigger ENSWRAP interrupt, instead of 19688c2ecf20Sopenharmony_ci * polling for DFIFOFULL 19698c2ecf20Sopenharmony_ci */ 19708c2ecf20Sopenharmony_ci the_time=jiffies + 100*HZ; 19718c2ecf20Sopenharmony_ci while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) 19728c2ecf20Sopenharmony_ci barrier(); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { 19758c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n"); 19768c2ecf20Sopenharmony_ci break; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci if(TESTHI(DMASTAT, DFIFOFULL)) { 19808c2ecf20Sopenharmony_ci fifodata = 128; 19818c2ecf20Sopenharmony_ci } else { 19828c2ecf20Sopenharmony_ci the_time=jiffies + 100*HZ; 19838c2ecf20Sopenharmony_ci while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) 19848c2ecf20Sopenharmony_ci barrier(); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if(TESTLO(SSTAT2, SEMPTY)) { 19878c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 19888c2ecf20Sopenharmony_ci "datai sempty timeout"); 19898c2ecf20Sopenharmony_ci break; 19908c2ecf20Sopenharmony_ci } 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci fifodata = GETPORT(FIFOSTAT); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if(CURRENT_SC->SCp.this_residual>0) { 19968c2ecf20Sopenharmony_ci while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) { 19978c2ecf20Sopenharmony_ci data_count = fifodata > CURRENT_SC->SCp.this_residual ? 19988c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual : 19998c2ecf20Sopenharmony_ci fifodata; 20008c2ecf20Sopenharmony_ci fifodata -= data_count; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (data_count & 1) { 20038c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 20048c2ecf20Sopenharmony_ci *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); 20058c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual--; 20068c2ecf20Sopenharmony_ci DATA_LEN++; 20078c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA); 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if (data_count > 1) { 20118c2ecf20Sopenharmony_ci data_count >>= 1; 20128c2ecf20Sopenharmony_ci insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); 20138c2ecf20Sopenharmony_ci CURRENT_SC->SCp.ptr += 2 * data_count; 20148c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual -= 2 * data_count; 20158c2ecf20Sopenharmony_ci DATA_LEN += 2 * data_count; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (CURRENT_SC->SCp.this_residual == 0 && 20198c2ecf20Sopenharmony_ci !sg_is_last(CURRENT_SC->SCp.buffer)) { 20208c2ecf20Sopenharmony_ci /* advance to next buffer */ 20218c2ecf20Sopenharmony_ci CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); 20228c2ecf20Sopenharmony_ci CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); 20238c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci } else if (fifodata > 0) { 20278c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 20288c2ecf20Sopenharmony_ci "no buffers left for %d(%d) bytes" 20298c2ecf20Sopenharmony_ci " (data overrun!?)\n", 20308c2ecf20Sopenharmony_ci fifodata, GETPORT(FIFOSTAT)); 20318c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 20328c2ecf20Sopenharmony_ci while(fifodata>0) { 20338c2ecf20Sopenharmony_ci GETPORT(DATAPORT); 20348c2ecf20Sopenharmony_ci fifodata--; 20358c2ecf20Sopenharmony_ci DATA_LEN++; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci if(TESTLO(DMASTAT, INTSTAT) || 20428c2ecf20Sopenharmony_ci TESTLO(DMASTAT, DFIFOEMP) || 20438c2ecf20Sopenharmony_ci TESTLO(SSTAT2, SEMPTY) || 20448c2ecf20Sopenharmony_ci GETPORT(FIFOSTAT)>0) { 20458c2ecf20Sopenharmony_ci /* 20468c2ecf20Sopenharmony_ci * something went wrong, if there's something left in the fifos 20478c2ecf20Sopenharmony_ci * or the phase didn't change 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 20508c2ecf20Sopenharmony_ci "fifos should be empty and phase should have changed\n"); 20518c2ecf20Sopenharmony_ci } 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if(DATA_LEN!=GETSTCNT()) { 20548c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 20558c2ecf20Sopenharmony_ci "manual transfer count differs from automatic " 20568c2ecf20Sopenharmony_ci "(count=%d;stcnt=%d;diff=%d;fifostat=%d)", 20578c2ecf20Sopenharmony_ci DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, 20588c2ecf20Sopenharmony_ci GETPORT(FIFOSTAT)); 20598c2ecf20Sopenharmony_ci mdelay(10000); 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci} 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt) 20648c2ecf20Sopenharmony_ci{ 20658c2ecf20Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -GETSTCNT()); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 20688c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, 0); 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci/* 20728c2ecf20Sopenharmony_ci * data out phase 20738c2ecf20Sopenharmony_ci * 20748c2ecf20Sopenharmony_ci */ 20758c2ecf20Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); 20788c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, WRITE_READ | ENDMA); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 20818c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci SETPORT(SIMODE0, 0); 20848c2ecf20Sopenharmony_ci SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci DATA_LEN = scsi_get_resid(CURRENT_SC); 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci unsigned long the_time; 20928c2ecf20Sopenharmony_ci int data_count; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* until phase changes or all data sent */ 20958c2ecf20Sopenharmony_ci while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) { 20968c2ecf20Sopenharmony_ci data_count = 128; 20978c2ecf20Sopenharmony_ci if(data_count > CURRENT_SC->SCp.this_residual) 20988c2ecf20Sopenharmony_ci data_count=CURRENT_SC->SCp.this_residual; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP)) { 21018c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 21028c2ecf20Sopenharmony_ci "datao fifo not empty (%d)", 21038c2ecf20Sopenharmony_ci GETPORT(FIFOSTAT)); 21048c2ecf20Sopenharmony_ci break; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if(data_count & 1) { 21088c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); 21098c2ecf20Sopenharmony_ci SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); 21108c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual--; 21118c2ecf20Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -1); 21128c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0,WRITE_READ|ENDMA); 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci if(data_count > 1) { 21168c2ecf20Sopenharmony_ci data_count >>= 1; 21178c2ecf20Sopenharmony_ci outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); 21188c2ecf20Sopenharmony_ci CURRENT_SC->SCp.ptr += 2 * data_count; 21198c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual -= 2 * data_count; 21208c2ecf20Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -2 * data_count); 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (CURRENT_SC->SCp.this_residual == 0 && 21248c2ecf20Sopenharmony_ci !sg_is_last(CURRENT_SC->SCp.buffer)) { 21258c2ecf20Sopenharmony_ci /* advance to next buffer */ 21268c2ecf20Sopenharmony_ci CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); 21278c2ecf20Sopenharmony_ci CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); 21288c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci the_time=jiffies + 100*HZ; 21328c2ecf20Sopenharmony_ci while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) 21338c2ecf20Sopenharmony_ci barrier(); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { 21368c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n"); 21378c2ecf20Sopenharmony_ci break; 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci} 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP)) { 21458c2ecf20Sopenharmony_ci u32 datao_cnt = GETSTCNT(); 21468c2ecf20Sopenharmony_ci int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC); 21478c2ecf20Sopenharmony_ci int done; 21488c2ecf20Sopenharmony_ci struct scatterlist *sg = scsi_sglist(CURRENT_SC); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC); 21538c2ecf20Sopenharmony_ci /* Locate the first SG entry not yet sent */ 21548c2ecf20Sopenharmony_ci while (done > 0 && !sg_is_last(sg)) { 21558c2ecf20Sopenharmony_ci if (done < sg->length) 21568c2ecf20Sopenharmony_ci break; 21578c2ecf20Sopenharmony_ci done -= sg->length; 21588c2ecf20Sopenharmony_ci sg = sg_next(sg); 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci CURRENT_SC->SCp.buffer = sg; 21628c2ecf20Sopenharmony_ci CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done; 21638c2ecf20Sopenharmony_ci CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length - 21648c2ecf20Sopenharmony_ci done; 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 21688c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, 0); 21718c2ecf20Sopenharmony_ci} 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci/* 21748c2ecf20Sopenharmony_ci * figure out what state we're in 21758c2ecf20Sopenharmony_ci * 21768c2ecf20Sopenharmony_ci */ 21778c2ecf20Sopenharmony_cistatic int update_state(struct Scsi_Host *shpnt) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci int dataphase=0; 21808c2ecf20Sopenharmony_ci unsigned int stat0 = GETPORT(SSTAT0); 21818c2ecf20Sopenharmony_ci unsigned int stat1 = GETPORT(SSTAT1); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci PREVSTATE = STATE; 21848c2ecf20Sopenharmony_ci STATE=unknown; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if(stat1 & SCSIRSTI) { 21878c2ecf20Sopenharmony_ci STATE=rsti; 21888c2ecf20Sopenharmony_ci SETPORT(SCSISEQ,0); 21898c2ecf20Sopenharmony_ci SETPORT(SSTAT1,SCSIRSTI); 21908c2ecf20Sopenharmony_ci } else if (stat0 & SELDI && PREVSTATE == busfree) { 21918c2ecf20Sopenharmony_ci STATE=seldi; 21928c2ecf20Sopenharmony_ci } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) { 21938c2ecf20Sopenharmony_ci STATE=seldo; 21948c2ecf20Sopenharmony_ci } else if(stat1 & SELTO) { 21958c2ecf20Sopenharmony_ci STATE=selto; 21968c2ecf20Sopenharmony_ci } else if(stat1 & BUSFREE) { 21978c2ecf20Sopenharmony_ci STATE=busfree; 21988c2ecf20Sopenharmony_ci SETPORT(SSTAT1,BUSFREE); 21998c2ecf20Sopenharmony_ci } else if(stat1 & SCSIPERR) { 22008c2ecf20Sopenharmony_ci STATE=parerr; 22018c2ecf20Sopenharmony_ci SETPORT(SSTAT1,SCSIPERR); 22028c2ecf20Sopenharmony_ci } else if(stat1 & REQINIT) { 22038c2ecf20Sopenharmony_ci switch(GETPORT(SCSISIG) & P_MASK) { 22048c2ecf20Sopenharmony_ci case P_MSGI: STATE=msgi; break; 22058c2ecf20Sopenharmony_ci case P_MSGO: STATE=msgo; break; 22068c2ecf20Sopenharmony_ci case P_DATAO: STATE=datao; break; 22078c2ecf20Sopenharmony_ci case P_DATAI: STATE=datai; break; 22088c2ecf20Sopenharmony_ci case P_STATUS: STATE=status; break; 22098c2ecf20Sopenharmony_ci case P_CMD: STATE=cmd; break; 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci dataphase=1; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if((stat0 & SELDI) && STATE!=seldi && !dataphase) { 22158c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?"); 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci if(STATE!=PREVSTATE) { 22198c2ecf20Sopenharmony_ci LASTSTATE=PREVSTATE; 22208c2ecf20Sopenharmony_ci } 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci return dataphase; 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci/* 22268c2ecf20Sopenharmony_ci * handle parity error 22278c2ecf20Sopenharmony_ci * 22288c2ecf20Sopenharmony_ci * FIXME: in which phase? 22298c2ecf20Sopenharmony_ci * 22308c2ecf20Sopenharmony_ci */ 22318c2ecf20Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt) 22328c2ecf20Sopenharmony_ci{ 22338c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n"); 22348c2ecf20Sopenharmony_ci done(shpnt, DID_PARITY << 16); 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci/* 22388c2ecf20Sopenharmony_ci * handle reset in 22398c2ecf20Sopenharmony_ci * 22408c2ecf20Sopenharmony_ci */ 22418c2ecf20Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt) 22428c2ecf20Sopenharmony_ci{ 22438c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n"); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci ptr=DISCONNECTED_SC; 22488c2ecf20Sopenharmony_ci while(ptr) { 22498c2ecf20Sopenharmony_ci struct scsi_cmnd *next = SCNEXT(ptr); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (!ptr->device->soft_reset) { 22528c2ecf20Sopenharmony_ci remove_SC(&DISCONNECTED_SC, ptr); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci kfree(ptr->host_scribble); 22558c2ecf20Sopenharmony_ci ptr->host_scribble=NULL; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci ptr->result = DID_RESET << 16; 22588c2ecf20Sopenharmony_ci ptr->scsi_done(ptr); 22598c2ecf20Sopenharmony_ci } 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci ptr = next; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci if(CURRENT_SC && !CURRENT_SC->device->soft_reset) 22658c2ecf20Sopenharmony_ci done(shpnt, DID_RESET << 16 ); 22668c2ecf20Sopenharmony_ci} 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci/* 22708c2ecf20Sopenharmony_ci * bottom-half handler 22718c2ecf20Sopenharmony_ci * 22728c2ecf20Sopenharmony_ci */ 22738c2ecf20Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci int dataphase; 22768c2ecf20Sopenharmony_ci unsigned long flags; 22778c2ecf20Sopenharmony_ci int pending; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci if(!shpnt) 22808c2ecf20Sopenharmony_ci return; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci DO_LOCK(flags); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if( HOSTDATA(shpnt)->service==0 ) { 22858c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 22868c2ecf20Sopenharmony_ci return; 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->service = 0; 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci if(HOSTDATA(shpnt)->in_intr) { 22928c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 22938c2ecf20Sopenharmony_ci /* aha152x_error never returns.. */ 22948c2ecf20Sopenharmony_ci aha152x_error(shpnt, "bottom-half already running!?"); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->in_intr++; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci /* 22998c2ecf20Sopenharmony_ci * loop while there are interrupt conditions pending 23008c2ecf20Sopenharmony_ci * 23018c2ecf20Sopenharmony_ci */ 23028c2ecf20Sopenharmony_ci do { 23038c2ecf20Sopenharmony_ci unsigned long start = jiffies; 23048c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci dataphase=update_state(shpnt); 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci /* 23098c2ecf20Sopenharmony_ci * end previous state 23108c2ecf20Sopenharmony_ci * 23118c2ecf20Sopenharmony_ci */ 23128c2ecf20Sopenharmony_ci if(PREVSTATE!=STATE && states[PREVSTATE].end) 23138c2ecf20Sopenharmony_ci states[PREVSTATE].end(shpnt); 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci /* 23168c2ecf20Sopenharmony_ci * disable SPIO mode if previous phase used it 23178c2ecf20Sopenharmony_ci * and this one doesn't 23188c2ecf20Sopenharmony_ci * 23198c2ecf20Sopenharmony_ci */ 23208c2ecf20Sopenharmony_ci if(states[PREVSTATE].spio && !states[STATE].spio) { 23218c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 23228c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, 0); 23238c2ecf20Sopenharmony_ci if(CURRENT_SC) 23248c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase &= ~spiordy; 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci /* 23288c2ecf20Sopenharmony_ci * accept current dataphase phase 23298c2ecf20Sopenharmony_ci * 23308c2ecf20Sopenharmony_ci */ 23318c2ecf20Sopenharmony_ci if(dataphase) { 23328c2ecf20Sopenharmony_ci SETPORT(SSTAT0, REQINIT); 23338c2ecf20Sopenharmony_ci SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); 23348c2ecf20Sopenharmony_ci SETPORT(SSTAT1, PHASECHG); 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci /* 23388c2ecf20Sopenharmony_ci * enable SPIO mode if previous didn't use it 23398c2ecf20Sopenharmony_ci * and this one does 23408c2ecf20Sopenharmony_ci * 23418c2ecf20Sopenharmony_ci */ 23428c2ecf20Sopenharmony_ci if(!states[PREVSTATE].spio && states[STATE].spio) { 23438c2ecf20Sopenharmony_ci SETPORT(DMACNTRL0, 0); 23448c2ecf20Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SPIOEN); 23458c2ecf20Sopenharmony_ci if(CURRENT_SC) 23468c2ecf20Sopenharmony_ci CURRENT_SC->SCp.phase |= spiordy; 23478c2ecf20Sopenharmony_ci } 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci /* 23508c2ecf20Sopenharmony_ci * initialize for new state 23518c2ecf20Sopenharmony_ci * 23528c2ecf20Sopenharmony_ci */ 23538c2ecf20Sopenharmony_ci if(PREVSTATE!=STATE && states[STATE].init) 23548c2ecf20Sopenharmony_ci states[STATE].init(shpnt); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci /* 23578c2ecf20Sopenharmony_ci * handle current state 23588c2ecf20Sopenharmony_ci * 23598c2ecf20Sopenharmony_ci */ 23608c2ecf20Sopenharmony_ci if(states[STATE].run) 23618c2ecf20Sopenharmony_ci states[STATE].run(shpnt); 23628c2ecf20Sopenharmony_ci else 23638c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 23648c2ecf20Sopenharmony_ci "unexpected state (%x)\n", STATE); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci /* 23678c2ecf20Sopenharmony_ci * setup controller to interrupt on 23688c2ecf20Sopenharmony_ci * the next expected condition and 23698c2ecf20Sopenharmony_ci * loop if it's already there 23708c2ecf20Sopenharmony_ci * 23718c2ecf20Sopenharmony_ci */ 23728c2ecf20Sopenharmony_ci DO_LOCK(flags); 23738c2ecf20Sopenharmony_ci pending=setup_expected_interrupts(shpnt); 23748c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 23758c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count[STATE]++; 23768c2ecf20Sopenharmony_ci if(PREVSTATE!=STATE) 23778c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count_trans[STATE]++; 23788c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->time[STATE] += jiffies-start; 23798c2ecf20Sopenharmony_ci#endif 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci } while(pending); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci /* 23848c2ecf20Sopenharmony_ci * enable interrupts and leave bottom-half 23858c2ecf20Sopenharmony_ci * 23868c2ecf20Sopenharmony_ci */ 23878c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->in_intr--; 23888c2ecf20Sopenharmony_ci SETBITS(DMACNTRL0, INTEN); 23898c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 23908c2ecf20Sopenharmony_ci} 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci/* 23948c2ecf20Sopenharmony_ci * Dump the current driver status and panic 23958c2ecf20Sopenharmony_ci */ 23968c2ecf20Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg) 23978c2ecf20Sopenharmony_ci{ 23988c2ecf20Sopenharmony_ci shost_printk(KERN_EMERG, shpnt, "%s\n", msg); 23998c2ecf20Sopenharmony_ci show_queues(shpnt); 24008c2ecf20Sopenharmony_ci panic("aha152x panic\n"); 24018c2ecf20Sopenharmony_ci} 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci/* 24048c2ecf20Sopenharmony_ci * display enabled interrupts 24058c2ecf20Sopenharmony_ci */ 24068c2ecf20Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt) 24078c2ecf20Sopenharmony_ci{ 24088c2ecf20Sopenharmony_ci int s0, s1; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci s0 = GETPORT(SIMODE0); 24118c2ecf20Sopenharmony_ci s1 = GETPORT(SIMODE1); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci shost_printk(KERN_DEBUG, shpnt, 24148c2ecf20Sopenharmony_ci "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", 24158c2ecf20Sopenharmony_ci (s0 & ENSELDO) ? "ENSELDO " : "", 24168c2ecf20Sopenharmony_ci (s0 & ENSELDI) ? "ENSELDI " : "", 24178c2ecf20Sopenharmony_ci (s0 & ENSELINGO) ? "ENSELINGO " : "", 24188c2ecf20Sopenharmony_ci (s0 & ENSWRAP) ? "ENSWRAP " : "", 24198c2ecf20Sopenharmony_ci (s0 & ENSDONE) ? "ENSDONE " : "", 24208c2ecf20Sopenharmony_ci (s0 & ENSPIORDY) ? "ENSPIORDY " : "", 24218c2ecf20Sopenharmony_ci (s0 & ENDMADONE) ? "ENDMADONE " : "", 24228c2ecf20Sopenharmony_ci (s1 & ENSELTIMO) ? "ENSELTIMO " : "", 24238c2ecf20Sopenharmony_ci (s1 & ENATNTARG) ? "ENATNTARG " : "", 24248c2ecf20Sopenharmony_ci (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "", 24258c2ecf20Sopenharmony_ci (s1 & ENBUSFREE) ? "ENBUSFREE " : "", 24268c2ecf20Sopenharmony_ci (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "", 24278c2ecf20Sopenharmony_ci (s1 & ENPHASECHG) ? "ENPHASECHG " : "", 24288c2ecf20Sopenharmony_ci (s1 & ENREQINIT) ? "ENREQINIT " : ""); 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci/* 24328c2ecf20Sopenharmony_ci * Show the command data of a command 24338c2ecf20Sopenharmony_ci */ 24348c2ecf20Sopenharmony_cistatic void show_command(struct scsi_cmnd *ptr) 24358c2ecf20Sopenharmony_ci{ 24368c2ecf20Sopenharmony_ci scsi_print_command(ptr); 24378c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, ptr, 24388c2ecf20Sopenharmony_ci "request_bufflen=%d; resid=%d; " 24398c2ecf20Sopenharmony_ci "phase |%s%s%s%s%s%s%s%s%s; next=0x%p", 24408c2ecf20Sopenharmony_ci scsi_bufflen(ptr), scsi_get_resid(ptr), 24418c2ecf20Sopenharmony_ci (ptr->SCp.phase & not_issued) ? "not issued|" : "", 24428c2ecf20Sopenharmony_ci (ptr->SCp.phase & selecting) ? "selecting|" : "", 24438c2ecf20Sopenharmony_ci (ptr->SCp.phase & identified) ? "identified|" : "", 24448c2ecf20Sopenharmony_ci (ptr->SCp.phase & disconnected) ? "disconnected|" : "", 24458c2ecf20Sopenharmony_ci (ptr->SCp.phase & completed) ? "completed|" : "", 24468c2ecf20Sopenharmony_ci (ptr->SCp.phase & spiordy) ? "spiordy|" : "", 24478c2ecf20Sopenharmony_ci (ptr->SCp.phase & syncneg) ? "syncneg|" : "", 24488c2ecf20Sopenharmony_ci (ptr->SCp.phase & aborted) ? "aborted|" : "", 24498c2ecf20Sopenharmony_ci (ptr->SCp.phase & resetted) ? "resetted|" : "", 24508c2ecf20Sopenharmony_ci (SCDATA(ptr)) ? SCNEXT(ptr) : NULL); 24518c2ecf20Sopenharmony_ci} 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci/* 24548c2ecf20Sopenharmony_ci * Dump the queued data 24558c2ecf20Sopenharmony_ci */ 24568c2ecf20Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt) 24578c2ecf20Sopenharmony_ci{ 24588c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 24598c2ecf20Sopenharmony_ci unsigned long flags; 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci DO_LOCK(flags); 24628c2ecf20Sopenharmony_ci printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); 24638c2ecf20Sopenharmony_ci for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 24648c2ecf20Sopenharmony_ci show_command(ptr); 24658c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "current_SC:\n"); 24688c2ecf20Sopenharmony_ci if (CURRENT_SC) 24698c2ecf20Sopenharmony_ci show_command(CURRENT_SC); 24708c2ecf20Sopenharmony_ci else 24718c2ecf20Sopenharmony_ci printk(KERN_DEBUG "none\n"); 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci printk(KERN_DEBUG "disconnected_SC:\n"); 24748c2ecf20Sopenharmony_ci for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL) 24758c2ecf20Sopenharmony_ci show_command(ptr); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci disp_enintr(shpnt); 24788c2ecf20Sopenharmony_ci} 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_cistatic void get_command(struct seq_file *m, struct scsi_cmnd * ptr) 24818c2ecf20Sopenharmony_ci{ 24828c2ecf20Sopenharmony_ci int i; 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ", 24858c2ecf20Sopenharmony_ci ptr, ptr->device->id, (u8)ptr->device->lun); 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) 24888c2ecf20Sopenharmony_ci seq_printf(m, "0x%02x ", ptr->cmnd[i]); 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", 24918c2ecf20Sopenharmony_ci scsi_get_resid(ptr), ptr->SCp.this_residual, 24928c2ecf20Sopenharmony_ci sg_nents(ptr->SCp.buffer) - 1); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (ptr->SCp.phase & not_issued) 24958c2ecf20Sopenharmony_ci seq_puts(m, "not issued|"); 24968c2ecf20Sopenharmony_ci if (ptr->SCp.phase & selecting) 24978c2ecf20Sopenharmony_ci seq_puts(m, "selecting|"); 24988c2ecf20Sopenharmony_ci if (ptr->SCp.phase & disconnected) 24998c2ecf20Sopenharmony_ci seq_puts(m, "disconnected|"); 25008c2ecf20Sopenharmony_ci if (ptr->SCp.phase & aborted) 25018c2ecf20Sopenharmony_ci seq_puts(m, "aborted|"); 25028c2ecf20Sopenharmony_ci if (ptr->SCp.phase & identified) 25038c2ecf20Sopenharmony_ci seq_puts(m, "identified|"); 25048c2ecf20Sopenharmony_ci if (ptr->SCp.phase & completed) 25058c2ecf20Sopenharmony_ci seq_puts(m, "completed|"); 25068c2ecf20Sopenharmony_ci if (ptr->SCp.phase & spiordy) 25078c2ecf20Sopenharmony_ci seq_puts(m, "spiordy|"); 25088c2ecf20Sopenharmony_ci if (ptr->SCp.phase & syncneg) 25098c2ecf20Sopenharmony_ci seq_puts(m, "syncneg|"); 25108c2ecf20Sopenharmony_ci seq_printf(m, "; next=0x%p\n", SCNEXT(ptr)); 25118c2ecf20Sopenharmony_ci} 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_cistatic void get_ports(struct seq_file *m, struct Scsi_Host *shpnt) 25148c2ecf20Sopenharmony_ci{ 25158c2ecf20Sopenharmony_ci int s; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci s = GETPORT(SCSISEQ); 25208c2ecf20Sopenharmony_ci seq_puts(m, "SCSISEQ( "); 25218c2ecf20Sopenharmony_ci if (s & TEMODEO) 25228c2ecf20Sopenharmony_ci seq_puts(m, "TARGET MODE "); 25238c2ecf20Sopenharmony_ci if (s & ENSELO) 25248c2ecf20Sopenharmony_ci seq_puts(m, "SELO "); 25258c2ecf20Sopenharmony_ci if (s & ENSELI) 25268c2ecf20Sopenharmony_ci seq_puts(m, "SELI "); 25278c2ecf20Sopenharmony_ci if (s & ENRESELI) 25288c2ecf20Sopenharmony_ci seq_puts(m, "RESELI "); 25298c2ecf20Sopenharmony_ci if (s & ENAUTOATNO) 25308c2ecf20Sopenharmony_ci seq_puts(m, "AUTOATNO "); 25318c2ecf20Sopenharmony_ci if (s & ENAUTOATNI) 25328c2ecf20Sopenharmony_ci seq_puts(m, "AUTOATNI "); 25338c2ecf20Sopenharmony_ci if (s & ENAUTOATNP) 25348c2ecf20Sopenharmony_ci seq_puts(m, "AUTOATNP "); 25358c2ecf20Sopenharmony_ci if (s & SCSIRSTO) 25368c2ecf20Sopenharmony_ci seq_puts(m, "SCSIRSTO "); 25378c2ecf20Sopenharmony_ci seq_puts(m, ");"); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci seq_puts(m, " SCSISIG("); 25408c2ecf20Sopenharmony_ci s = GETPORT(SCSISIG); 25418c2ecf20Sopenharmony_ci switch (s & P_MASK) { 25428c2ecf20Sopenharmony_ci case P_DATAO: 25438c2ecf20Sopenharmony_ci seq_puts(m, "DATA OUT"); 25448c2ecf20Sopenharmony_ci break; 25458c2ecf20Sopenharmony_ci case P_DATAI: 25468c2ecf20Sopenharmony_ci seq_puts(m, "DATA IN"); 25478c2ecf20Sopenharmony_ci break; 25488c2ecf20Sopenharmony_ci case P_CMD: 25498c2ecf20Sopenharmony_ci seq_puts(m, "COMMAND"); 25508c2ecf20Sopenharmony_ci break; 25518c2ecf20Sopenharmony_ci case P_STATUS: 25528c2ecf20Sopenharmony_ci seq_puts(m, "STATUS"); 25538c2ecf20Sopenharmony_ci break; 25548c2ecf20Sopenharmony_ci case P_MSGO: 25558c2ecf20Sopenharmony_ci seq_puts(m, "MESSAGE OUT"); 25568c2ecf20Sopenharmony_ci break; 25578c2ecf20Sopenharmony_ci case P_MSGI: 25588c2ecf20Sopenharmony_ci seq_puts(m, "MESSAGE IN"); 25598c2ecf20Sopenharmony_ci break; 25608c2ecf20Sopenharmony_ci default: 25618c2ecf20Sopenharmony_ci seq_puts(m, "*invalid*"); 25628c2ecf20Sopenharmony_ci break; 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci seq_puts(m, "); "); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci seq_puts(m, "SSTAT( "); 25708c2ecf20Sopenharmony_ci s = GETPORT(SSTAT0); 25718c2ecf20Sopenharmony_ci if (s & TARGET) 25728c2ecf20Sopenharmony_ci seq_puts(m, "TARGET "); 25738c2ecf20Sopenharmony_ci if (s & SELDO) 25748c2ecf20Sopenharmony_ci seq_puts(m, "SELDO "); 25758c2ecf20Sopenharmony_ci if (s & SELDI) 25768c2ecf20Sopenharmony_ci seq_puts(m, "SELDI "); 25778c2ecf20Sopenharmony_ci if (s & SELINGO) 25788c2ecf20Sopenharmony_ci seq_puts(m, "SELINGO "); 25798c2ecf20Sopenharmony_ci if (s & SWRAP) 25808c2ecf20Sopenharmony_ci seq_puts(m, "SWRAP "); 25818c2ecf20Sopenharmony_ci if (s & SDONE) 25828c2ecf20Sopenharmony_ci seq_puts(m, "SDONE "); 25838c2ecf20Sopenharmony_ci if (s & SPIORDY) 25848c2ecf20Sopenharmony_ci seq_puts(m, "SPIORDY "); 25858c2ecf20Sopenharmony_ci if (s & DMADONE) 25868c2ecf20Sopenharmony_ci seq_puts(m, "DMADONE "); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci s = GETPORT(SSTAT1); 25898c2ecf20Sopenharmony_ci if (s & SELTO) 25908c2ecf20Sopenharmony_ci seq_puts(m, "SELTO "); 25918c2ecf20Sopenharmony_ci if (s & ATNTARG) 25928c2ecf20Sopenharmony_ci seq_puts(m, "ATNTARG "); 25938c2ecf20Sopenharmony_ci if (s & SCSIRSTI) 25948c2ecf20Sopenharmony_ci seq_puts(m, "SCSIRSTI "); 25958c2ecf20Sopenharmony_ci if (s & PHASEMIS) 25968c2ecf20Sopenharmony_ci seq_puts(m, "PHASEMIS "); 25978c2ecf20Sopenharmony_ci if (s & BUSFREE) 25988c2ecf20Sopenharmony_ci seq_puts(m, "BUSFREE "); 25998c2ecf20Sopenharmony_ci if (s & SCSIPERR) 26008c2ecf20Sopenharmony_ci seq_puts(m, "SCSIPERR "); 26018c2ecf20Sopenharmony_ci if (s & PHASECHG) 26028c2ecf20Sopenharmony_ci seq_puts(m, "PHASECHG "); 26038c2ecf20Sopenharmony_ci if (s & REQINIT) 26048c2ecf20Sopenharmony_ci seq_puts(m, "REQINIT "); 26058c2ecf20Sopenharmony_ci seq_puts(m, "); "); 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci seq_puts(m, "SSTAT( "); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci s = GETPORT(SSTAT0) & GETPORT(SIMODE0); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci if (s & TARGET) 26138c2ecf20Sopenharmony_ci seq_puts(m, "TARGET "); 26148c2ecf20Sopenharmony_ci if (s & SELDO) 26158c2ecf20Sopenharmony_ci seq_puts(m, "SELDO "); 26168c2ecf20Sopenharmony_ci if (s & SELDI) 26178c2ecf20Sopenharmony_ci seq_puts(m, "SELDI "); 26188c2ecf20Sopenharmony_ci if (s & SELINGO) 26198c2ecf20Sopenharmony_ci seq_puts(m, "SELINGO "); 26208c2ecf20Sopenharmony_ci if (s & SWRAP) 26218c2ecf20Sopenharmony_ci seq_puts(m, "SWRAP "); 26228c2ecf20Sopenharmony_ci if (s & SDONE) 26238c2ecf20Sopenharmony_ci seq_puts(m, "SDONE "); 26248c2ecf20Sopenharmony_ci if (s & SPIORDY) 26258c2ecf20Sopenharmony_ci seq_puts(m, "SPIORDY "); 26268c2ecf20Sopenharmony_ci if (s & DMADONE) 26278c2ecf20Sopenharmony_ci seq_puts(m, "DMADONE "); 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci s = GETPORT(SSTAT1) & GETPORT(SIMODE1); 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci if (s & SELTO) 26328c2ecf20Sopenharmony_ci seq_puts(m, "SELTO "); 26338c2ecf20Sopenharmony_ci if (s & ATNTARG) 26348c2ecf20Sopenharmony_ci seq_puts(m, "ATNTARG "); 26358c2ecf20Sopenharmony_ci if (s & SCSIRSTI) 26368c2ecf20Sopenharmony_ci seq_puts(m, "SCSIRSTI "); 26378c2ecf20Sopenharmony_ci if (s & PHASEMIS) 26388c2ecf20Sopenharmony_ci seq_puts(m, "PHASEMIS "); 26398c2ecf20Sopenharmony_ci if (s & BUSFREE) 26408c2ecf20Sopenharmony_ci seq_puts(m, "BUSFREE "); 26418c2ecf20Sopenharmony_ci if (s & SCSIPERR) 26428c2ecf20Sopenharmony_ci seq_puts(m, "SCSIPERR "); 26438c2ecf20Sopenharmony_ci if (s & PHASECHG) 26448c2ecf20Sopenharmony_ci seq_puts(m, "PHASECHG "); 26458c2ecf20Sopenharmony_ci if (s & REQINIT) 26468c2ecf20Sopenharmony_ci seq_puts(m, "REQINIT "); 26478c2ecf20Sopenharmony_ci seq_puts(m, "); "); 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci seq_puts(m, "SXFRCTL0( "); 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci s = GETPORT(SXFRCTL0); 26528c2ecf20Sopenharmony_ci if (s & SCSIEN) 26538c2ecf20Sopenharmony_ci seq_puts(m, "SCSIEN "); 26548c2ecf20Sopenharmony_ci if (s & DMAEN) 26558c2ecf20Sopenharmony_ci seq_puts(m, "DMAEN "); 26568c2ecf20Sopenharmony_ci if (s & CH1) 26578c2ecf20Sopenharmony_ci seq_puts(m, "CH1 "); 26588c2ecf20Sopenharmony_ci if (s & CLRSTCNT) 26598c2ecf20Sopenharmony_ci seq_puts(m, "CLRSTCNT "); 26608c2ecf20Sopenharmony_ci if (s & SPIOEN) 26618c2ecf20Sopenharmony_ci seq_puts(m, "SPIOEN "); 26628c2ecf20Sopenharmony_ci if (s & CLRCH1) 26638c2ecf20Sopenharmony_ci seq_puts(m, "CLRCH1 "); 26648c2ecf20Sopenharmony_ci seq_puts(m, "); "); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci seq_puts(m, "SIGNAL( "); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci s = GETPORT(SCSISIG); 26698c2ecf20Sopenharmony_ci if (s & SIG_ATNI) 26708c2ecf20Sopenharmony_ci seq_puts(m, "ATNI "); 26718c2ecf20Sopenharmony_ci if (s & SIG_SELI) 26728c2ecf20Sopenharmony_ci seq_puts(m, "SELI "); 26738c2ecf20Sopenharmony_ci if (s & SIG_BSYI) 26748c2ecf20Sopenharmony_ci seq_puts(m, "BSYI "); 26758c2ecf20Sopenharmony_ci if (s & SIG_REQI) 26768c2ecf20Sopenharmony_ci seq_puts(m, "REQI "); 26778c2ecf20Sopenharmony_ci if (s & SIG_ACKI) 26788c2ecf20Sopenharmony_ci seq_puts(m, "ACKI "); 26798c2ecf20Sopenharmony_ci seq_puts(m, "); "); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci seq_printf(m, "SELID(%02x), ", GETPORT(SELID)); 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci seq_printf(m, "STCNT(%d), ", GETSTCNT()); 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci seq_puts(m, "SSTAT2( "); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci s = GETPORT(SSTAT2); 26888c2ecf20Sopenharmony_ci if (s & SOFFSET) 26898c2ecf20Sopenharmony_ci seq_puts(m, "SOFFSET "); 26908c2ecf20Sopenharmony_ci if (s & SEMPTY) 26918c2ecf20Sopenharmony_ci seq_puts(m, "SEMPTY "); 26928c2ecf20Sopenharmony_ci if (s & SFULL) 26938c2ecf20Sopenharmony_ci seq_puts(m, "SFULL "); 26948c2ecf20Sopenharmony_ci seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT)); 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci s = GETPORT(SSTAT3); 26978c2ecf20Sopenharmony_ci seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci seq_puts(m, "SSTAT4( "); 27008c2ecf20Sopenharmony_ci s = GETPORT(SSTAT4); 27018c2ecf20Sopenharmony_ci if (s & SYNCERR) 27028c2ecf20Sopenharmony_ci seq_puts(m, "SYNCERR "); 27038c2ecf20Sopenharmony_ci if (s & FWERR) 27048c2ecf20Sopenharmony_ci seq_puts(m, "FWERR "); 27058c2ecf20Sopenharmony_ci if (s & FRERR) 27068c2ecf20Sopenharmony_ci seq_puts(m, "FRERR "); 27078c2ecf20Sopenharmony_ci seq_puts(m, "); "); 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci seq_puts(m, "DMACNTRL0( "); 27108c2ecf20Sopenharmony_ci s = GETPORT(DMACNTRL0); 27118c2ecf20Sopenharmony_ci seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT"); 27128c2ecf20Sopenharmony_ci seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO"); 27138c2ecf20Sopenharmony_ci seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ"); 27148c2ecf20Sopenharmony_ci if (s & ENDMA) 27158c2ecf20Sopenharmony_ci seq_puts(m, "ENDMA "); 27168c2ecf20Sopenharmony_ci if (s & INTEN) 27178c2ecf20Sopenharmony_ci seq_puts(m, "INTEN "); 27188c2ecf20Sopenharmony_ci if (s & RSTFIFO) 27198c2ecf20Sopenharmony_ci seq_puts(m, "RSTFIFO "); 27208c2ecf20Sopenharmony_ci if (s & SWINT) 27218c2ecf20Sopenharmony_ci seq_puts(m, "SWINT "); 27228c2ecf20Sopenharmony_ci seq_puts(m, "); "); 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci seq_puts(m, "DMASTAT( "); 27258c2ecf20Sopenharmony_ci s = GETPORT(DMASTAT); 27268c2ecf20Sopenharmony_ci if (s & ATDONE) 27278c2ecf20Sopenharmony_ci seq_puts(m, "ATDONE "); 27288c2ecf20Sopenharmony_ci if (s & WORDRDY) 27298c2ecf20Sopenharmony_ci seq_puts(m, "WORDRDY "); 27308c2ecf20Sopenharmony_ci if (s & DFIFOFULL) 27318c2ecf20Sopenharmony_ci seq_puts(m, "DFIFOFULL "); 27328c2ecf20Sopenharmony_ci if (s & DFIFOEMP) 27338c2ecf20Sopenharmony_ci seq_puts(m, "DFIFOEMP "); 27348c2ecf20Sopenharmony_ci seq_puts(m, ")\n"); 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci seq_puts(m, "enabled interrupts( "); 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci s = GETPORT(SIMODE0); 27398c2ecf20Sopenharmony_ci if (s & ENSELDO) 27408c2ecf20Sopenharmony_ci seq_puts(m, "ENSELDO "); 27418c2ecf20Sopenharmony_ci if (s & ENSELDI) 27428c2ecf20Sopenharmony_ci seq_puts(m, "ENSELDI "); 27438c2ecf20Sopenharmony_ci if (s & ENSELINGO) 27448c2ecf20Sopenharmony_ci seq_puts(m, "ENSELINGO "); 27458c2ecf20Sopenharmony_ci if (s & ENSWRAP) 27468c2ecf20Sopenharmony_ci seq_puts(m, "ENSWRAP "); 27478c2ecf20Sopenharmony_ci if (s & ENSDONE) 27488c2ecf20Sopenharmony_ci seq_puts(m, "ENSDONE "); 27498c2ecf20Sopenharmony_ci if (s & ENSPIORDY) 27508c2ecf20Sopenharmony_ci seq_puts(m, "ENSPIORDY "); 27518c2ecf20Sopenharmony_ci if (s & ENDMADONE) 27528c2ecf20Sopenharmony_ci seq_puts(m, "ENDMADONE "); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci s = GETPORT(SIMODE1); 27558c2ecf20Sopenharmony_ci if (s & ENSELTIMO) 27568c2ecf20Sopenharmony_ci seq_puts(m, "ENSELTIMO "); 27578c2ecf20Sopenharmony_ci if (s & ENATNTARG) 27588c2ecf20Sopenharmony_ci seq_puts(m, "ENATNTARG "); 27598c2ecf20Sopenharmony_ci if (s & ENPHASEMIS) 27608c2ecf20Sopenharmony_ci seq_puts(m, "ENPHASEMIS "); 27618c2ecf20Sopenharmony_ci if (s & ENBUSFREE) 27628c2ecf20Sopenharmony_ci seq_puts(m, "ENBUSFREE "); 27638c2ecf20Sopenharmony_ci if (s & ENSCSIPERR) 27648c2ecf20Sopenharmony_ci seq_puts(m, "ENSCSIPERR "); 27658c2ecf20Sopenharmony_ci if (s & ENPHASECHG) 27668c2ecf20Sopenharmony_ci seq_puts(m, "ENPHASECHG "); 27678c2ecf20Sopenharmony_ci if (s & ENREQINIT) 27688c2ecf20Sopenharmony_ci seq_puts(m, "ENREQINIT "); 27698c2ecf20Sopenharmony_ci seq_puts(m, ")\n"); 27708c2ecf20Sopenharmony_ci} 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_cistatic int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length) 27738c2ecf20Sopenharmony_ci{ 27748c2ecf20Sopenharmony_ci if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) 27758c2ecf20Sopenharmony_ci return -EINVAL; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 27788c2ecf20Sopenharmony_ci if(length>13 && strncmp("reset", buffer+8, 5)==0) { 27798c2ecf20Sopenharmony_ci int i; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->total_commands=0; 27828c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->disconnections=0; 27838c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action=0; 27848c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command=0; 27858c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command=0; 27868c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command=0; 27878c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition=0; 27888c2ecf20Sopenharmony_ci for (i = idle; i<maxstate; i++) { 27898c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count[i]=0; 27908c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count_trans[i]=0; 27918c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->time[i]=0; 27928c2ecf20Sopenharmony_ci } 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_ci shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n"); 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci } else 27978c2ecf20Sopenharmony_ci#endif 27988c2ecf20Sopenharmony_ci { 27998c2ecf20Sopenharmony_ci return -EINVAL; 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci return length; 28048c2ecf20Sopenharmony_ci} 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_cistatic int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt) 28078c2ecf20Sopenharmony_ci{ 28088c2ecf20Sopenharmony_ci int i; 28098c2ecf20Sopenharmony_ci struct scsi_cmnd *ptr; 28108c2ecf20Sopenharmony_ci unsigned long flags; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci seq_puts(m, AHA152X_REVID "\n"); 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci seq_printf(m, "ioports 0x%04lx to 0x%04lx\n", 28158c2ecf20Sopenharmony_ci shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); 28168c2ecf20Sopenharmony_ci seq_printf(m, "interrupt 0x%02x\n", shpnt->irq); 28178c2ecf20Sopenharmony_ci seq_printf(m, "disconnection/reconnection %s\n", 28188c2ecf20Sopenharmony_ci RECONNECT ? "enabled" : "disabled"); 28198c2ecf20Sopenharmony_ci seq_printf(m, "parity checking %s\n", 28208c2ecf20Sopenharmony_ci PARITY ? "enabled" : "disabled"); 28218c2ecf20Sopenharmony_ci seq_printf(m, "synchronous transfers %s\n", 28228c2ecf20Sopenharmony_ci SYNCHRONOUS ? "enabled" : "disabled"); 28238c2ecf20Sopenharmony_ci seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if(SYNCHRONOUS) { 28268c2ecf20Sopenharmony_ci seq_puts(m, "synchronously operating targets (tick=50 ns):\n"); 28278c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 28288c2ecf20Sopenharmony_ci if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) 28298c2ecf20Sopenharmony_ci seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n", 28308c2ecf20Sopenharmony_ci i, 28318c2ecf20Sopenharmony_ci (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), 28328c2ecf20Sopenharmony_ci (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, 28338c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->syncrate[i] & 0x0f); 28348c2ecf20Sopenharmony_ci } 28358c2ecf20Sopenharmony_ci seq_puts(m, "\nqueue status:\n"); 28368c2ecf20Sopenharmony_ci DO_LOCK(flags); 28378c2ecf20Sopenharmony_ci if (ISSUE_SC) { 28388c2ecf20Sopenharmony_ci seq_puts(m, "not yet issued commands:\n"); 28398c2ecf20Sopenharmony_ci for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 28408c2ecf20Sopenharmony_ci get_command(m, ptr); 28418c2ecf20Sopenharmony_ci } else 28428c2ecf20Sopenharmony_ci seq_puts(m, "no not yet issued commands\n"); 28438c2ecf20Sopenharmony_ci DO_UNLOCK(flags); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci if (CURRENT_SC) { 28468c2ecf20Sopenharmony_ci seq_puts(m, "current command:\n"); 28478c2ecf20Sopenharmony_ci get_command(m, CURRENT_SC); 28488c2ecf20Sopenharmony_ci } else 28498c2ecf20Sopenharmony_ci seq_puts(m, "no current command\n"); 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci if (DISCONNECTED_SC) { 28528c2ecf20Sopenharmony_ci seq_puts(m, "disconnected commands:\n"); 28538c2ecf20Sopenharmony_ci for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) 28548c2ecf20Sopenharmony_ci get_command(m, ptr); 28558c2ecf20Sopenharmony_ci } else 28568c2ecf20Sopenharmony_ci seq_puts(m, "no disconnected commands\n"); 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci get_ports(m, shpnt); 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci#if defined(AHA152X_STAT) 28618c2ecf20Sopenharmony_ci seq_printf(m, "statistics:\n" 28628c2ecf20Sopenharmony_ci "total commands: %d\n" 28638c2ecf20Sopenharmony_ci "disconnections: %d\n" 28648c2ecf20Sopenharmony_ci "busfree with check condition: %d\n" 28658c2ecf20Sopenharmony_ci "busfree without old command: %d\n" 28668c2ecf20Sopenharmony_ci "busfree without new command: %d\n" 28678c2ecf20Sopenharmony_ci "busfree without done command: %d\n" 28688c2ecf20Sopenharmony_ci "busfree without any action: %d\n" 28698c2ecf20Sopenharmony_ci "state " 28708c2ecf20Sopenharmony_ci "transitions " 28718c2ecf20Sopenharmony_ci "count " 28728c2ecf20Sopenharmony_ci "time\n", 28738c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->total_commands, 28748c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->disconnections, 28758c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition, 28768c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command, 28778c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command, 28788c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command, 28798c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action); 28808c2ecf20Sopenharmony_ci for(i=0; i<maxstate; i++) { 28818c2ecf20Sopenharmony_ci seq_printf(m, "%-10s %-12d %-12d %-12ld\n", 28828c2ecf20Sopenharmony_ci states[i].name, 28838c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count_trans[i], 28848c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->count[i], 28858c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->time[i]); 28868c2ecf20Sopenharmony_ci } 28878c2ecf20Sopenharmony_ci#endif 28888c2ecf20Sopenharmony_ci return 0; 28898c2ecf20Sopenharmony_ci} 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_cistatic int aha152x_adjust_queue(struct scsi_device *device) 28928c2ecf20Sopenharmony_ci{ 28938c2ecf20Sopenharmony_ci blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); 28948c2ecf20Sopenharmony_ci return 0; 28958c2ecf20Sopenharmony_ci} 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_cistatic struct scsi_host_template aha152x_driver_template = { 28988c2ecf20Sopenharmony_ci .module = THIS_MODULE, 28998c2ecf20Sopenharmony_ci .name = AHA152X_REVID, 29008c2ecf20Sopenharmony_ci .proc_name = "aha152x", 29018c2ecf20Sopenharmony_ci .show_info = aha152x_show_info, 29028c2ecf20Sopenharmony_ci .write_info = aha152x_set_info, 29038c2ecf20Sopenharmony_ci .queuecommand = aha152x_queue, 29048c2ecf20Sopenharmony_ci .eh_abort_handler = aha152x_abort, 29058c2ecf20Sopenharmony_ci .eh_device_reset_handler = aha152x_device_reset, 29068c2ecf20Sopenharmony_ci .eh_bus_reset_handler = aha152x_bus_reset, 29078c2ecf20Sopenharmony_ci .bios_param = aha152x_biosparam, 29088c2ecf20Sopenharmony_ci .can_queue = 1, 29098c2ecf20Sopenharmony_ci .this_id = 7, 29108c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 29118c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 29128c2ecf20Sopenharmony_ci .slave_alloc = aha152x_adjust_queue, 29138c2ecf20Sopenharmony_ci}; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 29168c2ecf20Sopenharmony_cistatic int setup_count; 29178c2ecf20Sopenharmony_cistatic struct aha152x_setup setup[2]; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci/* possible i/o addresses for the AIC-6260; default first */ 29208c2ecf20Sopenharmony_cistatic unsigned short ports[] = { 0x340, 0x140 }; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci#if !defined(SKIP_BIOSTEST) 29238c2ecf20Sopenharmony_ci/* possible locations for the Adaptec BIOS; defaults first */ 29248c2ecf20Sopenharmony_cistatic unsigned int addresses[] = 29258c2ecf20Sopenharmony_ci{ 29268c2ecf20Sopenharmony_ci 0xdc000, /* default first */ 29278c2ecf20Sopenharmony_ci 0xc8000, 29288c2ecf20Sopenharmony_ci 0xcc000, 29298c2ecf20Sopenharmony_ci 0xd0000, 29308c2ecf20Sopenharmony_ci 0xd4000, 29318c2ecf20Sopenharmony_ci 0xd8000, 29328c2ecf20Sopenharmony_ci 0xe0000, 29338c2ecf20Sopenharmony_ci 0xeb800, /* VTech Platinum SMP */ 29348c2ecf20Sopenharmony_ci 0xf0000, 29358c2ecf20Sopenharmony_ci}; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci/* signatures for various AIC-6[23]60 based controllers. 29388c2ecf20Sopenharmony_ci The point in detecting signatures is to avoid useless and maybe 29398c2ecf20Sopenharmony_ci harmful probes on ports. I'm not sure that all listed boards pass 29408c2ecf20Sopenharmony_ci auto-configuration. For those which fail the BIOS signature is 29418c2ecf20Sopenharmony_ci obsolete, because user intervention to supply the configuration is 29428c2ecf20Sopenharmony_ci needed anyway. May be an information whether or not the BIOS supports 29438c2ecf20Sopenharmony_ci extended translation could be also useful here. */ 29448c2ecf20Sopenharmony_cistatic struct signature { 29458c2ecf20Sopenharmony_ci unsigned char *signature; 29468c2ecf20Sopenharmony_ci int sig_offset; 29478c2ecf20Sopenharmony_ci int sig_length; 29488c2ecf20Sopenharmony_ci} signatures[] = 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, 29518c2ecf20Sopenharmony_ci /* Adaptec 152x */ 29528c2ecf20Sopenharmony_ci { "Adaptec AHA-1520B", 0x000b, 17 }, 29538c2ecf20Sopenharmony_ci /* Adaptec 152x rev B */ 29548c2ecf20Sopenharmony_ci { "Adaptec AHA-1520B", 0x0026, 17 }, 29558c2ecf20Sopenharmony_ci /* Iomega Jaz Jet ISA (AIC6370Q) */ 29568c2ecf20Sopenharmony_ci { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, 29578c2ecf20Sopenharmony_ci /* on-board controller */ 29588c2ecf20Sopenharmony_ci { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, 29598c2ecf20Sopenharmony_ci /* on-board controller */ 29608c2ecf20Sopenharmony_ci { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, 29618c2ecf20Sopenharmony_ci /* on-board controller */ 29628c2ecf20Sopenharmony_ci { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, 29638c2ecf20Sopenharmony_ci /* on-board controller */ 29648c2ecf20Sopenharmony_ci { "ScsiPro SP-360 BIOS", 0x2873, 19 }, 29658c2ecf20Sopenharmony_ci /* ScsiPro-Controller */ 29668c2ecf20Sopenharmony_ci { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, 29678c2ecf20Sopenharmony_ci /* Gigabyte Local-Bus-SCSI */ 29688c2ecf20Sopenharmony_ci { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, 29698c2ecf20Sopenharmony_ci /* Adaptec 282x */ 29708c2ecf20Sopenharmony_ci { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, 29718c2ecf20Sopenharmony_ci /* IBM Thinkpad Dock II */ 29728c2ecf20Sopenharmony_ci { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, 29738c2ecf20Sopenharmony_ci /* IBM Thinkpad Dock II SCSI */ 29748c2ecf20Sopenharmony_ci { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, 29758c2ecf20Sopenharmony_ci /* DTC 3520A ISA SCSI */ 29768c2ecf20Sopenharmony_ci}; 29778c2ecf20Sopenharmony_ci#endif /* !SKIP_BIOSTEST */ 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci/* 29808c2ecf20Sopenharmony_ci * Test, if port_base is valid. 29818c2ecf20Sopenharmony_ci * 29828c2ecf20Sopenharmony_ci */ 29838c2ecf20Sopenharmony_cistatic int aha152x_porttest(int io_port) 29848c2ecf20Sopenharmony_ci{ 29858c2ecf20Sopenharmony_ci int i; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 29888c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 29898c2ecf20Sopenharmony_ci SETPORT(io_port + O_STACK, i); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 29928c2ecf20Sopenharmony_ci for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++) 29938c2ecf20Sopenharmony_ci ; 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci return (i == 16); 29968c2ecf20Sopenharmony_ci} 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_cistatic int tc1550_porttest(int io_port) 29998c2ecf20Sopenharmony_ci{ 30008c2ecf20Sopenharmony_ci int i; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 30038c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 30048c2ecf20Sopenharmony_ci SETPORT(io_port + O_STACK, i); 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 30078c2ecf20Sopenharmony_ci for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++) 30088c2ecf20Sopenharmony_ci ; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci return (i == 16); 30118c2ecf20Sopenharmony_ci} 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_cistatic int checksetup(struct aha152x_setup *setup) 30158c2ecf20Sopenharmony_ci{ 30168c2ecf20Sopenharmony_ci int i; 30178c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++) 30188c2ecf20Sopenharmony_ci ; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(ports)) 30218c2ecf20Sopenharmony_ci return 0; 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci if (!request_region(setup->io_port, IO_RANGE, "aha152x")) { 30248c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port); 30258c2ecf20Sopenharmony_ci return 0; 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci if( aha152x_porttest(setup->io_port) ) { 30298c2ecf20Sopenharmony_ci setup->tc1550=0; 30308c2ecf20Sopenharmony_ci } else if( tc1550_porttest(setup->io_port) ) { 30318c2ecf20Sopenharmony_ci setup->tc1550=1; 30328c2ecf20Sopenharmony_ci } else { 30338c2ecf20Sopenharmony_ci release_region(setup->io_port, IO_RANGE); 30348c2ecf20Sopenharmony_ci return 0; 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci release_region(setup->io_port, IO_RANGE); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) 30408c2ecf20Sopenharmony_ci return 0; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if ((setup->scsiid < 0) || (setup->scsiid > 7)) 30438c2ecf20Sopenharmony_ci return 0; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci if ((setup->reconnect < 0) || (setup->reconnect > 1)) 30468c2ecf20Sopenharmony_ci return 0; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci if ((setup->parity < 0) || (setup->parity > 1)) 30498c2ecf20Sopenharmony_ci return 0; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci if ((setup->synchronous < 0) || (setup->synchronous > 1)) 30528c2ecf20Sopenharmony_ci return 0; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) 30558c2ecf20Sopenharmony_ci return 0; 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci return 1; 30598c2ecf20Sopenharmony_ci} 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_cistatic int __init aha152x_init(void) 30638c2ecf20Sopenharmony_ci{ 30648c2ecf20Sopenharmony_ci int i, j, ok; 30658c2ecf20Sopenharmony_ci#if defined(AUTOCONF) 30668c2ecf20Sopenharmony_ci aha152x_config conf; 30678c2ecf20Sopenharmony_ci#endif 30688c2ecf20Sopenharmony_ci#ifdef __ISAPNP__ 30698c2ecf20Sopenharmony_ci struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL}; 30708c2ecf20Sopenharmony_ci#endif 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci if ( setup_count ) { 30738c2ecf20Sopenharmony_ci printk(KERN_INFO "aha152x: processing commandline: "); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci for (i = 0; i<setup_count; i++) { 30768c2ecf20Sopenharmony_ci if (!checksetup(&setup[i])) { 30778c2ecf20Sopenharmony_ci printk(KERN_ERR "\naha152x: %s\n", setup[i].conf); 30788c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: invalid line\n"); 30798c2ecf20Sopenharmony_ci } 30808c2ecf20Sopenharmony_ci } 30818c2ecf20Sopenharmony_ci printk("ok\n"); 30828c2ecf20Sopenharmony_ci } 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci#if defined(SETUP0) 30858c2ecf20Sopenharmony_ci if (setup_count < ARRAY_SIZE(setup)) { 30868c2ecf20Sopenharmony_ci struct aha152x_setup override = SETUP0; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 30898c2ecf20Sopenharmony_ci if (!checksetup(&override)) { 30908c2ecf20Sopenharmony_ci printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 30918c2ecf20Sopenharmony_ci override.io_port, 30928c2ecf20Sopenharmony_ci override.irq, 30938c2ecf20Sopenharmony_ci override.scsiid, 30948c2ecf20Sopenharmony_ci override.reconnect, 30958c2ecf20Sopenharmony_ci override.parity, 30968c2ecf20Sopenharmony_ci override.synchronous, 30978c2ecf20Sopenharmony_ci override.delay, 30988c2ecf20Sopenharmony_ci override.ext_trans); 30998c2ecf20Sopenharmony_ci } else 31008c2ecf20Sopenharmony_ci setup[setup_count++] = override; 31018c2ecf20Sopenharmony_ci } 31028c2ecf20Sopenharmony_ci } 31038c2ecf20Sopenharmony_ci#endif 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci#if defined(SETUP1) 31068c2ecf20Sopenharmony_ci if (setup_count < ARRAY_SIZE(setup)) { 31078c2ecf20Sopenharmony_ci struct aha152x_setup override = SETUP1; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 31108c2ecf20Sopenharmony_ci if (!checksetup(&override)) { 31118c2ecf20Sopenharmony_ci printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 31128c2ecf20Sopenharmony_ci override.io_port, 31138c2ecf20Sopenharmony_ci override.irq, 31148c2ecf20Sopenharmony_ci override.scsiid, 31158c2ecf20Sopenharmony_ci override.reconnect, 31168c2ecf20Sopenharmony_ci override.parity, 31178c2ecf20Sopenharmony_ci override.synchronous, 31188c2ecf20Sopenharmony_ci override.delay, 31198c2ecf20Sopenharmony_ci override.ext_trans); 31208c2ecf20Sopenharmony_ci } else 31218c2ecf20Sopenharmony_ci setup[setup_count++] = override; 31228c2ecf20Sopenharmony_ci } 31238c2ecf20Sopenharmony_ci } 31248c2ecf20Sopenharmony_ci#endif 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci#if defined(MODULE) 31278c2ecf20Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) { 31288c2ecf20Sopenharmony_ci if(aha152x[0]!=0) { 31298c2ecf20Sopenharmony_ci setup[setup_count].conf = ""; 31308c2ecf20Sopenharmony_ci setup[setup_count].io_port = aha152x[0]; 31318c2ecf20Sopenharmony_ci setup[setup_count].irq = aha152x[1]; 31328c2ecf20Sopenharmony_ci setup[setup_count].scsiid = aha152x[2]; 31338c2ecf20Sopenharmony_ci setup[setup_count].reconnect = aha152x[3]; 31348c2ecf20Sopenharmony_ci setup[setup_count].parity = aha152x[4]; 31358c2ecf20Sopenharmony_ci setup[setup_count].synchronous = aha152x[5]; 31368c2ecf20Sopenharmony_ci setup[setup_count].delay = aha152x[6]; 31378c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = aha152x[7]; 31388c2ecf20Sopenharmony_ci } else if (io[0] != 0 || irq[0] != 0) { 31398c2ecf20Sopenharmony_ci if(io[0]!=0) setup[setup_count].io_port = io[0]; 31408c2ecf20Sopenharmony_ci if(irq[0]!=0) setup[setup_count].irq = irq[0]; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci setup[setup_count].scsiid = scsiid[0]; 31438c2ecf20Sopenharmony_ci setup[setup_count].reconnect = reconnect[0]; 31448c2ecf20Sopenharmony_ci setup[setup_count].parity = parity[0]; 31458c2ecf20Sopenharmony_ci setup[setup_count].synchronous = sync[0]; 31468c2ecf20Sopenharmony_ci setup[setup_count].delay = delay[0]; 31478c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = exttrans[0]; 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (checksetup(&setup[setup_count])) 31518c2ecf20Sopenharmony_ci setup_count++; 31528c2ecf20Sopenharmony_ci else 31538c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n", 31548c2ecf20Sopenharmony_ci setup[setup_count].io_port, 31558c2ecf20Sopenharmony_ci setup[setup_count].irq, 31568c2ecf20Sopenharmony_ci setup[setup_count].scsiid, 31578c2ecf20Sopenharmony_ci setup[setup_count].reconnect, 31588c2ecf20Sopenharmony_ci setup[setup_count].parity, 31598c2ecf20Sopenharmony_ci setup[setup_count].synchronous, 31608c2ecf20Sopenharmony_ci setup[setup_count].delay, 31618c2ecf20Sopenharmony_ci setup[setup_count].ext_trans); 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) { 31658c2ecf20Sopenharmony_ci if(aha152x1[0]!=0) { 31668c2ecf20Sopenharmony_ci setup[setup_count].conf = ""; 31678c2ecf20Sopenharmony_ci setup[setup_count].io_port = aha152x1[0]; 31688c2ecf20Sopenharmony_ci setup[setup_count].irq = aha152x1[1]; 31698c2ecf20Sopenharmony_ci setup[setup_count].scsiid = aha152x1[2]; 31708c2ecf20Sopenharmony_ci setup[setup_count].reconnect = aha152x1[3]; 31718c2ecf20Sopenharmony_ci setup[setup_count].parity = aha152x1[4]; 31728c2ecf20Sopenharmony_ci setup[setup_count].synchronous = aha152x1[5]; 31738c2ecf20Sopenharmony_ci setup[setup_count].delay = aha152x1[6]; 31748c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = aha152x1[7]; 31758c2ecf20Sopenharmony_ci } else if (io[1] != 0 || irq[1] != 0) { 31768c2ecf20Sopenharmony_ci if(io[1]!=0) setup[setup_count].io_port = io[1]; 31778c2ecf20Sopenharmony_ci if(irq[1]!=0) setup[setup_count].irq = irq[1]; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci setup[setup_count].scsiid = scsiid[1]; 31808c2ecf20Sopenharmony_ci setup[setup_count].reconnect = reconnect[1]; 31818c2ecf20Sopenharmony_ci setup[setup_count].parity = parity[1]; 31828c2ecf20Sopenharmony_ci setup[setup_count].synchronous = sync[1]; 31838c2ecf20Sopenharmony_ci setup[setup_count].delay = delay[1]; 31848c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = exttrans[1]; 31858c2ecf20Sopenharmony_ci } 31868c2ecf20Sopenharmony_ci if (checksetup(&setup[setup_count])) 31878c2ecf20Sopenharmony_ci setup_count++; 31888c2ecf20Sopenharmony_ci else 31898c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n", 31908c2ecf20Sopenharmony_ci setup[setup_count].io_port, 31918c2ecf20Sopenharmony_ci setup[setup_count].irq, 31928c2ecf20Sopenharmony_ci setup[setup_count].scsiid, 31938c2ecf20Sopenharmony_ci setup[setup_count].reconnect, 31948c2ecf20Sopenharmony_ci setup[setup_count].parity, 31958c2ecf20Sopenharmony_ci setup[setup_count].synchronous, 31968c2ecf20Sopenharmony_ci setup[setup_count].delay, 31978c2ecf20Sopenharmony_ci setup[setup_count].ext_trans); 31988c2ecf20Sopenharmony_ci } 31998c2ecf20Sopenharmony_ci#endif 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci#ifdef __ISAPNP__ 32028c2ecf20Sopenharmony_ci for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) { 32038c2ecf20Sopenharmony_ci while ( setup_count<ARRAY_SIZE(setup) && 32048c2ecf20Sopenharmony_ci (dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) { 32058c2ecf20Sopenharmony_ci if (pnp_device_attach(dev) < 0) 32068c2ecf20Sopenharmony_ci continue; 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci if (pnp_activate_dev(dev) < 0) { 32098c2ecf20Sopenharmony_ci pnp_device_detach(dev); 32108c2ecf20Sopenharmony_ci continue; 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci if (!pnp_port_valid(dev, 0)) { 32148c2ecf20Sopenharmony_ci pnp_device_detach(dev); 32158c2ecf20Sopenharmony_ci continue; 32168c2ecf20Sopenharmony_ci } 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) { 32198c2ecf20Sopenharmony_ci pnp_device_detach(dev); 32208c2ecf20Sopenharmony_ci continue; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci setup[setup_count].io_port = pnp_port_start(dev, 0); 32248c2ecf20Sopenharmony_ci setup[setup_count].irq = pnp_irq(dev, 0); 32258c2ecf20Sopenharmony_ci setup[setup_count].scsiid = 7; 32268c2ecf20Sopenharmony_ci setup[setup_count].reconnect = 1; 32278c2ecf20Sopenharmony_ci setup[setup_count].parity = 1; 32288c2ecf20Sopenharmony_ci setup[setup_count].synchronous = 1; 32298c2ecf20Sopenharmony_ci setup[setup_count].delay = DELAY_DEFAULT; 32308c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = 0; 32318c2ecf20Sopenharmony_ci#if defined(__ISAPNP__) 32328c2ecf20Sopenharmony_ci pnpdev[setup_count] = dev; 32338c2ecf20Sopenharmony_ci#endif 32348c2ecf20Sopenharmony_ci printk (KERN_INFO 32358c2ecf20Sopenharmony_ci "aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n", 32368c2ecf20Sopenharmony_ci setup[setup_count].io_port, setup[setup_count].irq); 32378c2ecf20Sopenharmony_ci setup_count++; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci#endif 32418c2ecf20Sopenharmony_ci 32428c2ecf20Sopenharmony_ci#if defined(AUTOCONF) 32438c2ecf20Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup)) { 32448c2ecf20Sopenharmony_ci#if !defined(SKIP_BIOSTEST) 32458c2ecf20Sopenharmony_ci ok = 0; 32468c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) { 32478c2ecf20Sopenharmony_ci void __iomem *p = ioremap(addresses[i], 0x4000); 32488c2ecf20Sopenharmony_ci if (!p) 32498c2ecf20Sopenharmony_ci continue; 32508c2ecf20Sopenharmony_ci for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++) 32518c2ecf20Sopenharmony_ci ok = check_signature(p + signatures[j].sig_offset, 32528c2ecf20Sopenharmony_ci signatures[j].signature, signatures[j].sig_length); 32538c2ecf20Sopenharmony_ci iounmap(p); 32548c2ecf20Sopenharmony_ci } 32558c2ecf20Sopenharmony_ci if (!ok && setup_count == 0) 32568c2ecf20Sopenharmony_ci return -ENODEV; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci printk(KERN_INFO "aha152x: BIOS test: passed, "); 32598c2ecf20Sopenharmony_ci#else 32608c2ecf20Sopenharmony_ci printk(KERN_INFO "aha152x: "); 32618c2ecf20Sopenharmony_ci#endif /* !SKIP_BIOSTEST */ 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci ok = 0; 32648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) { 32658c2ecf20Sopenharmony_ci if ((setup_count == 1) && (setup[0].io_port == ports[i])) 32668c2ecf20Sopenharmony_ci continue; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci if (!request_region(ports[i], IO_RANGE, "aha152x")) { 32698c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]); 32708c2ecf20Sopenharmony_ci continue; 32718c2ecf20Sopenharmony_ci } 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci if (aha152x_porttest(ports[i])) { 32748c2ecf20Sopenharmony_ci setup[setup_count].tc1550 = 0; 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci conf.cf_port = 32778c2ecf20Sopenharmony_ci (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB); 32788c2ecf20Sopenharmony_ci } else if (tc1550_porttest(ports[i])) { 32798c2ecf20Sopenharmony_ci setup[setup_count].tc1550 = 1; 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci conf.cf_port = 32828c2ecf20Sopenharmony_ci (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB); 32838c2ecf20Sopenharmony_ci } else { 32848c2ecf20Sopenharmony_ci release_region(ports[i], IO_RANGE); 32858c2ecf20Sopenharmony_ci continue; 32868c2ecf20Sopenharmony_ci } 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci release_region(ports[i], IO_RANGE); 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci ok++; 32918c2ecf20Sopenharmony_ci setup[setup_count].io_port = ports[i]; 32928c2ecf20Sopenharmony_ci setup[setup_count].irq = IRQ_MIN + conf.cf_irq; 32938c2ecf20Sopenharmony_ci setup[setup_count].scsiid = conf.cf_id; 32948c2ecf20Sopenharmony_ci setup[setup_count].reconnect = conf.cf_tardisc; 32958c2ecf20Sopenharmony_ci setup[setup_count].parity = !conf.cf_parity; 32968c2ecf20Sopenharmony_ci setup[setup_count].synchronous = conf.cf_syncneg; 32978c2ecf20Sopenharmony_ci setup[setup_count].delay = DELAY_DEFAULT; 32988c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = 0; 32998c2ecf20Sopenharmony_ci setup_count++; 33008c2ecf20Sopenharmony_ci 33018c2ecf20Sopenharmony_ci } 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci if (ok) 33048c2ecf20Sopenharmony_ci printk("auto configuration: ok, "); 33058c2ecf20Sopenharmony_ci } 33068c2ecf20Sopenharmony_ci#endif 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci printk("%d controller(s) configured\n", setup_count); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci for (i=0; i<setup_count; i++) { 33118c2ecf20Sopenharmony_ci if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) { 33128c2ecf20Sopenharmony_ci struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]); 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci if( !shpnt ) { 33158c2ecf20Sopenharmony_ci release_region(setup[i].io_port, IO_RANGE); 33168c2ecf20Sopenharmony_ci#if defined(__ISAPNP__) 33178c2ecf20Sopenharmony_ci } else if( pnpdev[i] ) { 33188c2ecf20Sopenharmony_ci HOSTDATA(shpnt)->pnpdev=pnpdev[i]; 33198c2ecf20Sopenharmony_ci pnpdev[i]=NULL; 33208c2ecf20Sopenharmony_ci#endif 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci } else { 33238c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port); 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci#if defined(__ISAPNP__) 33278c2ecf20Sopenharmony_ci if( pnpdev[i] ) 33288c2ecf20Sopenharmony_ci pnp_device_detach(pnpdev[i]); 33298c2ecf20Sopenharmony_ci#endif 33308c2ecf20Sopenharmony_ci } 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci return 0; 33338c2ecf20Sopenharmony_ci} 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_cistatic void __exit aha152x_exit(void) 33368c2ecf20Sopenharmony_ci{ 33378c2ecf20Sopenharmony_ci struct aha152x_hostdata *hd, *tmp; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) { 33408c2ecf20Sopenharmony_ci struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci aha152x_release(shost); 33438c2ecf20Sopenharmony_ci } 33448c2ecf20Sopenharmony_ci} 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_cimodule_init(aha152x_init); 33478c2ecf20Sopenharmony_cimodule_exit(aha152x_exit); 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci#if !defined(MODULE) 33508c2ecf20Sopenharmony_cistatic int __init aha152x_setup(char *str) 33518c2ecf20Sopenharmony_ci{ 33528c2ecf20Sopenharmony_ci int ints[10]; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci get_options(str, ARRAY_SIZE(ints), ints); 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci if(setup_count>=ARRAY_SIZE(setup)) { 33578c2ecf20Sopenharmony_ci printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); 33588c2ecf20Sopenharmony_ci return 1; 33598c2ecf20Sopenharmony_ci } 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci setup[setup_count].conf = str; 33628c2ecf20Sopenharmony_ci setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; 33638c2ecf20Sopenharmony_ci setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; 33648c2ecf20Sopenharmony_ci setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; 33658c2ecf20Sopenharmony_ci setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; 33668c2ecf20Sopenharmony_ci setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; 33678c2ecf20Sopenharmony_ci setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; 33688c2ecf20Sopenharmony_ci setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; 33698c2ecf20Sopenharmony_ci setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; 33708c2ecf20Sopenharmony_ci if (ints[0] > 8) 33718c2ecf20Sopenharmony_ci printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" 33728c2ecf20Sopenharmony_ci "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n"); 33738c2ecf20Sopenharmony_ci else 33748c2ecf20Sopenharmony_ci setup_count++; 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci return 1; 33778c2ecf20Sopenharmony_ci} 33788c2ecf20Sopenharmony_ci__setup("aha152x=", aha152x_setup); 33798c2ecf20Sopenharmony_ci#endif 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci#endif /* !AHA152X_PCMCIA */ 3382