1119418Sobrien/*- 265312Smsmith * Copyright (c) 1996-2000 Distributed Processing Technology Corporation 382092Sscottl * Copyright (c) 2000-2001 Adaptec Corporation 465312Smsmith * All rights reserved. 565312Smsmith * 665312Smsmith * TERMS AND CONDITIONS OF USE 765312Smsmith * 865312Smsmith * Redistribution and use in source form, with or without modification, are 965312Smsmith * permitted provided that redistributions of source code must retain the 1065312Smsmith * above copyright notice, this list of conditions and the following disclaimer. 1165312Smsmith * 1265312Smsmith * This software is provided `as is' by Adaptec and any express or implied 1365312Smsmith * warranties, including, but not limited to, the implied warranties of 1465312Smsmith * merchantability and fitness for a particular purpose, are disclaimed. In no 1565312Smsmith * event shall Adaptec be liable for any direct, indirect, incidental, special, 1665312Smsmith * exemplary or consequential damages (including, but not limited to, 1765312Smsmith * procurement of substitute goods or services; loss of use, data, or profits; 1865312Smsmith * or business interruptions) however caused and on any theory of liability, 1965312Smsmith * whether in contract, strict liability, or tort (including negligence or 2065312Smsmith * otherwise) arising in any way out of the use of this driver software, even 2165312Smsmith * if advised of the possibility of such damage. 2265312Smsmith * 2365312Smsmith * SCSI I2O host adapter driver 2465312Smsmith * 25128964Sscottl * V1.10 2004/05/05 scottl@freebsd.org 26128964Sscottl * - Massive cleanup of the driver to remove dead code and 27128964Sscottl * non-conformant style. 28128964Sscottl * - Removed most i386-specific code to make it more portable. 29128964Sscottl * - Converted to the bus_space API. 3096554Sobrien * V1.08 2001/08/21 Mark_Salyzyn@adaptec.com 3196554Sobrien * - The 2000S and 2005S do not initialize on some machines, 3282092Sscottl * increased timeout to 255ms from 50ms for the StatusGet 3382092Sscottl * command. 3496554Sobrien * V1.07 2001/05/22 Mark_Salyzyn@adaptec.com 3596554Sobrien * - I knew this one was too good to be true. The error return 3696554Sobrien * on ioctl commands needs to be compared to CAM_REQ_CMP, not 3796554Sobrien * to the bit masked status. 3896554Sobrien * V1.06 2001/05/08 Mark_Salyzyn@adaptec.com 3996554Sobrien * - The 2005S that was supported is affectionately called the 4096554Sobrien * Conjoined BAR Firmware. In order to support RAID-5 in a 4196554Sobrien * 16MB low-cost configuration, Firmware was forced to go 4296554Sobrien * to a Split BAR Firmware. This requires a separate IOP and 4396554Sobrien * Messaging base address. 4496554Sobrien * V1.05 2001/04/25 Mark_Salyzyn@adaptec.com 4596554Sobrien * - Handle support for 2005S Zero Channel RAID solution. 4696554Sobrien * - System locked up if the Adapter locked up. Do not try 4796554Sobrien * to send other commands if the resetIOP command fails. The 4896554Sobrien * fail outstanding command discovery loop was flawed as the 4996554Sobrien * removal of the command from the list prevented discovering 5096554Sobrien * all the commands. 5196554Sobrien * - Comment changes to clarify driver. 5296554Sobrien * - SysInfo searched for an EATA SmartROM, not an I2O SmartROM. 5396554Sobrien * - We do not use the AC_FOUND_DEV event because of I2O. 5496554Sobrien * Removed asr_async. 5596554Sobrien * V1.04 2000/09/22 Mark_Salyzyn@adaptec.com, msmith@freebsd.org, 5696554Sobrien * lampa@fee.vutbr.cz and Scott_Long@adaptec.com. 5796554Sobrien * - Removed support for PM1554, PM2554 and PM2654 in Mode-0 5896554Sobrien * mode as this is confused with competitor adapters in run 5996554Sobrien * mode. 6096554Sobrien * - critical locking needed in ASR_ccbAdd and ASR_ccbRemove 6196554Sobrien * to prevent operating system panic. 6296554Sobrien * - moved default major number to 154 from 97. 6396554Sobrien * V1.03 2000/07/12 Mark_Salyzyn@adaptec.com 6496554Sobrien * - The controller is not actually an ASR (Adaptec SCSI RAID) 6596554Sobrien * series that is visible, it's more of an internal code name. 6696554Sobrien * remove any visible references within reason for now. 6796554Sobrien * - bus_ptr->LUN was not correctly zeroed when initially 6896554Sobrien * allocated causing a possible panic of the operating system 6996554Sobrien * during boot. 7096554Sobrien * V1.02 2000/06/26 Mark_Salyzyn@adaptec.com 7196554Sobrien * - Code always fails for ASR_getTid affecting performance. 7296554Sobrien * - initiated a set of changes that resulted from a formal 7396554Sobrien * code inspection by Mark_Salyzyn@adaptec.com, 7496554Sobrien * George_Dake@adaptec.com, Jeff_Zeak@adaptec.com, 7596554Sobrien * Martin_Wilson@adaptec.com and Vincent_Trandoan@adaptec.com. 7696554Sobrien * Their findings were focussed on the LCT & TID handler, and 7796554Sobrien * all resulting changes were to improve code readability, 7896554Sobrien * consistency or have a positive effect on performance. 7996554Sobrien * V1.01 2000/06/14 Mark_Salyzyn@adaptec.com 8096554Sobrien * - Passthrough returned an incorrect error. 8196554Sobrien * - Passthrough did not migrate the intrinsic scsi layer wakeup 8296554Sobrien * on command completion. 8396554Sobrien * - generate control device nodes using make_dev and delete_dev. 8496554Sobrien * - Performance affected by TID caching reallocing. 8596554Sobrien * - Made suggested changes by Justin_Gibbs@adaptec.com 8696554Sobrien * - use splcam instead of splbio. 8796554Sobrien * - use cam_imask instead of bio_imask. 8896554Sobrien * - use u_int8_t instead of u_char. 8996554Sobrien * - use u_int16_t instead of u_short. 9096554Sobrien * - use u_int32_t instead of u_long where appropriate. 9196554Sobrien * - use 64 bit context handler instead of 32 bit. 9296554Sobrien * - create_ccb should only allocate the worst case 9396554Sobrien * requirements for the driver since CAM may evolve 9496554Sobrien * making union ccb much larger than needed here. 9596554Sobrien * renamed create_ccb to asr_alloc_ccb. 9696554Sobrien * - go nutz justifying all debug prints as macros 9796554Sobrien * defined at the top and remove unsightly ifdefs. 9896554Sobrien * - INLINE STATIC viewed as confusing. Historically 9996554Sobrien * utilized to affect code performance and debug 10096554Sobrien * issues in OS, Compiler or OEM specific situations. 10196554Sobrien * V1.00 2000/05/31 Mark_Salyzyn@adaptec.com 10296554Sobrien * - Ported from FreeBSD 2.2.X DPT I2O driver. 10396554Sobrien * changed struct scsi_xfer to union ccb/struct ccb_hdr 10496554Sobrien * changed variable name xs to ccb 10596554Sobrien * changed struct scsi_link to struct cam_path 10696554Sobrien * changed struct scsibus_data to struct cam_sim 10796554Sobrien * stopped using fordriver for holding on to the TID 10896554Sobrien * use proprietary packet creation instead of scsi_inquire 10996554Sobrien * CAM layer sends synchronize commands. 11065312Smsmith */ 11165312Smsmith 112119418Sobrien#include <sys/cdefs.h> 113128786Sscottl#include <sys/param.h> /* TRUE=1 and FALSE=0 defined here */ 114128786Sscottl#include <sys/kernel.h> 115129879Sphk#include <sys/module.h> 116128786Sscottl#include <sys/systm.h> 117128786Sscottl#include <sys/malloc.h> 118128786Sscottl#include <sys/conf.h> 119128786Sscottl#include <sys/ioccom.h> 120164033Srwatson#include <sys/priv.h> 121128786Sscottl#include <sys/proc.h> 122128786Sscottl#include <sys/bus.h> 123128786Sscottl#include <machine/resource.h> 124128786Sscottl#include <machine/bus.h> 125128786Sscottl#include <sys/rman.h> 126128786Sscottl#include <sys/stat.h> 127155286Sscottl#include <sys/bus_dma.h> 128128786Sscottl 129128786Sscottl#include <cam/cam.h> 130128786Sscottl#include <cam/cam_ccb.h> 131128786Sscottl#include <cam/cam_sim.h> 132128786Sscottl#include <cam/cam_xpt_sim.h> 133128786Sscottl 134128786Sscottl#include <cam/scsi/scsi_all.h> 135128786Sscottl#include <cam/scsi/scsi_message.h> 136128786Sscottl 137128786Sscottl#include <vm/vm.h> 138128786Sscottl#include <vm/pmap.h> 139128786Sscottl 140128786Sscottl#if defined(__i386__) 141143729Scognet#include "opt_asr.h" 142128786Sscottl#include <i386/include/cputypes.h> 143143729Scognet 144143729Scognet#if defined(ASR_COMPAT) 145143729Scognet#define ASR_IOCTL_COMPAT 146143729Scognet#endif /* ASR_COMPAT */ 147128786Sscottl#endif 148128786Sscottl#include <machine/vmparam.h> 149128786Sscottl 150128786Sscottl#include <dev/pci/pcivar.h> 151128786Sscottl#include <dev/pci/pcireg.h> 152128786Sscottl 153128786Sscottl#define osdSwap4(x) ((u_long)ntohl((u_long)(x))) 154128786Sscottl#define KVTOPHYS(x) vtophys(x) 155155286Sscottl#include <dev/asr/dptalign.h> 156155286Sscottl#include <dev/asr/i2oexec.h> 157155286Sscottl#include <dev/asr/i2obscsi.h> 158155286Sscottl#include <dev/asr/i2odpt.h> 159155286Sscottl#include <dev/asr/i2oadptr.h> 160128786Sscottl 161155286Sscottl#include <dev/asr/sys_info.h> 162128786Sscottl 163119418Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/asr/asr.c 275982 2014-12-21 03:06:11Z smh $"); 164119418Sobrien 16596615Sobrien#define ASR_VERSION 1 166128964Sscottl#define ASR_REVISION '1' 167128964Sscottl#define ASR_SUBREVISION '0' 168128964Sscottl#define ASR_MONTH 5 169128964Sscottl#define ASR_DAY 5 170128964Sscottl#define ASR_YEAR (2004 - 1980) 17165312Smsmith 17265312Smsmith/* 17396554Sobrien * Debug macros to reduce the unsightly ifdefs 17465312Smsmith */ 17565312Smsmith#if (defined(DEBUG_ASR) || defined(DEBUG_ASR_USR_CMD) || defined(DEBUG_ASR_CMD)) 176128786Sscottlstatic __inline void 177128786Sscottldebug_asr_message(PI2O_MESSAGE_FRAME message) 178128786Sscottl{ 179128786Sscottl u_int32_t * pointer = (u_int32_t *)message; 180128786Sscottl u_int32_t length = I2O_MESSAGE_FRAME_getMessageSize(message); 181128786Sscottl u_int32_t counter = 0; 182128786Sscottl 183128786Sscottl while (length--) { 184128786Sscottl printf("%08lx%c", (u_long)*(pointer++), 185128786Sscottl (((++counter & 7) == 0) || (length == 0)) ? '\n' : ' '); 18696554Sobrien } 187128786Sscottl} 18865312Smsmith#endif /* DEBUG_ASR || DEBUG_ASR_USR_CMD || DEBUG_ASR_CMD */ 18965312Smsmith 190128786Sscottl#ifdef DEBUG_ASR 19165312Smsmith /* Breaks on none STDC based compilers :-( */ 192128786Sscottl#define debug_asr_printf(fmt,args...) printf(fmt, ##args) 193128786Sscottl#define debug_asr_dump_message(message) debug_asr_message(message) 194128786Sscottl#define debug_asr_print_path(ccb) xpt_print_path(ccb->ccb_h.path); 19565312Smsmith#else /* DEBUG_ASR */ 196128535Sscottl#define debug_asr_printf(fmt,args...) 197128535Sscottl#define debug_asr_dump_message(message) 198128535Sscottl#define debug_asr_print_path(ccb) 19965312Smsmith#endif /* DEBUG_ASR */ 20065312Smsmith 20165312Smsmith/* 20296554Sobrien * If DEBUG_ASR_CMD is defined: 20396554Sobrien * 0 - Display incoming SCSI commands 20496554Sobrien * 1 - add in a quick character before queueing. 20596554Sobrien * 2 - add in outgoing message frames. 20665312Smsmith */ 20765312Smsmith#if (defined(DEBUG_ASR_CMD)) 208128535Sscottl#define debug_asr_cmd_printf(fmt,args...) printf(fmt,##args) 209128786Sscottlstatic __inline void 210128786Sscottldebug_asr_dump_ccb(union ccb *ccb) 211128786Sscottl{ 212128786Sscottl u_int8_t *cp = (unsigned char *)&(ccb->csio.cdb_io); 213128786Sscottl int len = ccb->csio.cdb_len; 214128786Sscottl 215128786Sscottl while (len) { 216128786Sscottl debug_asr_cmd_printf (" %02x", *(cp++)); 217128786Sscottl --len; 21896554Sobrien } 219128786Sscottl} 220128535Sscottl#if (DEBUG_ASR_CMD > 0) 221128535Sscottl#define debug_asr_cmd1_printf debug_asr_cmd_printf 222128535Sscottl#else 223128535Sscottl#define debug_asr_cmd1_printf(fmt,args...) 224128535Sscottl#endif 225128535Sscottl#if (DEBUG_ASR_CMD > 1) 226128786Sscottl#define debug_asr_cmd2_printf debug_asr_cmd_printf 227128786Sscottl#define debug_asr_cmd2_dump_message(message) debug_asr_message(message) 228128535Sscottl#else 229128535Sscottl#define debug_asr_cmd2_printf(fmt,args...) 230128535Sscottl#define debug_asr_cmd2_dump_message(message) 231128535Sscottl#endif 23265312Smsmith#else /* DEBUG_ASR_CMD */ 233128535Sscottl#define debug_asr_cmd_printf(fmt,args...) 234128786Sscottl#define debug_asr_dump_ccb(ccb) 235128535Sscottl#define debug_asr_cmd1_printf(fmt,args...) 236128535Sscottl#define debug_asr_cmd2_printf(fmt,args...) 237128535Sscottl#define debug_asr_cmd2_dump_message(message) 23865312Smsmith#endif /* DEBUG_ASR_CMD */ 23965312Smsmith 24065312Smsmith#if (defined(DEBUG_ASR_USR_CMD)) 241128535Sscottl#define debug_usr_cmd_printf(fmt,args...) printf(fmt,##args) 242128535Sscottl#define debug_usr_cmd_dump_message(message) debug_usr_message(message) 24365312Smsmith#else /* DEBUG_ASR_USR_CMD */ 244128535Sscottl#define debug_usr_cmd_printf(fmt,args...) 245128535Sscottl#define debug_usr_cmd_dump_message(message) 24665312Smsmith#endif /* DEBUG_ASR_USR_CMD */ 24765312Smsmith 248143729Scognet#ifdef ASR_IOCTL_COMPAT 249143729Scognet#define dsDescription_size 46 /* Snug as a bug in a rug */ 250143729Scognet#endif /* ASR_IOCTL_COMPAT */ 251143729Scognet 25265312Smsmith#include "dev/asr/dptsig.h" 25365312Smsmith 25465312Smsmithstatic dpt_sig_S ASR_sig = { 25596554Sobrien { 'd', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, PROC_INTEL, 25696554Sobrien PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM, FT_HBADRVR, 0, 257128945Sscottl OEM_DPT, OS_FREE_BSD, CAP_ABOVE16MB, DEV_ALL, ADF_ALL_SC5, 25896554Sobrien 0, 0, ASR_VERSION, ASR_REVISION, ASR_SUBREVISION, 25996554Sobrien ASR_MONTH, ASR_DAY, ASR_YEAR, 26096554Sobrien/* 01234567890123456789012345678901234567890123456789 < 50 chars */ 26196554Sobrien "Adaptec FreeBSD 4.0.0 Unix SCSI I2O HBA Driver" 26296554Sobrien /* ^^^^^ asr_attach alters these to match OS */ 26365312Smsmith}; 26465312Smsmith 26565312Smsmith/* Configuration Definitions */ 26665312Smsmith 26796615Sobrien#define SG_SIZE 58 /* Scatter Gather list Size */ 26896615Sobrien#define MAX_TARGET_ID 126 /* Maximum Target ID supported */ 26996615Sobrien#define MAX_LUN 255 /* Maximum LUN Supported */ 27096615Sobrien#define MAX_CHANNEL 7 /* Maximum Channel # Supported by driver */ 27196615Sobrien#define MAX_INBOUND 2000 /* Max CCBs, Also Max Queue Size */ 27296615Sobrien#define MAX_OUTBOUND 256 /* Maximum outbound frames/adapter */ 27396615Sobrien#define MAX_INBOUND_SIZE 512 /* Maximum inbound frame size */ 27496615Sobrien#define MAX_MAP 4194304L /* Maximum mapping size of IOP */ 27596554Sobrien /* Also serves as the minimum map for */ 27696554Sobrien /* the 2005S zero channel RAID product */ 27765312Smsmith 27865312Smsmith/* I2O register set */ 279128944Sscottl#define I2O_REG_STATUS 0x30 280128944Sscottl#define I2O_REG_MASK 0x34 281128944Sscottl#define I2O_REG_TOFIFO 0x40 282128944Sscottl#define I2O_REG_FROMFIFO 0x44 28365312Smsmith 284128944Sscottl#define Mask_InterruptsDisabled 0x08 285128944Sscottl 28665312Smsmith/* 28765312Smsmith * A MIX of performance and space considerations for TID lookups 28865312Smsmith */ 28965312Smsmithtypedef u_int16_t tid_t; 29065312Smsmith 29165312Smsmithtypedef struct { 29296554Sobrien u_int32_t size; /* up to MAX_LUN */ 29396554Sobrien tid_t TID[1]; 29465312Smsmith} lun2tid_t; 29565312Smsmith 29665312Smsmithtypedef struct { 29796554Sobrien u_int32_t size; /* up to MAX_TARGET */ 29896554Sobrien lun2tid_t * LUN[1]; 29965312Smsmith} target2lun_t; 30065312Smsmith 30165312Smsmith/* 30296554Sobrien * To ensure that we only allocate and use the worst case ccb here, lets 30396554Sobrien * make our own local ccb union. If asr_alloc_ccb is utilized for another 30496554Sobrien * ccb type, ensure that you add the additional structures into our local 30596554Sobrien * ccb union. To ensure strict type checking, we will utilize the local 30696554Sobrien * ccb definition wherever possible. 30765312Smsmith */ 30865312Smsmithunion asr_ccb { 30996554Sobrien struct ccb_hdr ccb_h; /* For convenience */ 31096554Sobrien struct ccb_scsiio csio; 31196554Sobrien struct ccb_setasync csa; 31265312Smsmith}; 31365312Smsmith 314155307Sscottlstruct Asr_status_mem { 315155307Sscottl I2O_EXEC_STATUS_GET_REPLY status; 316155307Sscottl U32 rstatus; 317155307Sscottl}; 318155307Sscottl 319128944Sscottl/************************************************************************** 320128944Sscottl** ASR Host Adapter structure - One Structure For Each Host Adapter That ** 321128944Sscottl** Is Configured Into The System. The Structure Supplies Configuration ** 322128944Sscottl** Information, Status Info, Queue Info And An Active CCB List Pointer. ** 323128944Sscottl***************************************************************************/ 324128944Sscottl 32565312Smsmithtypedef struct Asr_softc { 326155286Sscottl device_t ha_dev; 32796554Sobrien u_int16_t ha_irq; 328128944Sscottl u_long ha_Base; /* base port for each board */ 329128944Sscottl bus_size_t ha_blinkLED; 330128944Sscottl bus_space_handle_t ha_i2o_bhandle; 331128944Sscottl bus_space_tag_t ha_i2o_btag; 332128944Sscottl bus_space_handle_t ha_frame_bhandle; 333128944Sscottl bus_space_tag_t ha_frame_btag; 33496554Sobrien I2O_IOP_ENTRY ha_SystemTable; 33596554Sobrien LIST_HEAD(,ccb_hdr) ha_ccb; /* ccbs in use */ 336155286Sscottl 337155286Sscottl bus_dma_tag_t ha_parent_dmat; 338155307Sscottl bus_dma_tag_t ha_statusmem_dmat; 339155307Sscottl bus_dmamap_t ha_statusmem_dmamap; 340155307Sscottl struct Asr_status_mem * ha_statusmem; 341155307Sscottl u_int32_t ha_rstatus_phys; 342155286Sscottl u_int32_t ha_status_phys; 34396554Sobrien struct cam_path * ha_path[MAX_CHANNEL+1]; 34496554Sobrien struct cam_sim * ha_sim[MAX_CHANNEL+1]; 34596554Sobrien struct resource * ha_mem_res; 34696554Sobrien struct resource * ha_mes_res; 34796554Sobrien struct resource * ha_irq_res; 34896554Sobrien void * ha_intr; 34996554Sobrien PI2O_LCT ha_LCT; /* Complete list of devices */ 350128535Sscottl#define le_type IdentityTag[0] 351128535Sscottl#define I2O_BSA 0x20 352128535Sscottl#define I2O_FCA 0x40 353128535Sscottl#define I2O_SCSI 0x00 354128535Sscottl#define I2O_PORT 0x80 355128535Sscottl#define I2O_UNKNOWN 0x7F 356128535Sscottl#define le_bus IdentityTag[1] 357128535Sscottl#define le_target IdentityTag[2] 358128535Sscottl#define le_lun IdentityTag[3] 35996554Sobrien target2lun_t * ha_targets[MAX_CHANNEL+1]; 36096554Sobrien PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME ha_Msgs; 36196554Sobrien u_long ha_Msgs_Phys; 36265312Smsmith 36396554Sobrien u_int8_t ha_in_reset; 364128535Sscottl#define HA_OPERATIONAL 0 365128535Sscottl#define HA_IN_RESET 1 366128535Sscottl#define HA_OFF_LINE 2 367128535Sscottl#define HA_OFF_LINE_RECOVERY 3 36896554Sobrien /* Configuration information */ 36996554Sobrien /* The target id maximums we take */ 37096554Sobrien u_int8_t ha_MaxBus; /* Maximum bus */ 37196554Sobrien u_int8_t ha_MaxId; /* Maximum target ID */ 37296554Sobrien u_int8_t ha_MaxLun; /* Maximum target LUN */ 37396554Sobrien u_int8_t ha_SgSize; /* Max SG elements */ 37496554Sobrien u_int8_t ha_pciBusNum; 37596554Sobrien u_int8_t ha_pciDeviceNum; 37696554Sobrien u_int8_t ha_adapter_target[MAX_CHANNEL+1]; 37796554Sobrien u_int16_t ha_QueueSize; /* Max outstanding commands */ 37896554Sobrien u_int16_t ha_Msgs_Count; 37965312Smsmith 38096554Sobrien /* Links into other parents and HBAs */ 381234503Sdim STAILQ_ENTRY(Asr_softc) ha_next; /* HBA list */ 382130585Sphk struct cdev *ha_devt; 38365312Smsmith} Asr_softc_t; 38465312Smsmith 385234503Sdimstatic STAILQ_HEAD(, Asr_softc) Asr_softc_list = 386234503Sdim STAILQ_HEAD_INITIALIZER(Asr_softc_list); 38765312Smsmith/* 38896554Sobrien * Prototypes of the routines we have in this object. 38965312Smsmith */ 39065312Smsmith 39165312Smsmith/* I2O HDM interface */ 392154363Sscottlstatic int asr_probe(device_t dev); 393154363Sscottlstatic int asr_attach(device_t dev); 39465312Smsmith 395130585Sphkstatic int asr_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, 396128784Sscottl struct thread *td); 397130585Sphkstatic int asr_open(struct cdev *dev, int32_t flags, int32_t ifmt, 398128784Sscottl struct thread *td); 399130585Sphkstatic int asr_close(struct cdev *dev, int flags, int ifmt, struct thread *td); 400128784Sscottlstatic int asr_intr(Asr_softc_t *sc); 401128784Sscottlstatic void asr_timeout(void *arg); 402128784Sscottlstatic int ASR_init(Asr_softc_t *sc); 403128784Sscottlstatic int ASR_acquireLct(Asr_softc_t *sc); 404128784Sscottlstatic int ASR_acquireHrt(Asr_softc_t *sc); 405128784Sscottlstatic void asr_action(struct cam_sim *sim, union ccb *ccb); 406128784Sscottlstatic void asr_poll(struct cam_sim *sim); 407128784Sscottlstatic int ASR_queue(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message); 40865312Smsmith 409275982Ssmhstatic __inline void 410275982Ssmhset_ccb_timeout_ch(union asr_ccb *ccb) 411275982Ssmh{ 412275982Ssmh struct callout_handle ch; 413275982Ssmh 414275982Ssmh ch = timeout(asr_timeout, (caddr_t)ccb, 415275982Ssmh (int)((u_int64_t)(ccb->ccb_h.timeout) * (u_int32_t)hz / 1000)); 416275982Ssmh ccb->ccb_h.sim_priv.entries[0].ptr = ch.callout; 417275982Ssmh} 418275982Ssmh 419275982Ssmhstatic __inline struct callout_handle 420275982Ssmhget_ccb_timeout_ch(union asr_ccb *ccb) 421275982Ssmh{ 422275982Ssmh struct callout_handle ch; 423275982Ssmh 424275982Ssmh ch.callout = ccb->ccb_h.sim_priv.entries[0].ptr; 425275982Ssmh return ch; 426275982Ssmh} 427275982Ssmh 42865312Smsmith/* 42996554Sobrien * Here is the auto-probe structure used to nest our tests appropriately 43096554Sobrien * during the startup phase of the operating system. 43165312Smsmith */ 432128784Sscottlstatic device_method_t asr_methods[] = { 43396554Sobrien DEVMETHOD(device_probe, asr_probe), 43496554Sobrien DEVMETHOD(device_attach, asr_attach), 43596554Sobrien { 0, 0 } 43665312Smsmith}; 43765312Smsmith 438128784Sscottlstatic driver_t asr_driver = { 43996554Sobrien "asr", 44096554Sobrien asr_methods, 44196554Sobrien sizeof(Asr_softc_t) 44265312Smsmith}; 44365312Smsmith 444128784Sscottlstatic devclass_t asr_devclass; 44565312SmsmithDRIVER_MODULE(asr, pci, asr_driver, asr_devclass, 0, 0); 446165102SmjacobMODULE_DEPEND(asr, pci, 1, 1, 1); 447165102SmjacobMODULE_DEPEND(asr, cam, 1, 1, 1); 44865312Smsmith 44965312Smsmith/* 45065312Smsmith * devsw for asr hba driver 45165312Smsmith * 45265312Smsmith * only ioctl is used. the sd driver provides all other access. 45365312Smsmith */ 454128784Sscottlstatic struct cdevsw asr_cdevsw = { 455126080Sphk .d_version = D_VERSION, 456126080Sphk .d_flags = D_NEEDGIANT, 457111815Sphk .d_open = asr_open, 458111815Sphk .d_close = asr_close, 459111815Sphk .d_ioctl = asr_ioctl, 460111815Sphk .d_name = "asr", 46165312Smsmith}; 46265312Smsmith 46365312Smsmith/* I2O support routines */ 46465312Smsmith 465128944Sscottlstatic __inline u_int32_t 466128944Sscottlasr_get_FromFIFO(Asr_softc_t *sc) 467128944Sscottl{ 468128944Sscottl return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, 469128944Sscottl I2O_REG_FROMFIFO)); 470128944Sscottl} 471128944Sscottl 472128944Sscottlstatic __inline u_int32_t 473128944Sscottlasr_get_ToFIFO(Asr_softc_t *sc) 474128944Sscottl{ 475128944Sscottl return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, 476128944Sscottl I2O_REG_TOFIFO)); 477128944Sscottl} 478128944Sscottl 479128944Sscottlstatic __inline u_int32_t 480128944Sscottlasr_get_intr(Asr_softc_t *sc) 481128944Sscottl{ 482128944Sscottl return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, 483128944Sscottl I2O_REG_MASK)); 484128944Sscottl} 485128944Sscottl 486128944Sscottlstatic __inline u_int32_t 487128944Sscottlasr_get_status(Asr_softc_t *sc) 488128944Sscottl{ 489128944Sscottl return (bus_space_read_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, 490128944Sscottl I2O_REG_STATUS)); 491128944Sscottl} 492128944Sscottl 493128944Sscottlstatic __inline void 494128944Sscottlasr_set_FromFIFO(Asr_softc_t *sc, u_int32_t val) 495128944Sscottl{ 496128944Sscottl bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_FROMFIFO, 497128944Sscottl val); 498128944Sscottl} 499128944Sscottl 500128944Sscottlstatic __inline void 501128944Sscottlasr_set_ToFIFO(Asr_softc_t *sc, u_int32_t val) 502128944Sscottl{ 503128944Sscottl bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_TOFIFO, 504128944Sscottl val); 505128944Sscottl} 506128944Sscottl 507128944Sscottlstatic __inline void 508128944Sscottlasr_set_intr(Asr_softc_t *sc, u_int32_t val) 509128944Sscottl{ 510128944Sscottl bus_space_write_4(sc->ha_i2o_btag, sc->ha_i2o_bhandle, I2O_REG_MASK, 511128944Sscottl val); 512128944Sscottl} 513128944Sscottl 514128944Sscottlstatic __inline void 515128944Sscottlasr_set_frame(Asr_softc_t *sc, void *frame, u_int32_t offset, int len) 516128944Sscottl{ 517128944Sscottl bus_space_write_region_4(sc->ha_frame_btag, sc->ha_frame_bhandle, 518128944Sscottl offset, (u_int32_t *)frame, len); 519128944Sscottl} 520128944Sscottl 52165312Smsmith/* 52296554Sobrien * Fill message with default. 52365312Smsmith */ 524128784Sscottlstatic PI2O_MESSAGE_FRAME 525128812SscottlASR_fillMessage(void *Message, u_int16_t size) 52665312Smsmith{ 527128784Sscottl PI2O_MESSAGE_FRAME Message_Ptr; 52865312Smsmith 529128812Sscottl Message_Ptr = (I2O_MESSAGE_FRAME *)Message; 530128787Sscottl bzero(Message_Ptr, size); 53196554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(Message_Ptr, I2O_VERSION_11); 53296554Sobrien I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr, 53396554Sobrien (size + sizeof(U32) - 1) >> 2); 53496554Sobrien I2O_MESSAGE_FRAME_setInitiatorAddress (Message_Ptr, 1); 535128908Sscottl KASSERT(Message_Ptr != NULL, ("Message_Ptr == NULL")); 53696554Sobrien return (Message_Ptr); 53765312Smsmith} /* ASR_fillMessage */ 53865312Smsmith 539155284Sscottl#define EMPTY_QUEUE (0xffffffff) 54065312Smsmith 541128784Sscottlstatic __inline U32 542128944SscottlASR_getMessage(Asr_softc_t *sc) 54365312Smsmith{ 544128784Sscottl U32 MessageOffset; 54565312Smsmith 546128944Sscottl MessageOffset = asr_get_ToFIFO(sc); 547128944Sscottl if (MessageOffset == EMPTY_QUEUE) 548128944Sscottl MessageOffset = asr_get_ToFIFO(sc); 549128944Sscottl 55096554Sobrien return (MessageOffset); 55165312Smsmith} /* ASR_getMessage */ 55265312Smsmith 55365312Smsmith/* Issue a polled command */ 554128784Sscottlstatic U32 555128944SscottlASR_initiateCp(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message) 55665312Smsmith{ 557155331Sscottl U32 Mask = 0xffffffff; 558128784Sscottl U32 MessageOffset; 559128784Sscottl u_int Delay = 1500; 56065312Smsmith 56196554Sobrien /* 56296554Sobrien * ASR_initiateCp is only used for synchronous commands and will 56396554Sobrien * be made more resiliant to adapter delays since commands like 56496554Sobrien * resetIOP can cause the adapter to be deaf for a little time. 56596554Sobrien */ 566128944Sscottl while (((MessageOffset = ASR_getMessage(sc)) == EMPTY_QUEUE) 56796554Sobrien && (--Delay != 0)) { 56896554Sobrien DELAY (10000); 56996554Sobrien } 57096554Sobrien if (MessageOffset != EMPTY_QUEUE) { 571128944Sscottl asr_set_frame(sc, Message, MessageOffset, 572128944Sscottl I2O_MESSAGE_FRAME_getMessageSize(Message)); 57396554Sobrien /* 57496554Sobrien * Disable the Interrupts 57596554Sobrien */ 576128944Sscottl Mask = asr_get_intr(sc); 577128944Sscottl asr_set_intr(sc, Mask | Mask_InterruptsDisabled); 578128944Sscottl asr_set_ToFIFO(sc, MessageOffset); 57996554Sobrien } 58096554Sobrien return (Mask); 58165312Smsmith} /* ASR_initiateCp */ 58265312Smsmith 58365312Smsmith/* 58496554Sobrien * Reset the adapter. 58565312Smsmith */ 586128784Sscottlstatic U32 587128944SscottlASR_resetIOP(Asr_softc_t *sc) 58865312Smsmith{ 589155307Sscottl I2O_EXEC_IOP_RESET_MESSAGE Message; 59096554Sobrien PI2O_EXEC_IOP_RESET_MESSAGE Message_Ptr; 591155286Sscottl U32 * Reply_Ptr; 59296554Sobrien U32 Old; 59365312Smsmith 59496554Sobrien /* 59596554Sobrien * Build up our copy of the Message. 59696554Sobrien */ 597128812Sscottl Message_Ptr = (PI2O_EXEC_IOP_RESET_MESSAGE)ASR_fillMessage(&Message, 59896554Sobrien sizeof(I2O_EXEC_IOP_RESET_MESSAGE)); 59996554Sobrien I2O_EXEC_IOP_RESET_MESSAGE_setFunction(Message_Ptr, I2O_EXEC_IOP_RESET); 60096554Sobrien /* 60196554Sobrien * Reset the Reply Status 60296554Sobrien */ 603155307Sscottl Reply_Ptr = &sc->ha_statusmem->rstatus; 604155286Sscottl *Reply_Ptr = 0; 60596554Sobrien I2O_EXEC_IOP_RESET_MESSAGE_setStatusWordLowAddress(Message_Ptr, 606155307Sscottl sc->ha_rstatus_phys); 60796554Sobrien /* 60896554Sobrien * Send the Message out 60996554Sobrien */ 610155284Sscottl if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) != 611155284Sscottl 0xffffffff) { 61296554Sobrien /* 613128786Sscottl * Wait for a response (Poll), timeouts are dangerous if 61496554Sobrien * the card is truly responsive. We assume response in 2s. 61596554Sobrien */ 61696554Sobrien u_int8_t Delay = 200; 61765312Smsmith 61896554Sobrien while ((*Reply_Ptr == 0) && (--Delay != 0)) { 61996554Sobrien DELAY (10000); 62096554Sobrien } 62196554Sobrien /* 62296554Sobrien * Re-enable the interrupts. 62396554Sobrien */ 624128944Sscottl asr_set_intr(sc, Old); 625128794Sscottl KASSERT(*Reply_Ptr != 0, ("*Reply_Ptr == 0")); 626128786Sscottl return(*Reply_Ptr); 62796554Sobrien } 628155331Sscottl KASSERT(Old != 0xffffffff, ("Old == -1")); 62996554Sobrien return (0); 63065312Smsmith} /* ASR_resetIOP */ 63165312Smsmith 63265312Smsmith/* 63396554Sobrien * Get the curent state of the adapter 63465312Smsmith */ 635128784Sscottlstatic PI2O_EXEC_STATUS_GET_REPLY 636155307SscottlASR_getStatus(Asr_softc_t *sc) 63765312Smsmith{ 638128812Sscottl I2O_EXEC_STATUS_GET_MESSAGE Message; 639128812Sscottl PI2O_EXEC_STATUS_GET_MESSAGE Message_Ptr; 640155307Sscottl PI2O_EXEC_STATUS_GET_REPLY buffer; 641128812Sscottl U32 Old; 64265312Smsmith 64396554Sobrien /* 64496554Sobrien * Build up our copy of the Message. 64596554Sobrien */ 646128812Sscottl Message_Ptr = (PI2O_EXEC_STATUS_GET_MESSAGE)ASR_fillMessage(&Message, 647128786Sscottl sizeof(I2O_EXEC_STATUS_GET_MESSAGE)); 64896554Sobrien I2O_EXEC_STATUS_GET_MESSAGE_setFunction(Message_Ptr, 649128786Sscottl I2O_EXEC_STATUS_GET); 65096554Sobrien I2O_EXEC_STATUS_GET_MESSAGE_setReplyBufferAddressLow(Message_Ptr, 651155307Sscottl sc->ha_status_phys); 65296554Sobrien /* This one is a Byte Count */ 65396554Sobrien I2O_EXEC_STATUS_GET_MESSAGE_setReplyBufferLength(Message_Ptr, 654128786Sscottl sizeof(I2O_EXEC_STATUS_GET_REPLY)); 65596554Sobrien /* 65696554Sobrien * Reset the Reply Status 65796554Sobrien */ 658155307Sscottl buffer = &sc->ha_statusmem->status; 659128787Sscottl bzero(buffer, sizeof(I2O_EXEC_STATUS_GET_REPLY)); 66096554Sobrien /* 66196554Sobrien * Send the Message out 66296554Sobrien */ 663155284Sscottl if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) != 664155284Sscottl 0xffffffff) { 66596554Sobrien /* 66696554Sobrien * Wait for a response (Poll), timeouts are dangerous if 66796554Sobrien * the card is truly responsive. We assume response in 50ms. 66896554Sobrien */ 66996554Sobrien u_int8_t Delay = 255; 67065312Smsmith 67196554Sobrien while (*((U8 * volatile)&(buffer->SyncByte)) == 0) { 67296554Sobrien if (--Delay == 0) { 673128511Sscottl buffer = NULL; 67496554Sobrien break; 67596554Sobrien } 67696554Sobrien DELAY (1000); 67796554Sobrien } 67896554Sobrien /* 67996554Sobrien * Re-enable the interrupts. 68096554Sobrien */ 681128944Sscottl asr_set_intr(sc, Old); 68296554Sobrien return (buffer); 68396554Sobrien } 684128511Sscottl return (NULL); 68565312Smsmith} /* ASR_getStatus */ 68665312Smsmith 68765312Smsmith/* 68896554Sobrien * Check if the device is a SCSI I2O HBA, and add it to the list. 68965312Smsmith */ 69065312Smsmith 69165312Smsmith/* 69265312Smsmith * Probe for ASR controller. If we find it, we will use it. 69365312Smsmith * virtual adapters. 69465312Smsmith */ 695128791Sscottlstatic int 696154363Sscottlasr_probe(device_t dev) 69765312Smsmith{ 698128791Sscottl u_int32_t id; 699128791Sscottl 700154363Sscottl id = (pci_get_device(dev) << 16) | pci_get_vendor(dev); 70196554Sobrien if ((id == 0xA5011044) || (id == 0xA5111044)) { 702154363Sscottl device_set_desc(dev, "Adaptec Caching SCSI RAID"); 703143163Simp return (BUS_PROBE_DEFAULT); 70496554Sobrien } 705128791Sscottl return (ENXIO); 70665312Smsmith} /* asr_probe */ 70765312Smsmith 708128784Sscottlstatic __inline union asr_ccb * 709128784Sscottlasr_alloc_ccb(Asr_softc_t *sc) 71065312Smsmith{ 711128784Sscottl union asr_ccb *new_ccb; 71265312Smsmith 71396554Sobrien if ((new_ccb = (union asr_ccb *)malloc(sizeof(*new_ccb), 714128511Sscottl M_DEVBUF, M_WAITOK | M_ZERO)) != NULL) { 71596554Sobrien new_ccb->ccb_h.pinfo.priority = 1; 71696554Sobrien new_ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX; 71796554Sobrien new_ccb->ccb_h.spriv_ptr0 = sc; 71896554Sobrien } 71996554Sobrien return (new_ccb); 72065312Smsmith} /* asr_alloc_ccb */ 72165312Smsmith 722128784Sscottlstatic __inline void 723128784Sscottlasr_free_ccb(union asr_ccb *free_ccb) 72465312Smsmith{ 72596554Sobrien free(free_ccb, M_DEVBUF); 72665312Smsmith} /* asr_free_ccb */ 72765312Smsmith 72865312Smsmith/* 72996554Sobrien * Print inquiry data `carefully' 73065312Smsmith */ 731128784Sscottlstatic void 732128784SscottlASR_prstring(u_int8_t *s, int len) 73365312Smsmith{ 73496554Sobrien while ((--len >= 0) && (*s) && (*s != ' ') && (*s != '-')) { 73596554Sobrien printf ("%c", *(s++)); 73696554Sobrien } 73765312Smsmith} /* ASR_prstring */ 73865312Smsmith 73965312Smsmith/* 74096554Sobrien * Send a message synchronously and without Interrupt to a ccb. 74165312Smsmith */ 742128784Sscottlstatic int 743128784SscottlASR_queue_s(union asr_ccb *ccb, PI2O_MESSAGE_FRAME Message) 74465312Smsmith{ 745128784Sscottl int s; 746128784Sscottl U32 Mask; 747128784Sscottl Asr_softc_t *sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0); 74865312Smsmith 74996554Sobrien /* 75096554Sobrien * We do not need any (optional byteswapping) method access to 75196554Sobrien * the Initiator context field. 75296554Sobrien */ 75396554Sobrien I2O_MESSAGE_FRAME_setInitiatorContext64(Message, (long)ccb); 75465312Smsmith 75596554Sobrien /* Prevent interrupt service */ 75696554Sobrien s = splcam (); 757128944Sscottl Mask = asr_get_intr(sc); 758128944Sscottl asr_set_intr(sc, Mask | Mask_InterruptsDisabled); 75965312Smsmith 760128944Sscottl if (ASR_queue(sc, Message) == EMPTY_QUEUE) { 76196554Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 76296554Sobrien ccb->ccb_h.status |= CAM_REQUEUE_REQ; 76396554Sobrien } 76465312Smsmith 76596554Sobrien /* 76696554Sobrien * Wait for this board to report a finished instruction. 76796554Sobrien */ 76896554Sobrien while ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 76996554Sobrien (void)asr_intr (sc); 77096554Sobrien } 77165312Smsmith 77296554Sobrien /* Re-enable Interrupts */ 773128944Sscottl asr_set_intr(sc, Mask); 77496554Sobrien splx(s); 77565312Smsmith 77696554Sobrien return (ccb->ccb_h.status); 77765312Smsmith} /* ASR_queue_s */ 77865312Smsmith 77965312Smsmith/* 780108533Sschweikh * Send a message synchronously to an Asr_softc_t. 78165312Smsmith */ 782128784Sscottlstatic int 783128784SscottlASR_queue_c(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message) 78465312Smsmith{ 785128784Sscottl union asr_ccb *ccb; 786128784Sscottl int status; 78765312Smsmith 788128511Sscottl if ((ccb = asr_alloc_ccb (sc)) == NULL) { 78996554Sobrien return (CAM_REQUEUE_REQ); 79096554Sobrien } 79165312Smsmith 79296554Sobrien status = ASR_queue_s (ccb, Message); 79365312Smsmith 79496554Sobrien asr_free_ccb(ccb); 79565312Smsmith 79696554Sobrien return (status); 79765312Smsmith} /* ASR_queue_c */ 79865312Smsmith 79965312Smsmith/* 80096554Sobrien * Add the specified ccb to the active queue 80165312Smsmith */ 802128784Sscottlstatic __inline void 803128784SscottlASR_ccbAdd(Asr_softc_t *sc, union asr_ccb *ccb) 80465312Smsmith{ 80596554Sobrien int s; 80666190Smsmith 80796554Sobrien s = splcam(); 80896554Sobrien LIST_INSERT_HEAD(&(sc->ha_ccb), &(ccb->ccb_h), sim_links.le); 80996554Sobrien if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { 81096554Sobrien if (ccb->ccb_h.timeout == CAM_TIME_DEFAULT) { 81196554Sobrien /* 81296554Sobrien * RAID systems can take considerable time to 81396554Sobrien * complete some commands given the large cache 81496554Sobrien * flashes switching from write back to write thru. 81596554Sobrien */ 81696554Sobrien ccb->ccb_h.timeout = 6 * 60 * 1000; 81796554Sobrien } 818275982Ssmh set_ccb_timeout_ch(ccb); 81996554Sobrien } 82096554Sobrien splx(s); 82165312Smsmith} /* ASR_ccbAdd */ 82265312Smsmith 82365312Smsmith/* 82496554Sobrien * Remove the specified ccb from the active queue. 82565312Smsmith */ 826128784Sscottlstatic __inline void 827128784SscottlASR_ccbRemove(Asr_softc_t *sc, union asr_ccb *ccb) 82865312Smsmith{ 82996554Sobrien int s; 83066190Smsmith 83196554Sobrien s = splcam(); 832255871Sscottl untimeout(asr_timeout, (caddr_t)ccb, get_ccb_timeout_ch(ccb)); 83396554Sobrien LIST_REMOVE(&(ccb->ccb_h), sim_links.le); 83496554Sobrien splx(s); 83565312Smsmith} /* ASR_ccbRemove */ 83665312Smsmith 83765312Smsmith/* 83896554Sobrien * Fail all the active commands, so they get re-issued by the operating 83996554Sobrien * system. 84065312Smsmith */ 841128784Sscottlstatic void 842128784SscottlASR_failActiveCommands(Asr_softc_t *sc) 84365312Smsmith{ 844128784Sscottl struct ccb_hdr *ccb; 845128784Sscottl int s; 84682092Sscottl 84796554Sobrien s = splcam(); 84896554Sobrien /* 84996554Sobrien * We do not need to inform the CAM layer that we had a bus 85096554Sobrien * reset since we manage it on our own, this also prevents the 85196554Sobrien * SCSI_DELAY settling that would be required on other systems. 85296554Sobrien * The `SCSI_DELAY' has already been handled by the card via the 85396554Sobrien * acquisition of the LCT table while we are at CAM priority level. 85496554Sobrien * for (int bus = 0; bus <= sc->ha_MaxBus; ++bus) { 85596554Sobrien * xpt_async (AC_BUS_RESET, sc->ha_path[bus], NULL); 85696554Sobrien * } 85796554Sobrien */ 858128511Sscottl while ((ccb = LIST_FIRST(&(sc->ha_ccb))) != NULL) { 85996554Sobrien ASR_ccbRemove (sc, (union asr_ccb *)ccb); 86065312Smsmith 86196554Sobrien ccb->status &= ~CAM_STATUS_MASK; 86296554Sobrien ccb->status |= CAM_REQUEUE_REQ; 86396554Sobrien /* Nothing Transfered */ 86496554Sobrien ((struct ccb_scsiio *)ccb)->resid 86596554Sobrien = ((struct ccb_scsiio *)ccb)->dxfer_len; 86665312Smsmith 86796554Sobrien if (ccb->path) { 86896554Sobrien xpt_done ((union ccb *)ccb); 86996554Sobrien } else { 870111748Sdes wakeup (ccb); 87196554Sobrien } 87296554Sobrien } 87396554Sobrien splx(s); 87465312Smsmith} /* ASR_failActiveCommands */ 87565312Smsmith 87665312Smsmith/* 87796554Sobrien * The following command causes the HBA to reset the specific bus 87865312Smsmith */ 879128784Sscottlstatic void 880128784SscottlASR_resetBus(Asr_softc_t *sc, int bus) 88165312Smsmith{ 882128812Sscottl I2O_HBA_BUS_RESET_MESSAGE Message; 883128812Sscottl I2O_HBA_BUS_RESET_MESSAGE *Message_Ptr; 884128812Sscottl PI2O_LCT_ENTRY Device; 88565312Smsmith 886128812Sscottl Message_Ptr = (I2O_HBA_BUS_RESET_MESSAGE *)ASR_fillMessage(&Message, 88796554Sobrien sizeof(I2O_HBA_BUS_RESET_MESSAGE)); 88896554Sobrien I2O_MESSAGE_FRAME_setFunction(&Message_Ptr->StdMessageFrame, 88996554Sobrien I2O_HBA_BUS_RESET); 89096554Sobrien for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY) 89196554Sobrien (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT)); 89296554Sobrien ++Device) { 89396554Sobrien if (((Device->le_type & I2O_PORT) != 0) 89496554Sobrien && (Device->le_bus == bus)) { 89596554Sobrien I2O_MESSAGE_FRAME_setTargetAddress( 89696554Sobrien &Message_Ptr->StdMessageFrame, 89796554Sobrien I2O_LCT_ENTRY_getLocalTID(Device)); 89896554Sobrien /* Asynchronous command, with no expectations */ 89996554Sobrien (void)ASR_queue(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 90096554Sobrien break; 90196554Sobrien } 90296554Sobrien } 90365312Smsmith} /* ASR_resetBus */ 90465312Smsmith 905128784Sscottlstatic __inline int 906128784SscottlASR_getBlinkLedCode(Asr_softc_t *sc) 90765312Smsmith{ 908128944Sscottl U8 blink; 909128944Sscottl 910128944Sscottl if (sc == NULL) 911128944Sscottl return (0); 912128944Sscottl 913128944Sscottl blink = bus_space_read_1(sc->ha_frame_btag, 914128944Sscottl sc->ha_frame_bhandle, sc->ha_blinkLED + 1); 915128944Sscottl if (blink != 0xBC) 916128944Sscottl return (0); 917128944Sscottl 918128944Sscottl blink = bus_space_read_1(sc->ha_frame_btag, 919128944Sscottl sc->ha_frame_bhandle, sc->ha_blinkLED); 920128944Sscottl return (blink); 92165312Smsmith} /* ASR_getBlinkCode */ 92265312Smsmith 92365312Smsmith/* 92496554Sobrien * Determine the address of an TID lookup. Must be done at high priority 92596554Sobrien * since the address can be changed by other threads of execution. 92665312Smsmith * 92796554Sobrien * Returns NULL pointer if not indexible (but will attempt to generate 92896554Sobrien * an index if `new_entry' flag is set to TRUE). 92965312Smsmith * 93096554Sobrien * All addressible entries are to be guaranteed zero if never initialized. 93165312Smsmith */ 932128784Sscottlstatic tid_t * 933128784SscottlASR_getTidAddress(Asr_softc_t *sc, int bus, int target, int lun, int new_entry) 93465312Smsmith{ 935128784Sscottl target2lun_t *bus_ptr; 936128784Sscottl lun2tid_t *target_ptr; 937128784Sscottl unsigned new_size; 93865312Smsmith 93996554Sobrien /* 94096554Sobrien * Validity checking of incoming parameters. More of a bound 94196554Sobrien * expansion limit than an issue with the code dealing with the 94296554Sobrien * values. 94396554Sobrien * 94496554Sobrien * sc must be valid before it gets here, so that check could be 94596554Sobrien * dropped if speed a critical issue. 94696554Sobrien */ 947128511Sscottl if ((sc == NULL) 94896554Sobrien || (bus > MAX_CHANNEL) 94996554Sobrien || (target > sc->ha_MaxId) 95096554Sobrien || (lun > sc->ha_MaxLun)) { 95196554Sobrien debug_asr_printf("(%lx,%d,%d,%d) target out of range\n", 95296554Sobrien (u_long)sc, bus, target, lun); 953128511Sscottl return (NULL); 95496554Sobrien } 95596554Sobrien /* 95696554Sobrien * See if there is an associated bus list. 95796554Sobrien * 95896554Sobrien * for performance, allocate in size of BUS_CHUNK chunks. 95996554Sobrien * BUS_CHUNK must be a power of two. This is to reduce 96096554Sobrien * fragmentation effects on the allocations. 96196554Sobrien */ 962128535Sscottl#define BUS_CHUNK 8 96396554Sobrien new_size = ((target + BUS_CHUNK - 1) & ~(BUS_CHUNK - 1)); 964128511Sscottl if ((bus_ptr = sc->ha_targets[bus]) == NULL) { 96596554Sobrien /* 96696554Sobrien * Allocate a new structure? 96796554Sobrien * Since one element in structure, the +1 96896554Sobrien * needed for size has been abstracted. 96996554Sobrien */ 97096554Sobrien if ((new_entry == FALSE) 97196554Sobrien || ((sc->ha_targets[bus] = bus_ptr = (target2lun_t *)malloc ( 97296554Sobrien sizeof(*bus_ptr) + (sizeof(bus_ptr->LUN) * new_size), 973111119Simp M_TEMP, M_WAITOK | M_ZERO)) 974128511Sscottl == NULL)) { 97596554Sobrien debug_asr_printf("failed to allocate bus list\n"); 976128511Sscottl return (NULL); 97796554Sobrien } 97896554Sobrien bus_ptr->size = new_size + 1; 97996554Sobrien } else if (bus_ptr->size <= new_size) { 98096554Sobrien target2lun_t * new_bus_ptr; 98165312Smsmith 98296554Sobrien /* 98396554Sobrien * Reallocate a new structure? 98496554Sobrien * Since one element in structure, the +1 98596554Sobrien * needed for size has been abstracted. 98696554Sobrien */ 98796554Sobrien if ((new_entry == FALSE) 98896554Sobrien || ((new_bus_ptr = (target2lun_t *)malloc ( 98996554Sobrien sizeof(*bus_ptr) + (sizeof(bus_ptr->LUN) * new_size), 990128511Sscottl M_TEMP, M_WAITOK | M_ZERO)) == NULL)) { 99196554Sobrien debug_asr_printf("failed to reallocate bus list\n"); 992128511Sscottl return (NULL); 99396554Sobrien } 99496554Sobrien /* 99596554Sobrien * Copy the whole thing, safer, simpler coding 99696554Sobrien * and not really performance critical at this point. 99796554Sobrien */ 998128786Sscottl bcopy(bus_ptr, new_bus_ptr, sizeof(*bus_ptr) 999128786Sscottl + (sizeof(bus_ptr->LUN) * (bus_ptr->size - 1))); 100096554Sobrien sc->ha_targets[bus] = new_bus_ptr; 1001128812Sscottl free(bus_ptr, M_TEMP); 100296554Sobrien bus_ptr = new_bus_ptr; 100396554Sobrien bus_ptr->size = new_size + 1; 100496554Sobrien } 100596554Sobrien /* 100696554Sobrien * We now have the bus list, lets get to the target list. 100796554Sobrien * Since most systems have only *one* lun, we do not allocate 100896554Sobrien * in chunks as above, here we allow one, then in chunk sizes. 100996554Sobrien * TARGET_CHUNK must be a power of two. This is to reduce 101096554Sobrien * fragmentation effects on the allocations. 101196554Sobrien */ 1012128535Sscottl#define TARGET_CHUNK 8 101396554Sobrien if ((new_size = lun) != 0) { 101496554Sobrien new_size = ((lun + TARGET_CHUNK - 1) & ~(TARGET_CHUNK - 1)); 101596554Sobrien } 1016128511Sscottl if ((target_ptr = bus_ptr->LUN[target]) == NULL) { 101796554Sobrien /* 101896554Sobrien * Allocate a new structure? 101996554Sobrien * Since one element in structure, the +1 102096554Sobrien * needed for size has been abstracted. 102196554Sobrien */ 102296554Sobrien if ((new_entry == FALSE) 102396554Sobrien || ((bus_ptr->LUN[target] = target_ptr = (lun2tid_t *)malloc ( 102496554Sobrien sizeof(*target_ptr) + (sizeof(target_ptr->TID) * new_size), 1025128511Sscottl M_TEMP, M_WAITOK | M_ZERO)) == NULL)) { 102696554Sobrien debug_asr_printf("failed to allocate target list\n"); 1027128511Sscottl return (NULL); 102896554Sobrien } 102996554Sobrien target_ptr->size = new_size + 1; 103096554Sobrien } else if (target_ptr->size <= new_size) { 103196554Sobrien lun2tid_t * new_target_ptr; 103265312Smsmith 103396554Sobrien /* 103496554Sobrien * Reallocate a new structure? 103596554Sobrien * Since one element in structure, the +1 103696554Sobrien * needed for size has been abstracted. 103796554Sobrien */ 103896554Sobrien if ((new_entry == FALSE) 103996554Sobrien || ((new_target_ptr = (lun2tid_t *)malloc ( 104096554Sobrien sizeof(*target_ptr) + (sizeof(target_ptr->TID) * new_size), 1041128511Sscottl M_TEMP, M_WAITOK | M_ZERO)) == NULL)) { 104296554Sobrien debug_asr_printf("failed to reallocate target list\n"); 1043128511Sscottl return (NULL); 104496554Sobrien } 104596554Sobrien /* 104696554Sobrien * Copy the whole thing, safer, simpler coding 104796554Sobrien * and not really performance critical at this point. 104896554Sobrien */ 1049128786Sscottl bcopy(target_ptr, new_target_ptr, sizeof(*target_ptr) 1050128786Sscottl + (sizeof(target_ptr->TID) * (target_ptr->size - 1))); 105196554Sobrien bus_ptr->LUN[target] = new_target_ptr; 1052128812Sscottl free(target_ptr, M_TEMP); 105396554Sobrien target_ptr = new_target_ptr; 105496554Sobrien target_ptr->size = new_size + 1; 105596554Sobrien } 105696554Sobrien /* 105796554Sobrien * Now, acquire the TID address from the LUN indexed list. 105896554Sobrien */ 105996554Sobrien return (&(target_ptr->TID[lun])); 106065312Smsmith} /* ASR_getTidAddress */ 106165312Smsmith 106265312Smsmith/* 106396554Sobrien * Get a pre-existing TID relationship. 106465312Smsmith * 106596554Sobrien * If the TID was never set, return (tid_t)-1. 106665312Smsmith * 106796554Sobrien * should use mutex rather than spl. 106865312Smsmith */ 1069128784Sscottlstatic __inline tid_t 1070128784SscottlASR_getTid(Asr_softc_t *sc, int bus, int target, int lun) 107165312Smsmith{ 1072128784Sscottl tid_t *tid_ptr; 1073128784Sscottl int s; 1074128784Sscottl tid_t retval; 107565312Smsmith 107696554Sobrien s = splcam(); 1077128511Sscottl if (((tid_ptr = ASR_getTidAddress(sc, bus, target, lun, FALSE)) == NULL) 107896554Sobrien /* (tid_t)0 or (tid_t)-1 indicate no TID */ 107996554Sobrien || (*tid_ptr == (tid_t)0)) { 108096554Sobrien splx(s); 108196554Sobrien return ((tid_t)-1); 108296554Sobrien } 108396554Sobrien retval = *tid_ptr; 108496554Sobrien splx(s); 108596554Sobrien return (retval); 108665312Smsmith} /* ASR_getTid */ 108765312Smsmith 108865312Smsmith/* 108996554Sobrien * Set a TID relationship. 109065312Smsmith * 109196554Sobrien * If the TID was not set, return (tid_t)-1. 109265312Smsmith * 109396554Sobrien * should use mutex rather than spl. 109465312Smsmith */ 1095128784Sscottlstatic __inline tid_t 1096128784SscottlASR_setTid(Asr_softc_t *sc, int bus, int target, int lun, tid_t TID) 109765312Smsmith{ 1098128784Sscottl tid_t *tid_ptr; 1099128784Sscottl int s; 110065312Smsmith 110196554Sobrien if (TID != (tid_t)-1) { 110296554Sobrien if (TID == 0) { 110396554Sobrien return ((tid_t)-1); 110496554Sobrien } 110596554Sobrien s = splcam(); 1106128784Sscottl if ((tid_ptr = ASR_getTidAddress(sc, bus, target, lun, TRUE)) 1107128511Sscottl == NULL) { 110896554Sobrien splx(s); 110996554Sobrien return ((tid_t)-1); 111096554Sobrien } 111196554Sobrien *tid_ptr = TID; 111296554Sobrien splx(s); 111396554Sobrien } 111496554Sobrien return (TID); 111565312Smsmith} /* ASR_setTid */ 111665312Smsmith 111765312Smsmith/*-------------------------------------------------------------------------*/ 111896554Sobrien/* Function ASR_rescan */ 111965312Smsmith/*-------------------------------------------------------------------------*/ 112096554Sobrien/* The Parameters Passed To This Function Are : */ 112196554Sobrien/* Asr_softc_t * : HBA miniport driver's adapter data storage. */ 112296554Sobrien/* */ 112396554Sobrien/* This Function Will rescan the adapter and resynchronize any data */ 112496554Sobrien/* */ 112596554Sobrien/* Return : 0 For OK, Error Code Otherwise */ 112665312Smsmith/*-------------------------------------------------------------------------*/ 112765312Smsmith 1128128784Sscottlstatic int 1129128784SscottlASR_rescan(Asr_softc_t *sc) 113065312Smsmith{ 1131128784Sscottl int bus; 1132128784Sscottl int error; 113365312Smsmith 113496554Sobrien /* 113596554Sobrien * Re-acquire the LCT table and synchronize us to the adapter. 113696554Sobrien */ 113796554Sobrien if ((error = ASR_acquireLct(sc)) == 0) { 113896554Sobrien error = ASR_acquireHrt(sc); 113996554Sobrien } 114065312Smsmith 114196554Sobrien if (error != 0) { 114296554Sobrien return error; 114396554Sobrien } 114465312Smsmith 114596554Sobrien bus = sc->ha_MaxBus; 114696554Sobrien /* Reset all existing cached TID lookups */ 114796554Sobrien do { 114896554Sobrien int target, event = 0; 114965312Smsmith 115096554Sobrien /* 115196554Sobrien * Scan for all targets on this bus to see if they 115296554Sobrien * got affected by the rescan. 115396554Sobrien */ 115496554Sobrien for (target = 0; target <= sc->ha_MaxId; ++target) { 115596554Sobrien int lun; 115665312Smsmith 115796554Sobrien /* Stay away from the controller ID */ 115896554Sobrien if (target == sc->ha_adapter_target[bus]) { 115996554Sobrien continue; 116096554Sobrien } 116196554Sobrien for (lun = 0; lun <= sc->ha_MaxLun; ++lun) { 116296554Sobrien PI2O_LCT_ENTRY Device; 116396554Sobrien tid_t TID = (tid_t)-1; 116496554Sobrien tid_t LastTID; 116565312Smsmith 116696554Sobrien /* 116796554Sobrien * See if the cached TID changed. Search for 116896554Sobrien * the device in our new LCT. 116996554Sobrien */ 117096554Sobrien for (Device = sc->ha_LCT->LCTEntry; 117196554Sobrien Device < (PI2O_LCT_ENTRY)(((U32 *)sc->ha_LCT) 117296554Sobrien + I2O_LCT_getTableSize(sc->ha_LCT)); 117396554Sobrien ++Device) { 117496554Sobrien if ((Device->le_type != I2O_UNKNOWN) 117596554Sobrien && (Device->le_bus == bus) 117696554Sobrien && (Device->le_target == target) 117796554Sobrien && (Device->le_lun == lun) 117896554Sobrien && (I2O_LCT_ENTRY_getUserTID(Device) 117996554Sobrien == 0xFFF)) { 118096554Sobrien TID = I2O_LCT_ENTRY_getLocalTID( 118196554Sobrien Device); 118296554Sobrien break; 118396554Sobrien } 118496554Sobrien } 118596554Sobrien /* 118696554Sobrien * Indicate to the OS that the label needs 118796554Sobrien * to be recalculated, or that the specific 118896554Sobrien * open device is no longer valid (Merde) 118996554Sobrien * because the cached TID changed. 119096554Sobrien */ 119196554Sobrien LastTID = ASR_getTid (sc, bus, target, lun); 119296554Sobrien if (LastTID != TID) { 119396554Sobrien struct cam_path * path; 119482092Sscottl 119596554Sobrien if (xpt_create_path(&path, 119696554Sobrien /*periph*/NULL, 119796554Sobrien cam_sim_path(sc->ha_sim[bus]), 119896554Sobrien target, lun) != CAM_REQ_CMP) { 119996554Sobrien if (TID == (tid_t)-1) { 120096554Sobrien event |= AC_LOST_DEVICE; 120196554Sobrien } else { 120296554Sobrien event |= AC_INQ_CHANGED 120396554Sobrien | AC_GETDEV_CHANGED; 120496554Sobrien } 120596554Sobrien } else { 120696554Sobrien if (TID == (tid_t)-1) { 120796554Sobrien xpt_async( 120896554Sobrien AC_LOST_DEVICE, 120996554Sobrien path, NULL); 121096554Sobrien } else if (LastTID == (tid_t)-1) { 121196554Sobrien struct ccb_getdev ccb; 121282092Sscottl 121396554Sobrien xpt_setup_ccb( 121496554Sobrien &(ccb.ccb_h), 121596554Sobrien path, /*priority*/5); 121696554Sobrien xpt_async( 121796554Sobrien AC_FOUND_DEVICE, 121896554Sobrien path, 121996554Sobrien &ccb); 122096554Sobrien } else { 122196554Sobrien xpt_async( 122296554Sobrien AC_INQ_CHANGED, 122396554Sobrien path, NULL); 122496554Sobrien xpt_async( 122596554Sobrien AC_GETDEV_CHANGED, 122696554Sobrien path, NULL); 122796554Sobrien } 122896554Sobrien } 122996554Sobrien } 123096554Sobrien /* 123196554Sobrien * We have the option of clearing the 123296554Sobrien * cached TID for it to be rescanned, or to 123396554Sobrien * set it now even if the device never got 123496554Sobrien * accessed. We chose the later since we 123596554Sobrien * currently do not use the condition that 123696554Sobrien * the TID ever got cached. 123796554Sobrien */ 123896554Sobrien ASR_setTid (sc, bus, target, lun, TID); 123996554Sobrien } 124096554Sobrien } 124196554Sobrien /* 124296554Sobrien * The xpt layer can not handle multiple events at the 124396554Sobrien * same call. 124496554Sobrien */ 124596554Sobrien if (event & AC_LOST_DEVICE) { 124696554Sobrien xpt_async(AC_LOST_DEVICE, sc->ha_path[bus], NULL); 124796554Sobrien } 124896554Sobrien if (event & AC_INQ_CHANGED) { 124996554Sobrien xpt_async(AC_INQ_CHANGED, sc->ha_path[bus], NULL); 125096554Sobrien } 125196554Sobrien if (event & AC_GETDEV_CHANGED) { 125296554Sobrien xpt_async(AC_GETDEV_CHANGED, sc->ha_path[bus], NULL); 125396554Sobrien } 125496554Sobrien } while (--bus >= 0); 125596554Sobrien return (error); 125665312Smsmith} /* ASR_rescan */ 125765312Smsmith 125865312Smsmith/*-------------------------------------------------------------------------*/ 125996554Sobrien/* Function ASR_reset */ 126065312Smsmith/*-------------------------------------------------------------------------*/ 126196554Sobrien/* The Parameters Passed To This Function Are : */ 126296554Sobrien/* Asr_softc_t * : HBA miniport driver's adapter data storage. */ 126396554Sobrien/* */ 126496554Sobrien/* This Function Will reset the adapter and resynchronize any data */ 126596554Sobrien/* */ 126696554Sobrien/* Return : None */ 126765312Smsmith/*-------------------------------------------------------------------------*/ 126865312Smsmith 1269128784Sscottlstatic int 1270128784SscottlASR_reset(Asr_softc_t *sc) 127165312Smsmith{ 1272128784Sscottl int s, retVal; 127382092Sscottl 127496554Sobrien s = splcam(); 127596554Sobrien if ((sc->ha_in_reset == HA_IN_RESET) 127696554Sobrien || (sc->ha_in_reset == HA_OFF_LINE_RECOVERY)) { 127796554Sobrien splx (s); 127896554Sobrien return (EBUSY); 127996554Sobrien } 128096554Sobrien /* 128196554Sobrien * Promotes HA_OPERATIONAL to HA_IN_RESET, 128296554Sobrien * or HA_OFF_LINE to HA_OFF_LINE_RECOVERY. 128396554Sobrien */ 128496554Sobrien ++(sc->ha_in_reset); 1285128944Sscottl if (ASR_resetIOP(sc) == 0) { 128696554Sobrien debug_asr_printf ("ASR_resetIOP failed\n"); 128796554Sobrien /* 128896554Sobrien * We really need to take this card off-line, easier said 128996554Sobrien * than make sense. Better to keep retrying for now since if a 129096554Sobrien * UART cable is connected the blinkLEDs the adapter is now in 129196554Sobrien * a hard state requiring action from the monitor commands to 129296554Sobrien * the HBA to continue. For debugging waiting forever is a 129396554Sobrien * good thing. In a production system, however, one may wish 129496554Sobrien * to instead take the card off-line ... 129596554Sobrien */ 1296128536Sscottl /* Wait Forever */ 1297128944Sscottl while (ASR_resetIOP(sc) == 0); 129896554Sobrien } 129996554Sobrien retVal = ASR_init (sc); 130096554Sobrien splx (s); 130196554Sobrien if (retVal != 0) { 130296554Sobrien debug_asr_printf ("ASR_init failed\n"); 130396554Sobrien sc->ha_in_reset = HA_OFF_LINE; 130496554Sobrien return (ENXIO); 130596554Sobrien } 130696554Sobrien if (ASR_rescan (sc) != 0) { 130796554Sobrien debug_asr_printf ("ASR_rescan failed\n"); 130896554Sobrien } 130996554Sobrien ASR_failActiveCommands (sc); 131096554Sobrien if (sc->ha_in_reset == HA_OFF_LINE_RECOVERY) { 131196554Sobrien printf ("asr%d: Brining adapter back on-line\n", 131296554Sobrien sc->ha_path[0] 131396554Sobrien ? cam_sim_unit(xpt_path_sim(sc->ha_path[0])) 131496554Sobrien : 0); 131596554Sobrien } 131696554Sobrien sc->ha_in_reset = HA_OPERATIONAL; 131796554Sobrien return (0); 131865312Smsmith} /* ASR_reset */ 131965312Smsmith 132065312Smsmith/* 132196554Sobrien * Device timeout handler. 132265312Smsmith */ 1323128784Sscottlstatic void 1324128784Sscottlasr_timeout(void *arg) 132565312Smsmith{ 1326128784Sscottl union asr_ccb *ccb = (union asr_ccb *)arg; 1327128784Sscottl Asr_softc_t *sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0); 132896554Sobrien int s; 132965312Smsmith 133096554Sobrien debug_asr_print_path(ccb); 133196554Sobrien debug_asr_printf("timed out"); 133265312Smsmith 133396554Sobrien /* 133496554Sobrien * Check if the adapter has locked up? 133596554Sobrien */ 133696554Sobrien if ((s = ASR_getBlinkLedCode(sc)) != 0) { 133796554Sobrien /* Reset Adapter */ 133896554Sobrien printf ("asr%d: Blink LED 0x%x resetting adapter\n", 133996554Sobrien cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)), s); 134096554Sobrien if (ASR_reset (sc) == ENXIO) { 134196554Sobrien /* Try again later */ 1342275982Ssmh set_ccb_timeout_ch(ccb); 134396554Sobrien } 134496554Sobrien return; 134596554Sobrien } 134696554Sobrien /* 134796554Sobrien * Abort does not function on the ASR card!!! Walking away from 134896554Sobrien * the SCSI command is also *very* dangerous. A SCSI BUS reset is 134996554Sobrien * our best bet, followed by a complete adapter reset if that fails. 135096554Sobrien */ 135196554Sobrien s = splcam(); 135296554Sobrien /* Check if we already timed out once to raise the issue */ 135396554Sobrien if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_CMD_TIMEOUT) { 135496554Sobrien debug_asr_printf (" AGAIN\nreinitializing adapter\n"); 135596554Sobrien if (ASR_reset (sc) == ENXIO) { 1356275982Ssmh set_ccb_timeout_ch(ccb); 135796554Sobrien } 135896554Sobrien splx(s); 135996554Sobrien return; 136096554Sobrien } 136196554Sobrien debug_asr_printf ("\nresetting bus\n"); 136296554Sobrien /* If the BUS reset does not take, then an adapter reset is next! */ 136396554Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 136496554Sobrien ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 1365275982Ssmh set_ccb_timeout_ch(ccb); 136696554Sobrien ASR_resetBus (sc, cam_sim_bus(xpt_path_sim(ccb->ccb_h.path))); 136796554Sobrien xpt_async (AC_BUS_RESET, ccb->ccb_h.path, NULL); 136896554Sobrien splx(s); 136965312Smsmith} /* asr_timeout */ 137065312Smsmith 137165312Smsmith/* 137265312Smsmith * send a message asynchronously 137365312Smsmith */ 1374128784Sscottlstatic int 1375128784SscottlASR_queue(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Message) 137665312Smsmith{ 1377128784Sscottl U32 MessageOffset; 1378128784Sscottl union asr_ccb *ccb; 137965312Smsmith 1380128786Sscottl debug_asr_printf("Host Command Dump:\n"); 1381128786Sscottl debug_asr_dump_message(Message); 138265312Smsmith 138396554Sobrien ccb = (union asr_ccb *)(long) 138496554Sobrien I2O_MESSAGE_FRAME_getInitiatorContext64(Message); 138565312Smsmith 1386128944Sscottl if ((MessageOffset = ASR_getMessage(sc)) != EMPTY_QUEUE) { 1387128944Sscottl asr_set_frame(sc, Message, MessageOffset, 1388128944Sscottl I2O_MESSAGE_FRAME_getMessageSize(Message)); 138996554Sobrien if (ccb) { 139096554Sobrien ASR_ccbAdd (sc, ccb); 139196554Sobrien } 139296554Sobrien /* Post the command */ 1393128944Sscottl asr_set_ToFIFO(sc, MessageOffset); 139496554Sobrien } else { 139596554Sobrien if (ASR_getBlinkLedCode(sc)) { 139696554Sobrien /* 139796554Sobrien * Unlikely we can do anything if we can't grab a 139896554Sobrien * message frame :-(, but lets give it a try. 139996554Sobrien */ 1400128784Sscottl (void)ASR_reset(sc); 140196554Sobrien } 140296554Sobrien } 140396554Sobrien return (MessageOffset); 140465312Smsmith} /* ASR_queue */ 140565312Smsmith 140665312Smsmith 140765312Smsmith/* Simple Scatter Gather elements */ 140896615Sobrien#define SG(SGL,Index,Flags,Buffer,Size) \ 140996554Sobrien I2O_FLAGS_COUNT_setCount( \ 141096554Sobrien &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index].FlagsCount), \ 141196554Sobrien Size); \ 141296554Sobrien I2O_FLAGS_COUNT_setFlags( \ 141396554Sobrien &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index].FlagsCount), \ 141496554Sobrien I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | (Flags)); \ 141596554Sobrien I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress( \ 141696554Sobrien &(((PI2O_SG_ELEMENT)(SGL))->u.Simple[Index]), \ 1417102291Sarchie (Buffer == NULL) ? 0 : KVTOPHYS(Buffer)) 141865312Smsmith 141965312Smsmith/* 142096554Sobrien * Retrieve Parameter Group. 142165312Smsmith */ 1422128784Sscottlstatic void * 1423128784SscottlASR_getParams(Asr_softc_t *sc, tid_t TID, int Group, void *Buffer, 1424128784Sscottl unsigned BufferSize) 142565312Smsmith{ 142696554Sobrien struct paramGetMessage { 142796554Sobrien I2O_UTIL_PARAMS_GET_MESSAGE M; 1428128784Sscottl char 1429128784Sscottl F[sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT)]; 143096554Sobrien struct Operations { 143196554Sobrien I2O_PARAM_OPERATIONS_LIST_HEADER Header; 143296554Sobrien I2O_PARAM_OPERATION_ALL_TEMPLATE Template[1]; 143396554Sobrien } O; 1434128812Sscottl } Message; 1435128812Sscottl struct Operations *Operations_Ptr; 1436128812Sscottl I2O_UTIL_PARAMS_GET_MESSAGE *Message_Ptr; 143796554Sobrien struct ParamBuffer { 143896554Sobrien I2O_PARAM_RESULTS_LIST_HEADER Header; 143996554Sobrien I2O_PARAM_READ_OPERATION_RESULT Read; 144096554Sobrien char Info[1]; 1441128812Sscottl } *Buffer_Ptr; 144265312Smsmith 1443128812Sscottl Message_Ptr = (I2O_UTIL_PARAMS_GET_MESSAGE *)ASR_fillMessage(&Message, 144496554Sobrien sizeof(I2O_UTIL_PARAMS_GET_MESSAGE) 144596554Sobrien + sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT)); 144696554Sobrien Operations_Ptr = (struct Operations *)((char *)Message_Ptr 144796554Sobrien + sizeof(I2O_UTIL_PARAMS_GET_MESSAGE) 144896554Sobrien + sizeof(I2O_SGE_SIMPLE_ELEMENT)*2 - sizeof(I2O_SG_ELEMENT)); 1449128787Sscottl bzero(Operations_Ptr, sizeof(struct Operations)); 145096554Sobrien I2O_PARAM_OPERATIONS_LIST_HEADER_setOperationCount( 145196554Sobrien &(Operations_Ptr->Header), 1); 145296554Sobrien I2O_PARAM_OPERATION_ALL_TEMPLATE_setOperation( 145396554Sobrien &(Operations_Ptr->Template[0]), I2O_PARAMS_OPERATION_FIELD_GET); 145496554Sobrien I2O_PARAM_OPERATION_ALL_TEMPLATE_setFieldCount( 145596554Sobrien &(Operations_Ptr->Template[0]), 0xFFFF); 145696554Sobrien I2O_PARAM_OPERATION_ALL_TEMPLATE_setGroupNumber( 145796554Sobrien &(Operations_Ptr->Template[0]), Group); 1458128812Sscottl Buffer_Ptr = (struct ParamBuffer *)Buffer; 1459128787Sscottl bzero(Buffer_Ptr, BufferSize); 146065312Smsmith 146196554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame), 146296554Sobrien I2O_VERSION_11 146396554Sobrien + (((sizeof(I2O_UTIL_PARAMS_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT)) 146496554Sobrien / sizeof(U32)) << 4)); 146596554Sobrien I2O_MESSAGE_FRAME_setTargetAddress (&(Message_Ptr->StdMessageFrame), 146696554Sobrien TID); 146796554Sobrien I2O_MESSAGE_FRAME_setFunction (&(Message_Ptr->StdMessageFrame), 146896554Sobrien I2O_UTIL_PARAMS_GET); 146996554Sobrien /* 147096554Sobrien * Set up the buffers as scatter gather elements. 147196554Sobrien */ 147296554Sobrien SG(&(Message_Ptr->SGL), 0, 147396554Sobrien I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER, 147496554Sobrien Operations_Ptr, sizeof(struct Operations)); 147596554Sobrien SG(&(Message_Ptr->SGL), 1, 147696554Sobrien I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, 147796554Sobrien Buffer_Ptr, BufferSize); 147865312Smsmith 147996554Sobrien if ((ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) == CAM_REQ_CMP) 148096554Sobrien && (Buffer_Ptr->Header.ResultCount)) { 148196554Sobrien return ((void *)(Buffer_Ptr->Info)); 148296554Sobrien } 1483128511Sscottl return (NULL); 148465312Smsmith} /* ASR_getParams */ 148565312Smsmith 148665312Smsmith/* 148796554Sobrien * Acquire the LCT information. 148865312Smsmith */ 1489128784Sscottlstatic int 1490128784SscottlASR_acquireLct(Asr_softc_t *sc) 149165312Smsmith{ 1492128784Sscottl PI2O_EXEC_LCT_NOTIFY_MESSAGE Message_Ptr; 1493128784Sscottl PI2O_SGE_SIMPLE_ELEMENT sg; 1494128784Sscottl int MessageSizeInBytes; 1495128784Sscottl caddr_t v; 1496128784Sscottl int len; 1497128784Sscottl I2O_LCT Table; 1498128784Sscottl PI2O_LCT_ENTRY Entry; 149965312Smsmith 150096554Sobrien /* 150196554Sobrien * sc value assumed valid 150296554Sobrien */ 1503128908Sscottl MessageSizeInBytes = sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE) - 1504128908Sscottl sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT); 1505128908Sscottl if ((Message_Ptr = (PI2O_EXEC_LCT_NOTIFY_MESSAGE)malloc( 1506128908Sscottl MessageSizeInBytes, M_TEMP, M_WAITOK)) == NULL) { 150796554Sobrien return (ENOMEM); 150896554Sobrien } 1509128812Sscottl (void)ASR_fillMessage((void *)Message_Ptr, MessageSizeInBytes); 151096554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame), 1511128908Sscottl (I2O_VERSION_11 + (((sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE) - 1512128908Sscottl sizeof(I2O_SG_ELEMENT)) / sizeof(U32)) << 4))); 151396554Sobrien I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame), 1514128908Sscottl I2O_EXEC_LCT_NOTIFY); 151596554Sobrien I2O_EXEC_LCT_NOTIFY_MESSAGE_setClassIdentifier(Message_Ptr, 1516128908Sscottl I2O_CLASS_MATCH_ANYCLASS); 151796554Sobrien /* 151896554Sobrien * Call the LCT table to determine the number of device entries 151996554Sobrien * to reserve space for. 152096554Sobrien */ 152196554Sobrien SG(&(Message_Ptr->SGL), 0, 152296554Sobrien I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, &Table, 152396554Sobrien sizeof(I2O_LCT)); 152496554Sobrien /* 152596554Sobrien * since this code is reused in several systems, code efficiency 152696554Sobrien * is greater by using a shift operation rather than a divide by 152796554Sobrien * sizeof(u_int32_t). 152896554Sobrien */ 152996554Sobrien I2O_LCT_setTableSize(&Table, 153096554Sobrien (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY)) >> 2); 153196554Sobrien (void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 153296554Sobrien /* 153396554Sobrien * Determine the size of the LCT table. 153496554Sobrien */ 153596554Sobrien if (sc->ha_LCT) { 1536128812Sscottl free(sc->ha_LCT, M_TEMP); 153796554Sobrien } 153896554Sobrien /* 153996554Sobrien * malloc only generates contiguous memory when less than a 154096554Sobrien * page is expected. We must break the request up into an SG list ... 154196554Sobrien */ 154296554Sobrien if (((len = (I2O_LCT_getTableSize(&Table) << 2)) <= 154396554Sobrien (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY))) 154496554Sobrien || (len > (128 * 1024))) { /* Arbitrary */ 1545128812Sscottl free(Message_Ptr, M_TEMP); 154696554Sobrien return (EINVAL); 154796554Sobrien } 1548128511Sscottl if ((sc->ha_LCT = (PI2O_LCT)malloc (len, M_TEMP, M_WAITOK)) == NULL) { 1549128812Sscottl free(Message_Ptr, M_TEMP); 155096554Sobrien return (ENOMEM); 155196554Sobrien } 155296554Sobrien /* 155396554Sobrien * since this code is reused in several systems, code efficiency 155496554Sobrien * is greater by using a shift operation rather than a divide by 155596554Sobrien * sizeof(u_int32_t). 155696554Sobrien */ 155796554Sobrien I2O_LCT_setTableSize(sc->ha_LCT, 155896554Sobrien (sizeof(I2O_LCT) - sizeof(I2O_LCT_ENTRY)) >> 2); 155996554Sobrien /* 156096554Sobrien * Convert the access to the LCT table into a SG list. 156196554Sobrien */ 156296554Sobrien sg = Message_Ptr->SGL.u.Simple; 156396554Sobrien v = (caddr_t)(sc->ha_LCT); 156496554Sobrien for (;;) { 156596554Sobrien int next, base, span; 156665312Smsmith 156796554Sobrien span = 0; 156896554Sobrien next = base = KVTOPHYS(v); 156996554Sobrien I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg, base); 157065312Smsmith 157196554Sobrien /* How far can we go contiguously */ 157296554Sobrien while ((len > 0) && (base == next)) { 157396554Sobrien int size; 157465312Smsmith 157596554Sobrien next = trunc_page(base) + PAGE_SIZE; 157696554Sobrien size = next - base; 157796554Sobrien if (size > len) { 157896554Sobrien size = len; 157996554Sobrien } 158096554Sobrien span += size; 158196554Sobrien v += size; 158296554Sobrien len -= size; 158396554Sobrien base = KVTOPHYS(v); 158496554Sobrien } 158565312Smsmith 158696554Sobrien /* Construct the Flags */ 158796554Sobrien I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount), span); 158896554Sobrien { 158996554Sobrien int rw = I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT; 159096554Sobrien if (len <= 0) { 159196554Sobrien rw = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT 159296554Sobrien | I2O_SGL_FLAGS_LAST_ELEMENT 159396554Sobrien | I2O_SGL_FLAGS_END_OF_BUFFER); 159496554Sobrien } 159596554Sobrien I2O_FLAGS_COUNT_setFlags(&(sg->FlagsCount), rw); 159696554Sobrien } 159765312Smsmith 159896554Sobrien if (len <= 0) { 159996554Sobrien break; 160096554Sobrien } 160165312Smsmith 160296554Sobrien /* 160396554Sobrien * Incrementing requires resizing of the packet. 160496554Sobrien */ 160596554Sobrien ++sg; 160696554Sobrien MessageSizeInBytes += sizeof(*sg); 160796554Sobrien I2O_MESSAGE_FRAME_setMessageSize( 160896554Sobrien &(Message_Ptr->StdMessageFrame), 160996554Sobrien I2O_MESSAGE_FRAME_getMessageSize( 161096554Sobrien &(Message_Ptr->StdMessageFrame)) 161196554Sobrien + (sizeof(*sg) / sizeof(U32))); 161296554Sobrien { 161396554Sobrien PI2O_EXEC_LCT_NOTIFY_MESSAGE NewMessage_Ptr; 161465312Smsmith 161596554Sobrien if ((NewMessage_Ptr = (PI2O_EXEC_LCT_NOTIFY_MESSAGE) 1616128511Sscottl malloc(MessageSizeInBytes, M_TEMP, M_WAITOK)) 1617128511Sscottl == NULL) { 1618128812Sscottl free(sc->ha_LCT, M_TEMP); 1619128511Sscottl sc->ha_LCT = NULL; 1620128812Sscottl free(Message_Ptr, M_TEMP); 162196554Sobrien return (ENOMEM); 162296554Sobrien } 162396554Sobrien span = ((caddr_t)sg) - (caddr_t)Message_Ptr; 1624128786Sscottl bcopy(Message_Ptr, NewMessage_Ptr, span); 1625128786Sscottl free(Message_Ptr, M_TEMP); 162696554Sobrien sg = (PI2O_SGE_SIMPLE_ELEMENT) 162796554Sobrien (((caddr_t)NewMessage_Ptr) + span); 162896554Sobrien Message_Ptr = NewMessage_Ptr; 162996554Sobrien } 163096554Sobrien } 163196554Sobrien { int retval; 163265312Smsmith 163396554Sobrien retval = ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 1634128812Sscottl free(Message_Ptr, M_TEMP); 163596554Sobrien if (retval != CAM_REQ_CMP) { 163696554Sobrien return (ENODEV); 163796554Sobrien } 163896554Sobrien } 163996554Sobrien /* If the LCT table grew, lets truncate accesses */ 164096554Sobrien if (I2O_LCT_getTableSize(&Table) < I2O_LCT_getTableSize(sc->ha_LCT)) { 164196554Sobrien I2O_LCT_setTableSize(sc->ha_LCT, I2O_LCT_getTableSize(&Table)); 164296554Sobrien } 164396554Sobrien for (Entry = sc->ha_LCT->LCTEntry; Entry < (PI2O_LCT_ENTRY) 164496554Sobrien (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT)); 164596554Sobrien ++Entry) { 164696554Sobrien Entry->le_type = I2O_UNKNOWN; 164796554Sobrien switch (I2O_CLASS_ID_getClass(&(Entry->ClassID))) { 164865312Smsmith 164996554Sobrien case I2O_CLASS_RANDOM_BLOCK_STORAGE: 165096554Sobrien Entry->le_type = I2O_BSA; 165196554Sobrien break; 165265312Smsmith 165396554Sobrien case I2O_CLASS_SCSI_PERIPHERAL: 165496554Sobrien Entry->le_type = I2O_SCSI; 165596554Sobrien break; 165665312Smsmith 165796554Sobrien case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: 165896554Sobrien Entry->le_type = I2O_FCA; 165996554Sobrien break; 166065312Smsmith 166196554Sobrien case I2O_CLASS_BUS_ADAPTER_PORT: 166296554Sobrien Entry->le_type = I2O_PORT | I2O_SCSI; 166396554Sobrien /* FALLTHRU */ 166496554Sobrien case I2O_CLASS_FIBRE_CHANNEL_PORT: 166596554Sobrien if (I2O_CLASS_ID_getClass(&(Entry->ClassID)) == 166696554Sobrien I2O_CLASS_FIBRE_CHANNEL_PORT) { 166796554Sobrien Entry->le_type = I2O_PORT | I2O_FCA; 166896554Sobrien } 166996554Sobrien { struct ControllerInfo { 167096554Sobrien I2O_PARAM_RESULTS_LIST_HEADER Header; 167196554Sobrien I2O_PARAM_READ_OPERATION_RESULT Read; 167296554Sobrien I2O_HBA_SCSI_CONTROLLER_INFO_SCALAR Info; 1673128812Sscottl } Buffer; 167496554Sobrien PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR Info; 167565312Smsmith 167696554Sobrien Entry->le_bus = 0xff; 167796554Sobrien Entry->le_target = 0xff; 167896554Sobrien Entry->le_lun = 0xff; 167965312Smsmith 168096554Sobrien if ((Info = (PI2O_HBA_SCSI_CONTROLLER_INFO_SCALAR) 168196554Sobrien ASR_getParams(sc, 168296554Sobrien I2O_LCT_ENTRY_getLocalTID(Entry), 168396554Sobrien I2O_HBA_SCSI_CONTROLLER_INFO_GROUP_NO, 1684128812Sscottl &Buffer, sizeof(struct ControllerInfo))) == NULL) { 168596554Sobrien continue; 168696554Sobrien } 168796554Sobrien Entry->le_target 168896554Sobrien = I2O_HBA_SCSI_CONTROLLER_INFO_SCALAR_getInitiatorID( 168996554Sobrien Info); 169096554Sobrien Entry->le_lun = 0; 169196554Sobrien } /* FALLTHRU */ 169296554Sobrien default: 169396554Sobrien continue; 169496554Sobrien } 169596554Sobrien { struct DeviceInfo { 169696554Sobrien I2O_PARAM_RESULTS_LIST_HEADER Header; 169796554Sobrien I2O_PARAM_READ_OPERATION_RESULT Read; 169896554Sobrien I2O_DPT_DEVICE_INFO_SCALAR Info; 1699128812Sscottl } Buffer; 170096554Sobrien PI2O_DPT_DEVICE_INFO_SCALAR Info; 170165312Smsmith 170296554Sobrien Entry->le_bus = 0xff; 170396554Sobrien Entry->le_target = 0xff; 170496554Sobrien Entry->le_lun = 0xff; 170565312Smsmith 170696554Sobrien if ((Info = (PI2O_DPT_DEVICE_INFO_SCALAR) 170796554Sobrien ASR_getParams(sc, 170896554Sobrien I2O_LCT_ENTRY_getLocalTID(Entry), 170996554Sobrien I2O_DPT_DEVICE_INFO_GROUP_NO, 1710128812Sscottl &Buffer, sizeof(struct DeviceInfo))) == NULL) { 171196554Sobrien continue; 171296554Sobrien } 171396554Sobrien Entry->le_type 171496554Sobrien |= I2O_DPT_DEVICE_INFO_SCALAR_getDeviceType(Info); 171596554Sobrien Entry->le_bus 171696554Sobrien = I2O_DPT_DEVICE_INFO_SCALAR_getBus(Info); 171796554Sobrien if ((Entry->le_bus > sc->ha_MaxBus) 171896554Sobrien && (Entry->le_bus <= MAX_CHANNEL)) { 171996554Sobrien sc->ha_MaxBus = Entry->le_bus; 172096554Sobrien } 172196554Sobrien Entry->le_target 172296554Sobrien = I2O_DPT_DEVICE_INFO_SCALAR_getIdentifier(Info); 172396554Sobrien Entry->le_lun 172496554Sobrien = I2O_DPT_DEVICE_INFO_SCALAR_getLunInfo(Info); 172596554Sobrien } 172696554Sobrien } 172796554Sobrien /* 172896554Sobrien * A zero return value indicates success. 172996554Sobrien */ 173096554Sobrien return (0); 173165312Smsmith} /* ASR_acquireLct */ 173265312Smsmith 173365312Smsmith/* 173465312Smsmith * Initialize a message frame. 173565312Smsmith * We assume that the CDB has already been set up, so all we do here is 173665312Smsmith * generate the Scatter Gather list. 173765312Smsmith */ 1738128784Sscottlstatic PI2O_MESSAGE_FRAME 1739128784SscottlASR_init_message(union asr_ccb *ccb, PI2O_MESSAGE_FRAME Message) 174065312Smsmith{ 1741128784Sscottl PI2O_MESSAGE_FRAME Message_Ptr; 174296554Sobrien PI2O_SGE_SIMPLE_ELEMENT sg; 1743128784Sscottl Asr_softc_t *sc = (Asr_softc_t *)(ccb->ccb_h.spriv_ptr0); 1744128784Sscottl vm_size_t size, len; 174596554Sobrien caddr_t v; 174696554Sobrien U32 MessageSize; 1747128784Sscottl int next, span, base, rw; 1748128784Sscottl int target = ccb->ccb_h.target_id; 1749128784Sscottl int lun = ccb->ccb_h.target_lun; 1750128784Sscottl int bus =cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); 1751128784Sscottl tid_t TID; 175265312Smsmith 175396554Sobrien /* We only need to zero out the PRIVATE_SCSI_SCB_EXECUTE_MESSAGE */ 1754128812Sscottl Message_Ptr = (I2O_MESSAGE_FRAME *)Message; 1755128784Sscottl bzero(Message_Ptr, (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) - 1756128784Sscottl sizeof(I2O_SG_ELEMENT))); 175765312Smsmith 1758128784Sscottl if ((TID = ASR_getTid (sc, bus, target, lun)) == (tid_t)-1) { 1759128784Sscottl PI2O_LCT_ENTRY Device; 176065312Smsmith 1761128784Sscottl TID = 0; 1762128784Sscottl for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY) 1763128784Sscottl (((U32 *)sc->ha_LCT) + I2O_LCT_getTableSize(sc->ha_LCT)); 1764128784Sscottl ++Device) { 1765128784Sscottl if ((Device->le_type != I2O_UNKNOWN) 1766128784Sscottl && (Device->le_bus == bus) 1767128784Sscottl && (Device->le_target == target) 1768128784Sscottl && (Device->le_lun == lun) 1769128784Sscottl && (I2O_LCT_ENTRY_getUserTID(Device) == 0xFFF)) { 1770128784Sscottl TID = I2O_LCT_ENTRY_getLocalTID(Device); 1771128784Sscottl ASR_setTid(sc, Device->le_bus, 1772128784Sscottl Device->le_target, Device->le_lun, 1773128784Sscottl TID); 1774128784Sscottl break; 177596554Sobrien } 177696554Sobrien } 177796554Sobrien } 1778128784Sscottl if (TID == (tid_t)0) { 1779128784Sscottl return (NULL); 1780128784Sscottl } 1781128784Sscottl I2O_MESSAGE_FRAME_setTargetAddress(Message_Ptr, TID); 1782128784Sscottl PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setTID( 1783128784Sscottl (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, TID); 178496554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(Message_Ptr, I2O_VERSION_11 | 178596554Sobrien (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) - sizeof(I2O_SG_ELEMENT)) 178696554Sobrien / sizeof(U32)) << 4)); 178796554Sobrien I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr, 178896554Sobrien (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 178996554Sobrien - sizeof(I2O_SG_ELEMENT)) / sizeof(U32)); 179096554Sobrien I2O_MESSAGE_FRAME_setInitiatorAddress (Message_Ptr, 1); 179196554Sobrien I2O_MESSAGE_FRAME_setFunction(Message_Ptr, I2O_PRIVATE_MESSAGE); 179296554Sobrien I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode ( 179396554Sobrien (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, I2O_SCSI_SCB_EXEC); 179496554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags ( 179596554Sobrien (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, 179696554Sobrien I2O_SCB_FLAG_ENABLE_DISCONNECT 179796554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 179896554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER); 179996554Sobrien /* 180096554Sobrien * We do not need any (optional byteswapping) method access to 180196554Sobrien * the Initiator & Transaction context field. 180296554Sobrien */ 180396554Sobrien I2O_MESSAGE_FRAME_setInitiatorContext64(Message, (long)ccb); 180465312Smsmith 180596554Sobrien I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID( 180696554Sobrien (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, DPT_ORGANIZATION_ID); 180796554Sobrien /* 180896554Sobrien * copy the cdb over 180996554Sobrien */ 181096554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength( 1811128786Sscottl (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, ccb->csio.cdb_len); 1812128786Sscottl bcopy(&(ccb->csio.cdb_io), 1813128786Sscottl ((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)->CDB, 1814128786Sscottl ccb->csio.cdb_len); 181565312Smsmith 181696554Sobrien /* 181796554Sobrien * Given a buffer describing a transfer, set up a scatter/gather map 181896554Sobrien * in a ccb to map that SCSI transfer. 181996554Sobrien */ 182065312Smsmith 182196554Sobrien rw = (ccb->ccb_h.flags & CAM_DIR_IN) ? 0 : I2O_SGL_FLAGS_DIR; 182265312Smsmith 182396554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags ( 182496554Sobrien (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, 182596554Sobrien (ccb->csio.dxfer_len) 182696554Sobrien ? ((rw) ? (I2O_SCB_FLAG_XFER_TO_DEVICE 182796554Sobrien | I2O_SCB_FLAG_ENABLE_DISCONNECT 182896554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 182996554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER) 183096554Sobrien : (I2O_SCB_FLAG_XFER_FROM_DEVICE 183196554Sobrien | I2O_SCB_FLAG_ENABLE_DISCONNECT 183296554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 183396554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER)) 183496554Sobrien : (I2O_SCB_FLAG_ENABLE_DISCONNECT 183596554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 183696554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER)); 183765312Smsmith 183896554Sobrien /* 183996554Sobrien * Given a transfer described by a `data', fill in the SG list. 184096554Sobrien */ 184196554Sobrien sg = &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)->SGL.u.Simple[0]; 184265312Smsmith 184396554Sobrien len = ccb->csio.dxfer_len; 184496554Sobrien v = ccb->csio.data_ptr; 1845128786Sscottl KASSERT(ccb->csio.dxfer_len >= 0, ("csio.dxfer_len < 0")); 184696554Sobrien MessageSize = I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr); 184796554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setByteCount( 184896554Sobrien (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, len); 184996554Sobrien while ((len > 0) && (sg < &((PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 185096554Sobrien Message_Ptr)->SGL.u.Simple[SG_SIZE])) { 185196554Sobrien span = 0; 185296554Sobrien next = base = KVTOPHYS(v); 185396554Sobrien I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg, base); 185465312Smsmith 185596554Sobrien /* How far can we go contiguously */ 185696554Sobrien while ((len > 0) && (base == next)) { 185796554Sobrien next = trunc_page(base) + PAGE_SIZE; 185896554Sobrien size = next - base; 185996554Sobrien if (size > len) { 186096554Sobrien size = len; 186196554Sobrien } 186296554Sobrien span += size; 186396554Sobrien v += size; 186496554Sobrien len -= size; 186596554Sobrien base = KVTOPHYS(v); 186696554Sobrien } 186765312Smsmith 186896554Sobrien I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount), span); 186996554Sobrien if (len == 0) { 187096554Sobrien rw |= I2O_SGL_FLAGS_LAST_ELEMENT; 187196554Sobrien } 187296554Sobrien I2O_FLAGS_COUNT_setFlags(&(sg->FlagsCount), 187396554Sobrien I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | rw); 187496554Sobrien ++sg; 187596554Sobrien MessageSize += sizeof(*sg) / sizeof(U32); 187696554Sobrien } 187796554Sobrien /* We always do the request sense ... */ 187896554Sobrien if ((span = ccb->csio.sense_len) == 0) { 187996554Sobrien span = sizeof(ccb->csio.sense_data); 188096554Sobrien } 188196554Sobrien SG(sg, 0, I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, 188296554Sobrien &(ccb->csio.sense_data), span); 188396554Sobrien I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr, 188496554Sobrien MessageSize + (sizeof(*sg) / sizeof(U32))); 188596554Sobrien return (Message_Ptr); 188665312Smsmith} /* ASR_init_message */ 188765312Smsmith 188865312Smsmith/* 188996554Sobrien * Reset the adapter. 189065312Smsmith */ 1891128784Sscottlstatic U32 1892128784SscottlASR_initOutBound(Asr_softc_t *sc) 189365312Smsmith{ 189496554Sobrien struct initOutBoundMessage { 189596554Sobrien I2O_EXEC_OUTBOUND_INIT_MESSAGE M; 189696554Sobrien U32 R; 1897128812Sscottl } Message; 1898128812Sscottl PI2O_EXEC_OUTBOUND_INIT_MESSAGE Message_Ptr; 1899128812Sscottl U32 *volatile Reply_Ptr; 1900128812Sscottl U32 Old; 190165312Smsmith 190296554Sobrien /* 190396554Sobrien * Build up our copy of the Message. 190496554Sobrien */ 1905128812Sscottl Message_Ptr = (PI2O_EXEC_OUTBOUND_INIT_MESSAGE)ASR_fillMessage(&Message, 190696554Sobrien sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE)); 190796554Sobrien I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame), 190896554Sobrien I2O_EXEC_OUTBOUND_INIT); 190996554Sobrien I2O_EXEC_OUTBOUND_INIT_MESSAGE_setHostPageFrameSize(Message_Ptr, PAGE_SIZE); 191096554Sobrien I2O_EXEC_OUTBOUND_INIT_MESSAGE_setOutboundMFrameSize(Message_Ptr, 191196554Sobrien sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)); 191296554Sobrien /* 191396554Sobrien * Reset the Reply Status 191496554Sobrien */ 191596554Sobrien *(Reply_Ptr = (U32 *)((char *)Message_Ptr 191696554Sobrien + sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE))) = 0; 191796554Sobrien SG (&(Message_Ptr->SGL), 0, I2O_SGL_FLAGS_LAST_ELEMENT, Reply_Ptr, 191896554Sobrien sizeof(U32)); 191996554Sobrien /* 192096554Sobrien * Send the Message out 192196554Sobrien */ 1922155284Sscottl if ((Old = ASR_initiateCp(sc, (PI2O_MESSAGE_FRAME)Message_Ptr)) != 1923155284Sscottl 0xffffffff) { 192496554Sobrien u_long size, addr; 192565312Smsmith 192696554Sobrien /* 192796554Sobrien * Wait for a response (Poll). 192896554Sobrien */ 192996554Sobrien while (*Reply_Ptr < I2O_EXEC_OUTBOUND_INIT_REJECTED); 193096554Sobrien /* 193196554Sobrien * Re-enable the interrupts. 193296554Sobrien */ 1933128944Sscottl asr_set_intr(sc, Old); 193496554Sobrien /* 193596554Sobrien * Populate the outbound table. 193696554Sobrien */ 1937128511Sscottl if (sc->ha_Msgs == NULL) { 193865312Smsmith 193996554Sobrien /* Allocate the reply frames */ 194096554Sobrien size = sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) 194196554Sobrien * sc->ha_Msgs_Count; 194265312Smsmith 194396554Sobrien /* 194496554Sobrien * contigmalloc only works reliably at 194596554Sobrien * initialization time. 194696554Sobrien */ 194796554Sobrien if ((sc->ha_Msgs = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) 1948111119Simp contigmalloc (size, M_DEVBUF, M_WAITOK, 0ul, 1949128511Sscottl 0xFFFFFFFFul, (u_long)sizeof(U32), 0ul)) != NULL) { 1950128787Sscottl bzero(sc->ha_Msgs, size); 195196554Sobrien sc->ha_Msgs_Phys = KVTOPHYS(sc->ha_Msgs); 195296554Sobrien } 195396554Sobrien } 195465312Smsmith 195596554Sobrien /* Initialize the outbound FIFO */ 1956128511Sscottl if (sc->ha_Msgs != NULL) 1957128944Sscottl for(size = sc->ha_Msgs_Count, addr = sc->ha_Msgs_Phys; 1958128944Sscottl size; --size) { 1959128944Sscottl asr_set_FromFIFO(sc, addr); 196096554Sobrien addr += sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME); 196196554Sobrien } 196296554Sobrien return (*Reply_Ptr); 196396554Sobrien } 196496554Sobrien return (0); 196565312Smsmith} /* ASR_initOutBound */ 196665312Smsmith 196765312Smsmith/* 196896554Sobrien * Set the system table 196965312Smsmith */ 1970128784Sscottlstatic int 1971128784SscottlASR_setSysTab(Asr_softc_t *sc) 197265312Smsmith{ 197396554Sobrien PI2O_EXEC_SYS_TAB_SET_MESSAGE Message_Ptr; 197496554Sobrien PI2O_SET_SYSTAB_HEADER SystemTable; 1975234503Sdim Asr_softc_t * ha, *next; 197696554Sobrien PI2O_SGE_SIMPLE_ELEMENT sg; 197796554Sobrien int retVal; 197865312Smsmith 197996554Sobrien if ((SystemTable = (PI2O_SET_SYSTAB_HEADER)malloc ( 1980128511Sscottl sizeof(I2O_SET_SYSTAB_HEADER), M_TEMP, M_WAITOK | M_ZERO)) == NULL) { 198196554Sobrien return (ENOMEM); 198296554Sobrien } 1983234503Sdim STAILQ_FOREACH(ha, &Asr_softc_list, ha_next) { 198496554Sobrien ++SystemTable->NumberEntries; 198596554Sobrien } 198696554Sobrien if ((Message_Ptr = (PI2O_EXEC_SYS_TAB_SET_MESSAGE)malloc ( 198796554Sobrien sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT) 198896554Sobrien + ((3+SystemTable->NumberEntries) * sizeof(I2O_SGE_SIMPLE_ELEMENT)), 1989128511Sscottl M_TEMP, M_WAITOK)) == NULL) { 1990128812Sscottl free(SystemTable, M_TEMP); 199196554Sobrien return (ENOMEM); 199296554Sobrien } 1993128908Sscottl (void)ASR_fillMessage((void *)Message_Ptr, 199496554Sobrien sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT) 199596554Sobrien + ((3+SystemTable->NumberEntries) * sizeof(I2O_SGE_SIMPLE_ELEMENT))); 199696554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame), 199796554Sobrien (I2O_VERSION_11 + 199896554Sobrien (((sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) - sizeof(I2O_SG_ELEMENT)) 199996554Sobrien / sizeof(U32)) << 4))); 200096554Sobrien I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame), 200196554Sobrien I2O_EXEC_SYS_TAB_SET); 200296554Sobrien /* 200396554Sobrien * Call the LCT table to determine the number of device entries 200496554Sobrien * to reserve space for. 200596554Sobrien * since this code is reused in several systems, code efficiency 200696554Sobrien * is greater by using a shift operation rather than a divide by 200796554Sobrien * sizeof(u_int32_t). 200896554Sobrien */ 200996554Sobrien sg = (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr 201096554Sobrien + ((I2O_MESSAGE_FRAME_getVersionOffset( 201196554Sobrien &(Message_Ptr->StdMessageFrame)) & 0xF0) >> 2)); 201296554Sobrien SG(sg, 0, I2O_SGL_FLAGS_DIR, SystemTable, sizeof(I2O_SET_SYSTAB_HEADER)); 201396554Sobrien ++sg; 2014234503Sdim STAILQ_FOREACH_SAFE(ha, &Asr_softc_list, ha_next, next) { 201596554Sobrien SG(sg, 0, 2016234503Sdim ((next) 201796554Sobrien ? (I2O_SGL_FLAGS_DIR) 201896554Sobrien : (I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER)), 201996554Sobrien &(ha->ha_SystemTable), sizeof(ha->ha_SystemTable)); 202096554Sobrien ++sg; 202196554Sobrien } 202296554Sobrien SG(sg, 0, I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_END_OF_BUFFER, NULL, 0); 202396554Sobrien SG(sg, 1, I2O_SGL_FLAGS_DIR | I2O_SGL_FLAGS_LAST_ELEMENT 202496554Sobrien | I2O_SGL_FLAGS_END_OF_BUFFER, NULL, 0); 202596554Sobrien retVal = ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 2026128812Sscottl free(Message_Ptr, M_TEMP); 2027128812Sscottl free(SystemTable, M_TEMP); 202896554Sobrien return (retVal); 202965312Smsmith} /* ASR_setSysTab */ 203065312Smsmith 2031128784Sscottlstatic int 2032128784SscottlASR_acquireHrt(Asr_softc_t *sc) 203365312Smsmith{ 2034128812Sscottl I2O_EXEC_HRT_GET_MESSAGE Message; 2035128812Sscottl I2O_EXEC_HRT_GET_MESSAGE *Message_Ptr; 203696554Sobrien struct { 203796554Sobrien I2O_HRT Header; 203896554Sobrien I2O_HRT_ENTRY Entry[MAX_CHANNEL]; 2039128812Sscottl } Hrt; 2040128812Sscottl u_int8_t NumberOfEntries; 2041128812Sscottl PI2O_HRT_ENTRY Entry; 204265312Smsmith 2043128787Sscottl bzero(&Hrt, sizeof (Hrt)); 2044128812Sscottl Message_Ptr = (I2O_EXEC_HRT_GET_MESSAGE *)ASR_fillMessage(&Message, 204596554Sobrien sizeof(I2O_EXEC_HRT_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT) 204696554Sobrien + sizeof(I2O_SGE_SIMPLE_ELEMENT)); 204796554Sobrien I2O_MESSAGE_FRAME_setVersionOffset(&(Message_Ptr->StdMessageFrame), 204896554Sobrien (I2O_VERSION_11 204996554Sobrien + (((sizeof(I2O_EXEC_HRT_GET_MESSAGE) - sizeof(I2O_SG_ELEMENT)) 205096554Sobrien / sizeof(U32)) << 4))); 205196554Sobrien I2O_MESSAGE_FRAME_setFunction (&(Message_Ptr->StdMessageFrame), 205296554Sobrien I2O_EXEC_HRT_GET); 205365312Smsmith 205496554Sobrien /* 205596554Sobrien * Set up the buffers as scatter gather elements. 205696554Sobrien */ 205796554Sobrien SG(&(Message_Ptr->SGL), 0, 205896554Sobrien I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, 205996554Sobrien &Hrt, sizeof(Hrt)); 206096554Sobrien if (ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) != CAM_REQ_CMP) { 206196554Sobrien return (ENODEV); 206296554Sobrien } 206396554Sobrien if ((NumberOfEntries = I2O_HRT_getNumberEntries(&Hrt.Header)) 206496554Sobrien > (MAX_CHANNEL + 1)) { 206596554Sobrien NumberOfEntries = MAX_CHANNEL + 1; 206696554Sobrien } 206796554Sobrien for (Entry = Hrt.Header.HRTEntry; 206896554Sobrien NumberOfEntries != 0; 206996554Sobrien ++Entry, --NumberOfEntries) { 207096554Sobrien PI2O_LCT_ENTRY Device; 207165312Smsmith 207296554Sobrien for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY) 207396554Sobrien (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT)); 207496554Sobrien ++Device) { 207596554Sobrien if (I2O_LCT_ENTRY_getLocalTID(Device) 207696554Sobrien == (I2O_HRT_ENTRY_getAdapterID(Entry) & 0xFFF)) { 207796554Sobrien Device->le_bus = I2O_HRT_ENTRY_getAdapterID( 207896554Sobrien Entry) >> 16; 207996554Sobrien if ((Device->le_bus > sc->ha_MaxBus) 208096554Sobrien && (Device->le_bus <= MAX_CHANNEL)) { 208196554Sobrien sc->ha_MaxBus = Device->le_bus; 208296554Sobrien } 208396554Sobrien } 208496554Sobrien } 208596554Sobrien } 208696554Sobrien return (0); 208765312Smsmith} /* ASR_acquireHrt */ 208865312Smsmith 208965312Smsmith/* 209096554Sobrien * Enable the adapter. 209165312Smsmith */ 2092128784Sscottlstatic int 2093128784SscottlASR_enableSys(Asr_softc_t *sc) 209465312Smsmith{ 2095128812Sscottl I2O_EXEC_SYS_ENABLE_MESSAGE Message; 2096128812Sscottl PI2O_EXEC_SYS_ENABLE_MESSAGE Message_Ptr; 209765312Smsmith 2098128812Sscottl Message_Ptr = (PI2O_EXEC_SYS_ENABLE_MESSAGE)ASR_fillMessage(&Message, 209996554Sobrien sizeof(I2O_EXEC_SYS_ENABLE_MESSAGE)); 210096554Sobrien I2O_MESSAGE_FRAME_setFunction(&(Message_Ptr->StdMessageFrame), 210196554Sobrien I2O_EXEC_SYS_ENABLE); 210296554Sobrien return (ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr) != 0); 210365312Smsmith} /* ASR_enableSys */ 210465312Smsmith 210565312Smsmith/* 210696554Sobrien * Perform the stages necessary to initialize the adapter 210765312Smsmith */ 2108128784Sscottlstatic int 2109128784SscottlASR_init(Asr_softc_t *sc) 211065312Smsmith{ 211196554Sobrien return ((ASR_initOutBound(sc) == 0) 211296554Sobrien || (ASR_setSysTab(sc) != CAM_REQ_CMP) 211396554Sobrien || (ASR_enableSys(sc) != CAM_REQ_CMP)); 211465312Smsmith} /* ASR_init */ 211565312Smsmith 211665312Smsmith/* 211796554Sobrien * Send a Synchronize Cache command to the target device. 211865312Smsmith */ 2119128784Sscottlstatic void 2120128784SscottlASR_sync(Asr_softc_t *sc, int bus, int target, int lun) 212165312Smsmith{ 2122128784Sscottl tid_t TID; 212365312Smsmith 212496554Sobrien /* 212596554Sobrien * We will not synchronize the device when there are outstanding 212696554Sobrien * commands issued by the OS (this is due to a locked up device, 212796554Sobrien * as the OS normally would flush all outstanding commands before 212896554Sobrien * issuing a shutdown or an adapter reset). 212996554Sobrien */ 2130128511Sscottl if ((sc != NULL) 2131128511Sscottl && (LIST_FIRST(&(sc->ha_ccb)) != NULL) 213296554Sobrien && ((TID = ASR_getTid (sc, bus, target, lun)) != (tid_t)-1) 213396554Sobrien && (TID != (tid_t)0)) { 2134128812Sscottl PRIVATE_SCSI_SCB_EXECUTE_MESSAGE Message; 2135128812Sscottl PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE Message_Ptr; 213665312Smsmith 2137128812Sscottl Message_Ptr = (PRIVATE_SCSI_SCB_EXECUTE_MESSAGE *)&Message; 2138128787Sscottl bzero(Message_Ptr, sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 2139128787Sscottl - sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT)); 214065312Smsmith 214196554Sobrien I2O_MESSAGE_FRAME_setVersionOffset( 214296554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, 214396554Sobrien I2O_VERSION_11 214496554Sobrien | (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 214596554Sobrien - sizeof(I2O_SG_ELEMENT)) 214696554Sobrien / sizeof(U32)) << 4)); 214796554Sobrien I2O_MESSAGE_FRAME_setMessageSize( 214896554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, 214996554Sobrien (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 215096554Sobrien - sizeof(I2O_SG_ELEMENT)) 215196554Sobrien / sizeof(U32)); 215296554Sobrien I2O_MESSAGE_FRAME_setInitiatorAddress ( 215396554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, 1); 215496554Sobrien I2O_MESSAGE_FRAME_setFunction( 215596554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_PRIVATE_MESSAGE); 215696554Sobrien I2O_MESSAGE_FRAME_setTargetAddress( 215796554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, TID); 215896554Sobrien I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode ( 215996554Sobrien (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, 216096554Sobrien I2O_SCSI_SCB_EXEC); 216196554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setTID(Message_Ptr, TID); 216296554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr, 216396554Sobrien I2O_SCB_FLAG_ENABLE_DISCONNECT 216496554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 216596554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER); 216696554Sobrien I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID( 216796554Sobrien (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, 216896554Sobrien DPT_ORGANIZATION_ID); 216996554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength(Message_Ptr, 6); 217096554Sobrien Message_Ptr->CDB[0] = SYNCHRONIZE_CACHE; 217196554Sobrien Message_Ptr->CDB[1] = (lun << 5); 217265312Smsmith 217396554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr, 217496554Sobrien (I2O_SCB_FLAG_XFER_FROM_DEVICE 217596554Sobrien | I2O_SCB_FLAG_ENABLE_DISCONNECT 217696554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 217796554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER)); 217865312Smsmith 217996554Sobrien (void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 218065312Smsmith 218196554Sobrien } 218265312Smsmith} 218365312Smsmith 2184128784Sscottlstatic void 2185128784SscottlASR_synchronize(Asr_softc_t *sc) 218665312Smsmith{ 2187128784Sscottl int bus, target, lun; 218865312Smsmith 218996554Sobrien for (bus = 0; bus <= sc->ha_MaxBus; ++bus) { 219096554Sobrien for (target = 0; target <= sc->ha_MaxId; ++target) { 219196554Sobrien for (lun = 0; lun <= sc->ha_MaxLun; ++lun) { 219296554Sobrien ASR_sync(sc,bus,target,lun); 219396554Sobrien } 219496554Sobrien } 219596554Sobrien } 219665312Smsmith} 219765312Smsmith 219865312Smsmith/* 219996554Sobrien * Reset the HBA, targets and BUS. 220096554Sobrien * Currently this resets *all* the SCSI busses. 220165312Smsmith */ 2202128784Sscottlstatic __inline void 2203128784Sscottlasr_hbareset(Asr_softc_t *sc) 220465312Smsmith{ 2205128784Sscottl ASR_synchronize(sc); 2206128784Sscottl (void)ASR_reset(sc); 220765312Smsmith} /* asr_hbareset */ 220865312Smsmith 220965312Smsmith/* 221096554Sobrien * A reduced copy of the real pci_map_mem, incorporating the MAX_MAP 221165312Smsmith * limit and a reduction in error checking (in the pre 4.0 case). 221265312Smsmith */ 2213128784Sscottlstatic int 2214154363Sscottlasr_pci_map_mem(device_t dev, Asr_softc_t *sc) 221565312Smsmith{ 2216128784Sscottl int rid; 2217128784Sscottl u_int32_t p, l, s; 221865312Smsmith 221996554Sobrien /* 222096554Sobrien * I2O specification says we must find first *memory* mapped BAR 222196554Sobrien */ 2222119690Sjhb for (rid = 0; rid < 4; rid++) { 2223154363Sscottl p = pci_read_config(dev, PCIR_BAR(rid), sizeof(p)); 222496554Sobrien if ((p & 1) == 0) { 222596554Sobrien break; 222696554Sobrien } 222796554Sobrien } 222896554Sobrien /* 222996554Sobrien * Give up? 223096554Sobrien */ 2231119690Sjhb if (rid >= 4) { 2232119690Sjhb rid = 0; 223396554Sobrien } 2234119690Sjhb rid = PCIR_BAR(rid); 2235154363Sscottl p = pci_read_config(dev, rid, sizeof(p)); 2236154363Sscottl pci_write_config(dev, rid, -1, sizeof(p)); 2237154363Sscottl l = 0 - (pci_read_config(dev, rid, sizeof(l)) & ~15); 2238154363Sscottl pci_write_config(dev, rid, p, sizeof(p)); 223996554Sobrien if (l > MAX_MAP) { 224096554Sobrien l = MAX_MAP; 224196554Sobrien } 224296554Sobrien /* 224396554Sobrien * The 2005S Zero Channel RAID solution is not a perfect PCI 224496554Sobrien * citizen. It asks for 4MB on BAR0, and 0MB on BAR1, once 224596554Sobrien * enabled it rewrites the size of BAR0 to 2MB, sets BAR1 to 224696554Sobrien * BAR0+2MB and sets it's size to 2MB. The IOP registers are 224796554Sobrien * accessible via BAR0, the messaging registers are accessible 224896554Sobrien * via BAR1. If the subdevice code is 50 to 59 decimal. 224996554Sobrien */ 2250154363Sscottl s = pci_read_config(dev, PCIR_DEVVENDOR, sizeof(s)); 225196554Sobrien if (s != 0xA5111044) { 2252154363Sscottl s = pci_read_config(dev, PCIR_SUBVEND_0, sizeof(s)); 225396554Sobrien if ((((ADPTDOMINATOR_SUB_ID_START ^ s) & 0xF000FFFF) == 0) 225496554Sobrien && (ADPTDOMINATOR_SUB_ID_START <= s) 225596554Sobrien && (s <= ADPTDOMINATOR_SUB_ID_END)) { 225696554Sobrien l = MAX_MAP; /* Conjoined BAR Raptor Daptor */ 225796554Sobrien } 225896554Sobrien } 225996554Sobrien p &= ~15; 2260154363Sscottl sc->ha_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 226196554Sobrien p, p + l, l, RF_ACTIVE); 2262128511Sscottl if (sc->ha_mem_res == NULL) { 226396554Sobrien return (0); 226496554Sobrien } 2265128944Sscottl sc->ha_Base = rman_get_start(sc->ha_mem_res); 2266128944Sscottl sc->ha_i2o_bhandle = rman_get_bushandle(sc->ha_mem_res); 2267128944Sscottl sc->ha_i2o_btag = rman_get_bustag(sc->ha_mem_res); 2268128944Sscottl 226996554Sobrien if (s == 0xA5111044) { /* Split BAR Raptor Daptor */ 2270119690Sjhb if ((rid += sizeof(u_int32_t)) >= PCIR_BAR(4)) { 227196554Sobrien return (0); 227296554Sobrien } 2273154363Sscottl p = pci_read_config(dev, rid, sizeof(p)); 2274154363Sscottl pci_write_config(dev, rid, -1, sizeof(p)); 2275154363Sscottl l = 0 - (pci_read_config(dev, rid, sizeof(l)) & ~15); 2276154363Sscottl pci_write_config(dev, rid, p, sizeof(p)); 227796554Sobrien if (l > MAX_MAP) { 227896554Sobrien l = MAX_MAP; 227996554Sobrien } 228096554Sobrien p &= ~15; 2281154363Sscottl sc->ha_mes_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 228296554Sobrien p, p + l, l, RF_ACTIVE); 2283128511Sscottl if (sc->ha_mes_res == NULL) { 228496554Sobrien return (0); 228596554Sobrien } 2286128944Sscottl sc->ha_frame_bhandle = rman_get_bushandle(sc->ha_mes_res); 2287128944Sscottl sc->ha_frame_btag = rman_get_bustag(sc->ha_mes_res); 228896554Sobrien } else { 2289128944Sscottl sc->ha_frame_bhandle = sc->ha_i2o_bhandle; 2290128944Sscottl sc->ha_frame_btag = sc->ha_i2o_btag; 229196554Sobrien } 229296554Sobrien return (1); 229365312Smsmith} /* asr_pci_map_mem */ 229465312Smsmith 229565312Smsmith/* 229696554Sobrien * A simplified copy of the real pci_map_int with additional 229765312Smsmith * registration requirements. 229865312Smsmith */ 2299128784Sscottlstatic int 2300154363Sscottlasr_pci_map_int(device_t dev, Asr_softc_t *sc) 230165312Smsmith{ 2302128784Sscottl int rid = 0; 230365312Smsmith 2304154363Sscottl sc->ha_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 2305127135Snjl RF_ACTIVE | RF_SHAREABLE); 2306128511Sscottl if (sc->ha_irq_res == NULL) { 230796554Sobrien return (0); 230896554Sobrien } 2309154363Sscottl if (bus_setup_intr(dev, sc->ha_irq_res, INTR_TYPE_CAM | INTR_ENTROPY, 2310166901Spiso NULL, (driver_intr_t *)asr_intr, (void *)sc, &(sc->ha_intr))) { 231196554Sobrien return (0); 231296554Sobrien } 2313154363Sscottl sc->ha_irq = pci_read_config(dev, PCIR_INTLINE, sizeof(char)); 231496554Sobrien return (1); 231565312Smsmith} /* asr_pci_map_int */ 231665312Smsmith 2317155286Sscottlstatic void 2318155286Sscottlasr_status_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2319155286Sscottl{ 2320155286Sscottl Asr_softc_t *sc; 2321155286Sscottl 2322155286Sscottl if (error) 2323155286Sscottl return; 2324155286Sscottl 2325155286Sscottl sc = (Asr_softc_t *)arg; 2326155286Sscottl 2327155286Sscottl /* XXX 2328155286Sscottl * The status word can be at a 64-bit address, but the existing 2329155286Sscottl * accessor macros simply cannot manipulate 64-bit addresses. 2330155286Sscottl */ 2331155307Sscottl sc->ha_status_phys = (u_int32_t)segs[0].ds_addr + 2332155307Sscottl offsetof(struct Asr_status_mem, status); 2333155307Sscottl sc->ha_rstatus_phys = (u_int32_t)segs[0].ds_addr + 2334155307Sscottl offsetof(struct Asr_status_mem, rstatus); 2335155286Sscottl} 2336155286Sscottl 2337155286Sscottlstatic int 2338155286Sscottlasr_alloc_dma(Asr_softc_t *sc) 2339155286Sscottl{ 2340155286Sscottl device_t dev; 2341155286Sscottl 2342155286Sscottl dev = sc->ha_dev; 2343155286Sscottl 2344232854Sscottl if (bus_dma_tag_create(bus_get_dma_tag(dev), /* PCI parent */ 2345155286Sscottl 1, 0, /* algnmnt, boundary */ 2346155286Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 2347155286Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 2348155286Sscottl NULL, NULL, /* filter, filterarg */ 2349155286Sscottl BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 2350155286Sscottl BUS_SPACE_UNRESTRICTED, /* nsegments */ 2351155286Sscottl BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 2352155286Sscottl 0, /* flags */ 2353155286Sscottl NULL, NULL, /* lockfunc, lockarg */ 2354155286Sscottl &sc->ha_parent_dmat)) { 2355155286Sscottl device_printf(dev, "Cannot allocate parent DMA tag\n"); 2356155286Sscottl return (ENOMEM); 2357155286Sscottl } 2358155286Sscottl 2359155286Sscottl if (bus_dma_tag_create(sc->ha_parent_dmat, /* parent */ 2360155286Sscottl 1, 0, /* algnmnt, boundary */ 2361155286Sscottl BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 2362155286Sscottl BUS_SPACE_MAXADDR, /* highaddr */ 2363155286Sscottl NULL, NULL, /* filter, filterarg */ 2364155307Sscottl sizeof(sc->ha_statusmem),/* maxsize */ 2365155286Sscottl 1, /* nsegments */ 2366155307Sscottl sizeof(sc->ha_statusmem),/* maxsegsize */ 2367155286Sscottl 0, /* flags */ 2368155286Sscottl NULL, NULL, /* lockfunc, lockarg */ 2369155307Sscottl &sc->ha_statusmem_dmat)) { 2370155286Sscottl device_printf(dev, "Cannot allocate status DMA tag\n"); 2371155286Sscottl bus_dma_tag_destroy(sc->ha_parent_dmat); 2372155286Sscottl return (ENOMEM); 2373155286Sscottl } 2374155286Sscottl 2375155307Sscottl if (bus_dmamem_alloc(sc->ha_statusmem_dmat, (void **)&sc->ha_statusmem, 2376155307Sscottl BUS_DMA_NOWAIT, &sc->ha_statusmem_dmamap)) { 2377155286Sscottl device_printf(dev, "Cannot allocate status memory\n"); 2378155307Sscottl bus_dma_tag_destroy(sc->ha_statusmem_dmat); 2379155286Sscottl bus_dma_tag_destroy(sc->ha_parent_dmat); 2380155286Sscottl return (ENOMEM); 2381155286Sscottl } 2382155307Sscottl (void)bus_dmamap_load(sc->ha_statusmem_dmat, sc->ha_statusmem_dmamap, 2383155307Sscottl sc->ha_statusmem, sizeof(sc->ha_statusmem), asr_status_cb, sc, 0); 2384155286Sscottl 2385155286Sscottl return (0); 2386155286Sscottl} 2387155286Sscottl 2388155286Sscottlstatic void 2389155286Sscottlasr_release_dma(Asr_softc_t *sc) 2390155286Sscottl{ 2391155286Sscottl 2392155307Sscottl if (sc->ha_rstatus_phys != 0) 2393155307Sscottl bus_dmamap_unload(sc->ha_statusmem_dmat, 2394155307Sscottl sc->ha_statusmem_dmamap); 2395155307Sscottl if (sc->ha_statusmem != NULL) 2396155307Sscottl bus_dmamem_free(sc->ha_statusmem_dmat, sc->ha_statusmem, 2397155307Sscottl sc->ha_statusmem_dmamap); 2398155307Sscottl if (sc->ha_statusmem_dmat != NULL) 2399155307Sscottl bus_dma_tag_destroy(sc->ha_statusmem_dmat); 2400155286Sscottl if (sc->ha_parent_dmat != NULL) 2401155286Sscottl bus_dma_tag_destroy(sc->ha_parent_dmat); 2402155286Sscottl} 2403155286Sscottl 240465312Smsmith/* 240596554Sobrien * Attach the devices, and virtual devices to the driver list. 240665312Smsmith */ 2407128791Sscottlstatic int 2408154363Sscottlasr_attach(device_t dev) 240965312Smsmith{ 2410128793Sscottl PI2O_EXEC_STATUS_GET_REPLY status; 2411128793Sscottl PI2O_LCT_ENTRY Device; 2412234503Sdim Asr_softc_t *sc; 2413128784Sscottl struct scsi_inquiry_data *iq; 2414154363Sscottl int bus, size, unit; 2415155286Sscottl int error; 241665312Smsmith 2417154363Sscottl sc = device_get_softc(dev); 2418154363Sscottl unit = device_get_unit(dev); 2419155286Sscottl sc->ha_dev = dev; 2420154363Sscottl 2421234503Sdim if (STAILQ_EMPTY(&Asr_softc_list)) { 242296554Sobrien /* 242396554Sobrien * Fixup the OS revision as saved in the dptsig for the 242496554Sobrien * engine (dptioctl.h) to pick up. 242596554Sobrien */ 2426128786Sscottl bcopy(osrelease, &ASR_sig.dsDescription[16], 5); 242796554Sobrien } 242896554Sobrien /* 242996554Sobrien * Initialize the software structure 243096554Sobrien */ 243196554Sobrien LIST_INIT(&(sc->ha_ccb)); 243296554Sobrien /* Link us into the HA list */ 2433234503Sdim STAILQ_INSERT_TAIL(&Asr_softc_list, sc, ha_next); 2434128793Sscottl 2435128793Sscottl /* 2436128793Sscottl * This is the real McCoy! 2437128793Sscottl */ 2438154363Sscottl if (!asr_pci_map_mem(dev, sc)) { 2439154363Sscottl device_printf(dev, "could not map memory\n"); 2440128793Sscottl return(ENXIO); 2441128793Sscottl } 2442128793Sscottl /* Enable if not formerly enabled */ 2443254263Sscottl pci_enable_busmaster(dev); 2444154364Sscottl 2445154364Sscottl sc->ha_pciBusNum = pci_get_bus(dev); 2446154364Sscottl sc->ha_pciDeviceNum = (pci_get_slot(dev) << 3) | pci_get_function(dev); 2447154364Sscottl 2448155286Sscottl if ((error = asr_alloc_dma(sc)) != 0) 2449155286Sscottl return (error); 2450155286Sscottl 2451128793Sscottl /* Check if the device is there? */ 2452155274Sscottl if (ASR_resetIOP(sc) == 0) { 2453155274Sscottl device_printf(dev, "Cannot reset adapter\n"); 2454155286Sscottl asr_release_dma(sc); 2455155274Sscottl return (EIO); 2456155274Sscottl } 2457155307Sscottl status = &sc->ha_statusmem->status; 2458155307Sscottl if (ASR_getStatus(sc) == NULL) { 2459154363Sscottl device_printf(dev, "could not initialize hardware\n"); 2460155286Sscottl asr_release_dma(sc); 2461155274Sscottl return(ENODEV); 2462128793Sscottl } 2463128793Sscottl sc->ha_SystemTable.OrganizationID = status->OrganizationID; 2464128793Sscottl sc->ha_SystemTable.IOP_ID = status->IOP_ID; 2465128793Sscottl sc->ha_SystemTable.I2oVersion = status->I2oVersion; 2466128793Sscottl sc->ha_SystemTable.IopState = status->IopState; 2467128793Sscottl sc->ha_SystemTable.MessengerType = status->MessengerType; 2468128793Sscottl sc->ha_SystemTable.InboundMessageFrameSize = status->InboundMFrameSize; 2469128793Sscottl sc->ha_SystemTable.MessengerInfo.InboundMessagePortAddressLow = 2470128944Sscottl (U32)(sc->ha_Base + I2O_REG_TOFIFO); /* XXX 64-bit */ 247165312Smsmith 2472154363Sscottl if (!asr_pci_map_int(dev, (void *)sc)) { 2473154363Sscottl device_printf(dev, "could not map interrupt\n"); 2474155286Sscottl asr_release_dma(sc); 2475128793Sscottl return(ENXIO); 2476128793Sscottl } 247765312Smsmith 2478128793Sscottl /* Adjust the maximim inbound count */ 2479128793Sscottl if (((sc->ha_QueueSize = 2480128793Sscottl I2O_EXEC_STATUS_GET_REPLY_getMaxInboundMFrames(status)) > 2481128793Sscottl MAX_INBOUND) || (sc->ha_QueueSize == 0)) { 2482128793Sscottl sc->ha_QueueSize = MAX_INBOUND; 2483128793Sscottl } 248465312Smsmith 2485128793Sscottl /* Adjust the maximum outbound count */ 2486128793Sscottl if (((sc->ha_Msgs_Count = 2487128793Sscottl I2O_EXEC_STATUS_GET_REPLY_getMaxOutboundMFrames(status)) > 2488128793Sscottl MAX_OUTBOUND) || (sc->ha_Msgs_Count == 0)) { 2489128793Sscottl sc->ha_Msgs_Count = MAX_OUTBOUND; 2490128793Sscottl } 2491128793Sscottl if (sc->ha_Msgs_Count > sc->ha_QueueSize) { 2492128793Sscottl sc->ha_Msgs_Count = sc->ha_QueueSize; 2493128793Sscottl } 249465312Smsmith 2495128793Sscottl /* Adjust the maximum SG size to adapter */ 2496128793Sscottl if ((size = (I2O_EXEC_STATUS_GET_REPLY_getInboundMFrameSize(status) << 2497128793Sscottl 2)) > MAX_INBOUND_SIZE) { 2498128793Sscottl size = MAX_INBOUND_SIZE; 249996554Sobrien } 2500128793Sscottl sc->ha_SgSize = (size - sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 2501128793Sscottl + sizeof(I2O_SG_ELEMENT)) / sizeof(I2O_SGE_SIMPLE_ELEMENT); 250265312Smsmith 250396554Sobrien /* 250496554Sobrien * Only do a bus/HBA reset on the first time through. On this 250596554Sobrien * first time through, we do not send a flush to the devices. 250696554Sobrien */ 250796554Sobrien if (ASR_init(sc) == 0) { 250896554Sobrien struct BufferInfo { 250996554Sobrien I2O_PARAM_RESULTS_LIST_HEADER Header; 251096554Sobrien I2O_PARAM_READ_OPERATION_RESULT Read; 251196554Sobrien I2O_DPT_EXEC_IOP_BUFFERS_SCALAR Info; 2512128812Sscottl } Buffer; 251396554Sobrien PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR Info; 2514128535Sscottl#define FW_DEBUG_BLED_OFFSET 8 251565312Smsmith 251696554Sobrien if ((Info = (PI2O_DPT_EXEC_IOP_BUFFERS_SCALAR) 2517128944Sscottl ASR_getParams(sc, 0, I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO, 2518128812Sscottl &Buffer, sizeof(struct BufferInfo))) != NULL) { 2519128944Sscottl sc->ha_blinkLED = FW_DEBUG_BLED_OFFSET + 2520128944Sscottl I2O_DPT_EXEC_IOP_BUFFERS_SCALAR_getSerialOutputOffset(Info); 252196554Sobrien } 252296554Sobrien if (ASR_acquireLct(sc) == 0) { 252396554Sobrien (void)ASR_acquireHrt(sc); 252496554Sobrien } 252596554Sobrien } else { 2526154363Sscottl device_printf(dev, "failed to initialize\n"); 2527155286Sscottl asr_release_dma(sc); 2528128791Sscottl return(ENXIO); 252996554Sobrien } 253096554Sobrien /* 253196554Sobrien * Add in additional probe responses for more channels. We 253296554Sobrien * are reusing the variable `target' for a channel loop counter. 253396554Sobrien * Done here because of we need both the acquireLct and 253496554Sobrien * acquireHrt data. 253596554Sobrien */ 2536128793Sscottl for (Device = sc->ha_LCT->LCTEntry; Device < (PI2O_LCT_ENTRY) 2537128793Sscottl (((U32 *)sc->ha_LCT)+I2O_LCT_getTableSize(sc->ha_LCT)); ++Device) { 2538128793Sscottl if (Device->le_type == I2O_UNKNOWN) { 2539128793Sscottl continue; 2540128793Sscottl } 2541128793Sscottl if (I2O_LCT_ENTRY_getUserTID(Device) == 0xFFF) { 2542128793Sscottl if (Device->le_target > sc->ha_MaxId) { 2543128793Sscottl sc->ha_MaxId = Device->le_target; 254496554Sobrien } 2545128793Sscottl if (Device->le_lun > sc->ha_MaxLun) { 2546128793Sscottl sc->ha_MaxLun = Device->le_lun; 254796554Sobrien } 254896554Sobrien } 2549128793Sscottl if (((Device->le_type & I2O_PORT) != 0) 2550128793Sscottl && (Device->le_bus <= MAX_CHANNEL)) { 2551128793Sscottl /* Do not increase MaxId for efficiency */ 2552128793Sscottl sc->ha_adapter_target[Device->le_bus] = 2553128793Sscottl Device->le_target; 2554128793Sscottl } 255596554Sobrien } 255665312Smsmith 255796554Sobrien /* 255896554Sobrien * Print the HBA model number as inquired from the card. 255996554Sobrien */ 256065312Smsmith 2561154363Sscottl device_printf(dev, " "); 256265312Smsmith 2563128793Sscottl if ((iq = (struct scsi_inquiry_data *)malloc( 2564128793Sscottl sizeof(struct scsi_inquiry_data), M_TEMP, M_WAITOK | M_ZERO)) != 2565128793Sscottl NULL) { 2566128812Sscottl PRIVATE_SCSI_SCB_EXECUTE_MESSAGE Message; 2567128812Sscottl PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE Message_Ptr; 2568128812Sscottl int posted = 0; 256965312Smsmith 2570128812Sscottl Message_Ptr = (PRIVATE_SCSI_SCB_EXECUTE_MESSAGE *)&Message; 2571128787Sscottl bzero(Message_Ptr, sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) - 2572128787Sscottl sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT)); 257365312Smsmith 257496554Sobrien I2O_MESSAGE_FRAME_setVersionOffset( 2575128787Sscottl (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_VERSION_11 | 2576128787Sscottl (((sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) 2577128787Sscottl - sizeof(I2O_SG_ELEMENT)) / sizeof(U32)) << 4)); 257896554Sobrien I2O_MESSAGE_FRAME_setMessageSize( 2579128787Sscottl (PI2O_MESSAGE_FRAME)Message_Ptr, 2580128787Sscottl (sizeof(PRIVATE_SCSI_SCB_EXECUTE_MESSAGE) - 2581128787Sscottl sizeof(I2O_SG_ELEMENT) + sizeof(I2O_SGE_SIMPLE_ELEMENT)) / 2582128787Sscottl sizeof(U32)); 2583128787Sscottl I2O_MESSAGE_FRAME_setInitiatorAddress( 2584128787Sscottl (PI2O_MESSAGE_FRAME)Message_Ptr, 1); 258596554Sobrien I2O_MESSAGE_FRAME_setFunction( 2586128787Sscottl (PI2O_MESSAGE_FRAME)Message_Ptr, I2O_PRIVATE_MESSAGE); 2587128787Sscottl I2O_PRIVATE_MESSAGE_FRAME_setXFunctionCode( 2588128787Sscottl (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, I2O_SCSI_SCB_EXEC); 258996554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr, 259096554Sobrien I2O_SCB_FLAG_ENABLE_DISCONNECT 259196554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 259296554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER); 259396554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setInterpret(Message_Ptr, 1); 259496554Sobrien I2O_PRIVATE_MESSAGE_FRAME_setOrganizationID( 2595128787Sscottl (PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr, 2596128787Sscottl DPT_ORGANIZATION_ID); 259796554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setCDBLength(Message_Ptr, 6); 259896554Sobrien Message_Ptr->CDB[0] = INQUIRY; 2599128793Sscottl Message_Ptr->CDB[4] = 2600128793Sscottl (unsigned char)sizeof(struct scsi_inquiry_data); 260196554Sobrien if (Message_Ptr->CDB[4] == 0) { 260296554Sobrien Message_Ptr->CDB[4] = 255; 260396554Sobrien } 260465312Smsmith 260596554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setSCBFlags (Message_Ptr, 260696554Sobrien (I2O_SCB_FLAG_XFER_FROM_DEVICE 260796554Sobrien | I2O_SCB_FLAG_ENABLE_DISCONNECT 260896554Sobrien | I2O_SCB_FLAG_SIMPLE_QUEUE_TAG 260996554Sobrien | I2O_SCB_FLAG_SENSE_DATA_IN_BUFFER)); 261065312Smsmith 261196554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_setByteCount( 261296554Sobrien (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr, 261396554Sobrien sizeof(struct scsi_inquiry_data)); 261496554Sobrien SG(&(Message_Ptr->SGL), 0, 261596554Sobrien I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER, 261696554Sobrien iq, sizeof(struct scsi_inquiry_data)); 261796554Sobrien (void)ASR_queue_c(sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 261865312Smsmith 261996554Sobrien if (iq->vendor[0] && (iq->vendor[0] != ' ')) { 262096554Sobrien printf (" "); 262196554Sobrien ASR_prstring (iq->vendor, 8); 262296554Sobrien ++posted; 262396554Sobrien } 262496554Sobrien if (iq->product[0] && (iq->product[0] != ' ')) { 262596554Sobrien printf (" "); 262696554Sobrien ASR_prstring (iq->product, 16); 262796554Sobrien ++posted; 262896554Sobrien } 262996554Sobrien if (iq->revision[0] && (iq->revision[0] != ' ')) { 263096554Sobrien printf (" FW Rev. "); 263196554Sobrien ASR_prstring (iq->revision, 4); 263296554Sobrien ++posted; 263396554Sobrien } 2634128812Sscottl free(iq, M_TEMP); 263596554Sobrien if (posted) { 263696554Sobrien printf (","); 263796554Sobrien } 263896554Sobrien } 263996554Sobrien printf (" %d channel, %d CCBs, Protocol I2O\n", sc->ha_MaxBus + 1, 264096554Sobrien (sc->ha_QueueSize > MAX_INBOUND) ? MAX_INBOUND : sc->ha_QueueSize); 264165312Smsmith 2642128793Sscottl for (bus = 0; bus <= sc->ha_MaxBus; ++bus) { 2643128793Sscottl struct cam_devq * devq; 2644128793Sscottl int QueueSize = sc->ha_QueueSize; 264565312Smsmith 2646128793Sscottl if (QueueSize > MAX_INBOUND) { 2647128793Sscottl QueueSize = MAX_INBOUND; 264896554Sobrien } 264965312Smsmith 2650128793Sscottl /* 2651128793Sscottl * Create the device queue for our SIM(s). 2652128793Sscottl */ 2653128793Sscottl if ((devq = cam_simq_alloc(QueueSize)) == NULL) { 2654128793Sscottl continue; 2655128793Sscottl } 265665312Smsmith 2657128793Sscottl /* 2658128793Sscottl * Construct our first channel SIM entry 2659128793Sscottl */ 2660128793Sscottl sc->ha_sim[bus] = cam_sim_alloc(asr_action, asr_poll, "asr", sc, 2661168752Sscottl unit, &Giant, 2662168752Sscottl 1, QueueSize, devq); 2663128793Sscottl if (sc->ha_sim[bus] == NULL) { 2664128793Sscottl continue; 2665128793Sscottl } 266665312Smsmith 2667170872Sscottl if (xpt_bus_register(sc->ha_sim[bus], dev, bus) != CAM_SUCCESS){ 2668128793Sscottl cam_sim_free(sc->ha_sim[bus], 2669128793Sscottl /*free_devq*/TRUE); 2670128793Sscottl sc->ha_sim[bus] = NULL; 2671128793Sscottl continue; 2672128793Sscottl } 267365312Smsmith 2674128793Sscottl if (xpt_create_path(&(sc->ha_path[bus]), /*periph*/NULL, 2675128793Sscottl cam_sim_path(sc->ha_sim[bus]), CAM_TARGET_WILDCARD, 2676128793Sscottl CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 2677128793Sscottl xpt_bus_deregister( cam_sim_path(sc->ha_sim[bus])); 2678128793Sscottl cam_sim_free(sc->ha_sim[bus], /*free_devq*/TRUE); 2679128793Sscottl sc->ha_sim[bus] = NULL; 2680128793Sscottl continue; 268196554Sobrien } 268296554Sobrien } 2683154365Sscottl 268496554Sobrien /* 268596554Sobrien * Generate the device node information 268696554Sobrien */ 2687128792Sscottl sc->ha_devt = make_dev(&asr_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, 2688128807Sscottl "asr%d", unit); 2689145658Sscottl if (sc->ha_devt != NULL) 2690145658Sscottl (void)make_dev_alias(sc->ha_devt, "rdpti%d", unit); 2691128792Sscottl sc->ha_devt->si_drv1 = sc; 2692128791Sscottl return(0); 269365312Smsmith} /* asr_attach */ 269465312Smsmith 2695128784Sscottlstatic void 2696128784Sscottlasr_poll(struct cam_sim *sim) 269765312Smsmith{ 269896554Sobrien asr_intr(cam_sim_softc(sim)); 269965312Smsmith} /* asr_poll */ 270065312Smsmith 2701128784Sscottlstatic void 2702128784Sscottlasr_action(struct cam_sim *sim, union ccb *ccb) 270365312Smsmith{ 2704128784Sscottl struct Asr_softc *sc; 270565312Smsmith 2706128786Sscottl debug_asr_printf("asr_action(%lx,%lx{%x})\n", (u_long)sim, (u_long)ccb, 2707128786Sscottl ccb->ccb_h.func_code); 270865312Smsmith 270996554Sobrien CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("asr_action\n")); 271065312Smsmith 271196554Sobrien ccb->ccb_h.spriv_ptr0 = sc = (struct Asr_softc *)cam_sim_softc(sim); 271265312Smsmith 2713234503Sdim switch ((int)ccb->ccb_h.func_code) { 271465312Smsmith 271596554Sobrien /* Common cases first */ 271696554Sobrien case XPT_SCSI_IO: /* Execute the requested I/O operation */ 271796554Sobrien { 271896554Sobrien struct Message { 271996554Sobrien char M[MAX_INBOUND_SIZE]; 2720128812Sscottl } Message; 272196554Sobrien PI2O_MESSAGE_FRAME Message_Ptr; 272265312Smsmith 272396554Sobrien /* Reject incoming commands while we are resetting the card */ 272496554Sobrien if (sc->ha_in_reset != HA_OPERATIONAL) { 272596554Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 272696554Sobrien if (sc->ha_in_reset >= HA_OFF_LINE) { 272796554Sobrien /* HBA is now off-line */ 272896554Sobrien ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; 272996554Sobrien } else { 273096554Sobrien /* HBA currently resetting, try again later. */ 273196554Sobrien ccb->ccb_h.status |= CAM_REQUEUE_REQ; 273296554Sobrien } 273396554Sobrien debug_asr_cmd_printf (" e\n"); 273496554Sobrien xpt_done(ccb); 273596554Sobrien debug_asr_cmd_printf (" q\n"); 273696554Sobrien break; 273796554Sobrien } 273896554Sobrien if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 273996554Sobrien printf( 274096554Sobrien "asr%d WARNING: scsi_cmd(%x) already done on b%dt%du%d\n", 274196554Sobrien cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)), 274296554Sobrien ccb->csio.cdb_io.cdb_bytes[0], 274396554Sobrien cam_sim_bus(sim), 274496554Sobrien ccb->ccb_h.target_id, 274596554Sobrien ccb->ccb_h.target_lun); 274696554Sobrien } 2747128786Sscottl debug_asr_cmd_printf("(%d,%d,%d,%d)", cam_sim_unit(sim), 2748128786Sscottl cam_sim_bus(sim), ccb->ccb_h.target_id, 2749128786Sscottl ccb->ccb_h.target_lun); 2750128786Sscottl debug_asr_dump_ccb(ccb); 275165312Smsmith 2752128812Sscottl if ((Message_Ptr = ASR_init_message((union asr_ccb *)ccb, 2753128812Sscottl (PI2O_MESSAGE_FRAME)&Message)) != NULL) { 275496554Sobrien debug_asr_cmd2_printf ("TID=%x:\n", 275596554Sobrien PRIVATE_SCSI_SCB_EXECUTE_MESSAGE_getTID( 275696554Sobrien (PPRIVATE_SCSI_SCB_EXECUTE_MESSAGE)Message_Ptr)); 275796554Sobrien debug_asr_cmd2_dump_message(Message_Ptr); 275896554Sobrien debug_asr_cmd1_printf (" q"); 275965312Smsmith 276096554Sobrien if (ASR_queue (sc, Message_Ptr) == EMPTY_QUEUE) { 276196554Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 276296554Sobrien ccb->ccb_h.status |= CAM_REQUEUE_REQ; 276396554Sobrien debug_asr_cmd_printf (" E\n"); 276496554Sobrien xpt_done(ccb); 276596554Sobrien } 2766128786Sscottl debug_asr_cmd_printf(" Q\n"); 276796554Sobrien break; 276896554Sobrien } 276996554Sobrien /* 277096554Sobrien * We will get here if there is no valid TID for the device 277196554Sobrien * referenced in the scsi command packet. 277296554Sobrien */ 277396554Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 277496554Sobrien ccb->ccb_h.status |= CAM_SEL_TIMEOUT; 277596554Sobrien debug_asr_cmd_printf (" B\n"); 277696554Sobrien xpt_done(ccb); 277796554Sobrien break; 277896554Sobrien } 277965312Smsmith 278096554Sobrien case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ 278196554Sobrien /* Rese HBA device ... */ 278296554Sobrien asr_hbareset (sc); 278396554Sobrien ccb->ccb_h.status = CAM_REQ_CMP; 278496554Sobrien xpt_done(ccb); 278596554Sobrien break; 278665312Smsmith 2787128535Sscottl#if (defined(REPORT_LUNS)) 278896554Sobrien case REPORT_LUNS: 2789128535Sscottl#endif 279096554Sobrien case XPT_ABORT: /* Abort the specified CCB */ 279196554Sobrien /* XXX Implement */ 279296554Sobrien ccb->ccb_h.status = CAM_REQ_INVALID; 279396554Sobrien xpt_done(ccb); 279496554Sobrien break; 279565312Smsmith 279696554Sobrien case XPT_SET_TRAN_SETTINGS: 279796554Sobrien /* XXX Implement */ 279896554Sobrien ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 279996554Sobrien xpt_done(ccb); 280096554Sobrien break; 280165312Smsmith 280296554Sobrien case XPT_GET_TRAN_SETTINGS: 280396554Sobrien /* Get default/user set transfer settings for the target */ 280496554Sobrien { 2805163816Smjacob struct ccb_trans_settings *cts = &(ccb->cts); 2806163816Smjacob struct ccb_trans_settings_scsi *scsi = 2807163816Smjacob &cts->proto_specific.scsi; 2808163816Smjacob struct ccb_trans_settings_spi *spi = 2809163816Smjacob &cts->xport_specific.spi; 281065312Smsmith 2811163816Smjacob if (cts->type == CTS_TYPE_USER_SETTINGS) { 2812163816Smjacob cts->protocol = PROTO_SCSI; 2813163816Smjacob cts->protocol_version = SCSI_REV_2; 2814163816Smjacob cts->transport = XPORT_SPI; 2815163816Smjacob cts->transport_version = 2; 2816163816Smjacob 2817163816Smjacob scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 2818163816Smjacob spi->flags = CTS_SPI_FLAGS_DISC_ENB; 2819163816Smjacob spi->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 2820163816Smjacob spi->sync_period = 6; /* 40MHz */ 2821163816Smjacob spi->sync_offset = 15; 2822163816Smjacob spi->valid = CTS_SPI_VALID_SYNC_RATE 2823163816Smjacob | CTS_SPI_VALID_SYNC_OFFSET 2824163816Smjacob | CTS_SPI_VALID_BUS_WIDTH 2825163816Smjacob | CTS_SPI_VALID_DISC; 2826163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 2827163816Smjacob 2828163816Smjacob ccb->ccb_h.status = CAM_REQ_CMP; 2829163816Smjacob } else { 2830163816Smjacob ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 2831163816Smjacob } 283296554Sobrien xpt_done(ccb); 283396554Sobrien break; 283496554Sobrien } 283565312Smsmith 283696554Sobrien case XPT_CALC_GEOMETRY: 283796554Sobrien { 283896554Sobrien struct ccb_calc_geometry *ccg; 283996554Sobrien u_int32_t size_mb; 284096554Sobrien u_int32_t secs_per_cylinder; 284165312Smsmith 284296554Sobrien ccg = &(ccb->ccg); 284396554Sobrien size_mb = ccg->volume_size 284496554Sobrien / ((1024L * 1024L) / ccg->block_size); 284565312Smsmith 284696554Sobrien if (size_mb > 4096) { 284796554Sobrien ccg->heads = 255; 284896554Sobrien ccg->secs_per_track = 63; 284996554Sobrien } else if (size_mb > 2048) { 285096554Sobrien ccg->heads = 128; 285196554Sobrien ccg->secs_per_track = 63; 285296554Sobrien } else if (size_mb > 1024) { 285396554Sobrien ccg->heads = 65; 285496554Sobrien ccg->secs_per_track = 63; 285596554Sobrien } else { 285696554Sobrien ccg->heads = 64; 285796554Sobrien ccg->secs_per_track = 32; 285896554Sobrien } 285996554Sobrien secs_per_cylinder = ccg->heads * ccg->secs_per_track; 286096554Sobrien ccg->cylinders = ccg->volume_size / secs_per_cylinder; 286196554Sobrien ccb->ccb_h.status = CAM_REQ_CMP; 286296554Sobrien xpt_done(ccb); 286396554Sobrien break; 286496554Sobrien } 286565312Smsmith 286696554Sobrien case XPT_RESET_BUS: /* Reset the specified SCSI bus */ 286796554Sobrien ASR_resetBus (sc, cam_sim_bus(sim)); 286896554Sobrien ccb->ccb_h.status = CAM_REQ_CMP; 286996554Sobrien xpt_done(ccb); 287096554Sobrien break; 287165312Smsmith 287296554Sobrien case XPT_TERM_IO: /* Terminate the I/O process */ 287396554Sobrien /* XXX Implement */ 287496554Sobrien ccb->ccb_h.status = CAM_REQ_INVALID; 287596554Sobrien xpt_done(ccb); 287696554Sobrien break; 287765312Smsmith 287896554Sobrien case XPT_PATH_INQ: /* Path routing inquiry */ 287996554Sobrien { 288096554Sobrien struct ccb_pathinq *cpi = &(ccb->cpi); 288165312Smsmith 288296554Sobrien cpi->version_num = 1; /* XXX??? */ 288396554Sobrien cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 288496554Sobrien cpi->target_sprt = 0; 288596554Sobrien /* Not necessary to reset bus, done by HDM initialization */ 288696554Sobrien cpi->hba_misc = PIM_NOBUSRESET; 288796554Sobrien cpi->hba_eng_cnt = 0; 288896554Sobrien cpi->max_target = sc->ha_MaxId; 288996554Sobrien cpi->max_lun = sc->ha_MaxLun; 289096554Sobrien cpi->initiator_id = sc->ha_adapter_target[cam_sim_bus(sim)]; 289196554Sobrien cpi->bus_id = cam_sim_bus(sim); 289296554Sobrien cpi->base_transfer_speed = 3300; 289396554Sobrien strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 289496554Sobrien strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN); 289596554Sobrien strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 289696554Sobrien cpi->unit_number = cam_sim_unit(sim); 289796554Sobrien cpi->ccb_h.status = CAM_REQ_CMP; 2898163816Smjacob cpi->transport = XPORT_SPI; 2899163816Smjacob cpi->transport_version = 2; 2900163816Smjacob cpi->protocol = PROTO_SCSI; 2901163816Smjacob cpi->protocol_version = SCSI_REV_2; 290296554Sobrien xpt_done(ccb); 290396554Sobrien break; 290496554Sobrien } 290596554Sobrien default: 290696554Sobrien ccb->ccb_h.status = CAM_REQ_INVALID; 290796554Sobrien xpt_done(ccb); 290896554Sobrien break; 290996554Sobrien } 291065312Smsmith} /* asr_action */ 291165312Smsmith 291265312Smsmith/* 291365312Smsmith * Handle processing of current CCB as pointed to by the Status. 291465312Smsmith */ 2915128784Sscottlstatic int 2916128784Sscottlasr_intr(Asr_softc_t *sc) 291765312Smsmith{ 2918128784Sscottl int processed; 291965312Smsmith 2920128944Sscottl for(processed = 0; asr_get_status(sc) & Mask_InterruptsDisabled; 2921128784Sscottl processed = 1) { 2922128784Sscottl union asr_ccb *ccb; 2923133041Smarius u_int dsc; 292496554Sobrien U32 ReplyOffset; 292596554Sobrien PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME Reply; 292665312Smsmith 2927128944Sscottl if (((ReplyOffset = asr_get_FromFIFO(sc)) == EMPTY_QUEUE) 2928128944Sscottl && ((ReplyOffset = asr_get_FromFIFO(sc)) == EMPTY_QUEUE)) { 292996554Sobrien break; 293096554Sobrien } 293196554Sobrien Reply = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)(ReplyOffset 293296554Sobrien - sc->ha_Msgs_Phys + (char *)(sc->ha_Msgs)); 293396554Sobrien /* 293496554Sobrien * We do not need any (optional byteswapping) method access to 293596554Sobrien * the Initiator context field. 293696554Sobrien */ 293796554Sobrien ccb = (union asr_ccb *)(long) 293896554Sobrien I2O_MESSAGE_FRAME_getInitiatorContext64( 293996554Sobrien &(Reply->StdReplyFrame.StdMessageFrame)); 294096554Sobrien if (I2O_MESSAGE_FRAME_getMsgFlags( 294196554Sobrien &(Reply->StdReplyFrame.StdMessageFrame)) 294296554Sobrien & I2O_MESSAGE_FLAGS_FAIL) { 2943128812Sscottl I2O_UTIL_NOP_MESSAGE Message; 2944128812Sscottl PI2O_UTIL_NOP_MESSAGE Message_Ptr; 2945128812Sscottl U32 MessageOffset; 294665312Smsmith 294796554Sobrien MessageOffset = (u_long) 294896554Sobrien I2O_FAILURE_REPLY_MESSAGE_FRAME_getPreservedMFA( 294996554Sobrien (PI2O_FAILURE_REPLY_MESSAGE_FRAME)Reply); 295096554Sobrien /* 295196554Sobrien * Get the Original Message Frame's address, and get 295296554Sobrien * it's Transaction Context into our space. (Currently 295396554Sobrien * unused at original authorship, but better to be 295496554Sobrien * safe than sorry). Straight copy means that we 295596554Sobrien * need not concern ourselves with the (optional 295696554Sobrien * byteswapping) method access. 295796554Sobrien */ 2958128944Sscottl Reply->StdReplyFrame.TransactionContext = 2959128944Sscottl bus_space_read_4(sc->ha_frame_btag, 2960128944Sscottl sc->ha_frame_bhandle, MessageOffset + 2961128944Sscottl offsetof(I2O_SINGLE_REPLY_MESSAGE_FRAME, 2962128944Sscottl TransactionContext)); 296396554Sobrien /* 296496554Sobrien * For 64 bit machines, we need to reconstruct the 296596554Sobrien * 64 bit context. 296696554Sobrien */ 296796554Sobrien ccb = (union asr_ccb *)(long) 296896554Sobrien I2O_MESSAGE_FRAME_getInitiatorContext64( 296996554Sobrien &(Reply->StdReplyFrame.StdMessageFrame)); 297096554Sobrien /* 297196554Sobrien * Unique error code for command failure. 297296554Sobrien */ 297396554Sobrien I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode( 297496554Sobrien &(Reply->StdReplyFrame), (u_int16_t)-2); 297596554Sobrien /* 297696554Sobrien * Modify the message frame to contain a NOP and 297796554Sobrien * re-issue it to the controller. 297896554Sobrien */ 297996554Sobrien Message_Ptr = (PI2O_UTIL_NOP_MESSAGE)ASR_fillMessage( 2980128812Sscottl &Message, sizeof(I2O_UTIL_NOP_MESSAGE)); 2981128535Sscottl#if (I2O_UTIL_NOP != 0) 298296554Sobrien I2O_MESSAGE_FRAME_setFunction ( 298396554Sobrien &(Message_Ptr->StdMessageFrame), 298496554Sobrien I2O_UTIL_NOP); 2985128535Sscottl#endif 298696554Sobrien /* 298796554Sobrien * Copy the packet out to the Original Message 298896554Sobrien */ 2989128944Sscottl asr_set_frame(sc, Message_Ptr, MessageOffset, 2990128944Sscottl sizeof(I2O_UTIL_NOP_MESSAGE)); 299196554Sobrien /* 299296554Sobrien * Issue the NOP 299396554Sobrien */ 2994128944Sscottl asr_set_ToFIFO(sc, MessageOffset); 299596554Sobrien } 299665312Smsmith 299796554Sobrien /* 299896554Sobrien * Asynchronous command with no return requirements, 299996554Sobrien * and a generic handler for immunity against odd error 300096554Sobrien * returns from the adapter. 300196554Sobrien */ 3002128511Sscottl if (ccb == NULL) { 300396554Sobrien /* 300496554Sobrien * Return Reply so that it can be used for the 300596554Sobrien * next command 300696554Sobrien */ 3007128944Sscottl asr_set_FromFIFO(sc, ReplyOffset); 300896554Sobrien continue; 300996554Sobrien } 301065312Smsmith 301196554Sobrien /* Welease Wadjah! (and stop timeouts) */ 301296554Sobrien ASR_ccbRemove (sc, ccb); 301365312Smsmith 3014133041Smarius dsc = I2O_SINGLE_REPLY_MESSAGE_FRAME_getDetailedStatusCode( 3015133041Smarius &(Reply->StdReplyFrame)); 3016133041Smarius ccb->csio.scsi_status = dsc & I2O_SCSI_DEVICE_DSC_MASK; 3017133041Smarius ccb->ccb_h.status &= ~CAM_STATUS_MASK; 3018133041Smarius switch (dsc) { 301965312Smsmith 302096554Sobrien case I2O_SCSI_DSC_SUCCESS: 302196554Sobrien ccb->ccb_h.status |= CAM_REQ_CMP; 302296554Sobrien break; 302365312Smsmith 302496554Sobrien case I2O_SCSI_DSC_CHECK_CONDITION: 3025133041Smarius ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | 3026133041Smarius CAM_AUTOSNS_VALID; 302796554Sobrien break; 302865312Smsmith 302996554Sobrien case I2O_SCSI_DSC_BUSY: 303096554Sobrien /* FALLTHRU */ 303196554Sobrien case I2O_SCSI_HBA_DSC_ADAPTER_BUSY: 303296554Sobrien /* FALLTHRU */ 303396554Sobrien case I2O_SCSI_HBA_DSC_SCSI_BUS_RESET: 303496554Sobrien /* FALLTHRU */ 303596554Sobrien case I2O_SCSI_HBA_DSC_BUS_BUSY: 303696554Sobrien ccb->ccb_h.status |= CAM_SCSI_BUSY; 303796554Sobrien break; 303865312Smsmith 303996554Sobrien case I2O_SCSI_HBA_DSC_SELECTION_TIMEOUT: 304096554Sobrien ccb->ccb_h.status |= CAM_SEL_TIMEOUT; 304196554Sobrien break; 304265312Smsmith 304396554Sobrien case I2O_SCSI_HBA_DSC_COMMAND_TIMEOUT: 304496554Sobrien /* FALLTHRU */ 304596554Sobrien case I2O_SCSI_HBA_DSC_DEVICE_NOT_PRESENT: 304696554Sobrien /* FALLTHRU */ 304796554Sobrien case I2O_SCSI_HBA_DSC_LUN_INVALID: 304896554Sobrien /* FALLTHRU */ 304996554Sobrien case I2O_SCSI_HBA_DSC_SCSI_TID_INVALID: 305096554Sobrien ccb->ccb_h.status |= CAM_CMD_TIMEOUT; 305196554Sobrien break; 305265312Smsmith 305396554Sobrien case I2O_SCSI_HBA_DSC_DATA_OVERRUN: 305496554Sobrien /* FALLTHRU */ 305596554Sobrien case I2O_SCSI_HBA_DSC_REQUEST_LENGTH_ERROR: 305696554Sobrien ccb->ccb_h.status |= CAM_DATA_RUN_ERR; 305796554Sobrien break; 305865312Smsmith 305996554Sobrien default: 306096554Sobrien ccb->ccb_h.status |= CAM_REQUEUE_REQ; 306196554Sobrien break; 306296554Sobrien } 306396554Sobrien if ((ccb->csio.resid = ccb->csio.dxfer_len) != 0) { 306496554Sobrien ccb->csio.resid -= 306596554Sobrien I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_getTransferCount( 306696554Sobrien Reply); 306796554Sobrien } 306865312Smsmith 306996554Sobrien /* Sense data in reply packet */ 307096554Sobrien if (ccb->ccb_h.status & CAM_AUTOSNS_VALID) { 307196554Sobrien u_int16_t size = I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_getAutoSenseTransferCount(Reply); 307265312Smsmith 307396554Sobrien if (size) { 307496554Sobrien if (size > sizeof(ccb->csio.sense_data)) { 307596554Sobrien size = sizeof(ccb->csio.sense_data); 307696554Sobrien } 307796554Sobrien if (size > I2O_SCSI_SENSE_DATA_SZ) { 307896554Sobrien size = I2O_SCSI_SENSE_DATA_SZ; 307996554Sobrien } 308096554Sobrien if ((ccb->csio.sense_len) 308196554Sobrien && (size > ccb->csio.sense_len)) { 308296554Sobrien size = ccb->csio.sense_len; 308396554Sobrien } 3084226350Smarius if (size < ccb->csio.sense_len) { 3085226350Smarius ccb->csio.sense_resid = 3086226350Smarius ccb->csio.sense_len - size; 3087226350Smarius } else { 3088226350Smarius ccb->csio.sense_resid = 0; 3089226350Smarius } 3090226350Smarius bzero(&(ccb->csio.sense_data), 3091226350Smarius sizeof(ccb->csio.sense_data)); 3092128786Sscottl bcopy(Reply->SenseData, 3093128786Sscottl &(ccb->csio.sense_data), size); 309496554Sobrien } 309596554Sobrien } 309665312Smsmith 309796554Sobrien /* 309896554Sobrien * Return Reply so that it can be used for the next command 309996554Sobrien * since we have no more need for it now 310096554Sobrien */ 3101128944Sscottl asr_set_FromFIFO(sc, ReplyOffset); 310265312Smsmith 310396554Sobrien if (ccb->ccb_h.path) { 310496554Sobrien xpt_done ((union ccb *)ccb); 310596554Sobrien } else { 3106111748Sdes wakeup (ccb); 310796554Sobrien } 310896554Sobrien } 310996554Sobrien return (processed); 311065312Smsmith} /* asr_intr */ 311165312Smsmith 311296554Sobrien#undef QueueSize /* Grrrr */ 311396554Sobrien#undef SG_Size /* Grrrr */ 311465312Smsmith 311565312Smsmith/* 311696554Sobrien * Meant to be included at the bottom of asr.c !!! 311765312Smsmith */ 311865312Smsmith 311965312Smsmith/* 312096554Sobrien * Included here as hard coded. Done because other necessary include 312196554Sobrien * files utilize C++ comment structures which make them a nuisance to 312296554Sobrien * included here just to pick up these three typedefs. 312365312Smsmith */ 312465312Smsmithtypedef U32 DPT_TAG_T; 312565312Smsmithtypedef U32 DPT_MSG_T; 312665312Smsmithtypedef U32 DPT_RTN_T; 312765312Smsmith 312896554Sobrien#undef SCSI_RESET /* Conflicts with "scsi/scsiconf.h" defintion */ 312996554Sobrien#include "dev/asr/osd_unix.h" 313065312Smsmith 3131183397Sed#define asr_unit(dev) dev2unit(dev) 313265312Smsmith 3133128784Sscottlstatic u_int8_t ASR_ctlr_held; 313465312Smsmith 3135128784Sscottlstatic int 3136130585Sphkasr_open(struct cdev *dev, int32_t flags, int32_t ifmt, struct thread *td) 313765312Smsmith{ 313896554Sobrien int s; 3139128784Sscottl int error; 314065312Smsmith 3141128792Sscottl if (dev->si_drv1 == NULL) { 314296554Sobrien return (ENODEV); 314396554Sobrien } 314496554Sobrien s = splcam (); 314596554Sobrien if (ASR_ctlr_held) { 314696554Sobrien error = EBUSY; 3147164033Srwatson } else if ((error = priv_check(td, PRIV_DRIVER)) == 0) { 314896554Sobrien ++ASR_ctlr_held; 314996554Sobrien } 315096554Sobrien splx(s); 315196554Sobrien return (error); 315265312Smsmith} /* asr_open */ 315365312Smsmith 3154128784Sscottlstatic int 3155130585Sphkasr_close(struct cdev *dev, int flags, int ifmt, struct thread *td) 315665312Smsmith{ 315765312Smsmith 315896554Sobrien ASR_ctlr_held = 0; 315996554Sobrien return (0); 316065312Smsmith} /* asr_close */ 316165312Smsmith 316265312Smsmith 316365312Smsmith/*-------------------------------------------------------------------------*/ 316496554Sobrien/* Function ASR_queue_i */ 316565312Smsmith/*-------------------------------------------------------------------------*/ 316696554Sobrien/* The Parameters Passed To This Function Are : */ 316796554Sobrien/* Asr_softc_t * : HBA miniport driver's adapter data storage. */ 316896554Sobrien/* PI2O_MESSAGE_FRAME : Msg Structure Pointer For This Command */ 316996554Sobrien/* I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME following the Msg Structure */ 317096554Sobrien/* */ 317196554Sobrien/* This Function Will Take The User Request Packet And Convert It To An */ 317296554Sobrien/* I2O MSG And Send It Off To The Adapter. */ 317396554Sobrien/* */ 317496554Sobrien/* Return : 0 For OK, Error Code Otherwise */ 317565312Smsmith/*-------------------------------------------------------------------------*/ 3176128784Sscottlstatic int 3177128784SscottlASR_queue_i(Asr_softc_t *sc, PI2O_MESSAGE_FRAME Packet) 317865312Smsmith{ 317996554Sobrien union asr_ccb * ccb; 318096554Sobrien PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME Reply; 318196554Sobrien PI2O_MESSAGE_FRAME Message_Ptr; 318296554Sobrien PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME Reply_Ptr; 318396554Sobrien int MessageSizeInBytes; 318496554Sobrien int ReplySizeInBytes; 318596554Sobrien int error; 318696554Sobrien int s; 318796554Sobrien /* Scatter Gather buffer list */ 318896554Sobrien struct ioctlSgList_S { 318996554Sobrien SLIST_ENTRY(ioctlSgList_S) link; 319096554Sobrien caddr_t UserSpace; 319196554Sobrien I2O_FLAGS_COUNT FlagsCount; 319296554Sobrien char KernelSpace[sizeof(long)]; 319396554Sobrien } * elm; 319496554Sobrien /* Generates a `first' entry */ 319596554Sobrien SLIST_HEAD(ioctlSgListHead_S, ioctlSgList_S) sgList; 319665312Smsmith 319796554Sobrien if (ASR_getBlinkLedCode(sc)) { 319896554Sobrien debug_usr_cmd_printf ("Adapter currently in BlinkLed %x\n", 319996554Sobrien ASR_getBlinkLedCode(sc)); 320096554Sobrien return (EIO); 320196554Sobrien } 320296554Sobrien /* Copy in the message into a local allocation */ 320396554Sobrien if ((Message_Ptr = (PI2O_MESSAGE_FRAME)malloc ( 3204128511Sscottl sizeof(I2O_MESSAGE_FRAME), M_TEMP, M_WAITOK)) == NULL) { 320596554Sobrien debug_usr_cmd_printf ( 320696554Sobrien "Failed to acquire I2O_MESSAGE_FRAME memory\n"); 320796554Sobrien return (ENOMEM); 320896554Sobrien } 320996554Sobrien if ((error = copyin ((caddr_t)Packet, (caddr_t)Message_Ptr, 321096554Sobrien sizeof(I2O_MESSAGE_FRAME))) != 0) { 3211128812Sscottl free(Message_Ptr, M_TEMP); 321296554Sobrien debug_usr_cmd_printf ("Can't copy in packet errno=%d\n", error); 321396554Sobrien return (error); 321496554Sobrien } 321596554Sobrien /* Acquire information to determine type of packet */ 321696554Sobrien MessageSizeInBytes = (I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr)<<2); 321796554Sobrien /* The offset of the reply information within the user packet */ 321896554Sobrien Reply = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)((char *)Packet 321996554Sobrien + MessageSizeInBytes); 322065312Smsmith 322196554Sobrien /* Check if the message is a synchronous initialization command */ 322296554Sobrien s = I2O_MESSAGE_FRAME_getFunction(Message_Ptr); 3223128812Sscottl free(Message_Ptr, M_TEMP); 322496554Sobrien switch (s) { 322565312Smsmith 322696554Sobrien case I2O_EXEC_IOP_RESET: 322796554Sobrien { U32 status; 322865312Smsmith 3229128944Sscottl status = ASR_resetIOP(sc); 323096554Sobrien ReplySizeInBytes = sizeof(status); 323196554Sobrien debug_usr_cmd_printf ("resetIOP done\n"); 323296554Sobrien return (copyout ((caddr_t)&status, (caddr_t)Reply, 323396554Sobrien ReplySizeInBytes)); 323496554Sobrien } 323565312Smsmith 323696554Sobrien case I2O_EXEC_STATUS_GET: 3237155307Sscottl { PI2O_EXEC_STATUS_GET_REPLY status; 323865312Smsmith 3239155307Sscottl status = &sc->ha_statusmem->status; 3240155307Sscottl if (ASR_getStatus(sc) == NULL) { 324196554Sobrien debug_usr_cmd_printf ("getStatus failed\n"); 324296554Sobrien return (ENXIO); 324396554Sobrien } 324496554Sobrien ReplySizeInBytes = sizeof(status); 324596554Sobrien debug_usr_cmd_printf ("getStatus done\n"); 3246155307Sscottl return (copyout ((caddr_t)status, (caddr_t)Reply, 324796554Sobrien ReplySizeInBytes)); 324896554Sobrien } 324965312Smsmith 325096554Sobrien case I2O_EXEC_OUTBOUND_INIT: 325196554Sobrien { U32 status; 325265312Smsmith 325396554Sobrien status = ASR_initOutBound(sc); 325496554Sobrien ReplySizeInBytes = sizeof(status); 325596554Sobrien debug_usr_cmd_printf ("intOutBound done\n"); 325696554Sobrien return (copyout ((caddr_t)&status, (caddr_t)Reply, 325796554Sobrien ReplySizeInBytes)); 325896554Sobrien } 325996554Sobrien } 326065312Smsmith 326196554Sobrien /* Determine if the message size is valid */ 326296554Sobrien if ((MessageSizeInBytes < sizeof(I2O_MESSAGE_FRAME)) 326396554Sobrien || (MAX_INBOUND_SIZE < MessageSizeInBytes)) { 326496554Sobrien debug_usr_cmd_printf ("Packet size %d incorrect\n", 326596554Sobrien MessageSizeInBytes); 326696554Sobrien return (EINVAL); 326796554Sobrien } 326865312Smsmith 326996554Sobrien if ((Message_Ptr = (PI2O_MESSAGE_FRAME)malloc (MessageSizeInBytes, 3270128511Sscottl M_TEMP, M_WAITOK)) == NULL) { 327196554Sobrien debug_usr_cmd_printf ("Failed to acquire frame[%d] memory\n", 327296554Sobrien MessageSizeInBytes); 327396554Sobrien return (ENOMEM); 327496554Sobrien } 327596554Sobrien if ((error = copyin ((caddr_t)Packet, (caddr_t)Message_Ptr, 327696554Sobrien MessageSizeInBytes)) != 0) { 3277128812Sscottl free(Message_Ptr, M_TEMP); 327896554Sobrien debug_usr_cmd_printf ("Can't copy in packet[%d] errno=%d\n", 327996554Sobrien MessageSizeInBytes, error); 328096554Sobrien return (error); 328196554Sobrien } 328265312Smsmith 328396554Sobrien /* Check the size of the reply frame, and start constructing */ 328465312Smsmith 328596554Sobrien if ((Reply_Ptr = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)malloc ( 3286128511Sscottl sizeof(I2O_MESSAGE_FRAME), M_TEMP, M_WAITOK)) == NULL) { 3287128812Sscottl free(Message_Ptr, M_TEMP); 328896554Sobrien debug_usr_cmd_printf ( 328996554Sobrien "Failed to acquire I2O_MESSAGE_FRAME memory\n"); 329096554Sobrien return (ENOMEM); 329196554Sobrien } 329296554Sobrien if ((error = copyin ((caddr_t)Reply, (caddr_t)Reply_Ptr, 329396554Sobrien sizeof(I2O_MESSAGE_FRAME))) != 0) { 3294128812Sscottl free(Reply_Ptr, M_TEMP); 3295128812Sscottl free(Message_Ptr, M_TEMP); 329696554Sobrien debug_usr_cmd_printf ( 329796554Sobrien "Failed to copy in reply frame, errno=%d\n", 329896554Sobrien error); 329996554Sobrien return (error); 330096554Sobrien } 330196554Sobrien ReplySizeInBytes = (I2O_MESSAGE_FRAME_getMessageSize( 330296554Sobrien &(Reply_Ptr->StdReplyFrame.StdMessageFrame)) << 2); 3303128812Sscottl free(Reply_Ptr, M_TEMP); 330496554Sobrien if (ReplySizeInBytes < sizeof(I2O_SINGLE_REPLY_MESSAGE_FRAME)) { 3305128812Sscottl free(Message_Ptr, M_TEMP); 330696554Sobrien debug_usr_cmd_printf ( 330796554Sobrien "Failed to copy in reply frame[%d], errno=%d\n", 330896554Sobrien ReplySizeInBytes, error); 330996554Sobrien return (EINVAL); 331096554Sobrien } 331165312Smsmith 331296554Sobrien if ((Reply_Ptr = (PI2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)malloc ( 331396554Sobrien ((ReplySizeInBytes > sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)) 3314128511Sscottl ? ReplySizeInBytes : sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME)), 3315128511Sscottl M_TEMP, M_WAITOK)) == NULL) { 3316128812Sscottl free(Message_Ptr, M_TEMP); 331796554Sobrien debug_usr_cmd_printf ("Failed to acquire frame[%d] memory\n", 331896554Sobrien ReplySizeInBytes); 331996554Sobrien return (ENOMEM); 332096554Sobrien } 3321128812Sscottl (void)ASR_fillMessage((void *)Reply_Ptr, ReplySizeInBytes); 332296554Sobrien Reply_Ptr->StdReplyFrame.StdMessageFrame.InitiatorContext 332396554Sobrien = Message_Ptr->InitiatorContext; 332496554Sobrien Reply_Ptr->StdReplyFrame.TransactionContext 332596554Sobrien = ((PI2O_PRIVATE_MESSAGE_FRAME)Message_Ptr)->TransactionContext; 332696554Sobrien I2O_MESSAGE_FRAME_setMsgFlags( 332796554Sobrien &(Reply_Ptr->StdReplyFrame.StdMessageFrame), 332896554Sobrien I2O_MESSAGE_FRAME_getMsgFlags( 332996554Sobrien &(Reply_Ptr->StdReplyFrame.StdMessageFrame)) 333096554Sobrien | I2O_MESSAGE_FLAGS_REPLY); 333165312Smsmith 333296554Sobrien /* Check if the message is a special case command */ 333396554Sobrien switch (I2O_MESSAGE_FRAME_getFunction(Message_Ptr)) { 333496554Sobrien case I2O_EXEC_SYS_TAB_SET: /* Special Case of empty Scatter Gather */ 333596554Sobrien if (MessageSizeInBytes == ((I2O_MESSAGE_FRAME_getVersionOffset( 333696554Sobrien Message_Ptr) & 0xF0) >> 2)) { 3337128812Sscottl free(Message_Ptr, M_TEMP); 333896554Sobrien I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode( 333996554Sobrien &(Reply_Ptr->StdReplyFrame), 334096554Sobrien (ASR_setSysTab(sc) != CAM_REQ_CMP)); 334196554Sobrien I2O_MESSAGE_FRAME_setMessageSize( 334296554Sobrien &(Reply_Ptr->StdReplyFrame.StdMessageFrame), 334396554Sobrien sizeof(I2O_SINGLE_REPLY_MESSAGE_FRAME)); 334496554Sobrien error = copyout ((caddr_t)Reply_Ptr, (caddr_t)Reply, 334596554Sobrien ReplySizeInBytes); 3346128812Sscottl free(Reply_Ptr, M_TEMP); 334796554Sobrien return (error); 334896554Sobrien } 334996554Sobrien } 335065312Smsmith 335196554Sobrien /* Deal in the general case */ 335296554Sobrien /* First allocate and optionally copy in each scatter gather element */ 335396554Sobrien SLIST_INIT(&sgList); 335496554Sobrien if ((I2O_MESSAGE_FRAME_getVersionOffset(Message_Ptr) & 0xF0) != 0) { 335596554Sobrien PI2O_SGE_SIMPLE_ELEMENT sg; 335665312Smsmith 335796554Sobrien /* 335896554Sobrien * since this code is reused in several systems, code 335996554Sobrien * efficiency is greater by using a shift operation rather 336096554Sobrien * than a divide by sizeof(u_int32_t). 336196554Sobrien */ 336296554Sobrien sg = (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr 336396554Sobrien + ((I2O_MESSAGE_FRAME_getVersionOffset(Message_Ptr) & 0xF0) 336496554Sobrien >> 2)); 336596554Sobrien while (sg < (PI2O_SGE_SIMPLE_ELEMENT)(((caddr_t)Message_Ptr) 336696554Sobrien + MessageSizeInBytes)) { 336796554Sobrien caddr_t v; 336896554Sobrien int len; 336965312Smsmith 337096554Sobrien if ((I2O_FLAGS_COUNT_getFlags(&(sg->FlagsCount)) 337196554Sobrien & I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT) == 0) { 337296554Sobrien error = EINVAL; 337396554Sobrien break; 337496554Sobrien } 337596554Sobrien len = I2O_FLAGS_COUNT_getCount(&(sg->FlagsCount)); 337696554Sobrien debug_usr_cmd_printf ("SG[%d] = %x[%d]\n", 337796554Sobrien sg - (PI2O_SGE_SIMPLE_ELEMENT)((char *)Message_Ptr 337896554Sobrien + ((I2O_MESSAGE_FRAME_getVersionOffset( 337996554Sobrien Message_Ptr) & 0xF0) >> 2)), 338096554Sobrien I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg), len); 338165312Smsmith 338296554Sobrien if ((elm = (struct ioctlSgList_S *)malloc ( 338396554Sobrien sizeof(*elm) - sizeof(elm->KernelSpace) + len, 3384128511Sscottl M_TEMP, M_WAITOK)) == NULL) { 338596554Sobrien debug_usr_cmd_printf ( 338696554Sobrien "Failed to allocate SG[%d]\n", len); 338796554Sobrien error = ENOMEM; 338896554Sobrien break; 338996554Sobrien } 339096554Sobrien SLIST_INSERT_HEAD(&sgList, elm, link); 339196554Sobrien elm->FlagsCount = sg->FlagsCount; 339296554Sobrien elm->UserSpace = (caddr_t) 339396554Sobrien (I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg)); 339496554Sobrien v = elm->KernelSpace; 339596554Sobrien /* Copy in outgoing data (DIR bit could be invalid) */ 339696554Sobrien if ((error = copyin (elm->UserSpace, (caddr_t)v, len)) 339796554Sobrien != 0) { 339896554Sobrien break; 339996554Sobrien } 340096554Sobrien /* 340196554Sobrien * If the buffer is not contiguous, lets 340296554Sobrien * break up the scatter/gather entries. 340396554Sobrien */ 340496554Sobrien while ((len > 0) 340596554Sobrien && (sg < (PI2O_SGE_SIMPLE_ELEMENT) 340696554Sobrien (((caddr_t)Message_Ptr) + MAX_INBOUND_SIZE))) { 340796554Sobrien int next, base, span; 340865312Smsmith 340996554Sobrien span = 0; 341096554Sobrien next = base = KVTOPHYS(v); 341196554Sobrien I2O_SGE_SIMPLE_ELEMENT_setPhysicalAddress(sg, 341296554Sobrien base); 341365312Smsmith 341496554Sobrien /* How far can we go physically contiguously */ 341596554Sobrien while ((len > 0) && (base == next)) { 341696554Sobrien int size; 341765312Smsmith 341896554Sobrien next = trunc_page(base) + PAGE_SIZE; 341996554Sobrien size = next - base; 342096554Sobrien if (size > len) { 342196554Sobrien size = len; 342296554Sobrien } 342396554Sobrien span += size; 342496554Sobrien v += size; 342596554Sobrien len -= size; 342696554Sobrien base = KVTOPHYS(v); 342796554Sobrien } 342865312Smsmith 342996554Sobrien /* Construct the Flags */ 343096554Sobrien I2O_FLAGS_COUNT_setCount(&(sg->FlagsCount), 343196554Sobrien span); 343296554Sobrien { 343396554Sobrien int flags = I2O_FLAGS_COUNT_getFlags( 343496554Sobrien &(elm->FlagsCount)); 343596554Sobrien /* Any remaining length? */ 343696554Sobrien if (len > 0) { 343796554Sobrien flags &= 343896554Sobrien ~(I2O_SGL_FLAGS_END_OF_BUFFER 343996554Sobrien | I2O_SGL_FLAGS_LAST_ELEMENT); 344096554Sobrien } 344196554Sobrien I2O_FLAGS_COUNT_setFlags( 344296554Sobrien &(sg->FlagsCount), flags); 344396554Sobrien } 344465312Smsmith 344596554Sobrien debug_usr_cmd_printf ("sg[%d] = %x[%d]\n", 344696554Sobrien sg - (PI2O_SGE_SIMPLE_ELEMENT) 344796554Sobrien ((char *)Message_Ptr 344896554Sobrien + ((I2O_MESSAGE_FRAME_getVersionOffset( 344996554Sobrien Message_Ptr) & 0xF0) >> 2)), 345096554Sobrien I2O_SGE_SIMPLE_ELEMENT_getPhysicalAddress(sg), 345196554Sobrien span); 345296554Sobrien if (len <= 0) { 345396554Sobrien break; 345496554Sobrien } 345565312Smsmith 345696554Sobrien /* 345796554Sobrien * Incrementing requires resizing of the 345896554Sobrien * packet, and moving up the existing SG 345996554Sobrien * elements. 346096554Sobrien */ 346196554Sobrien ++sg; 346296554Sobrien MessageSizeInBytes += sizeof(*sg); 346396554Sobrien I2O_MESSAGE_FRAME_setMessageSize(Message_Ptr, 346496554Sobrien I2O_MESSAGE_FRAME_getMessageSize(Message_Ptr) 346596554Sobrien + (sizeof(*sg) / sizeof(U32))); 346696554Sobrien { 346796554Sobrien PI2O_MESSAGE_FRAME NewMessage_Ptr; 346865312Smsmith 346996554Sobrien if ((NewMessage_Ptr 347096554Sobrien = (PI2O_MESSAGE_FRAME) 347196554Sobrien malloc (MessageSizeInBytes, 3472128511Sscottl M_TEMP, M_WAITOK)) == NULL) { 347396554Sobrien debug_usr_cmd_printf ( 347496554Sobrien "Failed to acquire frame[%d] memory\n", 347596554Sobrien MessageSizeInBytes); 347696554Sobrien error = ENOMEM; 347796554Sobrien break; 347896554Sobrien } 347996554Sobrien span = ((caddr_t)sg) 348096554Sobrien - (caddr_t)Message_Ptr; 3481128786Sscottl bcopy(Message_Ptr,NewMessage_Ptr, span); 3482128786Sscottl bcopy((caddr_t)(sg-1), 348396554Sobrien ((caddr_t)NewMessage_Ptr) + span, 348496554Sobrien MessageSizeInBytes - span); 3485128812Sscottl free(Message_Ptr, M_TEMP); 348696554Sobrien sg = (PI2O_SGE_SIMPLE_ELEMENT) 348796554Sobrien (((caddr_t)NewMessage_Ptr) + span); 348896554Sobrien Message_Ptr = NewMessage_Ptr; 348996554Sobrien } 349096554Sobrien } 349196554Sobrien if ((error) 349296554Sobrien || ((I2O_FLAGS_COUNT_getFlags(&(sg->FlagsCount)) 349396554Sobrien & I2O_SGL_FLAGS_LAST_ELEMENT) != 0)) { 349496554Sobrien break; 349596554Sobrien } 349696554Sobrien ++sg; 349796554Sobrien } 349896554Sobrien if (error) { 3499128511Sscottl while ((elm = SLIST_FIRST(&sgList)) != NULL) { 350096554Sobrien SLIST_REMOVE_HEAD(&sgList, link); 3501128812Sscottl free(elm, M_TEMP); 350296554Sobrien } 3503128812Sscottl free(Reply_Ptr, M_TEMP); 3504128812Sscottl free(Message_Ptr, M_TEMP); 350596554Sobrien return (error); 350696554Sobrien } 350796554Sobrien } 350865312Smsmith 350996554Sobrien debug_usr_cmd_printf ("Inbound: "); 351096554Sobrien debug_usr_cmd_dump_message(Message_Ptr); 351165312Smsmith 351296554Sobrien /* Send the command */ 3513128511Sscottl if ((ccb = asr_alloc_ccb (sc)) == NULL) { 351496554Sobrien /* Free up in-kernel buffers */ 3515128511Sscottl while ((elm = SLIST_FIRST(&sgList)) != NULL) { 351696554Sobrien SLIST_REMOVE_HEAD(&sgList, link); 3517128812Sscottl free(elm, M_TEMP); 351896554Sobrien } 3519128812Sscottl free(Reply_Ptr, M_TEMP); 3520128812Sscottl free(Message_Ptr, M_TEMP); 352196554Sobrien return (ENOMEM); 352296554Sobrien } 352365312Smsmith 352496554Sobrien /* 352596554Sobrien * We do not need any (optional byteswapping) method access to 352696554Sobrien * the Initiator context field. 352796554Sobrien */ 352896554Sobrien I2O_MESSAGE_FRAME_setInitiatorContext64( 352996554Sobrien (PI2O_MESSAGE_FRAME)Message_Ptr, (long)ccb); 353065312Smsmith 353196554Sobrien (void)ASR_queue (sc, (PI2O_MESSAGE_FRAME)Message_Ptr); 353265312Smsmith 3533128812Sscottl free(Message_Ptr, M_TEMP); 353465312Smsmith 353596554Sobrien /* 353696554Sobrien * Wait for the board to report a finished instruction. 353796554Sobrien */ 353896554Sobrien s = splcam(); 353996554Sobrien while ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 354096554Sobrien if (ASR_getBlinkLedCode(sc)) { 354196554Sobrien /* Reset Adapter */ 354296554Sobrien printf ("asr%d: Blink LED 0x%x resetting adapter\n", 354396554Sobrien cam_sim_unit(xpt_path_sim(ccb->ccb_h.path)), 354496554Sobrien ASR_getBlinkLedCode(sc)); 354596554Sobrien if (ASR_reset (sc) == ENXIO) { 354696554Sobrien /* Command Cleanup */ 354796554Sobrien ASR_ccbRemove(sc, ccb); 354896554Sobrien } 354996554Sobrien splx(s); 355096554Sobrien /* Free up in-kernel buffers */ 3551128511Sscottl while ((elm = SLIST_FIRST(&sgList)) != NULL) { 355296554Sobrien SLIST_REMOVE_HEAD(&sgList, link); 3553128812Sscottl free(elm, M_TEMP); 355496554Sobrien } 3555128812Sscottl free(Reply_Ptr, M_TEMP); 355696554Sobrien asr_free_ccb(ccb); 355796554Sobrien return (EIO); 355896554Sobrien } 355996554Sobrien /* Check every second for BlinkLed */ 356096554Sobrien /* There is no PRICAM, but outwardly PRIBIO is functional */ 3561111748Sdes tsleep(ccb, PRIBIO, "asr", hz); 356296554Sobrien } 356396554Sobrien splx(s); 356465312Smsmith 356596554Sobrien debug_usr_cmd_printf ("Outbound: "); 356696554Sobrien debug_usr_cmd_dump_message(Reply_Ptr); 356765312Smsmith 356896554Sobrien I2O_SINGLE_REPLY_MESSAGE_FRAME_setDetailedStatusCode( 356996554Sobrien &(Reply_Ptr->StdReplyFrame), 357096554Sobrien (ccb->ccb_h.status != CAM_REQ_CMP)); 357165312Smsmith 357296554Sobrien if (ReplySizeInBytes >= (sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) 357396554Sobrien - I2O_SCSI_SENSE_DATA_SZ - sizeof(U32))) { 357496554Sobrien I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_setTransferCount(Reply_Ptr, 357596554Sobrien ccb->csio.dxfer_len - ccb->csio.resid); 357696554Sobrien } 357796554Sobrien if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) && (ReplySizeInBytes 357896554Sobrien > (sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) 357996554Sobrien - I2O_SCSI_SENSE_DATA_SZ))) { 358096554Sobrien int size = ReplySizeInBytes 358196554Sobrien - sizeof(I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME) 358296554Sobrien - I2O_SCSI_SENSE_DATA_SZ; 358365312Smsmith 358496554Sobrien if (size > sizeof(ccb->csio.sense_data)) { 358596554Sobrien size = sizeof(ccb->csio.sense_data); 358696554Sobrien } 3587226350Smarius if (size < ccb->csio.sense_len) { 3588226350Smarius ccb->csio.sense_resid = ccb->csio.sense_len - size; 3589226350Smarius } else { 3590226350Smarius ccb->csio.sense_resid = 0; 3591226350Smarius } 3592226350Smarius bzero(&(ccb->csio.sense_data), sizeof(ccb->csio.sense_data)); 3593128786Sscottl bcopy(&(ccb->csio.sense_data), Reply_Ptr->SenseData, size); 359496554Sobrien I2O_SCSI_ERROR_REPLY_MESSAGE_FRAME_setAutoSenseTransferCount( 3595128786Sscottl Reply_Ptr, size); 359696554Sobrien } 359765312Smsmith 359896554Sobrien /* Free up in-kernel buffers */ 3599128511Sscottl while ((elm = SLIST_FIRST(&sgList)) != NULL) { 360096554Sobrien /* Copy out as necessary */ 360196554Sobrien if ((error == 0) 360296554Sobrien /* DIR bit considered `valid', error due to ignorance works */ 360396554Sobrien && ((I2O_FLAGS_COUNT_getFlags(&(elm->FlagsCount)) 360496554Sobrien & I2O_SGL_FLAGS_DIR) == 0)) { 3605128786Sscottl error = copyout((caddr_t)(elm->KernelSpace), 360696554Sobrien elm->UserSpace, 360796554Sobrien I2O_FLAGS_COUNT_getCount(&(elm->FlagsCount))); 360896554Sobrien } 360996554Sobrien SLIST_REMOVE_HEAD(&sgList, link); 3610128786Sscottl free(elm, M_TEMP); 361196554Sobrien } 361296554Sobrien if (error == 0) { 361396554Sobrien /* Copy reply frame to user space */ 3614128786Sscottl error = copyout((caddr_t)Reply_Ptr, (caddr_t)Reply, 3615128786Sscottl ReplySizeInBytes); 361696554Sobrien } 3617128786Sscottl free(Reply_Ptr, M_TEMP); 361896554Sobrien asr_free_ccb(ccb); 361965312Smsmith 362096554Sobrien return (error); 362165312Smsmith} /* ASR_queue_i */ 362265312Smsmith 362365312Smsmith/*----------------------------------------------------------------------*/ 362496554Sobrien/* Function asr_ioctl */ 362565312Smsmith/*----------------------------------------------------------------------*/ 362696554Sobrien/* The parameters passed to this function are : */ 362796554Sobrien/* dev : Device number. */ 362896554Sobrien/* cmd : Ioctl Command */ 362996554Sobrien/* data : User Argument Passed In. */ 363096554Sobrien/* flag : Mode Parameter */ 363196554Sobrien/* proc : Process Parameter */ 363296554Sobrien/* */ 363396554Sobrien/* This function is the user interface into this adapter driver */ 363496554Sobrien/* */ 363596554Sobrien/* Return : zero if OK, error code if not */ 363665312Smsmith/*----------------------------------------------------------------------*/ 363765312Smsmith 3638128784Sscottlstatic int 3639130585Sphkasr_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 364065312Smsmith{ 3641128792Sscottl Asr_softc_t *sc = dev->si_drv1; 3642128945Sscottl int i, error = 0; 3643143729Scognet#ifdef ASR_IOCTL_COMPAT 3644143729Scognet int j; 3645143729Scognet#endif /* ASR_IOCTL_COMPAT */ 364665312Smsmith 3647128511Sscottl if (sc != NULL) 364896554Sobrien switch(cmd) { 364965312Smsmith 365096554Sobrien case DPT_SIGNATURE: 3651143729Scognet#ifdef ASR_IOCTL_COMPAT 3652143729Scognet#if (dsDescription_size != 50) 3653143729Scognet case DPT_SIGNATURE + ((50 - dsDescription_size) << 16): 3654143729Scognet#endif 3655143729Scognet if (cmd & 0xFFFF0000) { 3656143729Scognet bcopy(&ASR_sig, data, sizeof(dpt_sig_S)); 3657143729Scognet return (0); 3658143729Scognet } 3659143729Scognet /* Traditional version of the ioctl interface */ 3660143729Scognet case DPT_SIGNATURE & 0x0000FFFF: 3661143729Scognet#endif 3662128945Sscottl return (copyout((caddr_t)(&ASR_sig), *((caddr_t *)data), 3663128945Sscottl sizeof(dpt_sig_S))); 366465312Smsmith 366596554Sobrien /* Traditional version of the ioctl interface */ 366696554Sobrien case DPT_CTRLINFO & 0x0000FFFF: 366796554Sobrien case DPT_CTRLINFO: { 366896554Sobrien struct { 366996554Sobrien u_int16_t length; 367096554Sobrien u_int16_t drvrHBAnum; 367196554Sobrien u_int32_t baseAddr; 367296554Sobrien u_int16_t blinkState; 367396554Sobrien u_int8_t pciBusNum; 367496554Sobrien u_int8_t pciDeviceNum; 367596554Sobrien u_int16_t hbaFlags; 367696554Sobrien u_int16_t Interrupt; 367796554Sobrien u_int32_t reserved1; 367896554Sobrien u_int32_t reserved2; 367996554Sobrien u_int32_t reserved3; 368096554Sobrien } CtlrInfo; 368165312Smsmith 3682128787Sscottl bzero(&CtlrInfo, sizeof(CtlrInfo)); 368396554Sobrien CtlrInfo.length = sizeof(CtlrInfo) - sizeof(u_int16_t); 368496554Sobrien CtlrInfo.drvrHBAnum = asr_unit(dev); 3685128944Sscottl CtlrInfo.baseAddr = sc->ha_Base; 368696554Sobrien i = ASR_getBlinkLedCode (sc); 3687128945Sscottl if (i == -1) 368896554Sobrien i = 0; 3689128945Sscottl 369096554Sobrien CtlrInfo.blinkState = i; 369196554Sobrien CtlrInfo.pciBusNum = sc->ha_pciBusNum; 369296554Sobrien CtlrInfo.pciDeviceNum = sc->ha_pciDeviceNum; 369396615Sobrien#define FLG_OSD_PCI_VALID 0x0001 369496615Sobrien#define FLG_OSD_DMA 0x0002 369596615Sobrien#define FLG_OSD_I2O 0x0004 3696128786Sscottl CtlrInfo.hbaFlags = FLG_OSD_PCI_VALID|FLG_OSD_DMA|FLG_OSD_I2O; 369796554Sobrien CtlrInfo.Interrupt = sc->ha_irq; 3698143729Scognet#ifdef ASR_IOCTL_COMPAT 3699143729Scognet if (cmd & 0xffff0000) 3700143729Scognet bcopy(&CtlrInfo, data, sizeof(CtlrInfo)); 3701143729Scognet else 3702143729Scognet#endif /* ASR_IOCTL_COMPAT */ 3703128945Sscottl error = copyout(&CtlrInfo, *(caddr_t *)data, sizeof(CtlrInfo)); 370496554Sobrien } return (error); 370565312Smsmith 370696554Sobrien /* Traditional version of the ioctl interface */ 370796554Sobrien case DPT_SYSINFO & 0x0000FFFF: 370896554Sobrien case DPT_SYSINFO: { 370996554Sobrien sysInfo_S Info; 3710143729Scognet#ifdef ASR_IOCTL_COMPAT 3711143729Scognet char * cp; 3712143729Scognet /* Kernel Specific ptok `hack' */ 3713143729Scognet#define ptok(a) ((char *)(uintptr_t)(a) + KERNBASE) 371465312Smsmith 3715128786Sscottl bzero(&Info, sizeof(Info)); 371665312Smsmith 3717143729Scognet /* Appears I am the only person in the Kernel doing this */ 3718143729Scognet outb (0x70, 0x12); 3719143729Scognet i = inb(0x71); 3720143729Scognet j = i >> 4; 3721143729Scognet if (i == 0x0f) { 3722143729Scognet outb (0x70, 0x19); 3723143729Scognet j = inb (0x71); 3724143729Scognet } 3725143729Scognet Info.drive0CMOS = j; 3726143729Scognet 3727143729Scognet j = i & 0x0f; 3728143729Scognet if (i == 0x0f) { 3729143729Scognet outb (0x70, 0x1a); 3730143729Scognet j = inb (0x71); 3731143729Scognet } 3732143729Scognet Info.drive1CMOS = j; 3733143729Scognet 3734143729Scognet Info.numDrives = *((char *)ptok(0x475)); 3735215843Sbrian#else /* ASR_IOCTL_COMPAT */ 3736215843Sbrian bzero(&Info, sizeof(Info)); 3737143729Scognet#endif /* ASR_IOCTL_COMPAT */ 3738143729Scognet 373996554Sobrien Info.processorFamily = ASR_sig.dsProcessorFamily; 374096614Sobrien#if defined(__i386__) 374196554Sobrien switch (cpu) { 374296554Sobrien case CPU_386SX: case CPU_386: 374396554Sobrien Info.processorType = PROC_386; break; 374496554Sobrien case CPU_486SX: case CPU_486: 374596554Sobrien Info.processorType = PROC_486; break; 374696554Sobrien case CPU_586: 374796554Sobrien Info.processorType = PROC_PENTIUM; break; 374896554Sobrien case CPU_686: 374996554Sobrien Info.processorType = PROC_SEXIUM; break; 375096554Sobrien } 375175062Sscottl#endif 375275062Sscottl 375396554Sobrien Info.osType = OS_BSDI_UNIX; 375496554Sobrien Info.osMajorVersion = osrelease[0] - '0'; 375596554Sobrien Info.osMinorVersion = osrelease[2] - '0'; 375696554Sobrien /* Info.osRevision = 0; */ 375796554Sobrien /* Info.osSubRevision = 0; */ 375896554Sobrien Info.busType = SI_PCI_BUS; 3759128945Sscottl Info.flags = SI_OSversionValid|SI_BusTypeValid|SI_NO_SmartROM; 376065312Smsmith 3761143729Scognet#ifdef ASR_IOCTL_COMPAT 3762143729Scognet Info.flags |= SI_CMOS_Valid | SI_NumDrivesValid; 3763143729Scognet /* Go Out And Look For I2O SmartROM */ 3764143729Scognet for(j = 0xC8000; j < 0xE0000; j += 2048) { 3765143729Scognet int k; 3766143729Scognet 3767143729Scognet cp = ptok(j); 3768143729Scognet if (*((unsigned short *)cp) != 0xAA55) { 3769143729Scognet continue; 3770143729Scognet } 3771143729Scognet j += (cp[2] * 512) - 2048; 3772143729Scognet if ((*((u_long *)(cp + 6)) 3773143729Scognet != ('S' + (' ' * 256) + (' ' * 65536L))) 3774143729Scognet || (*((u_long *)(cp + 10)) 3775143729Scognet != ('I' + ('2' * 256) + ('0' * 65536L)))) { 3776143729Scognet continue; 3777143729Scognet } 3778143729Scognet cp += 0x24; 3779143729Scognet for (k = 0; k < 64; ++k) { 3780143729Scognet if (*((unsigned short *)cp) 3781143729Scognet == (' ' + ('v' * 256))) { 3782143729Scognet break; 3783143729Scognet } 3784143729Scognet } 3785143729Scognet if (k < 64) { 3786143729Scognet Info.smartROMMajorVersion 3787143729Scognet = *((unsigned char *)(cp += 4)) - '0'; 3788143729Scognet Info.smartROMMinorVersion 3789143729Scognet = *((unsigned char *)(cp += 2)); 3790143729Scognet Info.smartROMRevision 3791143729Scognet = *((unsigned char *)(++cp)); 3792143729Scognet Info.flags |= SI_SmartROMverValid; 3793143729Scognet Info.flags &= ~SI_NO_SmartROM; 3794143729Scognet break; 3795143729Scognet } 3796143729Scognet } 3797143729Scognet /* Get The Conventional Memory Size From CMOS */ 3798143729Scognet outb (0x70, 0x16); 3799143729Scognet j = inb (0x71); 3800143729Scognet j <<= 8; 3801143729Scognet outb (0x70, 0x15); 3802143729Scognet j |= inb(0x71); 3803143729Scognet Info.conventionalMemSize = j; 3804143729Scognet 3805143729Scognet /* Get The Extended Memory Found At Power On From CMOS */ 3806143729Scognet outb (0x70, 0x31); 3807143729Scognet j = inb (0x71); 3808143729Scognet j <<= 8; 3809143729Scognet outb (0x70, 0x30); 3810143729Scognet j |= inb(0x71); 3811143729Scognet Info.extendedMemSize = j; 3812143729Scognet Info.flags |= SI_MemorySizeValid; 3813143729Scognet 3814143729Scognet /* Copy Out The Info Structure To The User */ 3815143729Scognet if (cmd & 0xFFFF0000) 3816143729Scognet bcopy(&Info, data, sizeof(Info)); 3817143729Scognet else 3818143729Scognet#endif /* ASR_IOCTL_COMPAT */ 3819128945Sscottl error = copyout(&Info, *(caddr_t *)data, sizeof(Info)); 382096554Sobrien return (error); } 382165312Smsmith 382296554Sobrien /* Get The BlinkLED State */ 382396554Sobrien case DPT_BLINKLED: 382496554Sobrien i = ASR_getBlinkLedCode (sc); 3825143729Scognet if (i == -1) 382696554Sobrien i = 0; 3827143729Scognet#ifdef ASR_IOCTL_COMPAT 3828143729Scognet if (cmd & 0xffff0000) 3829143729Scognet bcopy(&i, data, sizeof(i)); 3830143729Scognet else 3831143729Scognet#endif /* ASR_IOCTL_COMPAT */ 3832128945Sscottl error = copyout(&i, *(caddr_t *)data, sizeof(i)); 383396554Sobrien break; 383465312Smsmith 383596554Sobrien /* Send an I2O command */ 383696554Sobrien case I2OUSRCMD: 3837128786Sscottl return (ASR_queue_i(sc, *((PI2O_MESSAGE_FRAME *)data))); 383865312Smsmith 383996554Sobrien /* Reset and re-initialize the adapter */ 384096554Sobrien case I2ORESETCMD: 3841128786Sscottl return (ASR_reset(sc)); 384265312Smsmith 384396554Sobrien /* Rescan the LCT table and resynchronize the information */ 384496554Sobrien case I2ORESCANCMD: 3845128786Sscottl return (ASR_rescan(sc)); 384696554Sobrien } 384796554Sobrien return (EINVAL); 384865312Smsmith} /* asr_ioctl */ 3849