162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* aha152x.c -- Adaptec AHA-152x driver 362306a36Sopenharmony_ci * Author: Jürgen E. Fischer, fischer@norbit.de 462306a36Sopenharmony_ci * Copyright 1993-2004 Jürgen E. Fischer 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $ 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * $Log: aha152x.c,v $ 962306a36Sopenharmony_ci * Revision 2.7 2004/01/24 11:42:59 fischer 1062306a36Sopenharmony_ci * - gather code that is not used by PCMCIA at the end 1162306a36Sopenharmony_ci * - move request_region for !PCMCIA case to detection 1262306a36Sopenharmony_ci * - migration to new scsi host api (remove legacy code) 1362306a36Sopenharmony_ci * - free host scribble before scsi_done 1462306a36Sopenharmony_ci * - fix error handling 1562306a36Sopenharmony_ci * - one isapnp device added to id_table 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Revision 2.6 2003/10/30 20:52:47 fischer 1862306a36Sopenharmony_ci * - interfaces changes for kernel 2.6 1962306a36Sopenharmony_ci * - aha152x_probe_one introduced for pcmcia stub 2062306a36Sopenharmony_ci * - fixed pnpdev handling 2162306a36Sopenharmony_ci * - instead of allocation a new one, reuse command for request sense after check condition and reset 2262306a36Sopenharmony_ci * - fixes race in is_complete 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Revision 2.5 2002/04/14 11:24:53 fischer 2562306a36Sopenharmony_ci * - isapnp support 2662306a36Sopenharmony_ci * - abort fixed 2762306a36Sopenharmony_ci * - 2.5 support 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Revision 2.4 2000/12/16 12:53:56 fischer 3062306a36Sopenharmony_ci * - allow REQUEST SENSE to be queued 3162306a36Sopenharmony_ci * - handle shared PCI interrupts 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Revision 2.3 2000/11/04 16:40:26 fischer 3462306a36Sopenharmony_ci * - handle data overruns 3562306a36Sopenharmony_ci * - extend timeout for data phases 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Revision 2.2 2000/08/08 19:54:53 fischer 3862306a36Sopenharmony_ci * - minor changes 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Revision 2.1 2000/05/17 16:23:17 fischer 4162306a36Sopenharmony_ci * - signature update 4262306a36Sopenharmony_ci * - fix for data out w/o scatter gather 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * Revision 2.0 1999/12/25 15:07:32 fischer 4562306a36Sopenharmony_ci * - interrupt routine completly reworked 4662306a36Sopenharmony_ci * - basic support for new eh code 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Revision 1.21 1999/11/10 23:46:36 fischer 4962306a36Sopenharmony_ci * - default to synchronous operation 5062306a36Sopenharmony_ci * - synchronous negotiation fixed 5162306a36Sopenharmony_ci * - added timeout to loops 5262306a36Sopenharmony_ci * - debugging output can be controlled through procfs 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * Revision 1.20 1999/11/07 18:37:31 fischer 5562306a36Sopenharmony_ci * - synchronous operation works 5662306a36Sopenharmony_ci * - resid support for sg driver 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Revision 1.19 1999/11/02 22:39:59 fischer 5962306a36Sopenharmony_ci * - moved leading comments to README.aha152x 6062306a36Sopenharmony_ci * - new additional module parameters 6162306a36Sopenharmony_ci * - updates for 2.3 6262306a36Sopenharmony_ci * - support for the Tripace TC1550 controller 6362306a36Sopenharmony_ci * - interrupt handling changed 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Revision 1.18 1996/09/07 20:10:40 fischer 6662306a36Sopenharmony_ci * - fixed can_queue handling (multiple outstanding commands working again) 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * Revision 1.17 1996/08/17 16:05:14 fischer 6962306a36Sopenharmony_ci * - biosparam improved 7062306a36Sopenharmony_ci * - interrupt verification 7162306a36Sopenharmony_ci * - updated documentation 7262306a36Sopenharmony_ci * - cleanups 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * Revision 1.16 1996/06/09 00:04:56 root 7562306a36Sopenharmony_ci * - added configuration symbols for insmod (aha152x/aha152x1) 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Revision 1.15 1996/04/30 14:52:06 fischer 7862306a36Sopenharmony_ci * - proc info fixed 7962306a36Sopenharmony_ci * - support for extended translation for >1GB disks 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Revision 1.14 1996/01/17 15:11:20 fischer 8262306a36Sopenharmony_ci * - fixed lockup in MESSAGE IN phase after reconnection 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Revision 1.13 1996/01/09 02:15:53 fischer 8562306a36Sopenharmony_ci * - some cleanups 8662306a36Sopenharmony_ci * - moved request_irq behind controller initialization 8762306a36Sopenharmony_ci * (to avoid spurious interrupts) 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Revision 1.12 1995/12/16 12:26:07 fischer 9062306a36Sopenharmony_ci * - barrier()s added 9162306a36Sopenharmony_ci * - configurable RESET delay added 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Revision 1.11 1995/12/06 21:18:35 fischer 9462306a36Sopenharmony_ci * - some minor updates 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * Revision 1.10 1995/07/22 19:18:45 fischer 9762306a36Sopenharmony_ci * - support for 2 controllers 9862306a36Sopenharmony_ci * - started synchronous data transfers (not working yet) 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * Revision 1.9 1995/03/18 09:20:24 root 10162306a36Sopenharmony_ci * - patches for PCMCIA and modules 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * Revision 1.8 1995/01/21 22:07:19 root 10462306a36Sopenharmony_ci * - snarf_region => request_region 10562306a36Sopenharmony_ci * - aha152x_intr interface change 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * Revision 1.7 1995/01/02 23:19:36 root 10862306a36Sopenharmony_ci * - updated COMMAND_SIZE to cmd_len 10962306a36Sopenharmony_ci * - changed sti() to restore_flags() 11062306a36Sopenharmony_ci * - fixed some #ifdef which generated warnings 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * Revision 1.6 1994/11/24 20:35:27 root 11362306a36Sopenharmony_ci * - problem with odd number of bytes in fifo fixed 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Revision 1.5 1994/10/30 14:39:56 root 11662306a36Sopenharmony_ci * - abort code fixed 11762306a36Sopenharmony_ci * - debugging improved 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * Revision 1.4 1994/09/12 11:33:01 root 12062306a36Sopenharmony_ci * - irqaction to request_irq 12162306a36Sopenharmony_ci * - abortion updated 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * Revision 1.3 1994/08/04 13:53:05 root 12462306a36Sopenharmony_ci * - updates for mid-level-driver changes 12562306a36Sopenharmony_ci * - accept unexpected BUSFREE phase as error condition 12662306a36Sopenharmony_ci * - parity check now configurable 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * Revision 1.2 1994/07/03 12:56:36 root 12962306a36Sopenharmony_ci * - cleaned up debugging code 13062306a36Sopenharmony_ci * - more tweaking on reset delays 13162306a36Sopenharmony_ci * - updated abort/reset code (pretty untested...) 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Revision 1.1 1994/05/28 21:18:49 root 13462306a36Sopenharmony_ci * - update for mid-level interface change (abort-reset) 13562306a36Sopenharmony_ci * - delays after resets adjusted for some slow devices 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * Revision 1.0 1994/03/25 12:52:00 root 13862306a36Sopenharmony_ci * - Fixed "more data than expected" problem 13962306a36Sopenharmony_ci * - added new BIOS signatures 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Revision 0.102 1994/01/31 20:44:12 root 14262306a36Sopenharmony_ci * - minor changes in insw/outsw handling 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Revision 0.101 1993/12/13 01:16:27 root 14562306a36Sopenharmony_ci * - fixed STATUS phase (non-GOOD stati were dropped sometimes; 14662306a36Sopenharmony_ci * fixes problems with CD-ROM sector size detection & media change) 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * Revision 0.100 1993/12/10 16:58:47 root 14962306a36Sopenharmony_ci * - fix for unsuccessful selections in case of non-continuous id assignments 15062306a36Sopenharmony_ci * on the scsi bus. 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Revision 0.99 1993/10/24 16:19:59 root 15362306a36Sopenharmony_ci * - fixed DATA IN (rare read errors gone) 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * Revision 0.98 1993/10/17 12:54:44 root 15662306a36Sopenharmony_ci * - fixed some recent fixes (shame on me) 15762306a36Sopenharmony_ci * - moved initialization of scratch area to aha152x_queue 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * Revision 0.97 1993/10/09 18:53:53 root 16062306a36Sopenharmony_ci * - DATA IN fixed. Rarely left data in the fifo. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * Revision 0.96 1993/10/03 00:53:59 root 16362306a36Sopenharmony_ci * - minor changes on DATA IN 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * Revision 0.95 1993/09/24 10:36:01 root 16662306a36Sopenharmony_ci * - change handling of MSGI after reselection 16762306a36Sopenharmony_ci * - fixed sti/cli 16862306a36Sopenharmony_ci * - minor changes 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Revision 0.94 1993/09/18 14:08:22 root 17162306a36Sopenharmony_ci * - fixed bug in multiple outstanding command code 17262306a36Sopenharmony_ci * - changed detection 17362306a36Sopenharmony_ci * - support for kernel command line configuration 17462306a36Sopenharmony_ci * - reset corrected 17562306a36Sopenharmony_ci * - changed message handling 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * Revision 0.93 1993/09/15 20:41:19 root 17862306a36Sopenharmony_ci * - fixed bugs with multiple outstanding commands 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Revision 0.92 1993/09/13 02:46:33 root 18162306a36Sopenharmony_ci * - multiple outstanding commands work (no problems with IBM drive) 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * Revision 0.91 1993/09/12 20:51:46 root 18462306a36Sopenharmony_ci * added multiple outstanding commands 18562306a36Sopenharmony_ci * (some problem with this $%&? IBM device remain) 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Revision 0.9 1993/09/12 11:11:22 root 18862306a36Sopenharmony_ci * - corrected auto-configuration 18962306a36Sopenharmony_ci * - changed the auto-configuration (added some '#define's) 19062306a36Sopenharmony_ci * - added support for dis-/reconnection 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * Revision 0.8 1993/09/06 23:09:39 root 19362306a36Sopenharmony_ci * - added support for the drive activity light 19462306a36Sopenharmony_ci * - minor changes 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * Revision 0.7 1993/09/05 14:30:15 root 19762306a36Sopenharmony_ci * - improved phase detection 19862306a36Sopenharmony_ci * - now using the new snarf_region code of 0.99pl13 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Revision 0.6 1993/09/02 11:01:38 root 20162306a36Sopenharmony_ci * first public release; added some signatures and biosparam() 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Revision 0.5 1993/08/30 10:23:30 root 20462306a36Sopenharmony_ci * fixed timing problems with my IBM drive 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * Revision 0.4 1993/08/29 14:06:52 root 20762306a36Sopenharmony_ci * fixed some problems with timeouts due incomplete commands 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Revision 0.3 1993/08/28 15:55:03 root 21062306a36Sopenharmony_ci * writing data works too. mounted and worked on a dos partition 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Revision 0.2 1993/08/27 22:42:07 root 21362306a36Sopenharmony_ci * reading data works. Mounted a msdos partition. 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Revision 0.1 1993/08/25 13:38:30 root 21662306a36Sopenharmony_ci * first "damn thing doesn't work" version 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * Revision 0.0 1993/08/14 19:54:25 root 21962306a36Sopenharmony_ci * empty function bodies; detect() works. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci ************************************************************************** 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci see Documentation/scsi/aha152x.rst for configuration details 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci **************************************************************************/ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci#include <linux/module.h> 22862306a36Sopenharmony_ci#include <asm/irq.h> 22962306a36Sopenharmony_ci#include <linux/io.h> 23062306a36Sopenharmony_ci#include <linux/blkdev.h> 23162306a36Sopenharmony_ci#include <linux/completion.h> 23262306a36Sopenharmony_ci#include <linux/errno.h> 23362306a36Sopenharmony_ci#include <linux/string.h> 23462306a36Sopenharmony_ci#include <linux/wait.h> 23562306a36Sopenharmony_ci#include <linux/ioport.h> 23662306a36Sopenharmony_ci#include <linux/delay.h> 23762306a36Sopenharmony_ci#include <linux/proc_fs.h> 23862306a36Sopenharmony_ci#include <linux/interrupt.h> 23962306a36Sopenharmony_ci#include <linux/init.h> 24062306a36Sopenharmony_ci#include <linux/kernel.h> 24162306a36Sopenharmony_ci#include <linux/isapnp.h> 24262306a36Sopenharmony_ci#include <linux/spinlock.h> 24362306a36Sopenharmony_ci#include <linux/workqueue.h> 24462306a36Sopenharmony_ci#include <linux/list.h> 24562306a36Sopenharmony_ci#include <linux/slab.h> 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci#include <scsi/scsi.h> 24862306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 24962306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 25062306a36Sopenharmony_ci#include <scsi/scsi_device.h> 25162306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 25262306a36Sopenharmony_ci#include <scsi/scsi_host.h> 25362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 25462306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h> 25562306a36Sopenharmony_ci#include <scsi/scsicam.h> 25662306a36Sopenharmony_ci#include "aha152x.h" 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic LIST_HEAD(aha152x_host_list); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* DEFINES */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* For PCMCIA cards, always use AUTOCONF */ 26462306a36Sopenharmony_ci#if defined(AHA152X_PCMCIA) || defined(MODULE) 26562306a36Sopenharmony_ci#if !defined(AUTOCONF) 26662306a36Sopenharmony_ci#define AUTOCONF 26762306a36Sopenharmony_ci#endif 26862306a36Sopenharmony_ci#endif 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci#if !defined(AUTOCONF) && !defined(SETUP0) 27162306a36Sopenharmony_ci#error define AUTOCONF or SETUP0 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) 27562306a36Sopenharmony_ci#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci#define LEAD "(scsi%d:%d:%d) " 27862306a36Sopenharmony_ci#define INFO_LEAD KERN_INFO LEAD 27962306a36Sopenharmony_ci#define CMDINFO(cmd) \ 28062306a36Sopenharmony_ci (cmd) ? ((cmd)->device->host->host_no) : -1, \ 28162306a36Sopenharmony_ci (cmd) ? ((cmd)->device->id & 0x0f) : -1, \ 28262306a36Sopenharmony_ci (cmd) ? ((u8)(cmd)->device->lun & 0x07) : -1 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline void 28562306a36Sopenharmony_ciCMD_INC_RESID(struct scsi_cmnd *cmd, int inc) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci scsi_set_resid(cmd, scsi_get_resid(cmd) + inc); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci#define DELAY_DEFAULT 1000 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci#if defined(AHA152X_PCMCIA) 29362306a36Sopenharmony_ci#define IRQ_MIN 0 29462306a36Sopenharmony_ci#define IRQ_MAX 16 29562306a36Sopenharmony_ci#else 29662306a36Sopenharmony_ci#define IRQ_MIN 9 29762306a36Sopenharmony_ci#if defined(__PPC) 29862306a36Sopenharmony_ci#define IRQ_MAX (nr_irqs-1) 29962306a36Sopenharmony_ci#else 30062306a36Sopenharmony_ci#define IRQ_MAX 12 30162306a36Sopenharmony_ci#endif 30262306a36Sopenharmony_ci#endif 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cienum { 30562306a36Sopenharmony_ci not_issued = 0x0001, /* command not yet issued */ 30662306a36Sopenharmony_ci selecting = 0x0002, /* target is being selected */ 30762306a36Sopenharmony_ci identified = 0x0004, /* IDENTIFY was sent */ 30862306a36Sopenharmony_ci disconnected = 0x0008, /* target disconnected */ 30962306a36Sopenharmony_ci completed = 0x0010, /* target sent COMMAND COMPLETE */ 31062306a36Sopenharmony_ci aborted = 0x0020, /* ABORT was sent */ 31162306a36Sopenharmony_ci resetted = 0x0040, /* BUS DEVICE RESET was sent */ 31262306a36Sopenharmony_ci spiordy = 0x0080, /* waiting for SPIORDY to raise */ 31362306a36Sopenharmony_ci syncneg = 0x0100, /* synchronous negotiation in progress */ 31462306a36Sopenharmony_ci aborting = 0x0200, /* ABORT is pending */ 31562306a36Sopenharmony_ci resetting = 0x0400, /* BUS DEVICE RESET is pending */ 31662306a36Sopenharmony_ci check_condition = 0x0800, /* requesting sense after CHECK CONDITION */ 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistruct aha152x_cmd_priv { 32062306a36Sopenharmony_ci char *ptr; 32162306a36Sopenharmony_ci int this_residual; 32262306a36Sopenharmony_ci struct scatterlist *buffer; 32362306a36Sopenharmony_ci int status; 32462306a36Sopenharmony_ci int message; 32562306a36Sopenharmony_ci int sent_command; 32662306a36Sopenharmony_ci int phase; 32762306a36Sopenharmony_ci}; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return scsi_cmd_priv(cmd); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ciMODULE_AUTHOR("Jürgen Fischer"); 33562306a36Sopenharmony_ciMODULE_DESCRIPTION(AHA152X_REVID); 33662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 33962306a36Sopenharmony_ci#if defined(MODULE) 34062306a36Sopenharmony_cistatic int io[] = {0, 0}; 34162306a36Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0); 34262306a36Sopenharmony_ciMODULE_PARM_DESC(io,"base io address of controller"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int irq[] = {0, 0}; 34562306a36Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0); 34662306a36Sopenharmony_ciMODULE_PARM_DESC(irq,"interrupt for controller"); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int scsiid[] = {7, 7}; 34962306a36Sopenharmony_cimodule_param_array(scsiid, int, NULL, 0); 35062306a36Sopenharmony_ciMODULE_PARM_DESC(scsiid,"scsi id of controller"); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic int reconnect[] = {1, 1}; 35362306a36Sopenharmony_cimodule_param_array(reconnect, int, NULL, 0); 35462306a36Sopenharmony_ciMODULE_PARM_DESC(reconnect,"allow targets to disconnect"); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int parity[] = {1, 1}; 35762306a36Sopenharmony_cimodule_param_array(parity, int, NULL, 0); 35862306a36Sopenharmony_ciMODULE_PARM_DESC(parity,"use scsi parity"); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int sync[] = {1, 1}; 36162306a36Sopenharmony_cimodule_param_array(sync, int, NULL, 0); 36262306a36Sopenharmony_ciMODULE_PARM_DESC(sync,"use synchronous transfers"); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; 36562306a36Sopenharmony_cimodule_param_array(delay, int, NULL, 0); 36662306a36Sopenharmony_ciMODULE_PARM_DESC(delay,"scsi reset delay"); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int exttrans[] = {0, 0}; 36962306a36Sopenharmony_cimodule_param_array(exttrans, int, NULL, 0); 37062306a36Sopenharmony_ciMODULE_PARM_DESC(exttrans,"use extended translation"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 37362306a36Sopenharmony_cimodule_param_array(aha152x, int, NULL, 0); 37462306a36Sopenharmony_ciMODULE_PARM_DESC(aha152x, "parameters for first controller"); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; 37762306a36Sopenharmony_cimodule_param_array(aha152x1, int, NULL, 0); 37862306a36Sopenharmony_ciMODULE_PARM_DESC(aha152x1, "parameters for second controller"); 37962306a36Sopenharmony_ci#endif /* MODULE */ 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci#ifdef __ISAPNP__ 38262306a36Sopenharmony_cistatic struct isapnp_device_id id_table[] = { 38362306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, 38462306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, 38562306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, 38662306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, 38762306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, 38862306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, 38962306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, 39062306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, 39162306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, 39262306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, 39362306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, 39462306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, 39562306a36Sopenharmony_ci { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, 39662306a36Sopenharmony_ci { ISAPNP_DEVICE_SINGLE_END, } 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, id_table); 39962306a36Sopenharmony_ci#endif /* ISAPNP */ 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci#endif /* !AHA152X_PCMCIA */ 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic const struct scsi_host_template aha152x_driver_template; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci * internal states of the host 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_cienum aha152x_state { 41062306a36Sopenharmony_ci idle=0, 41162306a36Sopenharmony_ci unknown, 41262306a36Sopenharmony_ci seldo, 41362306a36Sopenharmony_ci seldi, 41462306a36Sopenharmony_ci selto, 41562306a36Sopenharmony_ci busfree, 41662306a36Sopenharmony_ci msgo, 41762306a36Sopenharmony_ci cmd, 41862306a36Sopenharmony_ci msgi, 41962306a36Sopenharmony_ci status, 42062306a36Sopenharmony_ci datai, 42162306a36Sopenharmony_ci datao, 42262306a36Sopenharmony_ci parerr, 42362306a36Sopenharmony_ci rsti, 42462306a36Sopenharmony_ci maxstate 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/* 42862306a36Sopenharmony_ci * current state information of the host 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_cistruct aha152x_hostdata { 43262306a36Sopenharmony_ci struct scsi_cmnd *issue_SC; 43362306a36Sopenharmony_ci /* pending commands to issue */ 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci struct scsi_cmnd *current_SC; 43662306a36Sopenharmony_ci /* current command on the bus */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci struct scsi_cmnd *disconnected_SC; 43962306a36Sopenharmony_ci /* commands that disconnected */ 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci struct scsi_cmnd *done_SC; 44262306a36Sopenharmony_ci /* command that was completed */ 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci spinlock_t lock; 44562306a36Sopenharmony_ci /* host lock */ 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci#if defined(AHA152X_STAT) 44862306a36Sopenharmony_ci int total_commands; 44962306a36Sopenharmony_ci int disconnections; 45062306a36Sopenharmony_ci int busfree_without_any_action; 45162306a36Sopenharmony_ci int busfree_without_old_command; 45262306a36Sopenharmony_ci int busfree_without_new_command; 45362306a36Sopenharmony_ci int busfree_without_done_command; 45462306a36Sopenharmony_ci int busfree_with_check_condition; 45562306a36Sopenharmony_ci int count[maxstate]; 45662306a36Sopenharmony_ci int count_trans[maxstate]; 45762306a36Sopenharmony_ci unsigned long time[maxstate]; 45862306a36Sopenharmony_ci#endif 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci int commands; /* current number of commands */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci int reconnect; /* disconnection allowed */ 46362306a36Sopenharmony_ci int parity; /* parity checking enabled */ 46462306a36Sopenharmony_ci int synchronous; /* synchronous transferes enabled */ 46562306a36Sopenharmony_ci int delay; /* reset out delay */ 46662306a36Sopenharmony_ci int ext_trans; /* extended translation enabled */ 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci int swint; /* software-interrupt was fired during detect() */ 46962306a36Sopenharmony_ci int service; /* bh needs to be run */ 47062306a36Sopenharmony_ci int in_intr; /* bh is running */ 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* current state, 47362306a36Sopenharmony_ci previous state, 47462306a36Sopenharmony_ci last state different from current state */ 47562306a36Sopenharmony_ci enum aha152x_state state, prevstate, laststate; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci int target; 47862306a36Sopenharmony_ci /* reconnecting target */ 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci unsigned char syncrate[8]; 48162306a36Sopenharmony_ci /* current synchronous transfer agreements */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci unsigned char syncneg[8]; 48462306a36Sopenharmony_ci /* 0: no negotiation; 48562306a36Sopenharmony_ci * 1: negotiation in progress; 48662306a36Sopenharmony_ci * 2: negotiation completed 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci int cmd_i; 49062306a36Sopenharmony_ci /* number of sent bytes of current command */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci int msgi_len; 49362306a36Sopenharmony_ci /* number of received message bytes */ 49462306a36Sopenharmony_ci unsigned char msgi[256]; 49562306a36Sopenharmony_ci /* received message bytes */ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci int msgo_i, msgo_len; 49862306a36Sopenharmony_ci /* number of sent bytes and length of current messages */ 49962306a36Sopenharmony_ci unsigned char msgo[256]; 50062306a36Sopenharmony_ci /* pending messages */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci int data_len; 50362306a36Sopenharmony_ci /* number of sent/received bytes in dataphase */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci unsigned long io_port0; 50662306a36Sopenharmony_ci unsigned long io_port1; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci#ifdef __ISAPNP__ 50962306a36Sopenharmony_ci struct pnp_dev *pnpdev; 51062306a36Sopenharmony_ci#endif 51162306a36Sopenharmony_ci struct list_head host_list; 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* 51662306a36Sopenharmony_ci * host specific command extension 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_cistruct aha152x_scdata { 52062306a36Sopenharmony_ci struct scsi_cmnd *next; /* next sc in queue */ 52162306a36Sopenharmony_ci struct completion *done;/* semaphore to block on */ 52262306a36Sopenharmony_ci struct scsi_eh_save ses; 52362306a36Sopenharmony_ci}; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci/* access macros for hostdata */ 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci#define HOSTNO ((shpnt)->host_no) 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) 53262306a36Sopenharmony_ci#define DONE_SC (HOSTDATA(shpnt)->done_SC) 53362306a36Sopenharmony_ci#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) 53462306a36Sopenharmony_ci#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) 53562306a36Sopenharmony_ci#define QLOCK (HOSTDATA(shpnt)->lock) 53662306a36Sopenharmony_ci#define QLOCKER (HOSTDATA(shpnt)->locker) 53762306a36Sopenharmony_ci#define QLOCKERL (HOSTDATA(shpnt)->lockerl) 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci#define STATE (HOSTDATA(shpnt)->state) 54062306a36Sopenharmony_ci#define PREVSTATE (HOSTDATA(shpnt)->prevstate) 54162306a36Sopenharmony_ci#define LASTSTATE (HOSTDATA(shpnt)->laststate) 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci#define RECONN_TARGET (HOSTDATA(shpnt)->target) 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci#define CMD_I (HOSTDATA(shpnt)->cmd_i) 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci#define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) 54862306a36Sopenharmony_ci#define MSGO_I (HOSTDATA(shpnt)->msgo_i) 54962306a36Sopenharmony_ci#define MSGOLEN (HOSTDATA(shpnt)->msgo_len) 55062306a36Sopenharmony_ci#define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow")) 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci#define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) 55362306a36Sopenharmony_ci#define MSGILEN (HOSTDATA(shpnt)->msgi_len) 55462306a36Sopenharmony_ci#define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow")) 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci#define DATA_LEN (HOSTDATA(shpnt)->data_len) 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id]) 55962306a36Sopenharmony_ci#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id]) 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci#define DELAY (HOSTDATA(shpnt)->delay) 56262306a36Sopenharmony_ci#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) 56362306a36Sopenharmony_ci#define TC1550 (HOSTDATA(shpnt)->tc1550) 56462306a36Sopenharmony_ci#define RECONNECT (HOSTDATA(shpnt)->reconnect) 56562306a36Sopenharmony_ci#define PARITY (HOSTDATA(shpnt)->parity) 56662306a36Sopenharmony_ci#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) 56962306a36Sopenharmony_ci#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) 57262306a36Sopenharmony_ci#define SCNEXT(SCpnt) SCDATA(SCpnt)->next 57362306a36Sopenharmony_ci#define SCSEM(SCpnt) SCDATA(SCpnt)->done 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci/* state handling */ 57862306a36Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt); 57962306a36Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt); 58062306a36Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt); 58162306a36Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt); 58462306a36Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt); 58562306a36Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt); 58862306a36Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt); 58962306a36Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt); 59262306a36Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt); 59362306a36Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt); 59662306a36Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt); 59762306a36Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt); 60262306a36Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt); 60562306a36Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * driver states 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci */ 61362306a36Sopenharmony_cistatic struct { 61462306a36Sopenharmony_ci char *name; 61562306a36Sopenharmony_ci void (*init)(struct Scsi_Host *); 61662306a36Sopenharmony_ci void (*run)(struct Scsi_Host *); 61762306a36Sopenharmony_ci void (*end)(struct Scsi_Host *); 61862306a36Sopenharmony_ci int spio; 61962306a36Sopenharmony_ci} states[] = { 62062306a36Sopenharmony_ci { "idle", NULL, NULL, NULL, 0}, 62162306a36Sopenharmony_ci { "unknown", NULL, NULL, NULL, 0}, 62262306a36Sopenharmony_ci { "seldo", NULL, seldo_run, NULL, 0}, 62362306a36Sopenharmony_ci { "seldi", NULL, seldi_run, NULL, 0}, 62462306a36Sopenharmony_ci { "selto", NULL, selto_run, NULL, 0}, 62562306a36Sopenharmony_ci { "busfree", NULL, busfree_run, NULL, 0}, 62662306a36Sopenharmony_ci { "msgo", msgo_init, msgo_run, msgo_end, 1}, 62762306a36Sopenharmony_ci { "cmd", cmd_init, cmd_run, cmd_end, 1}, 62862306a36Sopenharmony_ci { "msgi", NULL, msgi_run, msgi_end, 1}, 62962306a36Sopenharmony_ci { "status", NULL, status_run, NULL, 1}, 63062306a36Sopenharmony_ci { "datai", datai_init, datai_run, datai_end, 0}, 63162306a36Sopenharmony_ci { "datao", datao_init, datao_run, datao_end, 0}, 63262306a36Sopenharmony_ci { "parerr", NULL, parerr_run, NULL, 0}, 63362306a36Sopenharmony_ci { "rsti", NULL, rsti_run, NULL, 0}, 63462306a36Sopenharmony_ci}; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/* setup & interrupt */ 63762306a36Sopenharmony_cistatic irqreturn_t intr(int irq, void *dev_id); 63862306a36Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt); 63962306a36Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg); 64062306a36Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, unsigned char status_byte, 64162306a36Sopenharmony_ci unsigned char host_byte); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* diagnostics */ 64462306a36Sopenharmony_cistatic void show_command(struct scsi_cmnd * ptr); 64562306a36Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt); 64662306a36Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/* 65062306a36Sopenharmony_ci * queue services: 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_cistatic inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct scsi_cmnd *end; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci SCNEXT(new_SC) = NULL; 65862306a36Sopenharmony_ci if (!*SC) 65962306a36Sopenharmony_ci *SC = new_SC; 66062306a36Sopenharmony_ci else { 66162306a36Sopenharmony_ci for (end = *SC; SCNEXT(end); end = SCNEXT(end)) 66262306a36Sopenharmony_ci ; 66362306a36Sopenharmony_ci SCNEXT(end) = new_SC; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd ** SC) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct scsi_cmnd *ptr; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ptr = *SC; 67262306a36Sopenharmony_ci if (ptr) { 67362306a36Sopenharmony_ci *SC = SCNEXT(*SC); 67462306a36Sopenharmony_ci SCNEXT(ptr)=NULL; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci return ptr; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_lun_SC(struct scsi_cmnd ** SC, 68062306a36Sopenharmony_ci int target, int lun) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct scsi_cmnd *ptr, *prev; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci for (ptr = *SC, prev = NULL; 68562306a36Sopenharmony_ci ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); 68662306a36Sopenharmony_ci prev = ptr, ptr = SCNEXT(ptr)) 68762306a36Sopenharmony_ci ; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (ptr) { 69062306a36Sopenharmony_ci if (prev) 69162306a36Sopenharmony_ci SCNEXT(prev) = SCNEXT(ptr); 69262306a36Sopenharmony_ci else 69362306a36Sopenharmony_ci *SC = SCNEXT(ptr); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci SCNEXT(ptr)=NULL; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci return ptr; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, 70262306a36Sopenharmony_ci struct scsi_cmnd *SCp) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct scsi_cmnd *ptr, *prev; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (ptr = *SC, prev = NULL; 70762306a36Sopenharmony_ci ptr && SCp!=ptr; 70862306a36Sopenharmony_ci prev = ptr, ptr = SCNEXT(ptr)) 70962306a36Sopenharmony_ci ; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (ptr) { 71262306a36Sopenharmony_ci if (prev) 71362306a36Sopenharmony_ci SCNEXT(prev) = SCNEXT(ptr); 71462306a36Sopenharmony_ci else 71562306a36Sopenharmony_ci *SC = SCNEXT(ptr); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci SCNEXT(ptr)=NULL; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return ptr; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic irqreturn_t swintr(int irqno, void *dev_id) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct Scsi_Host *shpnt = dev_id; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci HOSTDATA(shpnt)->swint++; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci SETPORT(DMACNTRL0, INTEN); 73062306a36Sopenharmony_ci return IRQ_HANDLED; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistruct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct Scsi_Host *shpnt; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata)); 73862306a36Sopenharmony_ci if (!shpnt) { 73962306a36Sopenharmony_ci printk(KERN_ERR "aha152x: scsi_host_alloc failed\n"); 74062306a36Sopenharmony_ci return NULL; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt)); 74462306a36Sopenharmony_ci INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* need to have host registered before triggering any interrupt */ 74762306a36Sopenharmony_ci list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci shpnt->io_port = setup->io_port; 75062306a36Sopenharmony_ci shpnt->n_io_port = IO_RANGE; 75162306a36Sopenharmony_ci shpnt->irq = setup->irq; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (!setup->tc1550) { 75462306a36Sopenharmony_ci HOSTIOPORT0 = setup->io_port; 75562306a36Sopenharmony_ci HOSTIOPORT1 = setup->io_port; 75662306a36Sopenharmony_ci } else { 75762306a36Sopenharmony_ci HOSTIOPORT0 = setup->io_port+0x10; 75862306a36Sopenharmony_ci HOSTIOPORT1 = setup->io_port-0x10; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci spin_lock_init(&QLOCK); 76262306a36Sopenharmony_ci RECONNECT = setup->reconnect; 76362306a36Sopenharmony_ci SYNCHRONOUS = setup->synchronous; 76462306a36Sopenharmony_ci PARITY = setup->parity; 76562306a36Sopenharmony_ci DELAY = setup->delay; 76662306a36Sopenharmony_ci EXT_TRANS = setup->ext_trans; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci SETPORT(SCSIID, setup->scsiid << 4); 76962306a36Sopenharmony_ci shpnt->this_id = setup->scsiid; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (setup->reconnect) 77262306a36Sopenharmony_ci shpnt->can_queue = AHA152X_MAXQUEUE; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* RESET OUT */ 77562306a36Sopenharmony_ci printk("aha152x: resetting bus...\n"); 77662306a36Sopenharmony_ci SETPORT(SCSISEQ, SCSIRSTO); 77762306a36Sopenharmony_ci mdelay(256); 77862306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 77962306a36Sopenharmony_ci mdelay(DELAY); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci reset_ports(shpnt); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci printk(KERN_INFO 78462306a36Sopenharmony_ci "aha152x%d%s: " 78562306a36Sopenharmony_ci "vital data: rev=%x, " 78662306a36Sopenharmony_ci "io=0x%03lx (0x%03lx/0x%03lx), " 78762306a36Sopenharmony_ci "irq=%d, " 78862306a36Sopenharmony_ci "scsiid=%d, " 78962306a36Sopenharmony_ci "reconnect=%s, " 79062306a36Sopenharmony_ci "parity=%s, " 79162306a36Sopenharmony_ci "synchronous=%s, " 79262306a36Sopenharmony_ci "delay=%d, " 79362306a36Sopenharmony_ci "extended translation=%s\n", 79462306a36Sopenharmony_ci shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "", 79562306a36Sopenharmony_ci GETPORT(REV) & 0x7, 79662306a36Sopenharmony_ci shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, 79762306a36Sopenharmony_ci shpnt->irq, 79862306a36Sopenharmony_ci shpnt->this_id, 79962306a36Sopenharmony_ci RECONNECT ? "enabled" : "disabled", 80062306a36Sopenharmony_ci PARITY ? "enabled" : "disabled", 80162306a36Sopenharmony_ci SYNCHRONOUS ? "enabled" : "disabled", 80262306a36Sopenharmony_ci DELAY, 80362306a36Sopenharmony_ci EXT_TRANS ? "enabled" : "disabled"); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* not expecting any interrupts */ 80662306a36Sopenharmony_ci SETPORT(SIMODE0, 0); 80762306a36Sopenharmony_ci SETPORT(SIMODE1, 0); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (request_irq(shpnt->irq, swintr, IRQF_SHARED, "aha152x", shpnt)) { 81062306a36Sopenharmony_ci printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq); 81162306a36Sopenharmony_ci goto out_host_put; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci HOSTDATA(shpnt)->swint = 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci mb(); 81962306a36Sopenharmony_ci SETPORT(DMACNTRL0, SWINT|INTEN); 82062306a36Sopenharmony_ci mdelay(1000); 82162306a36Sopenharmony_ci free_irq(shpnt->irq, shpnt); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->swint) { 82462306a36Sopenharmony_ci if (TESTHI(DMASTAT, INTSTAT)) { 82562306a36Sopenharmony_ci printk("lost.\n"); 82662306a36Sopenharmony_ci } else { 82762306a36Sopenharmony_ci printk("failed.\n"); 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci SETPORT(DMACNTRL0, INTEN); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci printk(KERN_ERR "aha152x%d: irq %d possibly wrong. " 83362306a36Sopenharmony_ci "Please verify.\n", shpnt->host_no, shpnt->irq); 83462306a36Sopenharmony_ci goto out_host_put; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci printk("ok.\n"); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* clear interrupts */ 84062306a36Sopenharmony_ci SETPORT(SSTAT0, 0x7f); 84162306a36Sopenharmony_ci SETPORT(SSTAT1, 0xef); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (request_irq(shpnt->irq, intr, IRQF_SHARED, "aha152x", shpnt)) { 84462306a36Sopenharmony_ci printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq); 84562306a36Sopenharmony_ci goto out_host_put; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if( scsi_add_host(shpnt, NULL) ) { 84962306a36Sopenharmony_ci free_irq(shpnt->irq, shpnt); 85062306a36Sopenharmony_ci printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no); 85162306a36Sopenharmony_ci goto out_host_put; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci scsi_scan_host(shpnt); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return shpnt; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ciout_host_put: 85962306a36Sopenharmony_ci list_del(&HOSTDATA(shpnt)->host_list); 86062306a36Sopenharmony_ci scsi_host_put(shpnt); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return NULL; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_civoid aha152x_release(struct Scsi_Host *shpnt) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci if (!shpnt) 86862306a36Sopenharmony_ci return; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci scsi_remove_host(shpnt); 87162306a36Sopenharmony_ci if (shpnt->irq) 87262306a36Sopenharmony_ci free_irq(shpnt->irq, shpnt); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 87562306a36Sopenharmony_ci if (shpnt->io_port) 87662306a36Sopenharmony_ci release_region(shpnt->io_port, IO_RANGE); 87762306a36Sopenharmony_ci#endif 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci#ifdef __ISAPNP__ 88062306a36Sopenharmony_ci if (HOSTDATA(shpnt)->pnpdev) 88162306a36Sopenharmony_ci pnp_device_detach(HOSTDATA(shpnt)->pnpdev); 88262306a36Sopenharmony_ci#endif 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci list_del(&HOSTDATA(shpnt)->host_list); 88562306a36Sopenharmony_ci scsi_host_put(shpnt); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci/* 89062306a36Sopenharmony_ci * setup controller to generate interrupts depending 89162306a36Sopenharmony_ci * on current state (lock has to be acquired) 89262306a36Sopenharmony_ci * 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_cistatic int setup_expected_interrupts(struct Scsi_Host *shpnt) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci if(CURRENT_SC) { 89762306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci acp->phase |= 1 << 16; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (acp->phase & selecting) { 90262306a36Sopenharmony_ci SETPORT(SSTAT1, SELTO); 90362306a36Sopenharmony_ci SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); 90462306a36Sopenharmony_ci SETPORT(SIMODE1, ENSELTIMO); 90562306a36Sopenharmony_ci } else { 90662306a36Sopenharmony_ci SETPORT(SIMODE0, (acp->phase & spiordy) ? ENSPIORDY : 0); 90762306a36Sopenharmony_ci SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci } else if(STATE==seldi) { 91062306a36Sopenharmony_ci SETPORT(SIMODE0, 0); 91162306a36Sopenharmony_ci SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 91262306a36Sopenharmony_ci } else { 91362306a36Sopenharmony_ci SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); 91462306a36Sopenharmony_ci SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if(!HOSTDATA(shpnt)->in_intr) 91862306a36Sopenharmony_ci SETBITS(DMACNTRL0, INTEN); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return TESTHI(DMASTAT, INTSTAT); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci/* 92562306a36Sopenharmony_ci * Queue a command and setup interrupts for a free bus. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_cistatic int aha152x_internal_queue(struct scsi_cmnd *SCpnt, 92862306a36Sopenharmony_ci struct completion *complete, int phase) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt); 93162306a36Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 93262306a36Sopenharmony_ci unsigned long flags; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci acp->phase = not_issued | phase; 93562306a36Sopenharmony_ci acp->status = 0x1; /* Illegal status by SCSI standard */ 93662306a36Sopenharmony_ci acp->message = 0; 93762306a36Sopenharmony_ci acp->sent_command = 0; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (acp->phase & (resetting | check_condition)) { 94062306a36Sopenharmony_ci if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { 94162306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); 94262306a36Sopenharmony_ci return FAILED; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci } else { 94562306a36Sopenharmony_ci SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); 94662306a36Sopenharmony_ci if(!SCpnt->host_scribble) { 94762306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); 94862306a36Sopenharmony_ci return FAILED; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci SCNEXT(SCpnt) = NULL; 95362306a36Sopenharmony_ci SCSEM(SCpnt) = complete; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* setup scratch area 95662306a36Sopenharmony_ci SCp.ptr : buffer pointer 95762306a36Sopenharmony_ci SCp.this_residual : buffer length 95862306a36Sopenharmony_ci SCp.buffer : next buffer 95962306a36Sopenharmony_ci SCp.phase : current state of the command */ 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if ((phase & resetting) || !scsi_sglist(SCpnt)) { 96262306a36Sopenharmony_ci acp->ptr = NULL; 96362306a36Sopenharmony_ci acp->this_residual = 0; 96462306a36Sopenharmony_ci scsi_set_resid(SCpnt, 0); 96562306a36Sopenharmony_ci acp->buffer = NULL; 96662306a36Sopenharmony_ci } else { 96762306a36Sopenharmony_ci scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 96862306a36Sopenharmony_ci acp->buffer = scsi_sglist(SCpnt); 96962306a36Sopenharmony_ci acp->ptr = SG_ADDRESS(acp->buffer); 97062306a36Sopenharmony_ci acp->this_residual = acp->buffer->length; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci DO_LOCK(flags); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci#if defined(AHA152X_STAT) 97662306a36Sopenharmony_ci HOSTDATA(shpnt)->total_commands++; 97762306a36Sopenharmony_ci#endif 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* Turn led on, when this is the first command. */ 98062306a36Sopenharmony_ci HOSTDATA(shpnt)->commands++; 98162306a36Sopenharmony_ci if (HOSTDATA(shpnt)->commands==1) 98262306a36Sopenharmony_ci SETPORT(PORTA, 1); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci append_SC(&ISSUE_SC, SCpnt); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if(!HOSTDATA(shpnt)->in_intr) 98762306a36Sopenharmony_ci setup_expected_interrupts(shpnt); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci DO_UNLOCK(flags); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/* 99562306a36Sopenharmony_ci * queue a command 99662306a36Sopenharmony_ci * 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_cistatic int aha152x_queue_lck(struct scsi_cmnd *SCpnt) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci return aha152x_internal_queue(SCpnt, NULL, 0); 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic DEF_SCSI_QCMD(aha152x_queue) 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/* 100762306a36Sopenharmony_ci * 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_cistatic void reset_done(struct scsi_cmnd *SCpnt) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci if(SCSEM(SCpnt)) { 101262306a36Sopenharmony_ci complete(SCSEM(SCpnt)); 101362306a36Sopenharmony_ci } else { 101462306a36Sopenharmony_ci printk(KERN_ERR "aha152x: reset_done w/o completion\n"); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic void aha152x_scsi_done(struct scsi_cmnd *SCpnt) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci if (aha152x_priv(SCpnt)->phase & resetting) 102162306a36Sopenharmony_ci reset_done(SCpnt); 102262306a36Sopenharmony_ci else 102362306a36Sopenharmony_ci scsi_done(SCpnt); 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/* 102762306a36Sopenharmony_ci * Abort a command 102862306a36Sopenharmony_ci * 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_cistatic int aha152x_abort(struct scsi_cmnd *SCpnt) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 103362306a36Sopenharmony_ci struct scsi_cmnd *ptr; 103462306a36Sopenharmony_ci unsigned long flags; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci DO_LOCK(flags); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci ptr=remove_SC(&ISSUE_SC, SCpnt); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if(ptr) { 104162306a36Sopenharmony_ci HOSTDATA(shpnt)->commands--; 104262306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 104362306a36Sopenharmony_ci SETPORT(PORTA, 0); 104462306a36Sopenharmony_ci DO_UNLOCK(flags); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci kfree(SCpnt->host_scribble); 104762306a36Sopenharmony_ci SCpnt->host_scribble=NULL; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci return SUCCESS; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci DO_UNLOCK(flags); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* 105562306a36Sopenharmony_ci * FIXME: 105662306a36Sopenharmony_ci * for current command: queue ABORT for message out and raise ATN 105762306a36Sopenharmony_ci * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? 105862306a36Sopenharmony_ci * 105962306a36Sopenharmony_ci */ 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, 106262306a36Sopenharmony_ci "cannot abort running or disconnected command\n"); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci return FAILED; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci/* 106862306a36Sopenharmony_ci * Reset a device 106962306a36Sopenharmony_ci * 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_cistatic int aha152x_device_reset(struct scsi_cmnd * SCpnt) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct Scsi_Host *shpnt = SCpnt->device->host; 107462306a36Sopenharmony_ci DECLARE_COMPLETION(done); 107562306a36Sopenharmony_ci int ret, issued, disconnected; 107662306a36Sopenharmony_ci unsigned char old_cmd_len = SCpnt->cmd_len; 107762306a36Sopenharmony_ci unsigned long flags; 107862306a36Sopenharmony_ci unsigned long timeleft; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if(CURRENT_SC==SCpnt) { 108162306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n"); 108262306a36Sopenharmony_ci return FAILED; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci DO_LOCK(flags); 108662306a36Sopenharmony_ci issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; 108762306a36Sopenharmony_ci disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); 108862306a36Sopenharmony_ci DO_UNLOCK(flags); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci SCpnt->cmd_len = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci aha152x_internal_queue(SCpnt, &done, resetting); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci timeleft = wait_for_completion_timeout(&done, 100*HZ); 109562306a36Sopenharmony_ci if (!timeleft) { 109662306a36Sopenharmony_ci /* remove command from issue queue */ 109762306a36Sopenharmony_ci DO_LOCK(flags); 109862306a36Sopenharmony_ci remove_SC(&ISSUE_SC, SCpnt); 109962306a36Sopenharmony_ci DO_UNLOCK(flags); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci SCpnt->cmd_len = old_cmd_len; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci DO_LOCK(flags); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (aha152x_priv(SCpnt)->phase & resetted) { 110762306a36Sopenharmony_ci HOSTDATA(shpnt)->commands--; 110862306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 110962306a36Sopenharmony_ci SETPORT(PORTA, 0); 111062306a36Sopenharmony_ci kfree(SCpnt->host_scribble); 111162306a36Sopenharmony_ci SCpnt->host_scribble=NULL; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci ret = SUCCESS; 111462306a36Sopenharmony_ci } else { 111562306a36Sopenharmony_ci /* requeue */ 111662306a36Sopenharmony_ci if(!issued) { 111762306a36Sopenharmony_ci append_SC(&ISSUE_SC, SCpnt); 111862306a36Sopenharmony_ci } else if(disconnected) { 111962306a36Sopenharmony_ci append_SC(&DISCONNECTED_SC, SCpnt); 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ret = FAILED; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci DO_UNLOCK(flags); 112662306a36Sopenharmony_ci return ret; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void free_hard_reset_SCs(struct Scsi_Host *shpnt, 113062306a36Sopenharmony_ci struct scsi_cmnd **SCs) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci struct scsi_cmnd *ptr; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci ptr=*SCs; 113562306a36Sopenharmony_ci while(ptr) { 113662306a36Sopenharmony_ci struct scsi_cmnd *next; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if(SCDATA(ptr)) { 113962306a36Sopenharmony_ci next = SCNEXT(ptr); 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, ptr, 114262306a36Sopenharmony_ci "queue corrupted at %p\n", ptr); 114362306a36Sopenharmony_ci next = NULL; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (!ptr->device->soft_reset) { 114762306a36Sopenharmony_ci remove_SC(SCs, ptr); 114862306a36Sopenharmony_ci HOSTDATA(shpnt)->commands--; 114962306a36Sopenharmony_ci kfree(ptr->host_scribble); 115062306a36Sopenharmony_ci ptr->host_scribble=NULL; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ptr = next; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci} 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci/* 115862306a36Sopenharmony_ci * Reset the bus 115962306a36Sopenharmony_ci * 116062306a36Sopenharmony_ci * AIC-6260 has a hard reset (MRST signal), but apparently 116162306a36Sopenharmony_ci * one cannot trigger it via software. So live with 116262306a36Sopenharmony_ci * a soft reset; no-one seemed to have cared. 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_cistatic int aha152x_bus_reset_host(struct Scsi_Host *shpnt) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci unsigned long flags; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci DO_LOCK(flags); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci free_hard_reset_SCs(shpnt, &ISSUE_SC); 117162306a36Sopenharmony_ci free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci SETPORT(SCSISEQ, SCSIRSTO); 117462306a36Sopenharmony_ci mdelay(256); 117562306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 117662306a36Sopenharmony_ci mdelay(DELAY); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci setup_expected_interrupts(shpnt); 117962306a36Sopenharmony_ci if(HOSTDATA(shpnt)->commands==0) 118062306a36Sopenharmony_ci SETPORT(PORTA, 0); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci DO_UNLOCK(flags); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci return SUCCESS; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci/* 118862306a36Sopenharmony_ci * Reset the bus 118962306a36Sopenharmony_ci * 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_cistatic int aha152x_bus_reset(struct scsi_cmnd *SCpnt) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci return aha152x_bus_reset_host(SCpnt->device->host); 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci/* 119762306a36Sopenharmony_ci * Restore default values to the AIC-6260 registers and reset the fifos 119862306a36Sopenharmony_ci * 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_cistatic void reset_ports(struct Scsi_Host *shpnt) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci unsigned long flags; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* disable interrupts */ 120562306a36Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci SETPORT(SXFRCTL1, 0); 121062306a36Sopenharmony_ci SETPORT(SCSISIG, 0); 121162306a36Sopenharmony_ci SETRATE(0); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci /* clear all interrupt conditions */ 121462306a36Sopenharmony_ci SETPORT(SSTAT0, 0x7f); 121562306a36Sopenharmony_ci SETPORT(SSTAT1, 0xef); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci SETPORT(DMACNTRL0, 0); 122062306a36Sopenharmony_ci SETPORT(DMACNTRL1, 0); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci SETPORT(BRSTCNTRL, 0xf1); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* clear SCSI fifos and transfer count */ 122562306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 122662306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci DO_LOCK(flags); 122962306a36Sopenharmony_ci setup_expected_interrupts(shpnt); 123062306a36Sopenharmony_ci DO_UNLOCK(flags); 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/* 123462306a36Sopenharmony_ci * Reset the host (bus and controller) 123562306a36Sopenharmony_ci * 123662306a36Sopenharmony_ci */ 123762306a36Sopenharmony_ciint aha152x_host_reset_host(struct Scsi_Host *shpnt) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci aha152x_bus_reset_host(shpnt); 124062306a36Sopenharmony_ci reset_ports(shpnt); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return SUCCESS; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci/* 124662306a36Sopenharmony_ci * Return the "logical geometry" 124762306a36Sopenharmony_ci * 124862306a36Sopenharmony_ci */ 124962306a36Sopenharmony_cistatic int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, 125062306a36Sopenharmony_ci sector_t capacity, int *info_array) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci struct Scsi_Host *shpnt = sdev->host; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* try default translation */ 125562306a36Sopenharmony_ci info_array[0] = 64; 125662306a36Sopenharmony_ci info_array[1] = 32; 125762306a36Sopenharmony_ci info_array[2] = (unsigned long)capacity / (64 * 32); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* for disks >1GB do some guessing */ 126062306a36Sopenharmony_ci if (info_array[2] >= 1024) { 126162306a36Sopenharmony_ci int info[3]; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* try to figure out the geometry from the partition table */ 126462306a36Sopenharmony_ci if (scsicam_bios_param(bdev, capacity, info) < 0 || 126562306a36Sopenharmony_ci !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { 126662306a36Sopenharmony_ci if (EXT_TRANS) { 126762306a36Sopenharmony_ci printk(KERN_NOTICE 126862306a36Sopenharmony_ci "aha152x: unable to verify geometry for disk with >1GB.\n" 126962306a36Sopenharmony_ci " using extended translation.\n"); 127062306a36Sopenharmony_ci info_array[0] = 255; 127162306a36Sopenharmony_ci info_array[1] = 63; 127262306a36Sopenharmony_ci info_array[2] = (unsigned long)capacity / (255 * 63); 127362306a36Sopenharmony_ci } else { 127462306a36Sopenharmony_ci printk(KERN_NOTICE 127562306a36Sopenharmony_ci "aha152x: unable to verify geometry for disk with >1GB.\n" 127662306a36Sopenharmony_ci " Using default translation. Please verify yourself.\n" 127762306a36Sopenharmony_ci " Perhaps you need to enable extended translation in the driver.\n" 127862306a36Sopenharmony_ci " See Documentation/scsi/aha152x.rst for details.\n"); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci } else { 128162306a36Sopenharmony_ci info_array[0] = info[0]; 128262306a36Sopenharmony_ci info_array[1] = info[1]; 128362306a36Sopenharmony_ci info_array[2] = info[2]; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (info[0] == 255 && !EXT_TRANS) { 128662306a36Sopenharmony_ci printk(KERN_NOTICE 128762306a36Sopenharmony_ci "aha152x: current partition table is using extended translation.\n" 128862306a36Sopenharmony_ci " using it also, although it's not explicitly enabled.\n"); 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci/* 129762306a36Sopenharmony_ci * Internal done function 129862306a36Sopenharmony_ci * 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_cistatic void done(struct Scsi_Host *shpnt, unsigned char status_byte, 130162306a36Sopenharmony_ci unsigned char host_byte) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if (CURRENT_SC) { 130462306a36Sopenharmony_ci if(DONE_SC) 130562306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 130662306a36Sopenharmony_ci "there's already a completed command %p " 130762306a36Sopenharmony_ci "- will cause abort\n", DONE_SC); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci DONE_SC = CURRENT_SC; 131062306a36Sopenharmony_ci CURRENT_SC = NULL; 131162306a36Sopenharmony_ci set_status_byte(DONE_SC, status_byte); 131262306a36Sopenharmony_ci set_host_byte(DONE_SC, host_byte); 131362306a36Sopenharmony_ci } else 131462306a36Sopenharmony_ci printk(KERN_ERR "aha152x: done() called outside of command\n"); 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic struct work_struct aha152x_tq; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci/* 132062306a36Sopenharmony_ci * Run service completions on the card with interrupts enabled. 132162306a36Sopenharmony_ci * 132262306a36Sopenharmony_ci */ 132362306a36Sopenharmony_cistatic void run(struct work_struct *work) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci struct aha152x_hostdata *hd; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci list_for_each_entry(hd, &aha152x_host_list, host_list) { 132862306a36Sopenharmony_ci struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci is_complete(shost); 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci/* 133562306a36Sopenharmony_ci * Interrupt handler 133662306a36Sopenharmony_ci * 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_cistatic irqreturn_t intr(int irqno, void *dev_id) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct Scsi_Host *shpnt = dev_id; 134162306a36Sopenharmony_ci unsigned long flags; 134262306a36Sopenharmony_ci unsigned char rev, dmacntrl0; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* 134562306a36Sopenharmony_ci * Read a couple of registers that are known to not be all 1's. If 134662306a36Sopenharmony_ci * we read all 1's (-1), that means that either: 134762306a36Sopenharmony_ci * 134862306a36Sopenharmony_ci * a. The host adapter chip has gone bad, and we cannot control it, 134962306a36Sopenharmony_ci * OR 135062306a36Sopenharmony_ci * b. The host adapter is a PCMCIA card that has been ejected 135162306a36Sopenharmony_ci * 135262306a36Sopenharmony_ci * In either case, we cannot do anything with the host adapter at 135362306a36Sopenharmony_ci * this point in time. So just ignore the interrupt and return. 135462306a36Sopenharmony_ci * In the latter case, the interrupt might actually be meant for 135562306a36Sopenharmony_ci * someone else sharing this IRQ, and that driver will handle it. 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ci rev = GETPORT(REV); 135862306a36Sopenharmony_ci dmacntrl0 = GETPORT(DMACNTRL0); 135962306a36Sopenharmony_ci if ((rev == 0xFF) && (dmacntrl0 == 0xFF)) 136062306a36Sopenharmony_ci return IRQ_NONE; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if( TESTLO(DMASTAT, INTSTAT) ) 136362306a36Sopenharmony_ci return IRQ_NONE; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* no more interrupts from the controller, while we're busy. 136662306a36Sopenharmony_ci INTEN is restored by the BH handler */ 136762306a36Sopenharmony_ci CLRBITS(DMACNTRL0, INTEN); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci DO_LOCK(flags); 137062306a36Sopenharmony_ci if( HOSTDATA(shpnt)->service==0 ) { 137162306a36Sopenharmony_ci HOSTDATA(shpnt)->service=1; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci /* Poke the BH handler */ 137462306a36Sopenharmony_ci INIT_WORK(&aha152x_tq, run); 137562306a36Sopenharmony_ci schedule_work(&aha152x_tq); 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci DO_UNLOCK(flags); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci return IRQ_HANDLED; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/* 138362306a36Sopenharmony_ci * busfree phase 138462306a36Sopenharmony_ci * - handle completition/disconnection/error of current command 138562306a36Sopenharmony_ci * - start selection for next command (if any) 138662306a36Sopenharmony_ci */ 138762306a36Sopenharmony_cistatic void busfree_run(struct Scsi_Host *shpnt) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci unsigned long flags; 139062306a36Sopenharmony_ci#if defined(AHA152X_STAT) 139162306a36Sopenharmony_ci int action=0; 139262306a36Sopenharmony_ci#endif 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 139562306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if(CURRENT_SC) { 140062306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci#if defined(AHA152X_STAT) 140362306a36Sopenharmony_ci action++; 140462306a36Sopenharmony_ci#endif 140562306a36Sopenharmony_ci acp->phase &= ~syncneg; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (acp->phase & completed) { 140862306a36Sopenharmony_ci /* target sent COMMAND COMPLETE */ 140962306a36Sopenharmony_ci done(shpnt, acp->status, DID_OK); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci } else if (acp->phase & aborted) { 141262306a36Sopenharmony_ci done(shpnt, acp->status, DID_ABORT); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci } else if (acp->phase & resetted) { 141562306a36Sopenharmony_ci done(shpnt, acp->status, DID_RESET); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci } else if (acp->phase & disconnected) { 141862306a36Sopenharmony_ci /* target sent DISCONNECT */ 141962306a36Sopenharmony_ci#if defined(AHA152X_STAT) 142062306a36Sopenharmony_ci HOSTDATA(shpnt)->disconnections++; 142162306a36Sopenharmony_ci#endif 142262306a36Sopenharmony_ci append_SC(&DISCONNECTED_SC, CURRENT_SC); 142362306a36Sopenharmony_ci acp->phase |= 1 << 16; 142462306a36Sopenharmony_ci CURRENT_SC = NULL; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci } else { 142762306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_ERROR); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci#if defined(AHA152X_STAT) 143062306a36Sopenharmony_ci } else { 143162306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command++; 143262306a36Sopenharmony_ci#endif 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci DO_LOCK(flags); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if(DONE_SC) { 143862306a36Sopenharmony_ci#if defined(AHA152X_STAT) 143962306a36Sopenharmony_ci action++; 144062306a36Sopenharmony_ci#endif 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (aha152x_priv(DONE_SC)->phase & check_condition) { 144362306a36Sopenharmony_ci struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; 144462306a36Sopenharmony_ci struct aha152x_scdata *sc = SCDATA(cmd); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci scsi_eh_restore_cmnd(cmd, &sc->ses); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci aha152x_priv(cmd)->status = SAM_STAT_CHECK_CONDITION; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci HOSTDATA(shpnt)->commands--; 145162306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 145262306a36Sopenharmony_ci SETPORT(PORTA, 0); /* turn led off */ 145362306a36Sopenharmony_ci } else if (aha152x_priv(DONE_SC)->status == SAM_STAT_CHECK_CONDITION) { 145462306a36Sopenharmony_ci#if defined(AHA152X_STAT) 145562306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition++; 145662306a36Sopenharmony_ci#endif 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (!(aha152x_priv(DONE_SC)->phase & not_issued)) { 145962306a36Sopenharmony_ci struct aha152x_scdata *sc; 146062306a36Sopenharmony_ci struct scsi_cmnd *ptr = DONE_SC; 146162306a36Sopenharmony_ci DONE_SC=NULL; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci sc = SCDATA(ptr); 146462306a36Sopenharmony_ci /* It was allocated in aha152x_internal_queue? */ 146562306a36Sopenharmony_ci BUG_ON(!sc); 146662306a36Sopenharmony_ci scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci DO_UNLOCK(flags); 146962306a36Sopenharmony_ci aha152x_internal_queue(ptr, NULL, check_condition); 147062306a36Sopenharmony_ci DO_LOCK(flags); 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (DONE_SC) { 147562306a36Sopenharmony_ci struct scsi_cmnd *ptr = DONE_SC; 147662306a36Sopenharmony_ci DONE_SC=NULL; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci /* turn led off, when no commands are in the driver */ 147962306a36Sopenharmony_ci HOSTDATA(shpnt)->commands--; 148062306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->commands) 148162306a36Sopenharmony_ci SETPORT(PORTA, 0); /* turn led off */ 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci if (!(aha152x_priv(ptr)->phase & resetting)) { 148462306a36Sopenharmony_ci kfree(ptr->host_scribble); 148562306a36Sopenharmony_ci ptr->host_scribble=NULL; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci DO_UNLOCK(flags); 148962306a36Sopenharmony_ci aha152x_scsi_done(ptr); 149062306a36Sopenharmony_ci DO_LOCK(flags); 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci DONE_SC=NULL; 149462306a36Sopenharmony_ci#if defined(AHA152X_STAT) 149562306a36Sopenharmony_ci } else { 149662306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command++; 149762306a36Sopenharmony_ci#endif 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if(ISSUE_SC) 150162306a36Sopenharmony_ci CURRENT_SC = remove_first_SC(&ISSUE_SC); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci DO_UNLOCK(flags); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci if(CURRENT_SC) { 150662306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci#if defined(AHA152X_STAT) 150962306a36Sopenharmony_ci action++; 151062306a36Sopenharmony_ci#endif 151162306a36Sopenharmony_ci acp->phase |= selecting; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* clear selection timeout */ 151462306a36Sopenharmony_ci SETPORT(SSTAT1, SELTO); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id); 151762306a36Sopenharmony_ci SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); 151862306a36Sopenharmony_ci SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); 151962306a36Sopenharmony_ci } else { 152062306a36Sopenharmony_ci#if defined(AHA152X_STAT) 152162306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command++; 152262306a36Sopenharmony_ci#endif 152362306a36Sopenharmony_ci SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci#if defined(AHA152X_STAT) 152762306a36Sopenharmony_ci if(!action) 152862306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action++; 152962306a36Sopenharmony_ci#endif 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci/* 153362306a36Sopenharmony_ci * Selection done (OUT) 153462306a36Sopenharmony_ci * - queue IDENTIFY message and SDTR to selected target for message out 153562306a36Sopenharmony_ci * (ATN asserted automagically via ENAUTOATNO in busfree()) 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_cistatic void seldo_run(struct Scsi_Host *shpnt) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci SETPORT(SCSISIG, 0); 154262306a36Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 154362306a36Sopenharmony_ci SETPORT(SSTAT1, CLRPHASECHG); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci acp->phase &= ~(selecting | not_issued); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci if (TESTLO(SSTAT0, SELDO)) { 155062306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 155162306a36Sopenharmony_ci "aha152x: passing bus free condition\n"); 155262306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT); 155362306a36Sopenharmony_ci return; 155462306a36Sopenharmony_ci } 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci SETPORT(SSTAT0, CLRSELDO); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (acp->phase & aborting) { 156162306a36Sopenharmony_ci ADDMSGO(ABORT); 156262306a36Sopenharmony_ci } else if (acp->phase & resetting) { 156362306a36Sopenharmony_ci ADDMSGO(BUS_DEVICE_RESET); 156462306a36Sopenharmony_ci } else if (SYNCNEG==0 && SYNCHRONOUS) { 156562306a36Sopenharmony_ci acp->phase |= syncneg; 156662306a36Sopenharmony_ci MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8); 156762306a36Sopenharmony_ci SYNCNEG=1; /* negotiation in progress */ 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci SETRATE(SYNCRATE); 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci/* 157462306a36Sopenharmony_ci * Selection timeout 157562306a36Sopenharmony_ci * - return command to mid-level with failure cause 157662306a36Sopenharmony_ci * 157762306a36Sopenharmony_ci */ 157862306a36Sopenharmony_cistatic void selto_run(struct Scsi_Host *shpnt) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct aha152x_cmd_priv *acp; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 158362306a36Sopenharmony_ci SETPORT(SSTAT1, CLRSELTIMO); 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (!CURRENT_SC) 158662306a36Sopenharmony_ci return; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci acp = aha152x_priv(CURRENT_SC); 158962306a36Sopenharmony_ci acp->phase &= ~selecting; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci if (acp->phase & aborted) 159262306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_ABORT); 159362306a36Sopenharmony_ci else if (TESTLO(SSTAT0, SELINGO)) 159462306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY); 159562306a36Sopenharmony_ci else 159662306a36Sopenharmony_ci /* ARBITRATION won, but SELECTION failed */ 159762306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_NO_CONNECT); 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci/* 160162306a36Sopenharmony_ci * Selection in done 160262306a36Sopenharmony_ci * - put current command back to issue queue 160362306a36Sopenharmony_ci * (reconnection of a disconnected nexus instead 160462306a36Sopenharmony_ci * of successful selection out) 160562306a36Sopenharmony_ci * 160662306a36Sopenharmony_ci */ 160762306a36Sopenharmony_cistatic void seldi_run(struct Scsi_Host *shpnt) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci int selid; 161062306a36Sopenharmony_ci int target; 161162306a36Sopenharmony_ci unsigned long flags; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci SETPORT(SCSISIG, 0); 161462306a36Sopenharmony_ci SETPORT(SSTAT0, CLRSELDI); 161562306a36Sopenharmony_ci SETPORT(SSTAT1, CLRBUSFREE); 161662306a36Sopenharmony_ci SETPORT(SSTAT1, CLRPHASECHG); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci if(CURRENT_SC) { 161962306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (!(acp->phase & not_issued)) 162262306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 162362306a36Sopenharmony_ci "command should not have been issued yet\n"); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci DO_LOCK(flags); 162662306a36Sopenharmony_ci append_SC(&ISSUE_SC, CURRENT_SC); 162762306a36Sopenharmony_ci DO_UNLOCK(flags); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci CURRENT_SC = NULL; 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (!DISCONNECTED_SC) 163362306a36Sopenharmony_ci return; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci RECONN_TARGET=-1; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci selid = GETPORT(SELID) & ~(1 << shpnt->this_id); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (selid==0) { 164062306a36Sopenharmony_ci shost_printk(KERN_INFO, shpnt, 164162306a36Sopenharmony_ci "target id unknown (%02x)\n", selid); 164262306a36Sopenharmony_ci return; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci for(target=7; !(selid & (1 << target)); target--) 164662306a36Sopenharmony_ci ; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if(selid & ~(1 << target)) { 164962306a36Sopenharmony_ci shost_printk(KERN_INFO, shpnt, 165062306a36Sopenharmony_ci "multiple targets reconnected (%02x)\n", selid); 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci SETPORT(SCSIID, (shpnt->this_id << OID_) | target); 165562306a36Sopenharmony_ci SETPORT(SCSISEQ, 0); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci SETRATE(HOSTDATA(shpnt)->syncrate[target]); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci RECONN_TARGET=target; 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci/* 166362306a36Sopenharmony_ci * message in phase 166462306a36Sopenharmony_ci * - handle initial message after reconnection to identify 166562306a36Sopenharmony_ci * reconnecting nexus 166662306a36Sopenharmony_ci * - queue command on DISCONNECTED_SC on DISCONNECT message 166762306a36Sopenharmony_ci * - set completed flag on COMMAND COMPLETE 166862306a36Sopenharmony_ci * (other completition code moved to busfree_run) 166962306a36Sopenharmony_ci * - handle response to SDTR 167062306a36Sopenharmony_ci * - clear synchronous transfer agreements on BUS RESET 167162306a36Sopenharmony_ci * 167262306a36Sopenharmony_ci * FIXME: what about SAVE POINTERS, RESTORE POINTERS? 167362306a36Sopenharmony_ci * 167462306a36Sopenharmony_ci */ 167562306a36Sopenharmony_cistatic void msgi_run(struct Scsi_Host *shpnt) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci for(;;) { 167862306a36Sopenharmony_ci struct aha152x_cmd_priv *acp; 167962306a36Sopenharmony_ci int sstat1 = GETPORT(SSTAT1); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) 168262306a36Sopenharmony_ci return; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 168562306a36Sopenharmony_ci return; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci ADDMSGI(GETPORT(SCSIDAT)); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci if(!CURRENT_SC) { 169062306a36Sopenharmony_ci if(LASTSTATE!=seldi) { 169162306a36Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 169262306a36Sopenharmony_ci "message in w/o current command" 169362306a36Sopenharmony_ci " not after reselection\n"); 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* 169762306a36Sopenharmony_ci * Handle reselection 169862306a36Sopenharmony_ci */ 169962306a36Sopenharmony_ci if(!(MSGI(0) & IDENTIFY_BASE)) { 170062306a36Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 170162306a36Sopenharmony_ci "target didn't identify after reselection\n"); 170262306a36Sopenharmony_ci continue; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci if (!CURRENT_SC) { 170862306a36Sopenharmony_ci show_queues(shpnt); 170962306a36Sopenharmony_ci shost_printk(KERN_ERR, shpnt, 171062306a36Sopenharmony_ci "no disconnected command" 171162306a36Sopenharmony_ci " for target %d/%d\n", 171262306a36Sopenharmony_ci RECONN_TARGET, MSGI(0) & 0x3f); 171362306a36Sopenharmony_ci continue; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci acp = aha152x_priv(CURRENT_SC); 171762306a36Sopenharmony_ci acp->message = MSGI(0); 171862306a36Sopenharmony_ci acp->phase &= ~disconnected; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci MSGILEN=0; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci /* next message if any */ 172362306a36Sopenharmony_ci continue; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci acp = aha152x_priv(CURRENT_SC); 172762306a36Sopenharmony_ci acp->message = MSGI(0); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci switch (MSGI(0)) { 173062306a36Sopenharmony_ci case DISCONNECT: 173162306a36Sopenharmony_ci if (!RECONNECT) 173262306a36Sopenharmony_ci scmd_printk(KERN_WARNING, CURRENT_SC, 173362306a36Sopenharmony_ci "target was not allowed to disconnect\n"); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci acp->phase |= disconnected; 173662306a36Sopenharmony_ci break; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci case COMMAND_COMPLETE: 173962306a36Sopenharmony_ci acp->phase |= completed; 174062306a36Sopenharmony_ci break; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci case MESSAGE_REJECT: 174362306a36Sopenharmony_ci if (SYNCNEG==1) { 174462306a36Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 174562306a36Sopenharmony_ci "Synchronous Data Transfer Request" 174662306a36Sopenharmony_ci " was rejected\n"); 174762306a36Sopenharmony_ci SYNCNEG=2; /* negotiation completed */ 174862306a36Sopenharmony_ci } else 174962306a36Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 175062306a36Sopenharmony_ci "inbound message (MESSAGE REJECT)\n"); 175162306a36Sopenharmony_ci break; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci case SAVE_POINTERS: 175462306a36Sopenharmony_ci break; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci case RESTORE_POINTERS: 175762306a36Sopenharmony_ci break; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci case EXTENDED_MESSAGE: 176062306a36Sopenharmony_ci if(MSGILEN<2 || MSGILEN<MSGI(1)+2) { 176162306a36Sopenharmony_ci /* not yet completed */ 176262306a36Sopenharmony_ci continue; 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci switch (MSGI(2)) { 176662306a36Sopenharmony_ci case EXTENDED_SDTR: 176762306a36Sopenharmony_ci { 176862306a36Sopenharmony_ci long ticks; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (MSGI(1) != 3) { 177162306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 177262306a36Sopenharmony_ci "SDTR message length!=3\n"); 177362306a36Sopenharmony_ci break; 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (!HOSTDATA(shpnt)->synchronous) 177762306a36Sopenharmony_ci break; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci printk(INFO_LEAD, CMDINFO(CURRENT_SC)); 178062306a36Sopenharmony_ci spi_print_msg(&MSGI(0)); 178162306a36Sopenharmony_ci printk("\n"); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci ticks = (MSGI(3) * 4 + 49) / 50; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci if (syncneg) { 178662306a36Sopenharmony_ci /* negotiation in progress */ 178762306a36Sopenharmony_ci if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { 178862306a36Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 178962306a36Sopenharmony_ci scmd_printk(KERN_INFO, 179062306a36Sopenharmony_ci CURRENT_SC, 179162306a36Sopenharmony_ci "received Synchronous Data Transfer Request invalid - rejected\n"); 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 179662306a36Sopenharmony_ci } else if (ticks <= 9 && MSGI(4) >= 1) { 179762306a36Sopenharmony_ci ADDMSGO(EXTENDED_MESSAGE); 179862306a36Sopenharmony_ci ADDMSGO(3); 179962306a36Sopenharmony_ci ADDMSGO(EXTENDED_SDTR); 180062306a36Sopenharmony_ci if (ticks < 4) { 180162306a36Sopenharmony_ci ticks = 4; 180262306a36Sopenharmony_ci ADDMSGO(50); 180362306a36Sopenharmony_ci } else 180462306a36Sopenharmony_ci ADDMSGO(MSGI(3)); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (MSGI(4) > 8) 180762306a36Sopenharmony_ci MSGI(4) = 8; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci ADDMSGO(MSGI(4)); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); 181262306a36Sopenharmony_ci } else { 181362306a36Sopenharmony_ci /* requested SDTR is too slow, do it asynchronously */ 181462306a36Sopenharmony_ci scmd_printk(KERN_INFO, 181562306a36Sopenharmony_ci CURRENT_SC, 181662306a36Sopenharmony_ci "Synchronous Data Transfer Request too slow - Rejecting\n"); 181762306a36Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* negotiation completed */ 182162306a36Sopenharmony_ci SYNCNEG=2; 182262306a36Sopenharmony_ci SETRATE(SYNCRATE); 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci case BUS_DEVICE_RESET: 182762306a36Sopenharmony_ci { 182862306a36Sopenharmony_ci int i; 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci for(i=0; i<8; i++) { 183162306a36Sopenharmony_ci HOSTDATA(shpnt)->syncrate[i]=0; 183262306a36Sopenharmony_ci HOSTDATA(shpnt)->syncneg[i]=0; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci break; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci case EXTENDED_MODIFY_DATA_POINTER: 183962306a36Sopenharmony_ci case EXTENDED_EXTENDED_IDENTIFY: 184062306a36Sopenharmony_ci case EXTENDED_WDTR: 184162306a36Sopenharmony_ci default: 184262306a36Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 184362306a36Sopenharmony_ci break; 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci break; 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci MSGILEN=0; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void msgi_end(struct Scsi_Host *shpnt) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci if(MSGILEN>0) 185562306a36Sopenharmony_ci scmd_printk(KERN_WARNING, CURRENT_SC, 185662306a36Sopenharmony_ci "target left before message completed (%d)\n", 185762306a36Sopenharmony_ci MSGILEN); 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) 186062306a36Sopenharmony_ci SETPORT(SCSISIG, P_MSGI | SIG_ATNO); 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci/* 186462306a36Sopenharmony_ci * message out phase 186562306a36Sopenharmony_ci * 186662306a36Sopenharmony_ci */ 186762306a36Sopenharmony_cistatic void msgo_init(struct Scsi_Host *shpnt) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci if(MSGOLEN==0) { 187062306a36Sopenharmony_ci if ((aha152x_priv(CURRENT_SC)->phase & syncneg) && 187162306a36Sopenharmony_ci SYNCNEG == 2 && SYNCRATE == 0) { 187262306a36Sopenharmony_ci ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); 187362306a36Sopenharmony_ci } else { 187462306a36Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 187562306a36Sopenharmony_ci "unexpected MESSAGE OUT phase; rejecting\n"); 187662306a36Sopenharmony_ci ADDMSGO(MESSAGE_REJECT); 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci/* 188362306a36Sopenharmony_ci * message out phase 188462306a36Sopenharmony_ci * 188562306a36Sopenharmony_ci */ 188662306a36Sopenharmony_cistatic void msgo_run(struct Scsi_Host *shpnt) 188762306a36Sopenharmony_ci{ 188862306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci while(MSGO_I<MSGOLEN) { 189162306a36Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 189262306a36Sopenharmony_ci return; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if (MSGO_I==MSGOLEN-1) { 189562306a36Sopenharmony_ci /* Leave MESSAGE OUT after transfer */ 189662306a36Sopenharmony_ci SETPORT(SSTAT1, CLRATNO); 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci if (MSGO(MSGO_I) & IDENTIFY_BASE) 190162306a36Sopenharmony_ci acp->phase |= identified; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci if (MSGO(MSGO_I)==ABORT) 190462306a36Sopenharmony_ci acp->phase |= aborted; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (MSGO(MSGO_I)==BUS_DEVICE_RESET) 190762306a36Sopenharmony_ci acp->phase |= resetted; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci SETPORT(SCSIDAT, MSGO(MSGO_I++)); 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci} 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_cistatic void msgo_end(struct Scsi_Host *shpnt) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci if(MSGO_I<MSGOLEN) { 191662306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 191762306a36Sopenharmony_ci "message sent incompletely (%d/%d)\n", 191862306a36Sopenharmony_ci MSGO_I, MSGOLEN); 191962306a36Sopenharmony_ci if(SYNCNEG==1) { 192062306a36Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, 192162306a36Sopenharmony_ci "Synchronous Data Transfer Request was rejected\n"); 192262306a36Sopenharmony_ci SYNCNEG=2; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci MSGO_I = 0; 192762306a36Sopenharmony_ci MSGOLEN = 0; 192862306a36Sopenharmony_ci} 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci/* 193162306a36Sopenharmony_ci * command phase 193262306a36Sopenharmony_ci * 193362306a36Sopenharmony_ci */ 193462306a36Sopenharmony_cistatic void cmd_init(struct Scsi_Host *shpnt) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci if (aha152x_priv(CURRENT_SC)->sent_command) { 193762306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 193862306a36Sopenharmony_ci "command already sent\n"); 193962306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_ERROR); 194062306a36Sopenharmony_ci return; 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci CMD_I=0; 194462306a36Sopenharmony_ci} 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci/* 194762306a36Sopenharmony_ci * command phase 194862306a36Sopenharmony_ci * 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_cistatic void cmd_run(struct Scsi_Host *shpnt) 195162306a36Sopenharmony_ci{ 195262306a36Sopenharmony_ci while(CMD_I<CURRENT_SC->cmd_len) { 195362306a36Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 195462306a36Sopenharmony_ci return; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci} 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_cistatic void cmd_end(struct Scsi_Host *shpnt) 196162306a36Sopenharmony_ci{ 196262306a36Sopenharmony_ci if(CMD_I<CURRENT_SC->cmd_len) 196362306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 196462306a36Sopenharmony_ci "command sent incompletely (%d/%d)\n", 196562306a36Sopenharmony_ci CMD_I, CURRENT_SC->cmd_len); 196662306a36Sopenharmony_ci else 196762306a36Sopenharmony_ci aha152x_priv(CURRENT_SC)->sent_command++; 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci/* 197162306a36Sopenharmony_ci * status phase 197262306a36Sopenharmony_ci * 197362306a36Sopenharmony_ci */ 197462306a36Sopenharmony_cistatic void status_run(struct Scsi_Host *shpnt) 197562306a36Sopenharmony_ci{ 197662306a36Sopenharmony_ci if (TESTLO(SSTAT0, SPIORDY)) 197762306a36Sopenharmony_ci return; 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci aha152x_priv(CURRENT_SC)->status = GETPORT(SCSIDAT); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci/* 198462306a36Sopenharmony_ci * data in phase 198562306a36Sopenharmony_ci * 198662306a36Sopenharmony_ci */ 198762306a36Sopenharmony_cistatic void datai_init(struct Scsi_Host *shpnt) 198862306a36Sopenharmony_ci{ 198962306a36Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO); 199062306a36Sopenharmony_ci SETPORT(DMACNTRL0, RSTFIFO|ENDMA); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 199362306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci SETPORT(SIMODE0, 0); 199662306a36Sopenharmony_ci SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci DATA_LEN=0; 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cistatic void datai_run(struct Scsi_Host *shpnt) 200262306a36Sopenharmony_ci{ 200362306a36Sopenharmony_ci struct aha152x_cmd_priv *acp; 200462306a36Sopenharmony_ci unsigned long the_time; 200562306a36Sopenharmony_ci int fifodata, data_count; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* 200862306a36Sopenharmony_ci * loop while the phase persists or the fifos are not empty 200962306a36Sopenharmony_ci * 201062306a36Sopenharmony_ci */ 201162306a36Sopenharmony_ci while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { 201262306a36Sopenharmony_ci /* FIXME: maybe this should be done by setting up 201362306a36Sopenharmony_ci * STCNT to trigger ENSWRAP interrupt, instead of 201462306a36Sopenharmony_ci * polling for DFIFOFULL 201562306a36Sopenharmony_ci */ 201662306a36Sopenharmony_ci the_time=jiffies + 100*HZ; 201762306a36Sopenharmony_ci while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) 201862306a36Sopenharmony_ci barrier(); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { 202162306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n"); 202262306a36Sopenharmony_ci break; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if(TESTHI(DMASTAT, DFIFOFULL)) { 202662306a36Sopenharmony_ci fifodata = 128; 202762306a36Sopenharmony_ci } else { 202862306a36Sopenharmony_ci the_time=jiffies + 100*HZ; 202962306a36Sopenharmony_ci while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) 203062306a36Sopenharmony_ci barrier(); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if(TESTLO(SSTAT2, SEMPTY)) { 203362306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 203462306a36Sopenharmony_ci "datai sempty timeout"); 203562306a36Sopenharmony_ci break; 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci fifodata = GETPORT(FIFOSTAT); 203962306a36Sopenharmony_ci } 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci acp = aha152x_priv(CURRENT_SC); 204262306a36Sopenharmony_ci if (acp->this_residual > 0) { 204362306a36Sopenharmony_ci while (fifodata > 0 && acp->this_residual > 0) { 204462306a36Sopenharmony_ci data_count = fifodata > acp->this_residual ? 204562306a36Sopenharmony_ci acp->this_residual : fifodata; 204662306a36Sopenharmony_ci fifodata -= data_count; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci if (data_count & 1) { 204962306a36Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 205062306a36Sopenharmony_ci *acp->ptr++ = GETPORT(DATAPORT); 205162306a36Sopenharmony_ci acp->this_residual--; 205262306a36Sopenharmony_ci DATA_LEN++; 205362306a36Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA); 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (data_count > 1) { 205762306a36Sopenharmony_ci data_count >>= 1; 205862306a36Sopenharmony_ci insw(DATAPORT, acp->ptr, data_count); 205962306a36Sopenharmony_ci acp->ptr += 2 * data_count; 206062306a36Sopenharmony_ci acp->this_residual -= 2 * data_count; 206162306a36Sopenharmony_ci DATA_LEN += 2 * data_count; 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (acp->this_residual == 0 && 206562306a36Sopenharmony_ci !sg_is_last(acp->buffer)) { 206662306a36Sopenharmony_ci /* advance to next buffer */ 206762306a36Sopenharmony_ci acp->buffer = sg_next(acp->buffer); 206862306a36Sopenharmony_ci acp->ptr = SG_ADDRESS(acp->buffer); 206962306a36Sopenharmony_ci acp->this_residual = acp->buffer->length; 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci } 207262306a36Sopenharmony_ci } else if (fifodata > 0) { 207362306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 207462306a36Sopenharmony_ci "no buffers left for %d(%d) bytes" 207562306a36Sopenharmony_ci " (data overrun!?)\n", 207662306a36Sopenharmony_ci fifodata, GETPORT(FIFOSTAT)); 207762306a36Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 207862306a36Sopenharmony_ci while(fifodata>0) { 207962306a36Sopenharmony_ci GETPORT(DATAPORT); 208062306a36Sopenharmony_ci fifodata--; 208162306a36Sopenharmony_ci DATA_LEN++; 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci SETPORT(DMACNTRL0, ENDMA|_8BIT); 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci if(TESTLO(DMASTAT, INTSTAT) || 208862306a36Sopenharmony_ci TESTLO(DMASTAT, DFIFOEMP) || 208962306a36Sopenharmony_ci TESTLO(SSTAT2, SEMPTY) || 209062306a36Sopenharmony_ci GETPORT(FIFOSTAT)>0) { 209162306a36Sopenharmony_ci /* 209262306a36Sopenharmony_ci * something went wrong, if there's something left in the fifos 209362306a36Sopenharmony_ci * or the phase didn't change 209462306a36Sopenharmony_ci */ 209562306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 209662306a36Sopenharmony_ci "fifos should be empty and phase should have changed\n"); 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci if(DATA_LEN!=GETSTCNT()) { 210062306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 210162306a36Sopenharmony_ci "manual transfer count differs from automatic " 210262306a36Sopenharmony_ci "(count=%d;stcnt=%d;diff=%d;fifostat=%d)", 210362306a36Sopenharmony_ci DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, 210462306a36Sopenharmony_ci GETPORT(FIFOSTAT)); 210562306a36Sopenharmony_ci mdelay(10000); 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_cistatic void datai_end(struct Scsi_Host *shpnt) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -GETSTCNT()); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 211462306a36Sopenharmony_ci SETPORT(DMACNTRL0, 0); 211562306a36Sopenharmony_ci} 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci/* 211862306a36Sopenharmony_ci * data out phase 211962306a36Sopenharmony_ci * 212062306a36Sopenharmony_ci */ 212162306a36Sopenharmony_cistatic void datao_init(struct Scsi_Host *shpnt) 212262306a36Sopenharmony_ci{ 212362306a36Sopenharmony_ci SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); 212462306a36Sopenharmony_ci SETPORT(DMACNTRL0, WRITE_READ | ENDMA); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRSTCNT); 212762306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci SETPORT(SIMODE0, 0); 213062306a36Sopenharmony_ci SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci DATA_LEN = scsi_get_resid(CURRENT_SC); 213362306a36Sopenharmony_ci} 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic void datao_run(struct Scsi_Host *shpnt) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 213862306a36Sopenharmony_ci unsigned long the_time; 213962306a36Sopenharmony_ci int data_count; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci /* until phase changes or all data sent */ 214262306a36Sopenharmony_ci while (TESTLO(DMASTAT, INTSTAT) && acp->this_residual > 0) { 214362306a36Sopenharmony_ci data_count = 128; 214462306a36Sopenharmony_ci if (data_count > acp->this_residual) 214562306a36Sopenharmony_ci data_count = acp->this_residual; 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP)) { 214862306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 214962306a36Sopenharmony_ci "datao fifo not empty (%d)", 215062306a36Sopenharmony_ci GETPORT(FIFOSTAT)); 215162306a36Sopenharmony_ci break; 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci if(data_count & 1) { 215562306a36Sopenharmony_ci SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); 215662306a36Sopenharmony_ci SETPORT(DATAPORT, *acp->ptr++); 215762306a36Sopenharmony_ci acp->this_residual--; 215862306a36Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -1); 215962306a36Sopenharmony_ci SETPORT(DMACNTRL0,WRITE_READ|ENDMA); 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci if(data_count > 1) { 216362306a36Sopenharmony_ci data_count >>= 1; 216462306a36Sopenharmony_ci outsw(DATAPORT, acp->ptr, data_count); 216562306a36Sopenharmony_ci acp->ptr += 2 * data_count; 216662306a36Sopenharmony_ci acp->this_residual -= 2 * data_count; 216762306a36Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, -2 * data_count); 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci if (acp->this_residual == 0 && !sg_is_last(acp->buffer)) { 217162306a36Sopenharmony_ci /* advance to next buffer */ 217262306a36Sopenharmony_ci acp->buffer = sg_next(acp->buffer); 217362306a36Sopenharmony_ci acp->ptr = SG_ADDRESS(acp->buffer); 217462306a36Sopenharmony_ci acp->this_residual = acp->buffer->length; 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci the_time=jiffies + 100*HZ; 217862306a36Sopenharmony_ci while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) 217962306a36Sopenharmony_ci barrier(); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { 218262306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n"); 218362306a36Sopenharmony_ci break; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci} 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_cistatic void datao_end(struct Scsi_Host *shpnt) 218962306a36Sopenharmony_ci{ 219062306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if(TESTLO(DMASTAT, DFIFOEMP)) { 219362306a36Sopenharmony_ci u32 datao_cnt = GETSTCNT(); 219462306a36Sopenharmony_ci int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC); 219562306a36Sopenharmony_ci int done; 219662306a36Sopenharmony_ci struct scatterlist *sg = scsi_sglist(CURRENT_SC); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC); 220162306a36Sopenharmony_ci /* Locate the first SG entry not yet sent */ 220262306a36Sopenharmony_ci while (done > 0 && !sg_is_last(sg)) { 220362306a36Sopenharmony_ci if (done < sg->length) 220462306a36Sopenharmony_ci break; 220562306a36Sopenharmony_ci done -= sg->length; 220662306a36Sopenharmony_ci sg = sg_next(sg); 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci acp->buffer = sg; 221062306a36Sopenharmony_ci acp->ptr = SG_ADDRESS(acp->buffer) + done; 221162306a36Sopenharmony_ci acp->this_residual = acp->buffer->length - done; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); 221562306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci SETPORT(DMACNTRL0, 0); 221862306a36Sopenharmony_ci} 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci/* 222162306a36Sopenharmony_ci * figure out what state we're in 222262306a36Sopenharmony_ci * 222362306a36Sopenharmony_ci */ 222462306a36Sopenharmony_cistatic int update_state(struct Scsi_Host *shpnt) 222562306a36Sopenharmony_ci{ 222662306a36Sopenharmony_ci int dataphase=0; 222762306a36Sopenharmony_ci unsigned int stat0 = GETPORT(SSTAT0); 222862306a36Sopenharmony_ci unsigned int stat1 = GETPORT(SSTAT1); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci PREVSTATE = STATE; 223162306a36Sopenharmony_ci STATE=unknown; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci if(stat1 & SCSIRSTI) { 223462306a36Sopenharmony_ci STATE=rsti; 223562306a36Sopenharmony_ci SETPORT(SCSISEQ,0); 223662306a36Sopenharmony_ci SETPORT(SSTAT1,SCSIRSTI); 223762306a36Sopenharmony_ci } else if (stat0 & SELDI && PREVSTATE == busfree) { 223862306a36Sopenharmony_ci STATE=seldi; 223962306a36Sopenharmony_ci } else if (stat0 & SELDO && CURRENT_SC && 224062306a36Sopenharmony_ci (aha152x_priv(CURRENT_SC)->phase & selecting)) { 224162306a36Sopenharmony_ci STATE=seldo; 224262306a36Sopenharmony_ci } else if(stat1 & SELTO) { 224362306a36Sopenharmony_ci STATE=selto; 224462306a36Sopenharmony_ci } else if(stat1 & BUSFREE) { 224562306a36Sopenharmony_ci STATE=busfree; 224662306a36Sopenharmony_ci SETPORT(SSTAT1,BUSFREE); 224762306a36Sopenharmony_ci } else if(stat1 & SCSIPERR) { 224862306a36Sopenharmony_ci STATE=parerr; 224962306a36Sopenharmony_ci SETPORT(SSTAT1,SCSIPERR); 225062306a36Sopenharmony_ci } else if(stat1 & REQINIT) { 225162306a36Sopenharmony_ci switch(GETPORT(SCSISIG) & P_MASK) { 225262306a36Sopenharmony_ci case P_MSGI: STATE=msgi; break; 225362306a36Sopenharmony_ci case P_MSGO: STATE=msgo; break; 225462306a36Sopenharmony_ci case P_DATAO: STATE=datao; break; 225562306a36Sopenharmony_ci case P_DATAI: STATE=datai; break; 225662306a36Sopenharmony_ci case P_STATUS: STATE=status; break; 225762306a36Sopenharmony_ci case P_CMD: STATE=cmd; break; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci dataphase=1; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci if((stat0 & SELDI) && STATE!=seldi && !dataphase) { 226362306a36Sopenharmony_ci scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?"); 226462306a36Sopenharmony_ci } 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci if(STATE!=PREVSTATE) { 226762306a36Sopenharmony_ci LASTSTATE=PREVSTATE; 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci return dataphase; 227162306a36Sopenharmony_ci} 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci/* 227462306a36Sopenharmony_ci * handle parity error 227562306a36Sopenharmony_ci * 227662306a36Sopenharmony_ci * FIXME: in which phase? 227762306a36Sopenharmony_ci * 227862306a36Sopenharmony_ci */ 227962306a36Sopenharmony_cistatic void parerr_run(struct Scsi_Host *shpnt) 228062306a36Sopenharmony_ci{ 228162306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n"); 228262306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_PARITY); 228362306a36Sopenharmony_ci} 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci/* 228662306a36Sopenharmony_ci * handle reset in 228762306a36Sopenharmony_ci * 228862306a36Sopenharmony_ci */ 228962306a36Sopenharmony_cistatic void rsti_run(struct Scsi_Host *shpnt) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci struct scsi_cmnd *ptr; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n"); 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci ptr=DISCONNECTED_SC; 229662306a36Sopenharmony_ci while(ptr) { 229762306a36Sopenharmony_ci struct scsi_cmnd *next = SCNEXT(ptr); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (!ptr->device->soft_reset) { 230062306a36Sopenharmony_ci remove_SC(&DISCONNECTED_SC, ptr); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci kfree(ptr->host_scribble); 230362306a36Sopenharmony_ci ptr->host_scribble=NULL; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci set_host_byte(ptr, DID_RESET); 230662306a36Sopenharmony_ci aha152x_scsi_done(ptr); 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci ptr = next; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci if(CURRENT_SC && !CURRENT_SC->device->soft_reset) 231362306a36Sopenharmony_ci done(shpnt, SAM_STAT_GOOD, DID_RESET); 231462306a36Sopenharmony_ci} 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci/* 231862306a36Sopenharmony_ci * bottom-half handler 231962306a36Sopenharmony_ci * 232062306a36Sopenharmony_ci */ 232162306a36Sopenharmony_cistatic void is_complete(struct Scsi_Host *shpnt) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci int dataphase; 232462306a36Sopenharmony_ci unsigned long flags; 232562306a36Sopenharmony_ci int pending; 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci if(!shpnt) 232862306a36Sopenharmony_ci return; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci DO_LOCK(flags); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci if( HOSTDATA(shpnt)->service==0 ) { 233362306a36Sopenharmony_ci DO_UNLOCK(flags); 233462306a36Sopenharmony_ci return; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci HOSTDATA(shpnt)->service = 0; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci if(HOSTDATA(shpnt)->in_intr) { 234062306a36Sopenharmony_ci DO_UNLOCK(flags); 234162306a36Sopenharmony_ci /* aha152x_error never returns.. */ 234262306a36Sopenharmony_ci aha152x_error(shpnt, "bottom-half already running!?"); 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci HOSTDATA(shpnt)->in_intr++; 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci /* 234762306a36Sopenharmony_ci * loop while there are interrupt conditions pending 234862306a36Sopenharmony_ci * 234962306a36Sopenharmony_ci */ 235062306a36Sopenharmony_ci do { 235162306a36Sopenharmony_ci unsigned long start = jiffies; 235262306a36Sopenharmony_ci DO_UNLOCK(flags); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci dataphase=update_state(shpnt); 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* 235762306a36Sopenharmony_ci * end previous state 235862306a36Sopenharmony_ci * 235962306a36Sopenharmony_ci */ 236062306a36Sopenharmony_ci if(PREVSTATE!=STATE && states[PREVSTATE].end) 236162306a36Sopenharmony_ci states[PREVSTATE].end(shpnt); 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci /* 236462306a36Sopenharmony_ci * disable SPIO mode if previous phase used it 236562306a36Sopenharmony_ci * and this one doesn't 236662306a36Sopenharmony_ci * 236762306a36Sopenharmony_ci */ 236862306a36Sopenharmony_ci if(states[PREVSTATE].spio && !states[STATE].spio) { 236962306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1); 237062306a36Sopenharmony_ci SETPORT(DMACNTRL0, 0); 237162306a36Sopenharmony_ci if(CURRENT_SC) 237262306a36Sopenharmony_ci aha152x_priv(CURRENT_SC)->phase &= ~spiordy; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci /* 237662306a36Sopenharmony_ci * accept current dataphase phase 237762306a36Sopenharmony_ci * 237862306a36Sopenharmony_ci */ 237962306a36Sopenharmony_ci if(dataphase) { 238062306a36Sopenharmony_ci SETPORT(SSTAT0, REQINIT); 238162306a36Sopenharmony_ci SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); 238262306a36Sopenharmony_ci SETPORT(SSTAT1, PHASECHG); 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci /* 238662306a36Sopenharmony_ci * enable SPIO mode if previous didn't use it 238762306a36Sopenharmony_ci * and this one does 238862306a36Sopenharmony_ci * 238962306a36Sopenharmony_ci */ 239062306a36Sopenharmony_ci if(!states[PREVSTATE].spio && states[STATE].spio) { 239162306a36Sopenharmony_ci SETPORT(DMACNTRL0, 0); 239262306a36Sopenharmony_ci SETPORT(SXFRCTL0, CH1|SPIOEN); 239362306a36Sopenharmony_ci if(CURRENT_SC) 239462306a36Sopenharmony_ci aha152x_priv(CURRENT_SC)->phase |= spiordy; 239562306a36Sopenharmony_ci } 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci /* 239862306a36Sopenharmony_ci * initialize for new state 239962306a36Sopenharmony_ci * 240062306a36Sopenharmony_ci */ 240162306a36Sopenharmony_ci if(PREVSTATE!=STATE && states[STATE].init) 240262306a36Sopenharmony_ci states[STATE].init(shpnt); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* 240562306a36Sopenharmony_ci * handle current state 240662306a36Sopenharmony_ci * 240762306a36Sopenharmony_ci */ 240862306a36Sopenharmony_ci if(states[STATE].run) 240962306a36Sopenharmony_ci states[STATE].run(shpnt); 241062306a36Sopenharmony_ci else 241162306a36Sopenharmony_ci scmd_printk(KERN_ERR, CURRENT_SC, 241262306a36Sopenharmony_ci "unexpected state (%x)\n", STATE); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci /* 241562306a36Sopenharmony_ci * setup controller to interrupt on 241662306a36Sopenharmony_ci * the next expected condition and 241762306a36Sopenharmony_ci * loop if it's already there 241862306a36Sopenharmony_ci * 241962306a36Sopenharmony_ci */ 242062306a36Sopenharmony_ci DO_LOCK(flags); 242162306a36Sopenharmony_ci pending=setup_expected_interrupts(shpnt); 242262306a36Sopenharmony_ci#if defined(AHA152X_STAT) 242362306a36Sopenharmony_ci HOSTDATA(shpnt)->count[STATE]++; 242462306a36Sopenharmony_ci if(PREVSTATE!=STATE) 242562306a36Sopenharmony_ci HOSTDATA(shpnt)->count_trans[STATE]++; 242662306a36Sopenharmony_ci HOSTDATA(shpnt)->time[STATE] += jiffies-start; 242762306a36Sopenharmony_ci#endif 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci } while(pending); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci /* 243262306a36Sopenharmony_ci * enable interrupts and leave bottom-half 243362306a36Sopenharmony_ci * 243462306a36Sopenharmony_ci */ 243562306a36Sopenharmony_ci HOSTDATA(shpnt)->in_intr--; 243662306a36Sopenharmony_ci SETBITS(DMACNTRL0, INTEN); 243762306a36Sopenharmony_ci DO_UNLOCK(flags); 243862306a36Sopenharmony_ci} 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci/* 244262306a36Sopenharmony_ci * Dump the current driver status and panic 244362306a36Sopenharmony_ci */ 244462306a36Sopenharmony_cistatic void aha152x_error(struct Scsi_Host *shpnt, char *msg) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci shost_printk(KERN_EMERG, shpnt, "%s\n", msg); 244762306a36Sopenharmony_ci show_queues(shpnt); 244862306a36Sopenharmony_ci panic("aha152x panic\n"); 244962306a36Sopenharmony_ci} 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci/* 245262306a36Sopenharmony_ci * display enabled interrupts 245362306a36Sopenharmony_ci */ 245462306a36Sopenharmony_cistatic void disp_enintr(struct Scsi_Host *shpnt) 245562306a36Sopenharmony_ci{ 245662306a36Sopenharmony_ci int s0, s1; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci s0 = GETPORT(SIMODE0); 245962306a36Sopenharmony_ci s1 = GETPORT(SIMODE1); 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci shost_printk(KERN_DEBUG, shpnt, 246262306a36Sopenharmony_ci "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n", 246362306a36Sopenharmony_ci (s0 & ENSELDO) ? "ENSELDO " : "", 246462306a36Sopenharmony_ci (s0 & ENSELDI) ? "ENSELDI " : "", 246562306a36Sopenharmony_ci (s0 & ENSELINGO) ? "ENSELINGO " : "", 246662306a36Sopenharmony_ci (s0 & ENSWRAP) ? "ENSWRAP " : "", 246762306a36Sopenharmony_ci (s0 & ENSDONE) ? "ENSDONE " : "", 246862306a36Sopenharmony_ci (s0 & ENSPIORDY) ? "ENSPIORDY " : "", 246962306a36Sopenharmony_ci (s0 & ENDMADONE) ? "ENDMADONE " : "", 247062306a36Sopenharmony_ci (s1 & ENSELTIMO) ? "ENSELTIMO " : "", 247162306a36Sopenharmony_ci (s1 & ENATNTARG) ? "ENATNTARG " : "", 247262306a36Sopenharmony_ci (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "", 247362306a36Sopenharmony_ci (s1 & ENBUSFREE) ? "ENBUSFREE " : "", 247462306a36Sopenharmony_ci (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "", 247562306a36Sopenharmony_ci (s1 & ENPHASECHG) ? "ENPHASECHG " : "", 247662306a36Sopenharmony_ci (s1 & ENREQINIT) ? "ENREQINIT " : ""); 247762306a36Sopenharmony_ci} 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci/* 248062306a36Sopenharmony_ci * Show the command data of a command 248162306a36Sopenharmony_ci */ 248262306a36Sopenharmony_cistatic void show_command(struct scsi_cmnd *ptr) 248362306a36Sopenharmony_ci{ 248462306a36Sopenharmony_ci const int phase = aha152x_priv(ptr)->phase; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci scsi_print_command(ptr); 248762306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, ptr, 248862306a36Sopenharmony_ci "request_bufflen=%d; resid=%d; " 248962306a36Sopenharmony_ci "phase |%s%s%s%s%s%s%s%s%s; next=0x%p", 249062306a36Sopenharmony_ci scsi_bufflen(ptr), scsi_get_resid(ptr), 249162306a36Sopenharmony_ci phase & not_issued ? "not issued|" : "", 249262306a36Sopenharmony_ci phase & selecting ? "selecting|" : "", 249362306a36Sopenharmony_ci phase & identified ? "identified|" : "", 249462306a36Sopenharmony_ci phase & disconnected ? "disconnected|" : "", 249562306a36Sopenharmony_ci phase & completed ? "completed|" : "", 249662306a36Sopenharmony_ci phase & spiordy ? "spiordy|" : "", 249762306a36Sopenharmony_ci phase & syncneg ? "syncneg|" : "", 249862306a36Sopenharmony_ci phase & aborted ? "aborted|" : "", 249962306a36Sopenharmony_ci phase & resetted ? "resetted|" : "", 250062306a36Sopenharmony_ci SCDATA(ptr) ? SCNEXT(ptr) : NULL); 250162306a36Sopenharmony_ci} 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci/* 250462306a36Sopenharmony_ci * Dump the queued data 250562306a36Sopenharmony_ci */ 250662306a36Sopenharmony_cistatic void show_queues(struct Scsi_Host *shpnt) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct scsi_cmnd *ptr; 250962306a36Sopenharmony_ci unsigned long flags; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci DO_LOCK(flags); 251262306a36Sopenharmony_ci printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); 251362306a36Sopenharmony_ci for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 251462306a36Sopenharmony_ci show_command(ptr); 251562306a36Sopenharmony_ci DO_UNLOCK(flags); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci printk(KERN_DEBUG "current_SC:\n"); 251862306a36Sopenharmony_ci if (CURRENT_SC) 251962306a36Sopenharmony_ci show_command(CURRENT_SC); 252062306a36Sopenharmony_ci else 252162306a36Sopenharmony_ci printk(KERN_DEBUG "none\n"); 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci printk(KERN_DEBUG "disconnected_SC:\n"); 252462306a36Sopenharmony_ci for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL) 252562306a36Sopenharmony_ci show_command(ptr); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci disp_enintr(shpnt); 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic void get_command(struct seq_file *m, struct scsi_cmnd * ptr) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci struct aha152x_cmd_priv *acp = aha152x_priv(ptr); 253362306a36Sopenharmony_ci const int phase = acp->phase; 253462306a36Sopenharmony_ci int i; 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ", 253762306a36Sopenharmony_ci ptr, ptr->device->id, (u8)ptr->device->lun); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) 254062306a36Sopenharmony_ci seq_printf(m, "0x%02x ", ptr->cmnd[i]); 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", 254362306a36Sopenharmony_ci scsi_get_resid(ptr), acp->this_residual, 254462306a36Sopenharmony_ci sg_nents(acp->buffer) - 1); 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci if (phase & not_issued) 254762306a36Sopenharmony_ci seq_puts(m, "not issued|"); 254862306a36Sopenharmony_ci if (phase & selecting) 254962306a36Sopenharmony_ci seq_puts(m, "selecting|"); 255062306a36Sopenharmony_ci if (phase & disconnected) 255162306a36Sopenharmony_ci seq_puts(m, "disconnected|"); 255262306a36Sopenharmony_ci if (phase & aborted) 255362306a36Sopenharmony_ci seq_puts(m, "aborted|"); 255462306a36Sopenharmony_ci if (phase & identified) 255562306a36Sopenharmony_ci seq_puts(m, "identified|"); 255662306a36Sopenharmony_ci if (phase & completed) 255762306a36Sopenharmony_ci seq_puts(m, "completed|"); 255862306a36Sopenharmony_ci if (phase & spiordy) 255962306a36Sopenharmony_ci seq_puts(m, "spiordy|"); 256062306a36Sopenharmony_ci if (phase & syncneg) 256162306a36Sopenharmony_ci seq_puts(m, "syncneg|"); 256262306a36Sopenharmony_ci seq_printf(m, "; next=0x%p\n", SCNEXT(ptr)); 256362306a36Sopenharmony_ci} 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_cistatic void get_ports(struct seq_file *m, struct Scsi_Host *shpnt) 256662306a36Sopenharmony_ci{ 256762306a36Sopenharmony_ci int s; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci s = GETPORT(SCSISEQ); 257262306a36Sopenharmony_ci seq_puts(m, "SCSISEQ( "); 257362306a36Sopenharmony_ci if (s & TEMODEO) 257462306a36Sopenharmony_ci seq_puts(m, "TARGET MODE "); 257562306a36Sopenharmony_ci if (s & ENSELO) 257662306a36Sopenharmony_ci seq_puts(m, "SELO "); 257762306a36Sopenharmony_ci if (s & ENSELI) 257862306a36Sopenharmony_ci seq_puts(m, "SELI "); 257962306a36Sopenharmony_ci if (s & ENRESELI) 258062306a36Sopenharmony_ci seq_puts(m, "RESELI "); 258162306a36Sopenharmony_ci if (s & ENAUTOATNO) 258262306a36Sopenharmony_ci seq_puts(m, "AUTOATNO "); 258362306a36Sopenharmony_ci if (s & ENAUTOATNI) 258462306a36Sopenharmony_ci seq_puts(m, "AUTOATNI "); 258562306a36Sopenharmony_ci if (s & ENAUTOATNP) 258662306a36Sopenharmony_ci seq_puts(m, "AUTOATNP "); 258762306a36Sopenharmony_ci if (s & SCSIRSTO) 258862306a36Sopenharmony_ci seq_puts(m, "SCSIRSTO "); 258962306a36Sopenharmony_ci seq_puts(m, ");"); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci seq_puts(m, " SCSISIG("); 259262306a36Sopenharmony_ci s = GETPORT(SCSISIG); 259362306a36Sopenharmony_ci switch (s & P_MASK) { 259462306a36Sopenharmony_ci case P_DATAO: 259562306a36Sopenharmony_ci seq_puts(m, "DATA OUT"); 259662306a36Sopenharmony_ci break; 259762306a36Sopenharmony_ci case P_DATAI: 259862306a36Sopenharmony_ci seq_puts(m, "DATA IN"); 259962306a36Sopenharmony_ci break; 260062306a36Sopenharmony_ci case P_CMD: 260162306a36Sopenharmony_ci seq_puts(m, "COMMAND"); 260262306a36Sopenharmony_ci break; 260362306a36Sopenharmony_ci case P_STATUS: 260462306a36Sopenharmony_ci seq_puts(m, "STATUS"); 260562306a36Sopenharmony_ci break; 260662306a36Sopenharmony_ci case P_MSGO: 260762306a36Sopenharmony_ci seq_puts(m, "MESSAGE OUT"); 260862306a36Sopenharmony_ci break; 260962306a36Sopenharmony_ci case P_MSGI: 261062306a36Sopenharmony_ci seq_puts(m, "MESSAGE IN"); 261162306a36Sopenharmony_ci break; 261262306a36Sopenharmony_ci default: 261362306a36Sopenharmony_ci seq_puts(m, "*invalid*"); 261462306a36Sopenharmony_ci break; 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci seq_puts(m, "); "); 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci seq_puts(m, "SSTAT( "); 262262306a36Sopenharmony_ci s = GETPORT(SSTAT0); 262362306a36Sopenharmony_ci if (s & TARGET) 262462306a36Sopenharmony_ci seq_puts(m, "TARGET "); 262562306a36Sopenharmony_ci if (s & SELDO) 262662306a36Sopenharmony_ci seq_puts(m, "SELDO "); 262762306a36Sopenharmony_ci if (s & SELDI) 262862306a36Sopenharmony_ci seq_puts(m, "SELDI "); 262962306a36Sopenharmony_ci if (s & SELINGO) 263062306a36Sopenharmony_ci seq_puts(m, "SELINGO "); 263162306a36Sopenharmony_ci if (s & SWRAP) 263262306a36Sopenharmony_ci seq_puts(m, "SWRAP "); 263362306a36Sopenharmony_ci if (s & SDONE) 263462306a36Sopenharmony_ci seq_puts(m, "SDONE "); 263562306a36Sopenharmony_ci if (s & SPIORDY) 263662306a36Sopenharmony_ci seq_puts(m, "SPIORDY "); 263762306a36Sopenharmony_ci if (s & DMADONE) 263862306a36Sopenharmony_ci seq_puts(m, "DMADONE "); 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci s = GETPORT(SSTAT1); 264162306a36Sopenharmony_ci if (s & SELTO) 264262306a36Sopenharmony_ci seq_puts(m, "SELTO "); 264362306a36Sopenharmony_ci if (s & ATNTARG) 264462306a36Sopenharmony_ci seq_puts(m, "ATNTARG "); 264562306a36Sopenharmony_ci if (s & SCSIRSTI) 264662306a36Sopenharmony_ci seq_puts(m, "SCSIRSTI "); 264762306a36Sopenharmony_ci if (s & PHASEMIS) 264862306a36Sopenharmony_ci seq_puts(m, "PHASEMIS "); 264962306a36Sopenharmony_ci if (s & BUSFREE) 265062306a36Sopenharmony_ci seq_puts(m, "BUSFREE "); 265162306a36Sopenharmony_ci if (s & SCSIPERR) 265262306a36Sopenharmony_ci seq_puts(m, "SCSIPERR "); 265362306a36Sopenharmony_ci if (s & PHASECHG) 265462306a36Sopenharmony_ci seq_puts(m, "PHASECHG "); 265562306a36Sopenharmony_ci if (s & REQINIT) 265662306a36Sopenharmony_ci seq_puts(m, "REQINIT "); 265762306a36Sopenharmony_ci seq_puts(m, "); "); 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci seq_puts(m, "SSTAT( "); 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci s = GETPORT(SSTAT0) & GETPORT(SIMODE0); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci if (s & TARGET) 266562306a36Sopenharmony_ci seq_puts(m, "TARGET "); 266662306a36Sopenharmony_ci if (s & SELDO) 266762306a36Sopenharmony_ci seq_puts(m, "SELDO "); 266862306a36Sopenharmony_ci if (s & SELDI) 266962306a36Sopenharmony_ci seq_puts(m, "SELDI "); 267062306a36Sopenharmony_ci if (s & SELINGO) 267162306a36Sopenharmony_ci seq_puts(m, "SELINGO "); 267262306a36Sopenharmony_ci if (s & SWRAP) 267362306a36Sopenharmony_ci seq_puts(m, "SWRAP "); 267462306a36Sopenharmony_ci if (s & SDONE) 267562306a36Sopenharmony_ci seq_puts(m, "SDONE "); 267662306a36Sopenharmony_ci if (s & SPIORDY) 267762306a36Sopenharmony_ci seq_puts(m, "SPIORDY "); 267862306a36Sopenharmony_ci if (s & DMADONE) 267962306a36Sopenharmony_ci seq_puts(m, "DMADONE "); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci s = GETPORT(SSTAT1) & GETPORT(SIMODE1); 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci if (s & SELTO) 268462306a36Sopenharmony_ci seq_puts(m, "SELTO "); 268562306a36Sopenharmony_ci if (s & ATNTARG) 268662306a36Sopenharmony_ci seq_puts(m, "ATNTARG "); 268762306a36Sopenharmony_ci if (s & SCSIRSTI) 268862306a36Sopenharmony_ci seq_puts(m, "SCSIRSTI "); 268962306a36Sopenharmony_ci if (s & PHASEMIS) 269062306a36Sopenharmony_ci seq_puts(m, "PHASEMIS "); 269162306a36Sopenharmony_ci if (s & BUSFREE) 269262306a36Sopenharmony_ci seq_puts(m, "BUSFREE "); 269362306a36Sopenharmony_ci if (s & SCSIPERR) 269462306a36Sopenharmony_ci seq_puts(m, "SCSIPERR "); 269562306a36Sopenharmony_ci if (s & PHASECHG) 269662306a36Sopenharmony_ci seq_puts(m, "PHASECHG "); 269762306a36Sopenharmony_ci if (s & REQINIT) 269862306a36Sopenharmony_ci seq_puts(m, "REQINIT "); 269962306a36Sopenharmony_ci seq_puts(m, "); "); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci seq_puts(m, "SXFRCTL0( "); 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci s = GETPORT(SXFRCTL0); 270462306a36Sopenharmony_ci if (s & SCSIEN) 270562306a36Sopenharmony_ci seq_puts(m, "SCSIEN "); 270662306a36Sopenharmony_ci if (s & DMAEN) 270762306a36Sopenharmony_ci seq_puts(m, "DMAEN "); 270862306a36Sopenharmony_ci if (s & CH1) 270962306a36Sopenharmony_ci seq_puts(m, "CH1 "); 271062306a36Sopenharmony_ci if (s & CLRSTCNT) 271162306a36Sopenharmony_ci seq_puts(m, "CLRSTCNT "); 271262306a36Sopenharmony_ci if (s & SPIOEN) 271362306a36Sopenharmony_ci seq_puts(m, "SPIOEN "); 271462306a36Sopenharmony_ci if (s & CLRCH1) 271562306a36Sopenharmony_ci seq_puts(m, "CLRCH1 "); 271662306a36Sopenharmony_ci seq_puts(m, "); "); 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci seq_puts(m, "SIGNAL( "); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci s = GETPORT(SCSISIG); 272162306a36Sopenharmony_ci if (s & SIG_ATNI) 272262306a36Sopenharmony_ci seq_puts(m, "ATNI "); 272362306a36Sopenharmony_ci if (s & SIG_SELI) 272462306a36Sopenharmony_ci seq_puts(m, "SELI "); 272562306a36Sopenharmony_ci if (s & SIG_BSYI) 272662306a36Sopenharmony_ci seq_puts(m, "BSYI "); 272762306a36Sopenharmony_ci if (s & SIG_REQI) 272862306a36Sopenharmony_ci seq_puts(m, "REQI "); 272962306a36Sopenharmony_ci if (s & SIG_ACKI) 273062306a36Sopenharmony_ci seq_puts(m, "ACKI "); 273162306a36Sopenharmony_ci seq_puts(m, "); "); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci seq_printf(m, "SELID(%02x), ", GETPORT(SELID)); 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci seq_printf(m, "STCNT(%d), ", GETSTCNT()); 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci seq_puts(m, "SSTAT2( "); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci s = GETPORT(SSTAT2); 274062306a36Sopenharmony_ci if (s & SOFFSET) 274162306a36Sopenharmony_ci seq_puts(m, "SOFFSET "); 274262306a36Sopenharmony_ci if (s & SEMPTY) 274362306a36Sopenharmony_ci seq_puts(m, "SEMPTY "); 274462306a36Sopenharmony_ci if (s & SFULL) 274562306a36Sopenharmony_ci seq_puts(m, "SFULL "); 274662306a36Sopenharmony_ci seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT)); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci s = GETPORT(SSTAT3); 274962306a36Sopenharmony_ci seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci seq_puts(m, "SSTAT4( "); 275262306a36Sopenharmony_ci s = GETPORT(SSTAT4); 275362306a36Sopenharmony_ci if (s & SYNCERR) 275462306a36Sopenharmony_ci seq_puts(m, "SYNCERR "); 275562306a36Sopenharmony_ci if (s & FWERR) 275662306a36Sopenharmony_ci seq_puts(m, "FWERR "); 275762306a36Sopenharmony_ci if (s & FRERR) 275862306a36Sopenharmony_ci seq_puts(m, "FRERR "); 275962306a36Sopenharmony_ci seq_puts(m, "); "); 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci seq_puts(m, "DMACNTRL0( "); 276262306a36Sopenharmony_ci s = GETPORT(DMACNTRL0); 276362306a36Sopenharmony_ci seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT"); 276462306a36Sopenharmony_ci seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO"); 276562306a36Sopenharmony_ci seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ"); 276662306a36Sopenharmony_ci if (s & ENDMA) 276762306a36Sopenharmony_ci seq_puts(m, "ENDMA "); 276862306a36Sopenharmony_ci if (s & INTEN) 276962306a36Sopenharmony_ci seq_puts(m, "INTEN "); 277062306a36Sopenharmony_ci if (s & RSTFIFO) 277162306a36Sopenharmony_ci seq_puts(m, "RSTFIFO "); 277262306a36Sopenharmony_ci if (s & SWINT) 277362306a36Sopenharmony_ci seq_puts(m, "SWINT "); 277462306a36Sopenharmony_ci seq_puts(m, "); "); 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci seq_puts(m, "DMASTAT( "); 277762306a36Sopenharmony_ci s = GETPORT(DMASTAT); 277862306a36Sopenharmony_ci if (s & ATDONE) 277962306a36Sopenharmony_ci seq_puts(m, "ATDONE "); 278062306a36Sopenharmony_ci if (s & WORDRDY) 278162306a36Sopenharmony_ci seq_puts(m, "WORDRDY "); 278262306a36Sopenharmony_ci if (s & DFIFOFULL) 278362306a36Sopenharmony_ci seq_puts(m, "DFIFOFULL "); 278462306a36Sopenharmony_ci if (s & DFIFOEMP) 278562306a36Sopenharmony_ci seq_puts(m, "DFIFOEMP "); 278662306a36Sopenharmony_ci seq_puts(m, ")\n"); 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci seq_puts(m, "enabled interrupts( "); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci s = GETPORT(SIMODE0); 279162306a36Sopenharmony_ci if (s & ENSELDO) 279262306a36Sopenharmony_ci seq_puts(m, "ENSELDO "); 279362306a36Sopenharmony_ci if (s & ENSELDI) 279462306a36Sopenharmony_ci seq_puts(m, "ENSELDI "); 279562306a36Sopenharmony_ci if (s & ENSELINGO) 279662306a36Sopenharmony_ci seq_puts(m, "ENSELINGO "); 279762306a36Sopenharmony_ci if (s & ENSWRAP) 279862306a36Sopenharmony_ci seq_puts(m, "ENSWRAP "); 279962306a36Sopenharmony_ci if (s & ENSDONE) 280062306a36Sopenharmony_ci seq_puts(m, "ENSDONE "); 280162306a36Sopenharmony_ci if (s & ENSPIORDY) 280262306a36Sopenharmony_ci seq_puts(m, "ENSPIORDY "); 280362306a36Sopenharmony_ci if (s & ENDMADONE) 280462306a36Sopenharmony_ci seq_puts(m, "ENDMADONE "); 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci s = GETPORT(SIMODE1); 280762306a36Sopenharmony_ci if (s & ENSELTIMO) 280862306a36Sopenharmony_ci seq_puts(m, "ENSELTIMO "); 280962306a36Sopenharmony_ci if (s & ENATNTARG) 281062306a36Sopenharmony_ci seq_puts(m, "ENATNTARG "); 281162306a36Sopenharmony_ci if (s & ENPHASEMIS) 281262306a36Sopenharmony_ci seq_puts(m, "ENPHASEMIS "); 281362306a36Sopenharmony_ci if (s & ENBUSFREE) 281462306a36Sopenharmony_ci seq_puts(m, "ENBUSFREE "); 281562306a36Sopenharmony_ci if (s & ENSCSIPERR) 281662306a36Sopenharmony_ci seq_puts(m, "ENSCSIPERR "); 281762306a36Sopenharmony_ci if (s & ENPHASECHG) 281862306a36Sopenharmony_ci seq_puts(m, "ENPHASECHG "); 281962306a36Sopenharmony_ci if (s & ENREQINIT) 282062306a36Sopenharmony_ci seq_puts(m, "ENREQINIT "); 282162306a36Sopenharmony_ci seq_puts(m, ")\n"); 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_cistatic int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) 282762306a36Sopenharmony_ci return -EINVAL; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci#if defined(AHA152X_STAT) 283062306a36Sopenharmony_ci if(length>13 && strncmp("reset", buffer+8, 5)==0) { 283162306a36Sopenharmony_ci int i; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci HOSTDATA(shpnt)->total_commands=0; 283462306a36Sopenharmony_ci HOSTDATA(shpnt)->disconnections=0; 283562306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action=0; 283662306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command=0; 283762306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command=0; 283862306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command=0; 283962306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition=0; 284062306a36Sopenharmony_ci for (i = idle; i<maxstate; i++) { 284162306a36Sopenharmony_ci HOSTDATA(shpnt)->count[i]=0; 284262306a36Sopenharmony_ci HOSTDATA(shpnt)->count_trans[i]=0; 284362306a36Sopenharmony_ci HOSTDATA(shpnt)->time[i]=0; 284462306a36Sopenharmony_ci } 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n"); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci } else 284962306a36Sopenharmony_ci#endif 285062306a36Sopenharmony_ci { 285162306a36Sopenharmony_ci return -EINVAL; 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci return length; 285662306a36Sopenharmony_ci} 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_cistatic int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt) 285962306a36Sopenharmony_ci{ 286062306a36Sopenharmony_ci int i; 286162306a36Sopenharmony_ci struct scsi_cmnd *ptr; 286262306a36Sopenharmony_ci unsigned long flags; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci seq_puts(m, AHA152X_REVID "\n"); 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci seq_printf(m, "ioports 0x%04lx to 0x%04lx\n", 286762306a36Sopenharmony_ci shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); 286862306a36Sopenharmony_ci seq_printf(m, "interrupt 0x%02x\n", shpnt->irq); 286962306a36Sopenharmony_ci seq_printf(m, "disconnection/reconnection %s\n", 287062306a36Sopenharmony_ci RECONNECT ? "enabled" : "disabled"); 287162306a36Sopenharmony_ci seq_printf(m, "parity checking %s\n", 287262306a36Sopenharmony_ci PARITY ? "enabled" : "disabled"); 287362306a36Sopenharmony_ci seq_printf(m, "synchronous transfers %s\n", 287462306a36Sopenharmony_ci SYNCHRONOUS ? "enabled" : "disabled"); 287562306a36Sopenharmony_ci seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci if(SYNCHRONOUS) { 287862306a36Sopenharmony_ci seq_puts(m, "synchronously operating targets (tick=50 ns):\n"); 287962306a36Sopenharmony_ci for (i = 0; i < 8; i++) 288062306a36Sopenharmony_ci if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) 288162306a36Sopenharmony_ci seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n", 288262306a36Sopenharmony_ci i, 288362306a36Sopenharmony_ci (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), 288462306a36Sopenharmony_ci (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, 288562306a36Sopenharmony_ci HOSTDATA(shpnt)->syncrate[i] & 0x0f); 288662306a36Sopenharmony_ci } 288762306a36Sopenharmony_ci seq_puts(m, "\nqueue status:\n"); 288862306a36Sopenharmony_ci DO_LOCK(flags); 288962306a36Sopenharmony_ci if (ISSUE_SC) { 289062306a36Sopenharmony_ci seq_puts(m, "not yet issued commands:\n"); 289162306a36Sopenharmony_ci for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) 289262306a36Sopenharmony_ci get_command(m, ptr); 289362306a36Sopenharmony_ci } else 289462306a36Sopenharmony_ci seq_puts(m, "no not yet issued commands\n"); 289562306a36Sopenharmony_ci DO_UNLOCK(flags); 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci if (CURRENT_SC) { 289862306a36Sopenharmony_ci seq_puts(m, "current command:\n"); 289962306a36Sopenharmony_ci get_command(m, CURRENT_SC); 290062306a36Sopenharmony_ci } else 290162306a36Sopenharmony_ci seq_puts(m, "no current command\n"); 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci if (DISCONNECTED_SC) { 290462306a36Sopenharmony_ci seq_puts(m, "disconnected commands:\n"); 290562306a36Sopenharmony_ci for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) 290662306a36Sopenharmony_ci get_command(m, ptr); 290762306a36Sopenharmony_ci } else 290862306a36Sopenharmony_ci seq_puts(m, "no disconnected commands\n"); 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci get_ports(m, shpnt); 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci#if defined(AHA152X_STAT) 291362306a36Sopenharmony_ci seq_printf(m, "statistics:\n" 291462306a36Sopenharmony_ci "total commands: %d\n" 291562306a36Sopenharmony_ci "disconnections: %d\n" 291662306a36Sopenharmony_ci "busfree with check condition: %d\n" 291762306a36Sopenharmony_ci "busfree without old command: %d\n" 291862306a36Sopenharmony_ci "busfree without new command: %d\n" 291962306a36Sopenharmony_ci "busfree without done command: %d\n" 292062306a36Sopenharmony_ci "busfree without any action: %d\n" 292162306a36Sopenharmony_ci "state " 292262306a36Sopenharmony_ci "transitions " 292362306a36Sopenharmony_ci "count " 292462306a36Sopenharmony_ci "time\n", 292562306a36Sopenharmony_ci HOSTDATA(shpnt)->total_commands, 292662306a36Sopenharmony_ci HOSTDATA(shpnt)->disconnections, 292762306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_with_check_condition, 292862306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_old_command, 292962306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_new_command, 293062306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_done_command, 293162306a36Sopenharmony_ci HOSTDATA(shpnt)->busfree_without_any_action); 293262306a36Sopenharmony_ci for(i=0; i<maxstate; i++) { 293362306a36Sopenharmony_ci seq_printf(m, "%-10s %-12d %-12d %-12ld\n", 293462306a36Sopenharmony_ci states[i].name, 293562306a36Sopenharmony_ci HOSTDATA(shpnt)->count_trans[i], 293662306a36Sopenharmony_ci HOSTDATA(shpnt)->count[i], 293762306a36Sopenharmony_ci HOSTDATA(shpnt)->time[i]); 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci#endif 294062306a36Sopenharmony_ci return 0; 294162306a36Sopenharmony_ci} 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_cistatic int aha152x_adjust_queue(struct scsi_device *device) 294462306a36Sopenharmony_ci{ 294562306a36Sopenharmony_ci blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); 294662306a36Sopenharmony_ci return 0; 294762306a36Sopenharmony_ci} 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_cistatic const struct scsi_host_template aha152x_driver_template = { 295062306a36Sopenharmony_ci .module = THIS_MODULE, 295162306a36Sopenharmony_ci .name = AHA152X_REVID, 295262306a36Sopenharmony_ci .proc_name = "aha152x", 295362306a36Sopenharmony_ci .show_info = aha152x_show_info, 295462306a36Sopenharmony_ci .write_info = aha152x_set_info, 295562306a36Sopenharmony_ci .queuecommand = aha152x_queue, 295662306a36Sopenharmony_ci .eh_abort_handler = aha152x_abort, 295762306a36Sopenharmony_ci .eh_device_reset_handler = aha152x_device_reset, 295862306a36Sopenharmony_ci .eh_bus_reset_handler = aha152x_bus_reset, 295962306a36Sopenharmony_ci .bios_param = aha152x_biosparam, 296062306a36Sopenharmony_ci .can_queue = 1, 296162306a36Sopenharmony_ci .this_id = 7, 296262306a36Sopenharmony_ci .sg_tablesize = SG_ALL, 296362306a36Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 296462306a36Sopenharmony_ci .slave_alloc = aha152x_adjust_queue, 296562306a36Sopenharmony_ci .cmd_size = sizeof(struct aha152x_cmd_priv), 296662306a36Sopenharmony_ci}; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci#if !defined(AHA152X_PCMCIA) 296962306a36Sopenharmony_cistatic int setup_count; 297062306a36Sopenharmony_cistatic struct aha152x_setup setup[2]; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci/* possible i/o addresses for the AIC-6260; default first */ 297362306a36Sopenharmony_cistatic unsigned short ports[] = { 0x340, 0x140 }; 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci#if !defined(SKIP_BIOSTEST) 297662306a36Sopenharmony_ci/* possible locations for the Adaptec BIOS; defaults first */ 297762306a36Sopenharmony_cistatic unsigned int addresses[] = 297862306a36Sopenharmony_ci{ 297962306a36Sopenharmony_ci 0xdc000, /* default first */ 298062306a36Sopenharmony_ci 0xc8000, 298162306a36Sopenharmony_ci 0xcc000, 298262306a36Sopenharmony_ci 0xd0000, 298362306a36Sopenharmony_ci 0xd4000, 298462306a36Sopenharmony_ci 0xd8000, 298562306a36Sopenharmony_ci 0xe0000, 298662306a36Sopenharmony_ci 0xeb800, /* VTech Platinum SMP */ 298762306a36Sopenharmony_ci 0xf0000, 298862306a36Sopenharmony_ci}; 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci/* signatures for various AIC-6[23]60 based controllers. 299162306a36Sopenharmony_ci The point in detecting signatures is to avoid useless and maybe 299262306a36Sopenharmony_ci harmful probes on ports. I'm not sure that all listed boards pass 299362306a36Sopenharmony_ci auto-configuration. For those which fail the BIOS signature is 299462306a36Sopenharmony_ci obsolete, because user intervention to supply the configuration is 299562306a36Sopenharmony_ci needed anyway. May be an information whether or not the BIOS supports 299662306a36Sopenharmony_ci extended translation could be also useful here. */ 299762306a36Sopenharmony_cistatic struct signature { 299862306a36Sopenharmony_ci unsigned char *signature; 299962306a36Sopenharmony_ci int sig_offset; 300062306a36Sopenharmony_ci int sig_length; 300162306a36Sopenharmony_ci} signatures[] = 300262306a36Sopenharmony_ci{ 300362306a36Sopenharmony_ci { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, 300462306a36Sopenharmony_ci /* Adaptec 152x */ 300562306a36Sopenharmony_ci { "Adaptec AHA-1520B", 0x000b, 17 }, 300662306a36Sopenharmony_ci /* Adaptec 152x rev B */ 300762306a36Sopenharmony_ci { "Adaptec AHA-1520B", 0x0026, 17 }, 300862306a36Sopenharmony_ci /* Iomega Jaz Jet ISA (AIC6370Q) */ 300962306a36Sopenharmony_ci { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, 301062306a36Sopenharmony_ci /* on-board controller */ 301162306a36Sopenharmony_ci { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, 301262306a36Sopenharmony_ci /* on-board controller */ 301362306a36Sopenharmony_ci { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, 301462306a36Sopenharmony_ci /* on-board controller */ 301562306a36Sopenharmony_ci { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, 301662306a36Sopenharmony_ci /* on-board controller */ 301762306a36Sopenharmony_ci { "ScsiPro SP-360 BIOS", 0x2873, 19 }, 301862306a36Sopenharmony_ci /* ScsiPro-Controller */ 301962306a36Sopenharmony_ci { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, 302062306a36Sopenharmony_ci /* Gigabyte Local-Bus-SCSI */ 302162306a36Sopenharmony_ci { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, 302262306a36Sopenharmony_ci /* Adaptec 282x */ 302362306a36Sopenharmony_ci { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, 302462306a36Sopenharmony_ci /* IBM Thinkpad Dock II */ 302562306a36Sopenharmony_ci { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, 302662306a36Sopenharmony_ci /* IBM Thinkpad Dock II SCSI */ 302762306a36Sopenharmony_ci { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, 302862306a36Sopenharmony_ci /* DTC 3520A ISA SCSI */ 302962306a36Sopenharmony_ci}; 303062306a36Sopenharmony_ci#endif /* !SKIP_BIOSTEST */ 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci/* 303362306a36Sopenharmony_ci * Test, if port_base is valid. 303462306a36Sopenharmony_ci * 303562306a36Sopenharmony_ci */ 303662306a36Sopenharmony_cistatic int aha152x_porttest(int io_port) 303762306a36Sopenharmony_ci{ 303862306a36Sopenharmony_ci int i; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 304162306a36Sopenharmony_ci for (i = 0; i < 16; i++) 304262306a36Sopenharmony_ci SETPORT(io_port + O_STACK, i); 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ 304562306a36Sopenharmony_ci for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++) 304662306a36Sopenharmony_ci ; 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_ci return (i == 16); 304962306a36Sopenharmony_ci} 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_cistatic int tc1550_porttest(int io_port) 305262306a36Sopenharmony_ci{ 305362306a36Sopenharmony_ci int i; 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 305662306a36Sopenharmony_ci for (i = 0; i < 16; i++) 305762306a36Sopenharmony_ci SETPORT(io_port + O_STACK, i); 305862306a36Sopenharmony_ci 305962306a36Sopenharmony_ci SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ 306062306a36Sopenharmony_ci for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++) 306162306a36Sopenharmony_ci ; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci return (i == 16); 306462306a36Sopenharmony_ci} 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_cistatic int checksetup(struct aha152x_setup *setup) 306862306a36Sopenharmony_ci{ 306962306a36Sopenharmony_ci int i; 307062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++) 307162306a36Sopenharmony_ci ; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci if (i == ARRAY_SIZE(ports)) 307462306a36Sopenharmony_ci return 0; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci if (!request_region(setup->io_port, IO_RANGE, "aha152x")) { 307762306a36Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port); 307862306a36Sopenharmony_ci return 0; 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci if( aha152x_porttest(setup->io_port) ) { 308262306a36Sopenharmony_ci setup->tc1550=0; 308362306a36Sopenharmony_ci } else if( tc1550_porttest(setup->io_port) ) { 308462306a36Sopenharmony_ci setup->tc1550=1; 308562306a36Sopenharmony_ci } else { 308662306a36Sopenharmony_ci release_region(setup->io_port, IO_RANGE); 308762306a36Sopenharmony_ci return 0; 308862306a36Sopenharmony_ci } 308962306a36Sopenharmony_ci 309062306a36Sopenharmony_ci release_region(setup->io_port, IO_RANGE); 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) 309362306a36Sopenharmony_ci return 0; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci if ((setup->scsiid < 0) || (setup->scsiid > 7)) 309662306a36Sopenharmony_ci return 0; 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci if ((setup->reconnect < 0) || (setup->reconnect > 1)) 309962306a36Sopenharmony_ci return 0; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if ((setup->parity < 0) || (setup->parity > 1)) 310262306a36Sopenharmony_ci return 0; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci if ((setup->synchronous < 0) || (setup->synchronous > 1)) 310562306a36Sopenharmony_ci return 0; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) 310862306a36Sopenharmony_ci return 0; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci return 1; 311262306a36Sopenharmony_ci} 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_cistatic int __init aha152x_init(void) 311662306a36Sopenharmony_ci{ 311762306a36Sopenharmony_ci int i, j, ok; 311862306a36Sopenharmony_ci#if defined(AUTOCONF) 311962306a36Sopenharmony_ci aha152x_config conf; 312062306a36Sopenharmony_ci#endif 312162306a36Sopenharmony_ci#ifdef __ISAPNP__ 312262306a36Sopenharmony_ci struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL}; 312362306a36Sopenharmony_ci#endif 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci if ( setup_count ) { 312662306a36Sopenharmony_ci printk(KERN_INFO "aha152x: processing commandline: "); 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci for (i = 0; i<setup_count; i++) { 312962306a36Sopenharmony_ci if (!checksetup(&setup[i])) { 313062306a36Sopenharmony_ci printk(KERN_ERR "\naha152x: %s\n", setup[i].conf); 313162306a36Sopenharmony_ci printk(KERN_ERR "aha152x: invalid line\n"); 313262306a36Sopenharmony_ci } 313362306a36Sopenharmony_ci } 313462306a36Sopenharmony_ci printk("ok\n"); 313562306a36Sopenharmony_ci } 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci#if defined(SETUP0) 313862306a36Sopenharmony_ci if (setup_count < ARRAY_SIZE(setup)) { 313962306a36Sopenharmony_ci struct aha152x_setup override = SETUP0; 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 314262306a36Sopenharmony_ci if (!checksetup(&override)) { 314362306a36Sopenharmony_ci printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 314462306a36Sopenharmony_ci override.io_port, 314562306a36Sopenharmony_ci override.irq, 314662306a36Sopenharmony_ci override.scsiid, 314762306a36Sopenharmony_ci override.reconnect, 314862306a36Sopenharmony_ci override.parity, 314962306a36Sopenharmony_ci override.synchronous, 315062306a36Sopenharmony_ci override.delay, 315162306a36Sopenharmony_ci override.ext_trans); 315262306a36Sopenharmony_ci } else 315362306a36Sopenharmony_ci setup[setup_count++] = override; 315462306a36Sopenharmony_ci } 315562306a36Sopenharmony_ci } 315662306a36Sopenharmony_ci#endif 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci#if defined(SETUP1) 315962306a36Sopenharmony_ci if (setup_count < ARRAY_SIZE(setup)) { 316062306a36Sopenharmony_ci struct aha152x_setup override = SETUP1; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci if (setup_count == 0 || (override.io_port != setup[0].io_port)) { 316362306a36Sopenharmony_ci if (!checksetup(&override)) { 316462306a36Sopenharmony_ci printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", 316562306a36Sopenharmony_ci override.io_port, 316662306a36Sopenharmony_ci override.irq, 316762306a36Sopenharmony_ci override.scsiid, 316862306a36Sopenharmony_ci override.reconnect, 316962306a36Sopenharmony_ci override.parity, 317062306a36Sopenharmony_ci override.synchronous, 317162306a36Sopenharmony_ci override.delay, 317262306a36Sopenharmony_ci override.ext_trans); 317362306a36Sopenharmony_ci } else 317462306a36Sopenharmony_ci setup[setup_count++] = override; 317562306a36Sopenharmony_ci } 317662306a36Sopenharmony_ci } 317762306a36Sopenharmony_ci#endif 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci#if defined(MODULE) 318062306a36Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) { 318162306a36Sopenharmony_ci if(aha152x[0]!=0) { 318262306a36Sopenharmony_ci setup[setup_count].conf = ""; 318362306a36Sopenharmony_ci setup[setup_count].io_port = aha152x[0]; 318462306a36Sopenharmony_ci setup[setup_count].irq = aha152x[1]; 318562306a36Sopenharmony_ci setup[setup_count].scsiid = aha152x[2]; 318662306a36Sopenharmony_ci setup[setup_count].reconnect = aha152x[3]; 318762306a36Sopenharmony_ci setup[setup_count].parity = aha152x[4]; 318862306a36Sopenharmony_ci setup[setup_count].synchronous = aha152x[5]; 318962306a36Sopenharmony_ci setup[setup_count].delay = aha152x[6]; 319062306a36Sopenharmony_ci setup[setup_count].ext_trans = aha152x[7]; 319162306a36Sopenharmony_ci } else if (io[0] != 0 || irq[0] != 0) { 319262306a36Sopenharmony_ci if(io[0]!=0) setup[setup_count].io_port = io[0]; 319362306a36Sopenharmony_ci if(irq[0]!=0) setup[setup_count].irq = irq[0]; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci setup[setup_count].scsiid = scsiid[0]; 319662306a36Sopenharmony_ci setup[setup_count].reconnect = reconnect[0]; 319762306a36Sopenharmony_ci setup[setup_count].parity = parity[0]; 319862306a36Sopenharmony_ci setup[setup_count].synchronous = sync[0]; 319962306a36Sopenharmony_ci setup[setup_count].delay = delay[0]; 320062306a36Sopenharmony_ci setup[setup_count].ext_trans = exttrans[0]; 320162306a36Sopenharmony_ci } 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci if (checksetup(&setup[setup_count])) 320462306a36Sopenharmony_ci setup_count++; 320562306a36Sopenharmony_ci else 320662306a36Sopenharmony_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", 320762306a36Sopenharmony_ci setup[setup_count].io_port, 320862306a36Sopenharmony_ci setup[setup_count].irq, 320962306a36Sopenharmony_ci setup[setup_count].scsiid, 321062306a36Sopenharmony_ci setup[setup_count].reconnect, 321162306a36Sopenharmony_ci setup[setup_count].parity, 321262306a36Sopenharmony_ci setup[setup_count].synchronous, 321362306a36Sopenharmony_ci setup[setup_count].delay, 321462306a36Sopenharmony_ci setup[setup_count].ext_trans); 321562306a36Sopenharmony_ci } 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) { 321862306a36Sopenharmony_ci if(aha152x1[0]!=0) { 321962306a36Sopenharmony_ci setup[setup_count].conf = ""; 322062306a36Sopenharmony_ci setup[setup_count].io_port = aha152x1[0]; 322162306a36Sopenharmony_ci setup[setup_count].irq = aha152x1[1]; 322262306a36Sopenharmony_ci setup[setup_count].scsiid = aha152x1[2]; 322362306a36Sopenharmony_ci setup[setup_count].reconnect = aha152x1[3]; 322462306a36Sopenharmony_ci setup[setup_count].parity = aha152x1[4]; 322562306a36Sopenharmony_ci setup[setup_count].synchronous = aha152x1[5]; 322662306a36Sopenharmony_ci setup[setup_count].delay = aha152x1[6]; 322762306a36Sopenharmony_ci setup[setup_count].ext_trans = aha152x1[7]; 322862306a36Sopenharmony_ci } else if (io[1] != 0 || irq[1] != 0) { 322962306a36Sopenharmony_ci if(io[1]!=0) setup[setup_count].io_port = io[1]; 323062306a36Sopenharmony_ci if(irq[1]!=0) setup[setup_count].irq = irq[1]; 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_ci setup[setup_count].scsiid = scsiid[1]; 323362306a36Sopenharmony_ci setup[setup_count].reconnect = reconnect[1]; 323462306a36Sopenharmony_ci setup[setup_count].parity = parity[1]; 323562306a36Sopenharmony_ci setup[setup_count].synchronous = sync[1]; 323662306a36Sopenharmony_ci setup[setup_count].delay = delay[1]; 323762306a36Sopenharmony_ci setup[setup_count].ext_trans = exttrans[1]; 323862306a36Sopenharmony_ci } 323962306a36Sopenharmony_ci if (checksetup(&setup[setup_count])) 324062306a36Sopenharmony_ci setup_count++; 324162306a36Sopenharmony_ci else 324262306a36Sopenharmony_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", 324362306a36Sopenharmony_ci setup[setup_count].io_port, 324462306a36Sopenharmony_ci setup[setup_count].irq, 324562306a36Sopenharmony_ci setup[setup_count].scsiid, 324662306a36Sopenharmony_ci setup[setup_count].reconnect, 324762306a36Sopenharmony_ci setup[setup_count].parity, 324862306a36Sopenharmony_ci setup[setup_count].synchronous, 324962306a36Sopenharmony_ci setup[setup_count].delay, 325062306a36Sopenharmony_ci setup[setup_count].ext_trans); 325162306a36Sopenharmony_ci } 325262306a36Sopenharmony_ci#endif 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci#ifdef __ISAPNP__ 325562306a36Sopenharmony_ci for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) { 325662306a36Sopenharmony_ci while ( setup_count<ARRAY_SIZE(setup) && 325762306a36Sopenharmony_ci (dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) { 325862306a36Sopenharmony_ci if (pnp_device_attach(dev) < 0) 325962306a36Sopenharmony_ci continue; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci if (pnp_activate_dev(dev) < 0) { 326262306a36Sopenharmony_ci pnp_device_detach(dev); 326362306a36Sopenharmony_ci continue; 326462306a36Sopenharmony_ci } 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci if (!pnp_port_valid(dev, 0)) { 326762306a36Sopenharmony_ci pnp_device_detach(dev); 326862306a36Sopenharmony_ci continue; 326962306a36Sopenharmony_ci } 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) { 327262306a36Sopenharmony_ci pnp_device_detach(dev); 327362306a36Sopenharmony_ci continue; 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci setup[setup_count].io_port = pnp_port_start(dev, 0); 327762306a36Sopenharmony_ci setup[setup_count].irq = pnp_irq(dev, 0); 327862306a36Sopenharmony_ci setup[setup_count].scsiid = 7; 327962306a36Sopenharmony_ci setup[setup_count].reconnect = 1; 328062306a36Sopenharmony_ci setup[setup_count].parity = 1; 328162306a36Sopenharmony_ci setup[setup_count].synchronous = 1; 328262306a36Sopenharmony_ci setup[setup_count].delay = DELAY_DEFAULT; 328362306a36Sopenharmony_ci setup[setup_count].ext_trans = 0; 328462306a36Sopenharmony_ci#if defined(__ISAPNP__) 328562306a36Sopenharmony_ci pnpdev[setup_count] = dev; 328662306a36Sopenharmony_ci#endif 328762306a36Sopenharmony_ci printk (KERN_INFO 328862306a36Sopenharmony_ci "aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n", 328962306a36Sopenharmony_ci setup[setup_count].io_port, setup[setup_count].irq); 329062306a36Sopenharmony_ci setup_count++; 329162306a36Sopenharmony_ci } 329262306a36Sopenharmony_ci } 329362306a36Sopenharmony_ci#endif 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci#if defined(AUTOCONF) 329662306a36Sopenharmony_ci if (setup_count<ARRAY_SIZE(setup)) { 329762306a36Sopenharmony_ci#if !defined(SKIP_BIOSTEST) 329862306a36Sopenharmony_ci ok = 0; 329962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) { 330062306a36Sopenharmony_ci void __iomem *p = ioremap(addresses[i], 0x4000); 330162306a36Sopenharmony_ci if (!p) 330262306a36Sopenharmony_ci continue; 330362306a36Sopenharmony_ci for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++) 330462306a36Sopenharmony_ci ok = check_signature(p + signatures[j].sig_offset, 330562306a36Sopenharmony_ci signatures[j].signature, signatures[j].sig_length); 330662306a36Sopenharmony_ci iounmap(p); 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci if (!ok && setup_count == 0) 330962306a36Sopenharmony_ci return -ENODEV; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci printk(KERN_INFO "aha152x: BIOS test: passed, "); 331262306a36Sopenharmony_ci#else 331362306a36Sopenharmony_ci printk(KERN_INFO "aha152x: "); 331462306a36Sopenharmony_ci#endif /* !SKIP_BIOSTEST */ 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci ok = 0; 331762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) { 331862306a36Sopenharmony_ci if ((setup_count == 1) && (setup[0].io_port == ports[i])) 331962306a36Sopenharmony_ci continue; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci if (!request_region(ports[i], IO_RANGE, "aha152x")) { 332262306a36Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]); 332362306a36Sopenharmony_ci continue; 332462306a36Sopenharmony_ci } 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci if (aha152x_porttest(ports[i])) { 332762306a36Sopenharmony_ci setup[setup_count].tc1550 = 0; 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci conf.cf_port = 333062306a36Sopenharmony_ci (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB); 333162306a36Sopenharmony_ci } else if (tc1550_porttest(ports[i])) { 333262306a36Sopenharmony_ci setup[setup_count].tc1550 = 1; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci conf.cf_port = 333562306a36Sopenharmony_ci (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB); 333662306a36Sopenharmony_ci } else { 333762306a36Sopenharmony_ci release_region(ports[i], IO_RANGE); 333862306a36Sopenharmony_ci continue; 333962306a36Sopenharmony_ci } 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci release_region(ports[i], IO_RANGE); 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci ok++; 334462306a36Sopenharmony_ci setup[setup_count].io_port = ports[i]; 334562306a36Sopenharmony_ci setup[setup_count].irq = IRQ_MIN + conf.cf_irq; 334662306a36Sopenharmony_ci setup[setup_count].scsiid = conf.cf_id; 334762306a36Sopenharmony_ci setup[setup_count].reconnect = conf.cf_tardisc; 334862306a36Sopenharmony_ci setup[setup_count].parity = !conf.cf_parity; 334962306a36Sopenharmony_ci setup[setup_count].synchronous = conf.cf_syncneg; 335062306a36Sopenharmony_ci setup[setup_count].delay = DELAY_DEFAULT; 335162306a36Sopenharmony_ci setup[setup_count].ext_trans = 0; 335262306a36Sopenharmony_ci setup_count++; 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci } 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci if (ok) 335762306a36Sopenharmony_ci printk("auto configuration: ok, "); 335862306a36Sopenharmony_ci } 335962306a36Sopenharmony_ci#endif 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci printk("%d controller(s) configured\n", setup_count); 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci for (i=0; i<setup_count; i++) { 336462306a36Sopenharmony_ci if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) { 336562306a36Sopenharmony_ci struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]); 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci if( !shpnt ) { 336862306a36Sopenharmony_ci release_region(setup[i].io_port, IO_RANGE); 336962306a36Sopenharmony_ci#if defined(__ISAPNP__) 337062306a36Sopenharmony_ci } else if( pnpdev[i] ) { 337162306a36Sopenharmony_ci HOSTDATA(shpnt)->pnpdev=pnpdev[i]; 337262306a36Sopenharmony_ci pnpdev[i]=NULL; 337362306a36Sopenharmony_ci#endif 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci } else { 337662306a36Sopenharmony_ci printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port); 337762306a36Sopenharmony_ci } 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci#if defined(__ISAPNP__) 338062306a36Sopenharmony_ci if( pnpdev[i] ) 338162306a36Sopenharmony_ci pnp_device_detach(pnpdev[i]); 338262306a36Sopenharmony_ci#endif 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci return 0; 338662306a36Sopenharmony_ci} 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_cistatic void __exit aha152x_exit(void) 338962306a36Sopenharmony_ci{ 339062306a36Sopenharmony_ci struct aha152x_hostdata *hd, *tmp; 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) { 339362306a36Sopenharmony_ci struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci aha152x_release(shost); 339662306a36Sopenharmony_ci } 339762306a36Sopenharmony_ci} 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_cimodule_init(aha152x_init); 340062306a36Sopenharmony_cimodule_exit(aha152x_exit); 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_ci#if !defined(MODULE) 340362306a36Sopenharmony_cistatic int __init aha152x_setup(char *str) 340462306a36Sopenharmony_ci{ 340562306a36Sopenharmony_ci int ints[10]; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci get_options(str, ARRAY_SIZE(ints), ints); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci if(setup_count>=ARRAY_SIZE(setup)) { 341062306a36Sopenharmony_ci printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); 341162306a36Sopenharmony_ci return 1; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci setup[setup_count].conf = str; 341562306a36Sopenharmony_ci setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; 341662306a36Sopenharmony_ci setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; 341762306a36Sopenharmony_ci setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; 341862306a36Sopenharmony_ci setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; 341962306a36Sopenharmony_ci setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; 342062306a36Sopenharmony_ci setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; 342162306a36Sopenharmony_ci setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; 342262306a36Sopenharmony_ci setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; 342362306a36Sopenharmony_ci if (ints[0] > 8) 342462306a36Sopenharmony_ci printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>" 342562306a36Sopenharmony_ci "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n"); 342662306a36Sopenharmony_ci else 342762306a36Sopenharmony_ci setup_count++; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci return 1; 343062306a36Sopenharmony_ci} 343162306a36Sopenharmony_ci__setup("aha152x=", aha152x_setup); 343262306a36Sopenharmony_ci#endif 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci#endif /* !AHA152X_PCMCIA */ 3435