18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * dc395x.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Device Driver for Tekram DC395(U/UW/F), DC315(U) 58c2ecf20Sopenharmony_ci * PCI SCSI Bus Master Host Adapter 68c2ecf20Sopenharmony_ci * (SCSI chip set used Tekram ASIC TRM-S1040) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Authors: 98c2ecf20Sopenharmony_ci * C.L. Huang <ching@tekram.com.tw> 108c2ecf20Sopenharmony_ci * Erich Chen <erich@tekram.com.tw> 118c2ecf20Sopenharmony_ci * (C) Copyright 1995-1999 Tekram Technology Co., Ltd. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Kurt Garloff <garloff@suse.de> 148c2ecf20Sopenharmony_ci * (C) 1999-2000 Kurt Garloff 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Oliver Neukum <oliver@neukum.name> 178c2ecf20Sopenharmony_ci * Ali Akcaagac <aliakc@web.de> 188c2ecf20Sopenharmony_ci * Jamie Lenehan <lenehan@twibble.org> 198c2ecf20Sopenharmony_ci * (C) 2003 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * License: GNU GPL 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci ************************************************************************* 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 268c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 278c2ecf20Sopenharmony_ci * are met: 288c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 298c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 308c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 318c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 328c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 338c2ecf20Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 348c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 378c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 388c2ecf20Sopenharmony_ci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 398c2ecf20Sopenharmony_ci * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 408c2ecf20Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 418c2ecf20Sopenharmony_ci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 428c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 438c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 448c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 458c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci ************************************************************************ 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci#include <linux/module.h> 508c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 518c2ecf20Sopenharmony_ci#include <linux/delay.h> 528c2ecf20Sopenharmony_ci#include <linux/ctype.h> 538c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 548c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 558c2ecf20Sopenharmony_ci#include <linux/init.h> 568c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 578c2ecf20Sopenharmony_ci#include <linux/pci.h> 588c2ecf20Sopenharmony_ci#include <linux/list.h> 598c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 608c2ecf20Sopenharmony_ci#include <linux/slab.h> 618c2ecf20Sopenharmony_ci#include <asm/io.h> 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 648c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 658c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 668c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#include "dc395x.h" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define DC395X_NAME "dc395x" 718c2ecf20Sopenharmony_ci#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" 728c2ecf20Sopenharmony_ci#define DC395X_VERSION "v2.05, 2004/03/08" 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 758c2ecf20Sopenharmony_ci Features 768c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * Set to disable parts of the driver 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci/*#define DC395x_NO_DISCONNECT*/ 818c2ecf20Sopenharmony_ci/*#define DC395x_NO_TAGQ*/ 828c2ecf20Sopenharmony_ci/*#define DC395x_NO_SYNC*/ 838c2ecf20Sopenharmony_ci/*#define DC395x_NO_WIDE*/ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 868c2ecf20Sopenharmony_ci Debugging 878c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Types of debugging that can be enabled and disabled 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci#define DBG_KG 0x0001 928c2ecf20Sopenharmony_ci#define DBG_0 0x0002 938c2ecf20Sopenharmony_ci#define DBG_1 0x0004 948c2ecf20Sopenharmony_ci#define DBG_SG 0x0020 958c2ecf20Sopenharmony_ci#define DBG_FIFO 0x0040 968c2ecf20Sopenharmony_ci#define DBG_PIO 0x0080 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * Set set of things to output debugging for. 1018c2ecf20Sopenharmony_ci * Undefine to remove all debugging 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/ 1048c2ecf20Sopenharmony_ci/*#define DEBUG_MASK DBG_0*/ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * Output a kernel mesage at the specified level and append the 1098c2ecf20Sopenharmony_ci * driver name and a ": " to the start of the message 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci#define dprintkl(level, format, arg...) \ 1128c2ecf20Sopenharmony_ci printk(level DC395X_NAME ": " format , ## arg) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#ifdef DEBUG_MASK 1168c2ecf20Sopenharmony_ci/* 1178c2ecf20Sopenharmony_ci * print a debug message - this is formated with KERN_DEBUG, then the 1188c2ecf20Sopenharmony_ci * driver name followed by a ": " and then the message is output. 1198c2ecf20Sopenharmony_ci * This also checks that the specified debug level is enabled before 1208c2ecf20Sopenharmony_ci * outputing the message 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci#define dprintkdbg(type, format, arg...) \ 1238c2ecf20Sopenharmony_ci do { \ 1248c2ecf20Sopenharmony_ci if ((type) & (DEBUG_MASK)) \ 1258c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG , format , ## arg); \ 1268c2ecf20Sopenharmony_ci } while (0) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 1298c2ecf20Sopenharmony_ci * Check if the specified type of debugging is enabled 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci#define debug_enabled(type) ((DEBUG_MASK) & (type)) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#else 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * No debugging. Do nothing 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci#define dprintkdbg(type, format, arg...) \ 1388c2ecf20Sopenharmony_ci do {} while (0) 1398c2ecf20Sopenharmony_ci#define debug_enabled(type) (0) 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#endif 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#ifndef PCI_VENDOR_ID_TEKRAM 1458c2ecf20Sopenharmony_ci#define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ 1468c2ecf20Sopenharmony_ci#endif 1478c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040 1488c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_TEKRAM_TRMS1040 0x0391 /* Device ID */ 1498c2ecf20Sopenharmony_ci#endif 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci#define DC395x_LOCK_IO(dev,flags) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags) 1538c2ecf20Sopenharmony_ci#define DC395x_UNLOCK_IO(dev,flags) spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define DC395x_read8(acb,address) (u8)(inb(acb->io_port_base + (address))) 1568c2ecf20Sopenharmony_ci#define DC395x_read16(acb,address) (u16)(inw(acb->io_port_base + (address))) 1578c2ecf20Sopenharmony_ci#define DC395x_read32(acb,address) (u32)(inl(acb->io_port_base + (address))) 1588c2ecf20Sopenharmony_ci#define DC395x_write8(acb,address,value) outb((value), acb->io_port_base + (address)) 1598c2ecf20Sopenharmony_ci#define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address)) 1608c2ecf20Sopenharmony_ci#define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address)) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* cmd->result */ 1638c2ecf20Sopenharmony_ci#define RES_TARGET 0x000000FF /* Target State */ 1648c2ecf20Sopenharmony_ci#define RES_TARGET_LNX STATUS_MASK /* Only official ... */ 1658c2ecf20Sopenharmony_ci#define RES_ENDMSG 0x0000FF00 /* End Message */ 1668c2ecf20Sopenharmony_ci#define RES_DID 0x00FF0000 /* DID_ codes */ 1678c2ecf20Sopenharmony_ci#define RES_DRV 0xFF000000 /* DRIVER_ codes */ 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) 1708c2ecf20Sopenharmony_ci#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); } 1738c2ecf20Sopenharmony_ci#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } 1748c2ecf20Sopenharmony_ci#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } 1758c2ecf20Sopenharmony_ci#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } 1768c2ecf20Sopenharmony_ci#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define TAG_NONE 255 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* 1818c2ecf20Sopenharmony_ci * srb->segement_x is the hw sg list. It is always allocated as a 1828c2ecf20Sopenharmony_ci * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not 1838c2ecf20Sopenharmony_ci * cross a page boundy. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci#define SEGMENTX_LEN (sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY) 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistruct SGentry { 1898c2ecf20Sopenharmony_ci u32 address; /* bus! address */ 1908c2ecf20Sopenharmony_ci u32 length; 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* The SEEPROM structure for TRM_S1040 */ 1948c2ecf20Sopenharmony_cistruct NVRamTarget { 1958c2ecf20Sopenharmony_ci u8 cfg0; /* Target configuration byte 0 */ 1968c2ecf20Sopenharmony_ci u8 period; /* Target period */ 1978c2ecf20Sopenharmony_ci u8 cfg2; /* Target configuration byte 2 */ 1988c2ecf20Sopenharmony_ci u8 cfg3; /* Target configuration byte 3 */ 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistruct NvRamType { 2028c2ecf20Sopenharmony_ci u8 sub_vendor_id[2]; /* 0,1 Sub Vendor ID */ 2038c2ecf20Sopenharmony_ci u8 sub_sys_id[2]; /* 2,3 Sub System ID */ 2048c2ecf20Sopenharmony_ci u8 sub_class; /* 4 Sub Class */ 2058c2ecf20Sopenharmony_ci u8 vendor_id[2]; /* 5,6 Vendor ID */ 2068c2ecf20Sopenharmony_ci u8 device_id[2]; /* 7,8 Device ID */ 2078c2ecf20Sopenharmony_ci u8 reserved; /* 9 Reserved */ 2088c2ecf20Sopenharmony_ci struct NVRamTarget target[DC395x_MAX_SCSI_ID]; 2098c2ecf20Sopenharmony_ci /** 10,11,12,13 2108c2ecf20Sopenharmony_ci ** 14,15,16,17 2118c2ecf20Sopenharmony_ci ** .... 2128c2ecf20Sopenharmony_ci ** .... 2138c2ecf20Sopenharmony_ci ** 70,71,72,73 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci u8 scsi_id; /* 74 Host Adapter SCSI ID */ 2168c2ecf20Sopenharmony_ci u8 channel_cfg; /* 75 Channel configuration */ 2178c2ecf20Sopenharmony_ci u8 delay_time; /* 76 Power on delay time */ 2188c2ecf20Sopenharmony_ci u8 max_tag; /* 77 Maximum tags */ 2198c2ecf20Sopenharmony_ci u8 reserved0; /* 78 */ 2208c2ecf20Sopenharmony_ci u8 boot_target; /* 79 */ 2218c2ecf20Sopenharmony_ci u8 boot_lun; /* 80 */ 2228c2ecf20Sopenharmony_ci u8 reserved1; /* 81 */ 2238c2ecf20Sopenharmony_ci u16 reserved2[22]; /* 82,..125 */ 2248c2ecf20Sopenharmony_ci u16 cksum; /* 126,127 */ 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistruct ScsiReqBlk { 2288c2ecf20Sopenharmony_ci struct list_head list; /* next/prev ptrs for srb lists */ 2298c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 2308c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ 2338c2ecf20Sopenharmony_ci dma_addr_t sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci u8 sg_count; /* No of HW sg entries for this request */ 2368c2ecf20Sopenharmony_ci u8 sg_index; /* Index of HW sg entry for this request */ 2378c2ecf20Sopenharmony_ci size_t total_xfer_length; /* Total number of bytes remaining to be transferred */ 2388c2ecf20Sopenharmony_ci size_t request_length; /* Total number of bytes in this request */ 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * The sense buffer handling function, request_sense, uses 2418c2ecf20Sopenharmony_ci * the first hw sg entry (segment_x[0]) and the transfer 2428c2ecf20Sopenharmony_ci * length (total_xfer_length). While doing this it stores the 2438c2ecf20Sopenharmony_ci * original values into the last sg hw list 2448c2ecf20Sopenharmony_ci * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the 2458c2ecf20Sopenharmony_ci * total_xfer_length in xferred. These values are restored in 2468c2ecf20Sopenharmony_ci * pci_unmap_srb_sense. This is the only place xferred is used. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci size_t xferred; /* Saved copy of total_xfer_length */ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci u16 state; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci u8 msgin_buf[6]; 2538c2ecf20Sopenharmony_ci u8 msgout_buf[6]; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci u8 adapter_status; 2568c2ecf20Sopenharmony_ci u8 target_status; 2578c2ecf20Sopenharmony_ci u8 msg_count; 2588c2ecf20Sopenharmony_ci u8 end_message; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci u8 tag_number; 2618c2ecf20Sopenharmony_ci u8 status; 2628c2ecf20Sopenharmony_ci u8 retry_count; 2638c2ecf20Sopenharmony_ci u8 flag; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci u8 scsi_phase; 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistruct DeviceCtlBlk { 2698c2ecf20Sopenharmony_ci struct list_head list; /* next/prev ptrs for the dcb list */ 2708c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb; 2718c2ecf20Sopenharmony_ci struct list_head srb_going_list; /* head of going srb list */ 2728c2ecf20Sopenharmony_ci struct list_head srb_waiting_list; /* head of waiting srb list */ 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci struct ScsiReqBlk *active_srb; 2758c2ecf20Sopenharmony_ci u32 tag_mask; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci u16 max_command; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci u8 target_id; /* SCSI Target ID (SCSI Only) */ 2808c2ecf20Sopenharmony_ci u8 target_lun; /* SCSI Log. Unit (SCSI Only) */ 2818c2ecf20Sopenharmony_ci u8 identify_msg; 2828c2ecf20Sopenharmony_ci u8 dev_mode; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci u8 inquiry7; /* To store Inquiry flags */ 2858c2ecf20Sopenharmony_ci u8 sync_mode; /* 0:async mode */ 2868c2ecf20Sopenharmony_ci u8 min_nego_period; /* for nego. */ 2878c2ecf20Sopenharmony_ci u8 sync_period; /* for reg. */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci u8 sync_offset; /* for reg. and nego.(low nibble) */ 2908c2ecf20Sopenharmony_ci u8 flag; 2918c2ecf20Sopenharmony_ci u8 dev_type; 2928c2ecf20Sopenharmony_ci u8 init_tcq_flag; 2938c2ecf20Sopenharmony_ci}; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistruct AdapterCtlBlk { 2968c2ecf20Sopenharmony_ci struct Scsi_Host *scsi_host; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci unsigned long io_port_base; 2998c2ecf20Sopenharmony_ci unsigned long io_port_len; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci struct list_head dcb_list; /* head of going dcb list */ 3028c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb_run_robin; 3038c2ecf20Sopenharmony_ci struct DeviceCtlBlk *active_dcb; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci struct list_head srb_free_list; /* head of free srb list */ 3068c2ecf20Sopenharmony_ci struct ScsiReqBlk *tmp_srb; 3078c2ecf20Sopenharmony_ci struct timer_list waiting_timer; 3088c2ecf20Sopenharmony_ci struct timer_list selto_timer; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci unsigned long last_reset; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci u16 srb_count; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci u8 sel_timeout; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci unsigned int irq_level; 3178c2ecf20Sopenharmony_ci u8 tag_max_num; 3188c2ecf20Sopenharmony_ci u8 acb_flag; 3198c2ecf20Sopenharmony_ci u8 gmode2; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci u8 config; 3228c2ecf20Sopenharmony_ci u8 lun_chk; 3238c2ecf20Sopenharmony_ci u8 scan_devices; 3248c2ecf20Sopenharmony_ci u8 hostid_bit; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci u8 dcb_map[DC395x_MAX_SCSI_ID]; 3278c2ecf20Sopenharmony_ci struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32]; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci struct pci_dev *dev; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci u8 msg_len; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT]; 3348c2ecf20Sopenharmony_ci struct ScsiReqBlk srb; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci struct NvRamType eeprom; /* eeprom settings for this adapter */ 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 3418c2ecf20Sopenharmony_ci Forward declarations 3428c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 3438c2ecf20Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3448c2ecf20Sopenharmony_ci u16 *pscsi_status); 3458c2ecf20Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3468c2ecf20Sopenharmony_ci u16 *pscsi_status); 3478c2ecf20Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3488c2ecf20Sopenharmony_ci u16 *pscsi_status); 3498c2ecf20Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3508c2ecf20Sopenharmony_ci u16 *pscsi_status); 3518c2ecf20Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3528c2ecf20Sopenharmony_ci u16 *pscsi_status); 3538c2ecf20Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3548c2ecf20Sopenharmony_ci u16 *pscsi_status); 3558c2ecf20Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3568c2ecf20Sopenharmony_ci u16 *pscsi_status); 3578c2ecf20Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3588c2ecf20Sopenharmony_ci u16 *pscsi_status); 3598c2ecf20Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3608c2ecf20Sopenharmony_ci u16 *pscsi_status); 3618c2ecf20Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3628c2ecf20Sopenharmony_ci u16 *pscsi_status); 3638c2ecf20Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3648c2ecf20Sopenharmony_ci u16 *pscsi_status); 3658c2ecf20Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3668c2ecf20Sopenharmony_ci u16 *pscsi_status); 3678c2ecf20Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3688c2ecf20Sopenharmony_ci u16 *pscsi_status); 3698c2ecf20Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 3708c2ecf20Sopenharmony_ci u16 *pscsi_status); 3718c2ecf20Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb); 3728c2ecf20Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb, 3738c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3748c2ecf20Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb); 3758c2ecf20Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb, 3768c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb, u16 io_dir); 3778c2ecf20Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb); 3788c2ecf20Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb); 3798c2ecf20Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 3808c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3818c2ecf20Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb, 3828c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3838c2ecf20Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, 3848c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3858c2ecf20Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, 3868c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd, u8 force); 3878c2ecf20Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb); 3888c2ecf20Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); 3898c2ecf20Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, 3908c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3918c2ecf20Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 3928c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3938c2ecf20Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 3948c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb); 3958c2ecf20Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb, 3968c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb); 3978c2ecf20Sopenharmony_cistatic void waiting_timeout(struct timer_list *t); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 4018c2ecf20Sopenharmony_ci Static Data 4028c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 4038c2ecf20Sopenharmony_cistatic u16 current_sync_offset = 0; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void *dc395x_scsi_phase0[] = { 4068c2ecf20Sopenharmony_ci data_out_phase0,/* phase:0 */ 4078c2ecf20Sopenharmony_ci data_in_phase0, /* phase:1 */ 4088c2ecf20Sopenharmony_ci command_phase0, /* phase:2 */ 4098c2ecf20Sopenharmony_ci status_phase0, /* phase:3 */ 4108c2ecf20Sopenharmony_ci nop0, /* phase:4 PH_BUS_FREE .. initial phase */ 4118c2ecf20Sopenharmony_ci nop0, /* phase:5 PH_BUS_FREE .. initial phase */ 4128c2ecf20Sopenharmony_ci msgout_phase0, /* phase:6 */ 4138c2ecf20Sopenharmony_ci msgin_phase0, /* phase:7 */ 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void *dc395x_scsi_phase1[] = { 4178c2ecf20Sopenharmony_ci data_out_phase1,/* phase:0 */ 4188c2ecf20Sopenharmony_ci data_in_phase1, /* phase:1 */ 4198c2ecf20Sopenharmony_ci command_phase1, /* phase:2 */ 4208c2ecf20Sopenharmony_ci status_phase1, /* phase:3 */ 4218c2ecf20Sopenharmony_ci nop1, /* phase:4 PH_BUS_FREE .. initial phase */ 4228c2ecf20Sopenharmony_ci nop1, /* phase:5 PH_BUS_FREE .. initial phase */ 4238c2ecf20Sopenharmony_ci msgout_phase1, /* phase:6 */ 4248c2ecf20Sopenharmony_ci msgin_phase1, /* phase:7 */ 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci/* 4288c2ecf20Sopenharmony_ci *Fast20: 000 50ns, 20.0 MHz 4298c2ecf20Sopenharmony_ci * 001 75ns, 13.3 MHz 4308c2ecf20Sopenharmony_ci * 010 100ns, 10.0 MHz 4318c2ecf20Sopenharmony_ci * 011 125ns, 8.0 MHz 4328c2ecf20Sopenharmony_ci * 100 150ns, 6.6 MHz 4338c2ecf20Sopenharmony_ci * 101 175ns, 5.7 MHz 4348c2ecf20Sopenharmony_ci * 110 200ns, 5.0 MHz 4358c2ecf20Sopenharmony_ci * 111 250ns, 4.0 MHz 4368c2ecf20Sopenharmony_ci * 4378c2ecf20Sopenharmony_ci *Fast40(LVDS): 000 25ns, 40.0 MHz 4388c2ecf20Sopenharmony_ci * 001 50ns, 20.0 MHz 4398c2ecf20Sopenharmony_ci * 010 75ns, 13.3 MHz 4408c2ecf20Sopenharmony_ci * 011 100ns, 10.0 MHz 4418c2ecf20Sopenharmony_ci * 100 125ns, 8.0 MHz 4428c2ecf20Sopenharmony_ci * 101 150ns, 6.6 MHz 4438c2ecf20Sopenharmony_ci * 110 175ns, 5.7 MHz 4448c2ecf20Sopenharmony_ci * 111 200ns, 5.0 MHz 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ci/*static u8 clock_period[] = {12,19,25,31,37,44,50,62};*/ 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ 4498c2ecf20Sopenharmony_cistatic u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 }; 4508c2ecf20Sopenharmony_cistatic u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 4548c2ecf20Sopenharmony_ci Configuration 4558c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 4568c2ecf20Sopenharmony_ci/* 4578c2ecf20Sopenharmony_ci * Module/boot parameters currently effect *all* instances of the 4588c2ecf20Sopenharmony_ci * card in the system. 4598c2ecf20Sopenharmony_ci */ 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci/* 4628c2ecf20Sopenharmony_ci * Command line parameters are stored in a structure below. 4638c2ecf20Sopenharmony_ci * These are the index's into the structure for the various 4648c2ecf20Sopenharmony_ci * command line options. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ci#define CFG_ADAPTER_ID 0 4678c2ecf20Sopenharmony_ci#define CFG_MAX_SPEED 1 4688c2ecf20Sopenharmony_ci#define CFG_DEV_MODE 2 4698c2ecf20Sopenharmony_ci#define CFG_ADAPTER_MODE 3 4708c2ecf20Sopenharmony_ci#define CFG_TAGS 4 4718c2ecf20Sopenharmony_ci#define CFG_RESET_DELAY 5 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci#define CFG_NUM 6 /* number of configuration items */ 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/* 4778c2ecf20Sopenharmony_ci * Value used to indicate that a command line override 4788c2ecf20Sopenharmony_ci * hasn't been used to modify the value. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci#define CFG_PARAM_UNSET -1 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/* 4848c2ecf20Sopenharmony_ci * Hold command line parameters. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_cistruct ParameterData { 4878c2ecf20Sopenharmony_ci int value; /* value of this setting */ 4888c2ecf20Sopenharmony_ci int min; /* minimum value */ 4898c2ecf20Sopenharmony_ci int max; /* maximum value */ 4908c2ecf20Sopenharmony_ci int def; /* default value */ 4918c2ecf20Sopenharmony_ci int safe; /* safe value */ 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_cistatic struct ParameterData cfg_data[] = { 4948c2ecf20Sopenharmony_ci { /* adapter id */ 4958c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 4968c2ecf20Sopenharmony_ci 0, 4978c2ecf20Sopenharmony_ci 15, 4988c2ecf20Sopenharmony_ci 7, 4998c2ecf20Sopenharmony_ci 7 5008c2ecf20Sopenharmony_ci }, 5018c2ecf20Sopenharmony_ci { /* max speed */ 5028c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 5038c2ecf20Sopenharmony_ci 0, 5048c2ecf20Sopenharmony_ci 7, 5058c2ecf20Sopenharmony_ci 1, /* 13.3Mhz */ 5068c2ecf20Sopenharmony_ci 4, /* 6.7Hmz */ 5078c2ecf20Sopenharmony_ci }, 5088c2ecf20Sopenharmony_ci { /* dev mode */ 5098c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 5108c2ecf20Sopenharmony_ci 0, 5118c2ecf20Sopenharmony_ci 0x3f, 5128c2ecf20Sopenharmony_ci NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO | 5138c2ecf20Sopenharmony_ci NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING | 5148c2ecf20Sopenharmony_ci NTC_DO_SEND_START, 5158c2ecf20Sopenharmony_ci NTC_DO_PARITY_CHK | NTC_DO_SEND_START 5168c2ecf20Sopenharmony_ci }, 5178c2ecf20Sopenharmony_ci { /* adapter mode */ 5188c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 5198c2ecf20Sopenharmony_ci 0, 5208c2ecf20Sopenharmony_ci 0x2f, 5218c2ecf20Sopenharmony_ci NAC_SCANLUN | 5228c2ecf20Sopenharmony_ci NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET 5238c2ecf20Sopenharmony_ci /*| NAC_ACTIVE_NEG*/, 5248c2ecf20Sopenharmony_ci NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08 5258c2ecf20Sopenharmony_ci }, 5268c2ecf20Sopenharmony_ci { /* tags */ 5278c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 5288c2ecf20Sopenharmony_ci 0, 5298c2ecf20Sopenharmony_ci 5, 5308c2ecf20Sopenharmony_ci 3, /* 16 tags (??) */ 5318c2ecf20Sopenharmony_ci 2, 5328c2ecf20Sopenharmony_ci }, 5338c2ecf20Sopenharmony_ci { /* reset delay */ 5348c2ecf20Sopenharmony_ci CFG_PARAM_UNSET, 5358c2ecf20Sopenharmony_ci 0, 5368c2ecf20Sopenharmony_ci 180, 5378c2ecf20Sopenharmony_ci 1, /* 1 second */ 5388c2ecf20Sopenharmony_ci 10, /* 10 seconds */ 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* 5448c2ecf20Sopenharmony_ci * Safe settings. If set to zero the BIOS/default values with 5458c2ecf20Sopenharmony_ci * command line overrides will be used. If set to 1 then safe and 5468c2ecf20Sopenharmony_ci * slow settings will be used. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_cistatic bool use_safe_settings = 0; 5498c2ecf20Sopenharmony_cimodule_param_named(safe, use_safe_settings, bool, 0); 5508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cimodule_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0); 5548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)"); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cimodule_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0); 5578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz"); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cimodule_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0); 5608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev_mode, "Device mode."); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cimodule_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0); 5638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(adapter_mode, "Adapter mode."); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cimodule_param_named(tags, cfg_data[CFG_TAGS].value, int, 0); 5668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)"); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cimodule_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0); 5698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)"); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/** 5738c2ecf20Sopenharmony_ci * set_safe_settings - if the use_safe_settings option is set then 5748c2ecf20Sopenharmony_ci * set all values to the safe and slow values. 5758c2ecf20Sopenharmony_ci **/ 5768c2ecf20Sopenharmony_cistatic void set_safe_settings(void) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci if (use_safe_settings) 5798c2ecf20Sopenharmony_ci { 5808c2ecf20Sopenharmony_ci int i; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Using safe settings.\n"); 5838c2ecf20Sopenharmony_ci for (i = 0; i < CFG_NUM; i++) 5848c2ecf20Sopenharmony_ci { 5858c2ecf20Sopenharmony_ci cfg_data[i].value = cfg_data[i].safe; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/** 5928c2ecf20Sopenharmony_ci * fix_settings - reset any boot parameters which are out of range 5938c2ecf20Sopenharmony_ci * back to the default values. 5948c2ecf20Sopenharmony_ci **/ 5958c2ecf20Sopenharmony_cistatic void fix_settings(void) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci int i; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, 6008c2ecf20Sopenharmony_ci "setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x " 6018c2ecf20Sopenharmony_ci "AdapterMode=%08x Tags=%08x ResetDelay=%08x\n", 6028c2ecf20Sopenharmony_ci cfg_data[CFG_ADAPTER_ID].value, 6038c2ecf20Sopenharmony_ci cfg_data[CFG_MAX_SPEED].value, 6048c2ecf20Sopenharmony_ci cfg_data[CFG_DEV_MODE].value, 6058c2ecf20Sopenharmony_ci cfg_data[CFG_ADAPTER_MODE].value, 6068c2ecf20Sopenharmony_ci cfg_data[CFG_TAGS].value, 6078c2ecf20Sopenharmony_ci cfg_data[CFG_RESET_DELAY].value); 6088c2ecf20Sopenharmony_ci for (i = 0; i < CFG_NUM; i++) 6098c2ecf20Sopenharmony_ci { 6108c2ecf20Sopenharmony_ci if (cfg_data[i].value < cfg_data[i].min 6118c2ecf20Sopenharmony_ci || cfg_data[i].value > cfg_data[i].max) 6128c2ecf20Sopenharmony_ci cfg_data[i].value = cfg_data[i].def; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * Mapping from the eeprom delay index value (index into this array) 6208c2ecf20Sopenharmony_ci * to the number of actual seconds that the delay should be for. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistatic char eeprom_index_to_delay_map[] = 6238c2ecf20Sopenharmony_ci { 1, 3, 5, 10, 16, 30, 60, 120 }; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci/** 6278c2ecf20Sopenharmony_ci * eeprom_index_to_delay - Take the eeprom delay setting and convert it 6288c2ecf20Sopenharmony_ci * into a number of seconds. 6298c2ecf20Sopenharmony_ci * 6308c2ecf20Sopenharmony_ci * @eeprom: The eeprom structure in which we find the delay index to map. 6318c2ecf20Sopenharmony_ci **/ 6328c2ecf20Sopenharmony_cistatic void eeprom_index_to_delay(struct NvRamType *eeprom) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time]; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/** 6398c2ecf20Sopenharmony_ci * delay_to_eeprom_index - Take a delay in seconds and return the 6408c2ecf20Sopenharmony_ci * closest eeprom index which will delay for at least that amount of 6418c2ecf20Sopenharmony_ci * seconds. 6428c2ecf20Sopenharmony_ci * 6438c2ecf20Sopenharmony_ci * @delay: The delay, in seconds, to find the eeprom index for. 6448c2ecf20Sopenharmony_ci **/ 6458c2ecf20Sopenharmony_cistatic int delay_to_eeprom_index(int delay) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci u8 idx = 0; 6488c2ecf20Sopenharmony_ci while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) 6498c2ecf20Sopenharmony_ci idx++; 6508c2ecf20Sopenharmony_ci return idx; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/** 6558c2ecf20Sopenharmony_ci * eeprom_override - Override the eeprom settings, in the provided 6568c2ecf20Sopenharmony_ci * eeprom structure, with values that have been set on the command 6578c2ecf20Sopenharmony_ci * line. 6588c2ecf20Sopenharmony_ci * 6598c2ecf20Sopenharmony_ci * @eeprom: The eeprom data to override with command line options. 6608c2ecf20Sopenharmony_ci **/ 6618c2ecf20Sopenharmony_cistatic void eeprom_override(struct NvRamType *eeprom) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci u8 id; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Adapter Settings */ 6668c2ecf20Sopenharmony_ci if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) 6678c2ecf20Sopenharmony_ci eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) 6708c2ecf20Sopenharmony_ci eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) 6738c2ecf20Sopenharmony_ci eeprom->delay_time = delay_to_eeprom_index( 6748c2ecf20Sopenharmony_ci cfg_data[CFG_RESET_DELAY].value); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) 6778c2ecf20Sopenharmony_ci eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Device Settings */ 6808c2ecf20Sopenharmony_ci for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { 6818c2ecf20Sopenharmony_ci if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) 6828c2ecf20Sopenharmony_ci eeprom->target[id].cfg0 = 6838c2ecf20Sopenharmony_ci (u8)cfg_data[CFG_DEV_MODE].value; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) 6868c2ecf20Sopenharmony_ci eeprom->target[id].period = 6878c2ecf20Sopenharmony_ci (u8)cfg_data[CFG_MAX_SPEED].value; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/*--------------------------------------------------------------------------- 6948c2ecf20Sopenharmony_ci ---------------------------------------------------------------------------*/ 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic unsigned int list_size(struct list_head *head) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned int count = 0; 6998c2ecf20Sopenharmony_ci struct list_head *pos; 7008c2ecf20Sopenharmony_ci list_for_each(pos, head) 7018c2ecf20Sopenharmony_ci count++; 7028c2ecf20Sopenharmony_ci return count; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *dcb_get_next(struct list_head *head, 7078c2ecf20Sopenharmony_ci struct DeviceCtlBlk *pos) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci int use_next = 0; 7108c2ecf20Sopenharmony_ci struct DeviceCtlBlk* next = NULL; 7118c2ecf20Sopenharmony_ci struct DeviceCtlBlk* i; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (list_empty(head)) 7148c2ecf20Sopenharmony_ci return NULL; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* find supplied dcb and then select the next one */ 7178c2ecf20Sopenharmony_ci list_for_each_entry(i, head, list) 7188c2ecf20Sopenharmony_ci if (use_next) { 7198c2ecf20Sopenharmony_ci next = i; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci } else if (i == pos) { 7228c2ecf20Sopenharmony_ci use_next = 1; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci /* if no next one take the head one (ie, wraparound) */ 7258c2ecf20Sopenharmony_ci if (!next) 7268c2ecf20Sopenharmony_ci list_for_each_entry(i, head, list) { 7278c2ecf20Sopenharmony_ci next = i; 7288c2ecf20Sopenharmony_ci break; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return next; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci if (srb->tag_number < 255) { 7388c2ecf20Sopenharmony_ci dcb->tag_mask &= ~(1 << srb->tag_number); /* free tag mask */ 7398c2ecf20Sopenharmony_ci srb->tag_number = 255; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* Find cmd in SRB list */ 7458c2ecf20Sopenharmony_cistatic inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, 7468c2ecf20Sopenharmony_ci struct list_head *head) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct ScsiReqBlk *i; 7498c2ecf20Sopenharmony_ci list_for_each_entry(i, head, list) 7508c2ecf20Sopenharmony_ci if (i->cmd == cmd) 7518c2ecf20Sopenharmony_ci return i; 7528c2ecf20Sopenharmony_ci return NULL; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/* Sets the timer to wake us up */ 7568c2ecf20Sopenharmony_cistatic void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 7598c2ecf20Sopenharmony_ci return; 7608c2ecf20Sopenharmony_ci if (time_before(jiffies + to, acb->last_reset - HZ / 2)) 7618c2ecf20Sopenharmony_ci acb->waiting_timer.expires = 7628c2ecf20Sopenharmony_ci acb->last_reset - HZ / 2 + 1; 7638c2ecf20Sopenharmony_ci else 7648c2ecf20Sopenharmony_ci acb->waiting_timer.expires = jiffies + to + 1; 7658c2ecf20Sopenharmony_ci add_timer(&acb->waiting_timer); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/* Send the next command from the waiting list to the bus */ 7708c2ecf20Sopenharmony_cistatic void waiting_process_next(struct AdapterCtlBlk *acb) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct DeviceCtlBlk *start = NULL; 7738c2ecf20Sopenharmony_ci struct DeviceCtlBlk *pos; 7748c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 7758c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 7768c2ecf20Sopenharmony_ci struct list_head *dcb_list_head = &acb->dcb_list; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (acb->active_dcb 7798c2ecf20Sopenharmony_ci || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) 7808c2ecf20Sopenharmony_ci return; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 7838c2ecf20Sopenharmony_ci del_timer(&acb->waiting_timer); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (list_empty(dcb_list_head)) 7868c2ecf20Sopenharmony_ci return; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* 7898c2ecf20Sopenharmony_ci * Find the starting dcb. Need to find it again in the list 7908c2ecf20Sopenharmony_ci * since the list may have changed since we set the ptr to it 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci list_for_each_entry(dcb, dcb_list_head, list) 7938c2ecf20Sopenharmony_ci if (dcb == acb->dcb_run_robin) { 7948c2ecf20Sopenharmony_ci start = dcb; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci if (!start) { 7988c2ecf20Sopenharmony_ci /* This can happen! */ 7998c2ecf20Sopenharmony_ci start = list_entry(dcb_list_head->next, typeof(*start), list); 8008c2ecf20Sopenharmony_ci acb->dcb_run_robin = start; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* 8058c2ecf20Sopenharmony_ci * Loop over the dcb, but we start somewhere (potentially) in 8068c2ecf20Sopenharmony_ci * the middle of the loop so we need to manully do this. 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci pos = start; 8098c2ecf20Sopenharmony_ci do { 8108c2ecf20Sopenharmony_ci struct list_head *waiting_list_head = &pos->srb_waiting_list; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci /* Make sure, the next another device gets scheduled ... */ 8138c2ecf20Sopenharmony_ci acb->dcb_run_robin = dcb_get_next(dcb_list_head, 8148c2ecf20Sopenharmony_ci acb->dcb_run_robin); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (list_empty(waiting_list_head) || 8178c2ecf20Sopenharmony_ci pos->max_command <= list_size(&pos->srb_going_list)) { 8188c2ecf20Sopenharmony_ci /* move to next dcb */ 8198c2ecf20Sopenharmony_ci pos = dcb_get_next(dcb_list_head, pos); 8208c2ecf20Sopenharmony_ci } else { 8218c2ecf20Sopenharmony_ci srb = list_entry(waiting_list_head->next, 8228c2ecf20Sopenharmony_ci struct ScsiReqBlk, list); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Try to send to the bus */ 8258c2ecf20Sopenharmony_ci if (!start_scsi(acb, pos, srb)) 8268c2ecf20Sopenharmony_ci list_move(&srb->list, &pos->srb_going_list); 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ/50); 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci } while (pos != start); 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci/* Wake up waiting queue */ 8368c2ecf20Sopenharmony_cistatic void waiting_timeout(struct timer_list *t) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci unsigned long flags; 8398c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = from_timer(acb, t, waiting_timer); 8408c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, 8418c2ecf20Sopenharmony_ci "waiting_timeout: Queue woken up by timer. acb=%p\n", acb); 8428c2ecf20Sopenharmony_ci DC395x_LOCK_IO(acb->scsi_host, flags); 8438c2ecf20Sopenharmony_ci waiting_process_next(acb); 8448c2ecf20Sopenharmony_ci DC395x_UNLOCK_IO(acb->scsi_host, flags); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/* Get the DCB for a given ID/LUN combination */ 8498c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci return acb->children[id][lun]; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci/* Send SCSI Request Block (srb) to adapter (acb) */ 8568c2ecf20Sopenharmony_cistatic void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (dcb->max_command <= list_size(&dcb->srb_going_list) || 8618c2ecf20Sopenharmony_ci acb->active_dcb || 8628c2ecf20Sopenharmony_ci (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) { 8638c2ecf20Sopenharmony_ci list_add_tail(&srb->list, &dcb->srb_waiting_list); 8648c2ecf20Sopenharmony_ci waiting_process_next(acb); 8658c2ecf20Sopenharmony_ci return; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (!start_scsi(acb, dcb, srb)) { 8698c2ecf20Sopenharmony_ci list_add_tail(&srb->list, &dcb->srb_going_list); 8708c2ecf20Sopenharmony_ci } else { 8718c2ecf20Sopenharmony_ci list_add(&srb->list, &dcb->srb_waiting_list); 8728c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ / 50); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/* Prepare SRB for being sent to Device DCB w/ command *cmd */ 8778c2ecf20Sopenharmony_cistatic void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, 8788c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int nseg; 8818c2ecf20Sopenharmony_ci enum dma_data_direction dir = cmd->sc_data_direction; 8828c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n", 8838c2ecf20Sopenharmony_ci cmd, dcb->target_id, dcb->target_lun); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci srb->dcb = dcb; 8868c2ecf20Sopenharmony_ci srb->cmd = cmd; 8878c2ecf20Sopenharmony_ci srb->sg_count = 0; 8888c2ecf20Sopenharmony_ci srb->total_xfer_length = 0; 8898c2ecf20Sopenharmony_ci srb->sg_bus_addr = 0; 8908c2ecf20Sopenharmony_ci srb->sg_index = 0; 8918c2ecf20Sopenharmony_ci srb->adapter_status = 0; 8928c2ecf20Sopenharmony_ci srb->target_status = 0; 8938c2ecf20Sopenharmony_ci srb->msg_count = 0; 8948c2ecf20Sopenharmony_ci srb->status = 0; 8958c2ecf20Sopenharmony_ci srb->flag = 0; 8968c2ecf20Sopenharmony_ci srb->state = 0; 8978c2ecf20Sopenharmony_ci srb->retry_count = 0; 8988c2ecf20Sopenharmony_ci srb->tag_number = TAG_NONE; 8998c2ecf20Sopenharmony_ci srb->scsi_phase = PH_BUS_FREE; /* initial phase */ 9008c2ecf20Sopenharmony_ci srb->end_message = 0; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci nseg = scsi_dma_map(cmd); 9038c2ecf20Sopenharmony_ci BUG_ON(nseg < 0); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (dir == DMA_NONE || !nseg) { 9068c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, 9078c2ecf20Sopenharmony_ci "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", 9088c2ecf20Sopenharmony_ci cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd), 9098c2ecf20Sopenharmony_ci srb->segment_x[0].address); 9108c2ecf20Sopenharmony_ci } else { 9118c2ecf20Sopenharmony_ci int i; 9128c2ecf20Sopenharmony_ci u32 reqlen = scsi_bufflen(cmd); 9138c2ecf20Sopenharmony_ci struct scatterlist *sg; 9148c2ecf20Sopenharmony_ci struct SGentry *sgp = srb->segment_x; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci srb->sg_count = nseg; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, 9198c2ecf20Sopenharmony_ci "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", 9208c2ecf20Sopenharmony_ci reqlen, scsi_sglist(cmd), scsi_sg_count(cmd), 9218c2ecf20Sopenharmony_ci srb->sg_count); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, srb->sg_count, i) { 9248c2ecf20Sopenharmony_ci u32 busaddr = (u32)sg_dma_address(sg); 9258c2ecf20Sopenharmony_ci u32 seglen = (u32)sg->length; 9268c2ecf20Sopenharmony_ci sgp[i].address = busaddr; 9278c2ecf20Sopenharmony_ci sgp[i].length = seglen; 9288c2ecf20Sopenharmony_ci srb->total_xfer_length += seglen; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci sgp += srb->sg_count - 1; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* 9338c2ecf20Sopenharmony_ci * adjust last page if too big as it is allocated 9348c2ecf20Sopenharmony_ci * on even page boundaries 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci if (srb->total_xfer_length > reqlen) { 9378c2ecf20Sopenharmony_ci sgp->length -= (srb->total_xfer_length - reqlen); 9388c2ecf20Sopenharmony_ci srb->total_xfer_length = reqlen; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Fixup for WIDE padding - make sure length is even */ 9428c2ecf20Sopenharmony_ci if (dcb->sync_period & WIDE_SYNC && 9438c2ecf20Sopenharmony_ci srb->total_xfer_length % 2) { 9448c2ecf20Sopenharmony_ci srb->total_xfer_length++; 9458c2ecf20Sopenharmony_ci sgp->length++; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci srb->sg_bus_addr = dma_map_single(&dcb->acb->dev->dev, 9498c2ecf20Sopenharmony_ci srb->segment_x, SEGMENTX_LEN, DMA_TO_DEVICE); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", 9528c2ecf20Sopenharmony_ci srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci srb->request_length = srb->total_xfer_length; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/** 9608c2ecf20Sopenharmony_ci * dc395x_queue_command - queue scsi command passed from the mid 9618c2ecf20Sopenharmony_ci * layer, invoke 'done' on completion 9628c2ecf20Sopenharmony_ci * 9638c2ecf20Sopenharmony_ci * @cmd: pointer to scsi command object 9648c2ecf20Sopenharmony_ci * @done: function pointer to be invoked on completion 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci * Returns 1 if the adapter (host) is busy, else returns 0. One 9678c2ecf20Sopenharmony_ci * reason for an adapter to be busy is that the number 9688c2ecf20Sopenharmony_ci * of outstanding queued commands is already equal to 9698c2ecf20Sopenharmony_ci * struct Scsi_Host::can_queue . 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Required: if struct Scsi_Host::can_queue is ever non-zero 9728c2ecf20Sopenharmony_ci * then this function is required. 9738c2ecf20Sopenharmony_ci * 9748c2ecf20Sopenharmony_ci * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") 9758c2ecf20Sopenharmony_ci * and is expected to be held on return. 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci **/ 9788c2ecf20Sopenharmony_cistatic int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 9818c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 9828c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = 9838c2ecf20Sopenharmony_ci (struct AdapterCtlBlk *)cmd->device->host->hostdata; 9848c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n", 9858c2ecf20Sopenharmony_ci cmd, cmd->device->id, (u8)cmd->device->lun, cmd->cmnd[0]); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Assume BAD_TARGET; will be cleared later */ 9888c2ecf20Sopenharmony_ci cmd->result = DID_BAD_TARGET << 16; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* ignore invalid targets */ 9918c2ecf20Sopenharmony_ci if (cmd->device->id >= acb->scsi_host->max_id || 9928c2ecf20Sopenharmony_ci cmd->device->lun >= acb->scsi_host->max_lun || 9938c2ecf20Sopenharmony_ci cmd->device->lun >31) { 9948c2ecf20Sopenharmony_ci goto complete; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* does the specified lun on the specified device exist */ 9988c2ecf20Sopenharmony_ci if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) { 9998c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n", 10008c2ecf20Sopenharmony_ci cmd->device->id, (u8)cmd->device->lun); 10018c2ecf20Sopenharmony_ci goto complete; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* do we have a DCB for the device */ 10058c2ecf20Sopenharmony_ci dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); 10068c2ecf20Sopenharmony_ci if (!dcb) { 10078c2ecf20Sopenharmony_ci /* should never happen */ 10088c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>", 10098c2ecf20Sopenharmony_ci cmd->device->id, (u8)cmd->device->lun); 10108c2ecf20Sopenharmony_ci goto complete; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* set callback and clear result in the command */ 10148c2ecf20Sopenharmony_ci cmd->scsi_done = done; 10158c2ecf20Sopenharmony_ci cmd->result = 0; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci srb = list_first_entry_or_null(&acb->srb_free_list, 10188c2ecf20Sopenharmony_ci struct ScsiReqBlk, list); 10198c2ecf20Sopenharmony_ci if (!srb) { 10208c2ecf20Sopenharmony_ci /* 10218c2ecf20Sopenharmony_ci * Return 1 since we are unable to queue this command at this 10228c2ecf20Sopenharmony_ci * point in time. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "queue_command: No free srb's\n"); 10258c2ecf20Sopenharmony_ci return 1; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci list_del(&srb->list); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci build_srb(cmd, dcb, srb); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_waiting_list)) { 10328c2ecf20Sopenharmony_ci /* append to waiting queue */ 10338c2ecf20Sopenharmony_ci list_add_tail(&srb->list, &dcb->srb_waiting_list); 10348c2ecf20Sopenharmony_ci waiting_process_next(acb); 10358c2ecf20Sopenharmony_ci } else { 10368c2ecf20Sopenharmony_ci /* process immediately */ 10378c2ecf20Sopenharmony_ci send_srb(acb, srb); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd); 10408c2ecf20Sopenharmony_ci return 0; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cicomplete: 10438c2ecf20Sopenharmony_ci /* 10448c2ecf20Sopenharmony_ci * Complete the command immediatey, and then return 0 to 10458c2ecf20Sopenharmony_ci * indicate that we have handled the command. This is usually 10468c2ecf20Sopenharmony_ci * done when the commad is for things like non existent 10478c2ecf20Sopenharmony_ci * devices. 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci done(cmd); 10508c2ecf20Sopenharmony_ci return 0; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(dc395x_queue_command) 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic void dump_register_info(struct AdapterCtlBlk *acb, 10568c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci u16 pstat; 10598c2ecf20Sopenharmony_ci struct pci_dev *dev = acb->dev; 10608c2ecf20Sopenharmony_ci pci_read_config_word(dev, PCI_STATUS, &pstat); 10618c2ecf20Sopenharmony_ci if (!dcb) 10628c2ecf20Sopenharmony_ci dcb = acb->active_dcb; 10638c2ecf20Sopenharmony_ci if (!srb && dcb) 10648c2ecf20Sopenharmony_ci srb = dcb->active_srb; 10658c2ecf20Sopenharmony_ci if (srb) { 10668c2ecf20Sopenharmony_ci if (!srb->cmd) 10678c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", 10688c2ecf20Sopenharmony_ci srb, srb->cmd); 10698c2ecf20Sopenharmony_ci else 10708c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "dump: srb=%p cmd=%p " 10718c2ecf20Sopenharmony_ci "cmnd=0x%02x <%02i-%i>\n", 10728c2ecf20Sopenharmony_ci srb, srb->cmd, 10738c2ecf20Sopenharmony_ci srb->cmd->cmnd[0], srb->cmd->device->id, 10748c2ecf20Sopenharmony_ci (u8)srb->cmd->device->lun); 10758c2ecf20Sopenharmony_ci printk(" sglist=%p cnt=%i idx=%i len=%zu\n", 10768c2ecf20Sopenharmony_ci srb->segment_x, srb->sg_count, srb->sg_index, 10778c2ecf20Sopenharmony_ci srb->total_xfer_length); 10788c2ecf20Sopenharmony_ci printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", 10798c2ecf20Sopenharmony_ci srb->state, srb->status, srb->scsi_phase, 10808c2ecf20Sopenharmony_ci (acb->active_dcb) ? "" : "not"); 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x " 10838c2ecf20Sopenharmony_ci "signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x " 10848c2ecf20Sopenharmony_ci "rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x " 10858c2ecf20Sopenharmony_ci "config2=0x%02x cmd=0x%02x selto=0x%02x}\n", 10868c2ecf20Sopenharmony_ci DC395x_read16(acb, TRM_S1040_SCSI_STATUS), 10878c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), 10888c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), 10898c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS), 10908c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_SYNC), 10918c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), 10928c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), 10938c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), 10948c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_INTEN), 10958c2ecf20Sopenharmony_ci DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), 10968c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), 10978c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), 10988c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); 10998c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x " 11008c2ecf20Sopenharmony_ci "irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x " 11018c2ecf20Sopenharmony_ci "ctctr=0x%08x addr=0x%08x:0x%08x}\n", 11028c2ecf20Sopenharmony_ci DC395x_read16(acb, TRM_S1040_DMA_COMMAND), 11038c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 11048c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 11058c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_STATUS), 11068c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_INTEN), 11078c2ecf20Sopenharmony_ci DC395x_read16(acb, TRM_S1040_DMA_CONFIG), 11088c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_XCNT), 11098c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_CXCNT), 11108c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), 11118c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); 11128c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} " 11138c2ecf20Sopenharmony_ci "pci{status=0x%04x}\n", 11148c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_GEN_CONTROL), 11158c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_GEN_STATUS), 11168c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_GEN_TIMER), 11178c2ecf20Sopenharmony_ci pstat); 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci#if debug_enabled(DBG_FIFO) 11248c2ecf20Sopenharmony_ci u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); 11258c2ecf20Sopenharmony_ci u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); 11268c2ecf20Sopenharmony_ci if (!(fifocnt & 0x40)) 11278c2ecf20Sopenharmony_ci dprintkdbg(DBG_FIFO, 11288c2ecf20Sopenharmony_ci "clear_fifo: (%i bytes) on phase %02x in %s\n", 11298c2ecf20Sopenharmony_ci fifocnt & 0x3f, lines, txt); 11308c2ecf20Sopenharmony_ci#endif 11318c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic void reset_dev_param(struct AdapterCtlBlk *acb) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 11388c2ecf20Sopenharmony_ci struct NvRamType *eeprom = &acb->eeprom; 11398c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci list_for_each_entry(dcb, &acb->dcb_list, list) { 11428c2ecf20Sopenharmony_ci u8 period_index; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE); 11458c2ecf20Sopenharmony_ci dcb->sync_period = 0; 11468c2ecf20Sopenharmony_ci dcb->sync_offset = 0; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci dcb->dev_mode = eeprom->target[dcb->target_id].cfg0; 11498c2ecf20Sopenharmony_ci period_index = eeprom->target[dcb->target_id].period & 0x07; 11508c2ecf20Sopenharmony_ci dcb->min_nego_period = clock_period[period_index]; 11518c2ecf20Sopenharmony_ci if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO) 11528c2ecf20Sopenharmony_ci || !(acb->config & HCC_WIDE_CARD)) 11538c2ecf20Sopenharmony_ci dcb->sync_mode &= ~WIDE_NEGO_ENABLE; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci/* 11598c2ecf20Sopenharmony_ci * perform a hard reset on the SCSI bus 11608c2ecf20Sopenharmony_ci * @cmd - some command for this host (for fetching hooks) 11618c2ecf20Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). 11628c2ecf20Sopenharmony_ci */ 11638c2ecf20Sopenharmony_cistatic int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = 11668c2ecf20Sopenharmony_ci (struct AdapterCtlBlk *)cmd->device->host->hostdata; 11678c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 11688c2ecf20Sopenharmony_ci "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n", 11698c2ecf20Sopenharmony_ci cmd, cmd->device->id, (u8)cmd->device->lun, cmd); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 11728c2ecf20Sopenharmony_ci del_timer(&acb->waiting_timer); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* 11758c2ecf20Sopenharmony_ci * disable interrupt 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00); 11788c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00); 11798c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); 11808c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci reset_scsi_bus(acb); 11838c2ecf20Sopenharmony_ci udelay(500); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* We may be in serious trouble. Wait some seconds */ 11868c2ecf20Sopenharmony_ci acb->last_reset = 11878c2ecf20Sopenharmony_ci jiffies + 3 * HZ / 2 + 11888c2ecf20Sopenharmony_ci HZ * acb->eeprom.delay_time; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci /* 11918c2ecf20Sopenharmony_ci * re-enable interrupt 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_ci /* Clear SCSI FIFO */ 11948c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); 11958c2ecf20Sopenharmony_ci clear_fifo(acb, "eh_bus_reset"); 11968c2ecf20Sopenharmony_ci /* Delete pending IRQ */ 11978c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); 11988c2ecf20Sopenharmony_ci set_basic_config(acb); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci reset_dev_param(acb); 12018c2ecf20Sopenharmony_ci doing_srb_done(acb, DID_RESET, cmd, 0); 12028c2ecf20Sopenharmony_ci acb->active_dcb = NULL; 12038c2ecf20Sopenharmony_ci acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ 12048c2ecf20Sopenharmony_ci waiting_process_next(acb); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci return SUCCESS; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic int dc395x_eh_bus_reset(struct scsi_cmnd *cmd) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci int rc; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci spin_lock_irq(cmd->device->host->host_lock); 12148c2ecf20Sopenharmony_ci rc = __dc395x_eh_bus_reset(cmd); 12158c2ecf20Sopenharmony_ci spin_unlock_irq(cmd->device->host->host_lock); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci return rc; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci/* 12218c2ecf20Sopenharmony_ci * abort an errant SCSI command 12228c2ecf20Sopenharmony_ci * @cmd - command to be aborted 12238c2ecf20Sopenharmony_ci * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). 12248c2ecf20Sopenharmony_ci */ 12258c2ecf20Sopenharmony_cistatic int dc395x_eh_abort(struct scsi_cmnd *cmd) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci /* 12288c2ecf20Sopenharmony_ci * Look into our command queues: If it has not been sent already, 12298c2ecf20Sopenharmony_ci * we remove it and return success. Otherwise fail. 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = 12328c2ecf20Sopenharmony_ci (struct AdapterCtlBlk *)cmd->device->host->hostdata; 12338c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 12348c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 12358c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n", 12368c2ecf20Sopenharmony_ci cmd, cmd->device->id, (u8)cmd->device->lun, cmd); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); 12398c2ecf20Sopenharmony_ci if (!dcb) { 12408c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "eh_abort: No such device\n"); 12418c2ecf20Sopenharmony_ci return FAILED; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci srb = find_cmd(cmd, &dcb->srb_waiting_list); 12458c2ecf20Sopenharmony_ci if (srb) { 12468c2ecf20Sopenharmony_ci list_del(&srb->list); 12478c2ecf20Sopenharmony_ci pci_unmap_srb_sense(acb, srb); 12488c2ecf20Sopenharmony_ci pci_unmap_srb(acb, srb); 12498c2ecf20Sopenharmony_ci free_tag(dcb, srb); 12508c2ecf20Sopenharmony_ci list_add_tail(&srb->list, &acb->srb_free_list); 12518c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); 12528c2ecf20Sopenharmony_ci cmd->result = DID_ABORT << 16; 12538c2ecf20Sopenharmony_ci return SUCCESS; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci srb = find_cmd(cmd, &dcb->srb_going_list); 12568c2ecf20Sopenharmony_ci if (srb) { 12578c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n"); 12588c2ecf20Sopenharmony_ci /* XXX: Should abort the command here */ 12598c2ecf20Sopenharmony_ci } else { 12608c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "eh_abort: Command not found\n"); 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci return FAILED; 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci/* SDTR */ 12678c2ecf20Sopenharmony_cistatic void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 12688c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci u8 *ptr = srb->msgout_buf + srb->msg_count; 12718c2ecf20Sopenharmony_ci if (srb->msg_count > 1) { 12728c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 12738c2ecf20Sopenharmony_ci "build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n", 12748c2ecf20Sopenharmony_ci srb->msg_count, srb->msgout_buf[0], 12758c2ecf20Sopenharmony_ci srb->msgout_buf[1]); 12768c2ecf20Sopenharmony_ci return; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) { 12798c2ecf20Sopenharmony_ci dcb->sync_offset = 0; 12808c2ecf20Sopenharmony_ci dcb->min_nego_period = 200 >> 2; 12818c2ecf20Sopenharmony_ci } else if (dcb->sync_offset == 0) 12828c2ecf20Sopenharmony_ci dcb->sync_offset = SYNC_NEGO_OFFSET; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci *ptr++ = MSG_EXTENDED; /* (01h) */ 12858c2ecf20Sopenharmony_ci *ptr++ = 3; /* length */ 12868c2ecf20Sopenharmony_ci *ptr++ = EXTENDED_SDTR; /* (01h) */ 12878c2ecf20Sopenharmony_ci *ptr++ = dcb->min_nego_period; /* Transfer period (in 4ns) */ 12888c2ecf20Sopenharmony_ci *ptr++ = dcb->sync_offset; /* Transfer period (max. REQ/ACK dist) */ 12898c2ecf20Sopenharmony_ci srb->msg_count += 5; 12908c2ecf20Sopenharmony_ci srb->state |= SRB_DO_SYNC_NEGO; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci/* WDTR */ 12958c2ecf20Sopenharmony_cistatic void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 12968c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & 12998c2ecf20Sopenharmony_ci (acb->config & HCC_WIDE_CARD)) ? 1 : 0; 13008c2ecf20Sopenharmony_ci u8 *ptr = srb->msgout_buf + srb->msg_count; 13018c2ecf20Sopenharmony_ci if (srb->msg_count > 1) { 13028c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 13038c2ecf20Sopenharmony_ci "build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n", 13048c2ecf20Sopenharmony_ci srb->msg_count, srb->msgout_buf[0], 13058c2ecf20Sopenharmony_ci srb->msgout_buf[1]); 13068c2ecf20Sopenharmony_ci return; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci *ptr++ = MSG_EXTENDED; /* (01h) */ 13098c2ecf20Sopenharmony_ci *ptr++ = 2; /* length */ 13108c2ecf20Sopenharmony_ci *ptr++ = EXTENDED_WDTR; /* (03h) */ 13118c2ecf20Sopenharmony_ci *ptr++ = wide; 13128c2ecf20Sopenharmony_ci srb->msg_count += 4; 13138c2ecf20Sopenharmony_ci srb->state |= SRB_DO_WIDE_NEGO; 13148c2ecf20Sopenharmony_ci} 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci#if 0 13188c2ecf20Sopenharmony_ci/* Timer to work around chip flaw: When selecting and the bus is 13198c2ecf20Sopenharmony_ci * busy, we sometimes miss a Selection timeout IRQ */ 13208c2ecf20Sopenharmony_civoid selection_timeout_missed(unsigned long ptr); 13218c2ecf20Sopenharmony_ci/* Sets the timer to wake us up */ 13228c2ecf20Sopenharmony_cistatic void selto_timer(struct AdapterCtlBlk *acb) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci if (timer_pending(&acb->selto_timer)) 13258c2ecf20Sopenharmony_ci return; 13268c2ecf20Sopenharmony_ci acb->selto_timer.function = selection_timeout_missed; 13278c2ecf20Sopenharmony_ci acb->selto_timer.data = (unsigned long) acb; 13288c2ecf20Sopenharmony_ci if (time_before 13298c2ecf20Sopenharmony_ci (jiffies + HZ, acb->last_reset + HZ / 2)) 13308c2ecf20Sopenharmony_ci acb->selto_timer.expires = 13318c2ecf20Sopenharmony_ci acb->last_reset + HZ / 2 + 1; 13328c2ecf20Sopenharmony_ci else 13338c2ecf20Sopenharmony_ci acb->selto_timer.expires = jiffies + HZ + 1; 13348c2ecf20Sopenharmony_ci add_timer(&acb->selto_timer); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_civoid selection_timeout_missed(unsigned long ptr) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci unsigned long flags; 13418c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; 13428c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 13438c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); 13448c2ecf20Sopenharmony_ci if (!acb->active_dcb || !acb->active_dcb->active_srb) { 13458c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n"); 13468c2ecf20Sopenharmony_ci return; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci DC395x_LOCK_IO(acb->scsi_host, flags); 13498c2ecf20Sopenharmony_ci srb = acb->active_dcb->active_srb; 13508c2ecf20Sopenharmony_ci disconnect(acb); 13518c2ecf20Sopenharmony_ci DC395x_UNLOCK_IO(acb->scsi_host, flags); 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci#endif 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cistatic u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, 13578c2ecf20Sopenharmony_ci struct ScsiReqBlk* srb) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci u16 s_stat2, return_code; 13608c2ecf20Sopenharmony_ci u8 s_stat, scsicommand, i, identify_message; 13618c2ecf20Sopenharmony_ci u8 *ptr; 13628c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", 13638c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, srb); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); 13688c2ecf20Sopenharmony_ci s_stat2 = 0; 13698c2ecf20Sopenharmony_ci s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); 13708c2ecf20Sopenharmony_ci#if 1 13718c2ecf20Sopenharmony_ci if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { 13728c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n", 13738c2ecf20Sopenharmony_ci s_stat, s_stat2); 13748c2ecf20Sopenharmony_ci /* 13758c2ecf20Sopenharmony_ci * Try anyway? 13768c2ecf20Sopenharmony_ci * 13778c2ecf20Sopenharmony_ci * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection 13788c2ecf20Sopenharmony_ci * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed! 13798c2ecf20Sopenharmony_ci * (This is likely to be a bug in the hardware. Obviously, most people 13808c2ecf20Sopenharmony_ci * only have one initiator per SCSI bus.) 13818c2ecf20Sopenharmony_ci * Instead let this fail and have the timer make sure the command is 13828c2ecf20Sopenharmony_ci * tried again after a short time 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_ci /*selto_timer (acb); */ 13858c2ecf20Sopenharmony_ci return 1; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci#endif 13888c2ecf20Sopenharmony_ci if (acb->active_dcb) { 13898c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a" 13908c2ecf20Sopenharmony_ci "command while another command (0x%p) is active.", 13918c2ecf20Sopenharmony_ci srb->cmd, 13928c2ecf20Sopenharmony_ci acb->active_dcb->active_srb ? 13938c2ecf20Sopenharmony_ci acb->active_dcb->active_srb->cmd : 0); 13948c2ecf20Sopenharmony_ci return 1; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { 13978c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd); 13988c2ecf20Sopenharmony_ci return 1; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci /* Allow starting of SCSI commands half a second before we allow the mid-level 14018c2ecf20Sopenharmony_ci * to queue them again after a reset */ 14028c2ecf20Sopenharmony_ci if (time_before(jiffies, acb->last_reset - HZ / 2)) { 14038c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); 14048c2ecf20Sopenharmony_ci return 1; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci /* Flush FIFO */ 14088c2ecf20Sopenharmony_ci clear_fifo(acb, "start_scsi"); 14098c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); 14108c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); 14118c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); 14128c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); 14138c2ecf20Sopenharmony_ci srb->scsi_phase = PH_BUS_FREE; /* initial phase */ 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci identify_message = dcb->identify_msg; 14168c2ecf20Sopenharmony_ci /*DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message); */ 14178c2ecf20Sopenharmony_ci /* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */ 14188c2ecf20Sopenharmony_ci if (srb->flag & AUTO_REQSENSE) 14198c2ecf20Sopenharmony_ci identify_message &= 0xBF; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (((srb->cmd->cmnd[0] == INQUIRY) 14228c2ecf20Sopenharmony_ci || (srb->cmd->cmnd[0] == REQUEST_SENSE) 14238c2ecf20Sopenharmony_ci || (srb->flag & AUTO_REQSENSE)) 14248c2ecf20Sopenharmony_ci && (((dcb->sync_mode & WIDE_NEGO_ENABLE) 14258c2ecf20Sopenharmony_ci && !(dcb->sync_mode & WIDE_NEGO_DONE)) 14268c2ecf20Sopenharmony_ci || ((dcb->sync_mode & SYNC_NEGO_ENABLE) 14278c2ecf20Sopenharmony_ci && !(dcb->sync_mode & SYNC_NEGO_DONE))) 14288c2ecf20Sopenharmony_ci && (dcb->target_lun == 0)) { 14298c2ecf20Sopenharmony_ci srb->msgout_buf[0] = identify_message; 14308c2ecf20Sopenharmony_ci srb->msg_count = 1; 14318c2ecf20Sopenharmony_ci scsicommand = SCMD_SEL_ATNSTOP; 14328c2ecf20Sopenharmony_ci srb->state = SRB_MSGOUT; 14338c2ecf20Sopenharmony_ci#ifndef SYNC_FIRST 14348c2ecf20Sopenharmony_ci if (dcb->sync_mode & WIDE_NEGO_ENABLE 14358c2ecf20Sopenharmony_ci && dcb->inquiry7 & SCSI_INQ_WBUS16) { 14368c2ecf20Sopenharmony_ci build_wdtr(acb, dcb, srb); 14378c2ecf20Sopenharmony_ci goto no_cmd; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci#endif 14408c2ecf20Sopenharmony_ci if (dcb->sync_mode & SYNC_NEGO_ENABLE 14418c2ecf20Sopenharmony_ci && dcb->inquiry7 & SCSI_INQ_SYNC) { 14428c2ecf20Sopenharmony_ci build_sdtr(acb, dcb, srb); 14438c2ecf20Sopenharmony_ci goto no_cmd; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci if (dcb->sync_mode & WIDE_NEGO_ENABLE 14468c2ecf20Sopenharmony_ci && dcb->inquiry7 & SCSI_INQ_WBUS16) { 14478c2ecf20Sopenharmony_ci build_wdtr(acb, dcb, srb); 14488c2ecf20Sopenharmony_ci goto no_cmd; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci srb->msg_count = 0; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci /* Send identify message */ 14538c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci scsicommand = SCMD_SEL_ATN; 14568c2ecf20Sopenharmony_ci srb->state = SRB_START_; 14578c2ecf20Sopenharmony_ci#ifndef DC395x_NO_TAGQ 14588c2ecf20Sopenharmony_ci if ((dcb->sync_mode & EN_TAG_QUEUEING) 14598c2ecf20Sopenharmony_ci && (identify_message & 0xC0)) { 14608c2ecf20Sopenharmony_ci /* Send Tag message */ 14618c2ecf20Sopenharmony_ci u32 tag_mask = 1; 14628c2ecf20Sopenharmony_ci u8 tag_number = 0; 14638c2ecf20Sopenharmony_ci while (tag_mask & dcb->tag_mask 14648c2ecf20Sopenharmony_ci && tag_number < dcb->max_command) { 14658c2ecf20Sopenharmony_ci tag_mask = tag_mask << 1; 14668c2ecf20Sopenharmony_ci tag_number++; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci if (tag_number >= dcb->max_command) { 14698c2ecf20Sopenharmony_ci dprintkl(KERN_WARNING, "start_scsi: (0x%p) " 14708c2ecf20Sopenharmony_ci "Out of tags target=<%02i-%i>)\n", 14718c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, 14728c2ecf20Sopenharmony_ci (u8)srb->cmd->device->lun); 14738c2ecf20Sopenharmony_ci srb->state = SRB_READY; 14748c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, 14758c2ecf20Sopenharmony_ci DO_HWRESELECT); 14768c2ecf20Sopenharmony_ci return 1; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci /* Send Tag id */ 14798c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG); 14808c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number); 14818c2ecf20Sopenharmony_ci dcb->tag_mask |= tag_mask; 14828c2ecf20Sopenharmony_ci srb->tag_number = tag_number; 14838c2ecf20Sopenharmony_ci scsicommand = SCMD_SEL_ATN3; 14848c2ecf20Sopenharmony_ci srb->state = SRB_START_; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci#endif 14878c2ecf20Sopenharmony_ci/*polling:*/ 14888c2ecf20Sopenharmony_ci /* Send CDB ..command block ......... */ 14898c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n", 14908c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun, 14918c2ecf20Sopenharmony_ci srb->cmd->cmnd[0], srb->tag_number); 14928c2ecf20Sopenharmony_ci if (srb->flag & AUTO_REQSENSE) { 14938c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); 14948c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); 14958c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 14968c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 14978c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); 14988c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 14998c2ecf20Sopenharmony_ci } else { 15008c2ecf20Sopenharmony_ci ptr = (u8 *)srb->cmd->cmnd; 15018c2ecf20Sopenharmony_ci for (i = 0; i < srb->cmd->cmd_len; i++) 15028c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci no_cmd: 15058c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, 15068c2ecf20Sopenharmony_ci DO_HWRESELECT | DO_DATALATCH); 15078c2ecf20Sopenharmony_ci if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { 15088c2ecf20Sopenharmony_ci /* 15098c2ecf20Sopenharmony_ci * If start_scsi return 1: 15108c2ecf20Sopenharmony_ci * we caught an interrupt (must be reset or reselection ... ) 15118c2ecf20Sopenharmony_ci * : Let's process it first! 15128c2ecf20Sopenharmony_ci */ 15138c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n", 15148c2ecf20Sopenharmony_ci srb->cmd, dcb->target_id, dcb->target_lun); 15158c2ecf20Sopenharmony_ci srb->state = SRB_READY; 15168c2ecf20Sopenharmony_ci free_tag(dcb, srb); 15178c2ecf20Sopenharmony_ci srb->msg_count = 0; 15188c2ecf20Sopenharmony_ci return_code = 1; 15198c2ecf20Sopenharmony_ci /* This IRQ should NOT get lost, as we did not acknowledge it */ 15208c2ecf20Sopenharmony_ci } else { 15218c2ecf20Sopenharmony_ci /* 15228c2ecf20Sopenharmony_ci * If start_scsi returns 0: 15238c2ecf20Sopenharmony_ci * we know that the SCSI processor is free 15248c2ecf20Sopenharmony_ci */ 15258c2ecf20Sopenharmony_ci srb->scsi_phase = PH_BUS_FREE; /* initial phase */ 15268c2ecf20Sopenharmony_ci dcb->active_srb = srb; 15278c2ecf20Sopenharmony_ci acb->active_dcb = dcb; 15288c2ecf20Sopenharmony_ci return_code = 0; 15298c2ecf20Sopenharmony_ci /* it's important for atn stop */ 15308c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, 15318c2ecf20Sopenharmony_ci DO_DATALATCH | DO_HWRESELECT); 15328c2ecf20Sopenharmony_ci /* SCSI command */ 15338c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand); 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci return return_code; 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci#define DC395x_ENABLE_MSGOUT \ 15408c2ecf20Sopenharmony_ci DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ 15418c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci/* abort command */ 15458c2ecf20Sopenharmony_cistatic inline void enable_msgout_abort(struct AdapterCtlBlk *acb, 15468c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci srb->msgout_buf[0] = ABORT; 15498c2ecf20Sopenharmony_ci srb->msg_count = 1; 15508c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 15518c2ecf20Sopenharmony_ci srb->state &= ~SRB_MSGIN; 15528c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci/** 15578c2ecf20Sopenharmony_ci * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to 15588c2ecf20Sopenharmony_ci * have been triggered for this card. 15598c2ecf20Sopenharmony_ci * 15608c2ecf20Sopenharmony_ci * @acb: a pointer to the adpter control block 15618c2ecf20Sopenharmony_ci * @scsi_status: the status return when we checked the card 15628c2ecf20Sopenharmony_ci **/ 15638c2ecf20Sopenharmony_cistatic void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, 15648c2ecf20Sopenharmony_ci u16 scsi_status) 15658c2ecf20Sopenharmony_ci{ 15668c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 15678c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 15688c2ecf20Sopenharmony_ci u16 phase; 15698c2ecf20Sopenharmony_ci u8 scsi_intstatus; 15708c2ecf20Sopenharmony_ci unsigned long flags; 15718c2ecf20Sopenharmony_ci void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, 15728c2ecf20Sopenharmony_ci u16 *); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci DC395x_LOCK_IO(acb->scsi_host, flags); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci /* This acknowledges the IRQ */ 15778c2ecf20Sopenharmony_ci scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); 15788c2ecf20Sopenharmony_ci if ((scsi_status & 0x2007) == 0x2002) 15798c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 15808c2ecf20Sopenharmony_ci "COP after COP completed? %04x\n", scsi_status); 15818c2ecf20Sopenharmony_ci if (debug_enabled(DBG_KG)) { 15828c2ecf20Sopenharmony_ci if (scsi_intstatus & INT_SELTIMEOUT) 15838c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n"); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci /*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */ 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (timer_pending(&acb->selto_timer)) 15888c2ecf20Sopenharmony_ci del_timer(&acb->selto_timer); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) { 15918c2ecf20Sopenharmony_ci disconnect(acb); /* bus free interrupt */ 15928c2ecf20Sopenharmony_ci goto out_unlock; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci if (scsi_intstatus & INT_RESELECTED) { 15958c2ecf20Sopenharmony_ci reselect(acb); 15968c2ecf20Sopenharmony_ci goto out_unlock; 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci if (scsi_intstatus & INT_SELECT) { 15998c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Host does not support target mode!\n"); 16008c2ecf20Sopenharmony_ci goto out_unlock; 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci if (scsi_intstatus & INT_SCSIRESET) { 16038c2ecf20Sopenharmony_ci scsi_reset_detect(acb); 16048c2ecf20Sopenharmony_ci goto out_unlock; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { 16078c2ecf20Sopenharmony_ci dcb = acb->active_dcb; 16088c2ecf20Sopenharmony_ci if (!dcb) { 16098c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 16108c2ecf20Sopenharmony_ci "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", 16118c2ecf20Sopenharmony_ci scsi_status, scsi_intstatus); 16128c2ecf20Sopenharmony_ci goto out_unlock; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci srb = dcb->active_srb; 16158c2ecf20Sopenharmony_ci if (dcb->flag & ABORT_DEV_) { 16168c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); 16178c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci /* software sequential machine */ 16218c2ecf20Sopenharmony_ci phase = (u16)srb->scsi_phase; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* 16248c2ecf20Sopenharmony_ci * 62037 or 62137 16258c2ecf20Sopenharmony_ci * call dc395x_scsi_phase0[]... "phase entry" 16268c2ecf20Sopenharmony_ci * handle every phase before start transfer 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_ci /* data_out_phase0, phase:0 */ 16298c2ecf20Sopenharmony_ci /* data_in_phase0, phase:1 */ 16308c2ecf20Sopenharmony_ci /* command_phase0, phase:2 */ 16318c2ecf20Sopenharmony_ci /* status_phase0, phase:3 */ 16328c2ecf20Sopenharmony_ci /* nop0, phase:4 PH_BUS_FREE .. initial phase */ 16338c2ecf20Sopenharmony_ci /* nop0, phase:5 PH_BUS_FREE .. initial phase */ 16348c2ecf20Sopenharmony_ci /* msgout_phase0, phase:6 */ 16358c2ecf20Sopenharmony_ci /* msgin_phase0, phase:7 */ 16368c2ecf20Sopenharmony_ci dc395x_statev = dc395x_scsi_phase0[phase]; 16378c2ecf20Sopenharmony_ci dc395x_statev(acb, srb, &scsi_status); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* 16408c2ecf20Sopenharmony_ci * if there were any exception occurred scsi_status 16418c2ecf20Sopenharmony_ci * will be modify to bus free phase new scsi_status 16428c2ecf20Sopenharmony_ci * transfer out from ... previous dc395x_statev 16438c2ecf20Sopenharmony_ci */ 16448c2ecf20Sopenharmony_ci srb->scsi_phase = scsi_status & PHASEMASK; 16458c2ecf20Sopenharmony_ci phase = (u16)scsi_status & PHASEMASK; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci /* 16488c2ecf20Sopenharmony_ci * call dc395x_scsi_phase1[]... "phase entry" handle 16498c2ecf20Sopenharmony_ci * every phase to do transfer 16508c2ecf20Sopenharmony_ci */ 16518c2ecf20Sopenharmony_ci /* data_out_phase1, phase:0 */ 16528c2ecf20Sopenharmony_ci /* data_in_phase1, phase:1 */ 16538c2ecf20Sopenharmony_ci /* command_phase1, phase:2 */ 16548c2ecf20Sopenharmony_ci /* status_phase1, phase:3 */ 16558c2ecf20Sopenharmony_ci /* nop1, phase:4 PH_BUS_FREE .. initial phase */ 16568c2ecf20Sopenharmony_ci /* nop1, phase:5 PH_BUS_FREE .. initial phase */ 16578c2ecf20Sopenharmony_ci /* msgout_phase1, phase:6 */ 16588c2ecf20Sopenharmony_ci /* msgin_phase1, phase:7 */ 16598c2ecf20Sopenharmony_ci dc395x_statev = dc395x_scsi_phase1[phase]; 16608c2ecf20Sopenharmony_ci dc395x_statev(acb, srb, &scsi_status); 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci out_unlock: 16638c2ecf20Sopenharmony_ci DC395x_UNLOCK_IO(acb->scsi_host, flags); 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic irqreturn_t dc395x_interrupt(int irq, void *dev_id) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = dev_id; 16708c2ecf20Sopenharmony_ci u16 scsi_status; 16718c2ecf20Sopenharmony_ci u8 dma_status; 16728c2ecf20Sopenharmony_ci irqreturn_t handled = IRQ_NONE; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* 16758c2ecf20Sopenharmony_ci * Check for pending interrupt 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ci scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); 16788c2ecf20Sopenharmony_ci dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); 16798c2ecf20Sopenharmony_ci if (scsi_status & SCSIINTERRUPT) { 16808c2ecf20Sopenharmony_ci /* interrupt pending - let's process it! */ 16818c2ecf20Sopenharmony_ci dc395x_handle_interrupt(acb, scsi_status); 16828c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci else if (dma_status & 0x20) { 16858c2ecf20Sopenharmony_ci /* Error from the DMA engine */ 16868c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status); 16878c2ecf20Sopenharmony_ci#if 0 16888c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); 16898c2ecf20Sopenharmony_ci if (acb->active_dcb) { 16908c2ecf20Sopenharmony_ci acb->active_dcb-> flag |= ABORT_DEV_; 16918c2ecf20Sopenharmony_ci if (acb->active_dcb->active_srb) 16928c2ecf20Sopenharmony_ci enable_msgout_abort(acb, acb->active_dcb->active_srb); 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); 16958c2ecf20Sopenharmony_ci#else 16968c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n"); 16978c2ecf20Sopenharmony_ci acb = NULL; 16988c2ecf20Sopenharmony_ci#endif 16998c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci return handled; 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_cistatic void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 17078c2ecf20Sopenharmony_ci u16 *pscsi_status) 17088c2ecf20Sopenharmony_ci{ 17098c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd); 17108c2ecf20Sopenharmony_ci if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) 17118c2ecf20Sopenharmony_ci *pscsi_status = PH_BUS_FREE; /*.. initial phase */ 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 17148c2ecf20Sopenharmony_ci srb->state &= ~SRB_MSGOUT; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_cistatic void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 17198c2ecf20Sopenharmony_ci u16 *pscsi_status) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci u16 i; 17228c2ecf20Sopenharmony_ci u8 *ptr; 17238c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci clear_fifo(acb, "msgout_phase1"); 17268c2ecf20Sopenharmony_ci if (!(srb->state & SRB_MSGOUT)) { 17278c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT; 17288c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 17298c2ecf20Sopenharmony_ci "msgout_phase1: (0x%p) Phase unexpected\n", 17308c2ecf20Sopenharmony_ci srb->cmd); /* So what ? */ 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci if (!srb->msg_count) { 17338c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n", 17348c2ecf20Sopenharmony_ci srb->cmd); 17358c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); 17368c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 17378c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); 17388c2ecf20Sopenharmony_ci return; 17398c2ecf20Sopenharmony_ci } 17408c2ecf20Sopenharmony_ci ptr = (u8 *)srb->msgout_buf; 17418c2ecf20Sopenharmony_ci for (i = 0; i < srb->msg_count; i++) 17428c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); 17438c2ecf20Sopenharmony_ci srb->msg_count = 0; 17448c2ecf20Sopenharmony_ci if (srb->msgout_buf[0] == MSG_ABORT) 17458c2ecf20Sopenharmony_ci srb->state = SRB_ABORT_SENT; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 17528c2ecf20Sopenharmony_ci u16 *pscsi_status) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd); 17558c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 17608c2ecf20Sopenharmony_ci u16 *pscsi_status) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 17638c2ecf20Sopenharmony_ci u8 *ptr; 17648c2ecf20Sopenharmony_ci u16 i; 17658c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd); 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci clear_fifo(acb, "command_phase1"); 17688c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); 17698c2ecf20Sopenharmony_ci if (!(srb->flag & AUTO_REQSENSE)) { 17708c2ecf20Sopenharmony_ci ptr = (u8 *)srb->cmd->cmnd; 17718c2ecf20Sopenharmony_ci for (i = 0; i < srb->cmd->cmd_len; i++) { 17728c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr); 17738c2ecf20Sopenharmony_ci ptr++; 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci } else { 17768c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); 17778c2ecf20Sopenharmony_ci dcb = acb->active_dcb; 17788c2ecf20Sopenharmony_ci /* target id */ 17798c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); 17808c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 17818c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 17828c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); 17838c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci srb->state |= SRB_COMMAND; 17868c2ecf20Sopenharmony_ci /* it's important for atn stop */ 17878c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); 17888c2ecf20Sopenharmony_ci /* SCSI command */ 17898c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci/* 17948c2ecf20Sopenharmony_ci * Verify that the remaining space in the hw sg lists is the same as 17958c2ecf20Sopenharmony_ci * the count of remaining bytes in srb->total_xfer_length 17968c2ecf20Sopenharmony_ci */ 17978c2ecf20Sopenharmony_cistatic void sg_verify_length(struct ScsiReqBlk *srb) 17988c2ecf20Sopenharmony_ci{ 17998c2ecf20Sopenharmony_ci if (debug_enabled(DBG_SG)) { 18008c2ecf20Sopenharmony_ci unsigned len = 0; 18018c2ecf20Sopenharmony_ci unsigned idx = srb->sg_index; 18028c2ecf20Sopenharmony_ci struct SGentry *psge = srb->segment_x + idx; 18038c2ecf20Sopenharmony_ci for (; idx < srb->sg_count; psge++, idx++) 18048c2ecf20Sopenharmony_ci len += psge->length; 18058c2ecf20Sopenharmony_ci if (len != srb->total_xfer_length) 18068c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, 18078c2ecf20Sopenharmony_ci "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", 18088c2ecf20Sopenharmony_ci srb->total_xfer_length, len); 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci/* 18148c2ecf20Sopenharmony_ci * Compute the next Scatter Gather list index and adjust its length 18158c2ecf20Sopenharmony_ci * and address if necessary 18168c2ecf20Sopenharmony_ci */ 18178c2ecf20Sopenharmony_cistatic void sg_update_list(struct ScsiReqBlk *srb, u32 left) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci u8 idx; 18208c2ecf20Sopenharmony_ci u32 xferred = srb->total_xfer_length - left; /* bytes transferred */ 18218c2ecf20Sopenharmony_ci struct SGentry *psge = srb->segment_x + srb->sg_index; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, 18248c2ecf20Sopenharmony_ci "sg_update_list: Transferred %i of %i bytes, %i remain\n", 18258c2ecf20Sopenharmony_ci xferred, srb->total_xfer_length, left); 18268c2ecf20Sopenharmony_ci if (xferred == 0) { 18278c2ecf20Sopenharmony_ci /* nothing to update since we did not transfer any data */ 18288c2ecf20Sopenharmony_ci return; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci sg_verify_length(srb); 18328c2ecf20Sopenharmony_ci srb->total_xfer_length = left; /* update remaining count */ 18338c2ecf20Sopenharmony_ci for (idx = srb->sg_index; idx < srb->sg_count; idx++) { 18348c2ecf20Sopenharmony_ci if (xferred >= psge->length) { 18358c2ecf20Sopenharmony_ci /* Complete SG entries done */ 18368c2ecf20Sopenharmony_ci xferred -= psge->length; 18378c2ecf20Sopenharmony_ci } else { 18388c2ecf20Sopenharmony_ci /* Partial SG entry done */ 18398c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&srb->dcb->acb->dev->dev, 18408c2ecf20Sopenharmony_ci srb->sg_bus_addr, SEGMENTX_LEN, 18418c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 18428c2ecf20Sopenharmony_ci psge->length -= xferred; 18438c2ecf20Sopenharmony_ci psge->address += xferred; 18448c2ecf20Sopenharmony_ci srb->sg_index = idx; 18458c2ecf20Sopenharmony_ci dma_sync_single_for_device(&srb->dcb->acb->dev->dev, 18468c2ecf20Sopenharmony_ci srb->sg_bus_addr, SEGMENTX_LEN, 18478c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 18488c2ecf20Sopenharmony_ci break; 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci psge++; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci sg_verify_length(srb); 18538c2ecf20Sopenharmony_ci} 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci/* 18578c2ecf20Sopenharmony_ci * We have transferred a single byte (PIO mode?) and need to update 18588c2ecf20Sopenharmony_ci * the count of bytes remaining (total_xfer_length) and update the sg 18598c2ecf20Sopenharmony_ci * entry to either point to next byte in the current sg entry, or of 18608c2ecf20Sopenharmony_ci * already at the end to point to the start of the next sg entry 18618c2ecf20Sopenharmony_ci */ 18628c2ecf20Sopenharmony_cistatic void sg_subtract_one(struct ScsiReqBlk *srb) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci sg_update_list(srb, srb->total_xfer_length - 1); 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci/* 18698c2ecf20Sopenharmony_ci * cleanup_after_transfer 18708c2ecf20Sopenharmony_ci * 18718c2ecf20Sopenharmony_ci * Makes sure, DMA and SCSI engine are empty, after the transfer has finished 18728c2ecf20Sopenharmony_ci * KG: Currently called from StatusPhase1 () 18738c2ecf20Sopenharmony_ci * Should probably also be called from other places 18748c2ecf20Sopenharmony_ci * Best might be to call it in DataXXPhase0, if new phase will differ 18758c2ecf20Sopenharmony_ci */ 18768c2ecf20Sopenharmony_cistatic void cleanup_after_transfer(struct AdapterCtlBlk *acb, 18778c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci /*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */ 18808c2ecf20Sopenharmony_ci if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) { /* read */ 18818c2ecf20Sopenharmony_ci if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) 18828c2ecf20Sopenharmony_ci clear_fifo(acb, "cleanup/in"); 18838c2ecf20Sopenharmony_ci if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) 18848c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); 18858c2ecf20Sopenharmony_ci } else { /* write */ 18868c2ecf20Sopenharmony_ci if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) 18878c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); 18888c2ecf20Sopenharmony_ci if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) 18898c2ecf20Sopenharmony_ci clear_fifo(acb, "cleanup/out"); 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci/* 18968c2ecf20Sopenharmony_ci * Those no of bytes will be transferred w/ PIO through the SCSI FIFO 18978c2ecf20Sopenharmony_ci * Seems to be needed for unknown reasons; could be a hardware bug :-( 18988c2ecf20Sopenharmony_ci */ 18998c2ecf20Sopenharmony_ci#define DC395x_LASTPIO 4 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 19038c2ecf20Sopenharmony_ci u16 *pscsi_status) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 19068c2ecf20Sopenharmony_ci u16 scsi_status = *pscsi_status; 19078c2ecf20Sopenharmony_ci u32 d_left_counter = 0; 19088c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n", 19098c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* 19128c2ecf20Sopenharmony_ci * KG: We need to drain the buffers before we draw any conclusions! 19138c2ecf20Sopenharmony_ci * This means telling the DMA to push the rest into SCSI, telling 19148c2ecf20Sopenharmony_ci * SCSI to push the rest to the bus. 19158c2ecf20Sopenharmony_ci * However, the device might have been the one to stop us (phase 19168c2ecf20Sopenharmony_ci * change), and the data in transit just needs to be accounted so 19178c2ecf20Sopenharmony_ci * it can be retransmitted.) 19188c2ecf20Sopenharmony_ci */ 19198c2ecf20Sopenharmony_ci /* 19208c2ecf20Sopenharmony_ci * KG: Stop DMA engine pushing more data into the SCSI FIFO 19218c2ecf20Sopenharmony_ci * If we need more data, the DMA SG list will be freshly set up, anyway 19228c2ecf20Sopenharmony_ci */ 19238c2ecf20Sopenharmony_ci dprintkdbg(DBG_PIO, "data_out_phase0: " 19248c2ecf20Sopenharmony_ci "DMA{fifocnt=0x%02x fifostat=0x%02x} " 19258c2ecf20Sopenharmony_ci "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", 19268c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 19278c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 19288c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), 19298c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, 19308c2ecf20Sopenharmony_ci srb->total_xfer_length); 19318c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (!(srb->state & SRB_XFERPAD)) { 19348c2ecf20Sopenharmony_ci if (scsi_status & PARITYERROR) 19358c2ecf20Sopenharmony_ci srb->status |= PARITY_ERROR; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* 19388c2ecf20Sopenharmony_ci * KG: Right, we can't just rely on the SCSI_COUNTER, because this 19398c2ecf20Sopenharmony_ci * is the no of bytes it got from the DMA engine not the no it 19408c2ecf20Sopenharmony_ci * transferred successfully to the device. (And the difference could 19418c2ecf20Sopenharmony_ci * be as much as the FIFO size, I guess ...) 19428c2ecf20Sopenharmony_ci */ 19438c2ecf20Sopenharmony_ci if (!(scsi_status & SCSIXFERDONE)) { 19448c2ecf20Sopenharmony_ci /* 19458c2ecf20Sopenharmony_ci * when data transfer from DMA FIFO to SCSI FIFO 19468c2ecf20Sopenharmony_ci * if there was some data left in SCSI FIFO 19478c2ecf20Sopenharmony_ci */ 19488c2ecf20Sopenharmony_ci d_left_counter = 19498c2ecf20Sopenharmony_ci (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 19508c2ecf20Sopenharmony_ci 0x1F); 19518c2ecf20Sopenharmony_ci if (dcb->sync_period & WIDE_SYNC) 19528c2ecf20Sopenharmony_ci d_left_counter <<= 1; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n" 19558c2ecf20Sopenharmony_ci "SCSI{fifocnt=0x%02x cnt=0x%08x} " 19568c2ecf20Sopenharmony_ci "DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n", 19578c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), 19588c2ecf20Sopenharmony_ci (dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", 19598c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), 19608c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), 19618c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 19628c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 19638c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci /* 19668c2ecf20Sopenharmony_ci * calculate all the residue data that not yet tranfered 19678c2ecf20Sopenharmony_ci * SCSI transfer counter + left in SCSI FIFO data 19688c2ecf20Sopenharmony_ci * 19698c2ecf20Sopenharmony_ci * .....TRM_S1040_SCSI_COUNTER (24bits) 19708c2ecf20Sopenharmony_ci * The counter always decrement by one for every SCSI byte transfer. 19718c2ecf20Sopenharmony_ci * .....TRM_S1040_SCSI_FIFOCNT ( 5bits) 19728c2ecf20Sopenharmony_ci * The counter is SCSI FIFO offset counter (in units of bytes or! words) 19738c2ecf20Sopenharmony_ci */ 19748c2ecf20Sopenharmony_ci if (srb->total_xfer_length > DC395x_LASTPIO) 19758c2ecf20Sopenharmony_ci d_left_counter += 19768c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* Is this a good idea? */ 19798c2ecf20Sopenharmony_ci /*clear_fifo(acb, "DOP1"); */ 19808c2ecf20Sopenharmony_ci /* KG: What is this supposed to be useful for? WIDE padding stuff? */ 19818c2ecf20Sopenharmony_ci if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC 19828c2ecf20Sopenharmony_ci && scsi_bufflen(srb->cmd) % 2) { 19838c2ecf20Sopenharmony_ci d_left_counter = 0; 19848c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 19858c2ecf20Sopenharmony_ci "data_out_phase0: Discard 1 byte (0x%02x)\n", 19868c2ecf20Sopenharmony_ci scsi_status); 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci /* 19898c2ecf20Sopenharmony_ci * KG: Oops again. Same thinko as above: The SCSI might have been 19908c2ecf20Sopenharmony_ci * faster than the DMA engine, so that it ran out of data. 19918c2ecf20Sopenharmony_ci * In that case, we have to do just nothing! 19928c2ecf20Sopenharmony_ci * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or? 19938c2ecf20Sopenharmony_ci */ 19948c2ecf20Sopenharmony_ci /* 19958c2ecf20Sopenharmony_ci * KG: This is nonsense: We have been WRITING data to the bus 19968c2ecf20Sopenharmony_ci * If the SCSI engine has no bytes left, how should the DMA engine? 19978c2ecf20Sopenharmony_ci */ 19988c2ecf20Sopenharmony_ci if (d_left_counter == 0) { 19998c2ecf20Sopenharmony_ci srb->total_xfer_length = 0; 20008c2ecf20Sopenharmony_ci } else { 20018c2ecf20Sopenharmony_ci /* 20028c2ecf20Sopenharmony_ci * if transfer not yet complete 20038c2ecf20Sopenharmony_ci * there were some data residue in SCSI FIFO or 20048c2ecf20Sopenharmony_ci * SCSI transfer counter not empty 20058c2ecf20Sopenharmony_ci */ 20068c2ecf20Sopenharmony_ci long oldxferred = 20078c2ecf20Sopenharmony_ci srb->total_xfer_length - d_left_counter; 20088c2ecf20Sopenharmony_ci const int diff = 20098c2ecf20Sopenharmony_ci (dcb->sync_period & WIDE_SYNC) ? 2 : 1; 20108c2ecf20Sopenharmony_ci sg_update_list(srb, d_left_counter); 20118c2ecf20Sopenharmony_ci /* KG: Most ugly hack! Apparently, this works around a chip bug */ 20128c2ecf20Sopenharmony_ci if ((srb->segment_x[srb->sg_index].length == 20138c2ecf20Sopenharmony_ci diff && scsi_sg_count(srb->cmd)) 20148c2ecf20Sopenharmony_ci || ((oldxferred & ~PAGE_MASK) == 20158c2ecf20Sopenharmony_ci (PAGE_SIZE - diff)) 20168c2ecf20Sopenharmony_ci ) { 20178c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "data_out_phase0: " 20188c2ecf20Sopenharmony_ci "Work around chip bug (%i)?\n", diff); 20198c2ecf20Sopenharmony_ci d_left_counter = 20208c2ecf20Sopenharmony_ci srb->total_xfer_length - diff; 20218c2ecf20Sopenharmony_ci sg_update_list(srb, d_left_counter); 20228c2ecf20Sopenharmony_ci /*srb->total_xfer_length -= diff; */ 20238c2ecf20Sopenharmony_ci /*srb->virt_addr += diff; */ 20248c2ecf20Sopenharmony_ci /*if (srb->cmd->use_sg) */ 20258c2ecf20Sopenharmony_ci /* srb->sg_index++; */ 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { 20308c2ecf20Sopenharmony_ci cleanup_after_transfer(acb, srb); 20318c2ecf20Sopenharmony_ci } 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_cistatic void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 20368c2ecf20Sopenharmony_ci u16 *pscsi_status) 20378c2ecf20Sopenharmony_ci{ 20388c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n", 20398c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 20408c2ecf20Sopenharmony_ci clear_fifo(acb, "data_out_phase1"); 20418c2ecf20Sopenharmony_ci /* do prepare before transfer when data out phase */ 20428c2ecf20Sopenharmony_ci data_io_transfer(acb, srb, XFERDATAOUT); 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_cistatic void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 20468c2ecf20Sopenharmony_ci u16 *pscsi_status) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci u16 scsi_status = *pscsi_status; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n", 20518c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* 20548c2ecf20Sopenharmony_ci * KG: DataIn is much more tricky than DataOut. When the device is finished 20558c2ecf20Sopenharmony_ci * and switches to another phase, the SCSI engine should be finished too. 20568c2ecf20Sopenharmony_ci * But: There might still be bytes left in its FIFO to be fetched by the DMA 20578c2ecf20Sopenharmony_ci * engine and transferred to memory. 20588c2ecf20Sopenharmony_ci * We should wait for the FIFOs to be emptied by that (is there any way to 20598c2ecf20Sopenharmony_ci * enforce this?) and then stop the DMA engine, because it might think, that 20608c2ecf20Sopenharmony_ci * there are more bytes to follow. Yes, the device might disconnect prior to 20618c2ecf20Sopenharmony_ci * having all bytes transferred! 20628c2ecf20Sopenharmony_ci * Also we should make sure that all data from the DMA engine buffer's really 20638c2ecf20Sopenharmony_ci * made its way to the system memory! Some documentation on this would not 20648c2ecf20Sopenharmony_ci * seem to be a bad idea, actually. 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_ci if (!(srb->state & SRB_XFERPAD)) { 20678c2ecf20Sopenharmony_ci u32 d_left_counter; 20688c2ecf20Sopenharmony_ci unsigned int sc, fc; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci if (scsi_status & PARITYERROR) { 20718c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "data_in_phase0: (0x%p) " 20728c2ecf20Sopenharmony_ci "Parity Error\n", srb->cmd); 20738c2ecf20Sopenharmony_ci srb->status |= PARITY_ERROR; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci /* 20768c2ecf20Sopenharmony_ci * KG: We should wait for the DMA FIFO to be empty ... 20778c2ecf20Sopenharmony_ci * but: it would be better to wait first for the SCSI FIFO and then the 20788c2ecf20Sopenharmony_ci * the DMA FIFO to become empty? How do we know, that the device not already 20798c2ecf20Sopenharmony_ci * sent data to the FIFO in a MsgIn phase, eg.? 20808c2ecf20Sopenharmony_ci */ 20818c2ecf20Sopenharmony_ci if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) { 20828c2ecf20Sopenharmony_ci#if 0 20838c2ecf20Sopenharmony_ci int ctr = 6000000; 20848c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 20858c2ecf20Sopenharmony_ci "DIP0: Wait for DMA FIFO to flush ...\n"); 20868c2ecf20Sopenharmony_ci /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ 20878c2ecf20Sopenharmony_ci /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ 20888c2ecf20Sopenharmony_ci /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ 20898c2ecf20Sopenharmony_ci while (! 20908c2ecf20Sopenharmony_ci (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) & 20918c2ecf20Sopenharmony_ci 0x80) && --ctr); 20928c2ecf20Sopenharmony_ci if (ctr < 6000000 - 1) 20938c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG 20948c2ecf20Sopenharmony_ci "DIP0: Had to wait for DMA ...\n"); 20958c2ecf20Sopenharmony_ci if (!ctr) 20968c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, 20978c2ecf20Sopenharmony_ci "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); 20988c2ecf20Sopenharmony_ci /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ 20998c2ecf20Sopenharmony_ci#endif 21008c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "data_in_phase0: " 21018c2ecf20Sopenharmony_ci "DMA{fifocnt=0x%02x fifostat=0x%02x}\n", 21028c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), 21038c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci /* Now: Check remainig data: The SCSI counters should tell us ... */ 21068c2ecf20Sopenharmony_ci sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); 21078c2ecf20Sopenharmony_ci fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); 21088c2ecf20Sopenharmony_ci d_left_counter = sc + ((fc & 0x1f) 21098c2ecf20Sopenharmony_ci << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 21108c2ecf20Sopenharmony_ci 0)); 21118c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "data_in_phase0: " 21128c2ecf20Sopenharmony_ci "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " 21138c2ecf20Sopenharmony_ci "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " 21148c2ecf20Sopenharmony_ci "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", 21158c2ecf20Sopenharmony_ci fc, 21168c2ecf20Sopenharmony_ci (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", 21178c2ecf20Sopenharmony_ci sc, 21188c2ecf20Sopenharmony_ci fc, 21198c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), 21208c2ecf20Sopenharmony_ci DC395x_read32(acb, TRM_S1040_DMA_CXCNT), 21218c2ecf20Sopenharmony_ci srb->total_xfer_length, d_left_counter); 21228c2ecf20Sopenharmony_ci#if DC395x_LASTPIO 21238c2ecf20Sopenharmony_ci /* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */ 21248c2ecf20Sopenharmony_ci if (d_left_counter 21258c2ecf20Sopenharmony_ci && srb->total_xfer_length <= DC395x_LASTPIO) { 21268c2ecf20Sopenharmony_ci size_t left_io = srb->total_xfer_length; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci /*u32 addr = (srb->segment_x[srb->sg_index].address); */ 21298c2ecf20Sopenharmony_ci /*sg_update_list (srb, d_left_counter); */ 21308c2ecf20Sopenharmony_ci dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) " 21318c2ecf20Sopenharmony_ci "for remaining %i bytes:", 21328c2ecf20Sopenharmony_ci fc & 0x1f, 21338c2ecf20Sopenharmony_ci (srb->dcb->sync_period & WIDE_SYNC) ? 21348c2ecf20Sopenharmony_ci "words" : "bytes", 21358c2ecf20Sopenharmony_ci srb->total_xfer_length); 21368c2ecf20Sopenharmony_ci if (srb->dcb->sync_period & WIDE_SYNC) 21378c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 21388c2ecf20Sopenharmony_ci CFG2_WIDEFIFO); 21398c2ecf20Sopenharmony_ci while (left_io) { 21408c2ecf20Sopenharmony_ci unsigned char *virt, *base = NULL; 21418c2ecf20Sopenharmony_ci unsigned long flags = 0; 21428c2ecf20Sopenharmony_ci size_t len = left_io; 21438c2ecf20Sopenharmony_ci size_t offset = srb->request_length - left_io; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci local_irq_save(flags); 21468c2ecf20Sopenharmony_ci /* Assumption: it's inside one page as it's at most 4 bytes and 21478c2ecf20Sopenharmony_ci I just assume it's on a 4-byte boundary */ 21488c2ecf20Sopenharmony_ci base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), 21498c2ecf20Sopenharmony_ci srb->sg_count, &offset, &len); 21508c2ecf20Sopenharmony_ci virt = base + offset; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci left_io -= len; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci while (len) { 21558c2ecf20Sopenharmony_ci u8 byte; 21568c2ecf20Sopenharmony_ci byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 21578c2ecf20Sopenharmony_ci *virt++ = byte; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 21608c2ecf20Sopenharmony_ci printk(" %02x", byte); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci d_left_counter--; 21638c2ecf20Sopenharmony_ci sg_subtract_one(srb); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci len--; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (fc == 0x40) { 21708c2ecf20Sopenharmony_ci left_io = 0; 21718c2ecf20Sopenharmony_ci break; 21728c2ecf20Sopenharmony_ci } 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci WARN_ON((fc != 0x40) == !d_left_counter); 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) { 21788c2ecf20Sopenharmony_ci /* Read the last byte ... */ 21798c2ecf20Sopenharmony_ci if (srb->total_xfer_length > 0) { 21808c2ecf20Sopenharmony_ci u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci *virt++ = byte; 21838c2ecf20Sopenharmony_ci srb->total_xfer_length--; 21848c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 21858c2ecf20Sopenharmony_ci printk(" %02x", byte); 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci scsi_kunmap_atomic_sg(base); 21928c2ecf20Sopenharmony_ci local_irq_restore(flags); 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ 21958c2ecf20Sopenharmony_ci /*srb->total_xfer_length = 0; */ 21968c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 21978c2ecf20Sopenharmony_ci printk("\n"); 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci#endif /* DC395x_LASTPIO */ 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci#if 0 22028c2ecf20Sopenharmony_ci /* 22038c2ecf20Sopenharmony_ci * KG: This was in DATAOUT. Does it also belong here? 22048c2ecf20Sopenharmony_ci * Nobody seems to know what counter and fifo_cnt count exactly ... 22058c2ecf20Sopenharmony_ci */ 22068c2ecf20Sopenharmony_ci if (!(scsi_status & SCSIXFERDONE)) { 22078c2ecf20Sopenharmony_ci /* 22088c2ecf20Sopenharmony_ci * when data transfer from DMA FIFO to SCSI FIFO 22098c2ecf20Sopenharmony_ci * if there was some data left in SCSI FIFO 22108c2ecf20Sopenharmony_ci */ 22118c2ecf20Sopenharmony_ci d_left_counter = 22128c2ecf20Sopenharmony_ci (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 22138c2ecf20Sopenharmony_ci 0x1F); 22148c2ecf20Sopenharmony_ci if (srb->dcb->sync_period & WIDE_SYNC) 22158c2ecf20Sopenharmony_ci d_left_counter <<= 1; 22168c2ecf20Sopenharmony_ci /* 22178c2ecf20Sopenharmony_ci * if WIDE scsi SCSI FIFOCNT unit is word !!! 22188c2ecf20Sopenharmony_ci * so need to *= 2 22198c2ecf20Sopenharmony_ci * KG: Seems to be correct ... 22208c2ecf20Sopenharmony_ci */ 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci#endif 22238c2ecf20Sopenharmony_ci /* KG: This should not be needed any more! */ 22248c2ecf20Sopenharmony_ci if (d_left_counter == 0 22258c2ecf20Sopenharmony_ci || (scsi_status & SCSIXFERCNT_2_ZERO)) { 22268c2ecf20Sopenharmony_ci#if 0 22278c2ecf20Sopenharmony_ci int ctr = 6000000; 22288c2ecf20Sopenharmony_ci u8 TempDMAstatus; 22298c2ecf20Sopenharmony_ci do { 22308c2ecf20Sopenharmony_ci TempDMAstatus = 22318c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_DMA_STATUS); 22328c2ecf20Sopenharmony_ci } while (!(TempDMAstatus & DMAXFERCOMP) && --ctr); 22338c2ecf20Sopenharmony_ci if (!ctr) 22348c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, 22358c2ecf20Sopenharmony_ci "Deadlock in DataInPhase0 waiting for DMA!!\n"); 22368c2ecf20Sopenharmony_ci srb->total_xfer_length = 0; 22378c2ecf20Sopenharmony_ci#endif 22388c2ecf20Sopenharmony_ci srb->total_xfer_length = d_left_counter; 22398c2ecf20Sopenharmony_ci } else { /* phase changed */ 22408c2ecf20Sopenharmony_ci /* 22418c2ecf20Sopenharmony_ci * parsing the case: 22428c2ecf20Sopenharmony_ci * when a transfer not yet complete 22438c2ecf20Sopenharmony_ci * but be disconnected by target 22448c2ecf20Sopenharmony_ci * if transfer not yet complete 22458c2ecf20Sopenharmony_ci * there were some data residue in SCSI FIFO or 22468c2ecf20Sopenharmony_ci * SCSI transfer counter not empty 22478c2ecf20Sopenharmony_ci */ 22488c2ecf20Sopenharmony_ci sg_update_list(srb, d_left_counter); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci /* KG: The target may decide to disconnect: Empty FIFO before! */ 22528c2ecf20Sopenharmony_ci if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { 22538c2ecf20Sopenharmony_ci cleanup_after_transfer(acb, srb); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 22598c2ecf20Sopenharmony_ci u16 *pscsi_status) 22608c2ecf20Sopenharmony_ci{ 22618c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n", 22628c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 22638c2ecf20Sopenharmony_ci data_io_transfer(acb, srb, XFERDATAIN); 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_cistatic void data_io_transfer(struct AdapterCtlBlk *acb, 22688c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb, u16 io_dir) 22698c2ecf20Sopenharmony_ci{ 22708c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 22718c2ecf20Sopenharmony_ci u8 bval; 22728c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, 22738c2ecf20Sopenharmony_ci "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n", 22748c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun, 22758c2ecf20Sopenharmony_ci ((io_dir & DMACMD_DIR) ? 'r' : 'w'), 22768c2ecf20Sopenharmony_ci srb->total_xfer_length, srb->sg_index, srb->sg_count); 22778c2ecf20Sopenharmony_ci if (srb == acb->tmp_srb) 22788c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n"); 22798c2ecf20Sopenharmony_ci if (srb->sg_index >= srb->sg_count) { 22808c2ecf20Sopenharmony_ci /* can't happen? out of bounds error */ 22818c2ecf20Sopenharmony_ci return; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci if (srb->total_xfer_length > DC395x_LASTPIO) { 22858c2ecf20Sopenharmony_ci u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); 22868c2ecf20Sopenharmony_ci /* 22878c2ecf20Sopenharmony_ci * KG: What should we do: Use SCSI Cmd 0x90/0x92? 22888c2ecf20Sopenharmony_ci * Maybe, even ABORTXFER would be appropriate 22898c2ecf20Sopenharmony_ci */ 22908c2ecf20Sopenharmony_ci if (dma_status & XFERPENDING) { 22918c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! " 22928c2ecf20Sopenharmony_ci "Expect trouble!\n"); 22938c2ecf20Sopenharmony_ci dump_register_info(acb, dcb, srb); 22948c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci /* clear_fifo(acb, "IO"); */ 22978c2ecf20Sopenharmony_ci /* 22988c2ecf20Sopenharmony_ci * load what physical address of Scatter/Gather list table 22998c2ecf20Sopenharmony_ci * want to be transfer 23008c2ecf20Sopenharmony_ci */ 23018c2ecf20Sopenharmony_ci srb->state |= SRB_DATA_XFER; 23028c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); 23038c2ecf20Sopenharmony_ci if (scsi_sg_count(srb->cmd)) { /* with S/G */ 23048c2ecf20Sopenharmony_ci io_dir |= DMACMD_SG; 23058c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, 23068c2ecf20Sopenharmony_ci srb->sg_bus_addr + 23078c2ecf20Sopenharmony_ci sizeof(struct SGentry) * 23088c2ecf20Sopenharmony_ci srb->sg_index); 23098c2ecf20Sopenharmony_ci /* load how many bytes in the sg list table */ 23108c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_DMA_XCNT, 23118c2ecf20Sopenharmony_ci ((u32)(srb->sg_count - 23128c2ecf20Sopenharmony_ci srb->sg_index) << 3)); 23138c2ecf20Sopenharmony_ci } else { /* without S/G */ 23148c2ecf20Sopenharmony_ci io_dir &= ~DMACMD_SG; 23158c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, 23168c2ecf20Sopenharmony_ci srb->segment_x[0].address); 23178c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_DMA_XCNT, 23188c2ecf20Sopenharmony_ci srb->segment_x[0].length); 23198c2ecf20Sopenharmony_ci } 23208c2ecf20Sopenharmony_ci /* load total transfer length (24bits) max value 16Mbyte */ 23218c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 23228c2ecf20Sopenharmony_ci srb->total_xfer_length); 23238c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 23248c2ecf20Sopenharmony_ci if (io_dir & DMACMD_DIR) { /* read */ 23258c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, 23268c2ecf20Sopenharmony_ci SCMD_DMA_IN); 23278c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); 23288c2ecf20Sopenharmony_ci } else { 23298c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); 23308c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, 23318c2ecf20Sopenharmony_ci SCMD_DMA_OUT); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci#if DC395x_LASTPIO 23368c2ecf20Sopenharmony_ci else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ 23378c2ecf20Sopenharmony_ci /* 23388c2ecf20Sopenharmony_ci * load what physical address of Scatter/Gather list table 23398c2ecf20Sopenharmony_ci * want to be transfer 23408c2ecf20Sopenharmony_ci */ 23418c2ecf20Sopenharmony_ci srb->state |= SRB_DATA_XFER; 23428c2ecf20Sopenharmony_ci /* load total transfer length (24bits) max value 16Mbyte */ 23438c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 23448c2ecf20Sopenharmony_ci srb->total_xfer_length); 23458c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 23468c2ecf20Sopenharmony_ci if (io_dir & DMACMD_DIR) { /* read */ 23478c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, 23488c2ecf20Sopenharmony_ci SCMD_FIFO_IN); 23498c2ecf20Sopenharmony_ci } else { /* write */ 23508c2ecf20Sopenharmony_ci int ln = srb->total_xfer_length; 23518c2ecf20Sopenharmony_ci size_t left_io = srb->total_xfer_length; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (srb->dcb->sync_period & WIDE_SYNC) 23548c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 23558c2ecf20Sopenharmony_ci CFG2_WIDEFIFO); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci while (left_io) { 23588c2ecf20Sopenharmony_ci unsigned char *virt, *base = NULL; 23598c2ecf20Sopenharmony_ci unsigned long flags = 0; 23608c2ecf20Sopenharmony_ci size_t len = left_io; 23618c2ecf20Sopenharmony_ci size_t offset = srb->request_length - left_io; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci local_irq_save(flags); 23648c2ecf20Sopenharmony_ci /* Again, max 4 bytes */ 23658c2ecf20Sopenharmony_ci base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), 23668c2ecf20Sopenharmony_ci srb->sg_count, &offset, &len); 23678c2ecf20Sopenharmony_ci virt = base + offset; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci left_io -= len; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci while (len--) { 23728c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 23738c2ecf20Sopenharmony_ci printk(" %02x", *virt); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci sg_subtract_one(srb); 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci scsi_kunmap_atomic_sg(base); 23818c2ecf20Sopenharmony_ci local_irq_restore(flags); 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci if (srb->dcb->sync_period & WIDE_SYNC) { 23848c2ecf20Sopenharmony_ci if (ln % 2) { 23858c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); 23868c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 23878c2ecf20Sopenharmony_ci printk(" |00"); 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ 23928c2ecf20Sopenharmony_ci if (debug_enabled(DBG_PIO)) 23938c2ecf20Sopenharmony_ci printk("\n"); 23948c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, 23958c2ecf20Sopenharmony_ci SCMD_FIFO_OUT); 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci#endif /* DC395x_LASTPIO */ 23998c2ecf20Sopenharmony_ci else { /* xfer pad */ 24008c2ecf20Sopenharmony_ci u8 data = 0, data2 = 0; 24018c2ecf20Sopenharmony_ci if (srb->sg_count) { 24028c2ecf20Sopenharmony_ci srb->adapter_status = H_OVER_UNDER_RUN; 24038c2ecf20Sopenharmony_ci srb->status |= OVER_RUN; 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci /* 24068c2ecf20Sopenharmony_ci * KG: despite the fact that we are using 16 bits I/O ops 24078c2ecf20Sopenharmony_ci * the SCSI FIFO is only 8 bits according to the docs 24088c2ecf20Sopenharmony_ci * (we can set bit 1 in 0x8f to serialize FIFO access ...) 24098c2ecf20Sopenharmony_ci */ 24108c2ecf20Sopenharmony_ci if (dcb->sync_period & WIDE_SYNC) { 24118c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); 24128c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 24138c2ecf20Sopenharmony_ci CFG2_WIDEFIFO); 24148c2ecf20Sopenharmony_ci if (io_dir & DMACMD_DIR) { 24158c2ecf20Sopenharmony_ci data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 24168c2ecf20Sopenharmony_ci data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 24178c2ecf20Sopenharmony_ci } else { 24188c2ecf20Sopenharmony_ci /* Danger, Robinson: If you find KGs 24198c2ecf20Sopenharmony_ci * scattered over the wide disk, the driver 24208c2ecf20Sopenharmony_ci * or chip is to blame :-( */ 24218c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); 24228c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G'); 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); 24258c2ecf20Sopenharmony_ci } else { 24268c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); 24278c2ecf20Sopenharmony_ci /* Danger, Robinson: If you find a collection of Ks on your disk 24288c2ecf20Sopenharmony_ci * something broke :-( */ 24298c2ecf20Sopenharmony_ci if (io_dir & DMACMD_DIR) 24308c2ecf20Sopenharmony_ci data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 24318c2ecf20Sopenharmony_ci else 24328c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci srb->state |= SRB_XFERPAD; 24358c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 24368c2ecf20Sopenharmony_ci /* SCSI command */ 24378c2ecf20Sopenharmony_ci bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT; 24388c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); 24398c2ecf20Sopenharmony_ci } 24408c2ecf20Sopenharmony_ci} 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_cistatic void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 24448c2ecf20Sopenharmony_ci u16 *pscsi_status) 24458c2ecf20Sopenharmony_ci{ 24468c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n", 24478c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 24488c2ecf20Sopenharmony_ci srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 24498c2ecf20Sopenharmony_ci srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ 24508c2ecf20Sopenharmony_ci srb->state = SRB_COMPLETED; 24518c2ecf20Sopenharmony_ci *pscsi_status = PH_BUS_FREE; /*.. initial phase */ 24528c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 24538c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); 24548c2ecf20Sopenharmony_ci} 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_cistatic void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 24588c2ecf20Sopenharmony_ci u16 *pscsi_status) 24598c2ecf20Sopenharmony_ci{ 24608c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n", 24618c2ecf20Sopenharmony_ci srb->cmd, srb->cmd->device->id, (u8)srb->cmd->device->lun); 24628c2ecf20Sopenharmony_ci srb->state = SRB_STATUS; 24638c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 24648c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); 24658c2ecf20Sopenharmony_ci} 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci/* Check if the message is complete */ 24698c2ecf20Sopenharmony_cistatic inline u8 msgin_completed(u8 * msgbuf, u32 len) 24708c2ecf20Sopenharmony_ci{ 24718c2ecf20Sopenharmony_ci if (*msgbuf == EXTENDED_MESSAGE) { 24728c2ecf20Sopenharmony_ci if (len < 2) 24738c2ecf20Sopenharmony_ci return 0; 24748c2ecf20Sopenharmony_ci if (len < msgbuf[1] + 2) 24758c2ecf20Sopenharmony_ci return 0; 24768c2ecf20Sopenharmony_ci } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) /* two byte messages */ 24778c2ecf20Sopenharmony_ci if (len < 2) 24788c2ecf20Sopenharmony_ci return 0; 24798c2ecf20Sopenharmony_ci return 1; 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci/* reject_msg */ 24838c2ecf20Sopenharmony_cistatic inline void msgin_reject(struct AdapterCtlBlk *acb, 24848c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 24858c2ecf20Sopenharmony_ci{ 24868c2ecf20Sopenharmony_ci srb->msgout_buf[0] = MESSAGE_REJECT; 24878c2ecf20Sopenharmony_ci srb->msg_count = 1; 24888c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 24898c2ecf20Sopenharmony_ci srb->state &= ~SRB_MSGIN; 24908c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT; 24918c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n", 24928c2ecf20Sopenharmony_ci srb->msgin_buf[0], 24938c2ecf20Sopenharmony_ci srb->dcb->target_id, srb->dcb->target_lun); 24948c2ecf20Sopenharmony_ci} 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_cistatic struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, 24988c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb, u8 tag) 24998c2ecf20Sopenharmony_ci{ 25008c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb = NULL; 25018c2ecf20Sopenharmony_ci struct ScsiReqBlk *i; 25028c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n", 25038c2ecf20Sopenharmony_ci srb->cmd, tag, srb); 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci if (!(dcb->tag_mask & (1 << tag))) 25068c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 25078c2ecf20Sopenharmony_ci "msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n", 25088c2ecf20Sopenharmony_ci dcb->tag_mask, tag); 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (list_empty(&dcb->srb_going_list)) 25118c2ecf20Sopenharmony_ci goto mingx0; 25128c2ecf20Sopenharmony_ci list_for_each_entry(i, &dcb->srb_going_list, list) { 25138c2ecf20Sopenharmony_ci if (i->tag_number == tag) { 25148c2ecf20Sopenharmony_ci srb = i; 25158c2ecf20Sopenharmony_ci break; 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci if (!srb) 25198c2ecf20Sopenharmony_ci goto mingx0; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n", 25228c2ecf20Sopenharmony_ci srb->cmd, srb->dcb->target_id, srb->dcb->target_lun); 25238c2ecf20Sopenharmony_ci if (dcb->flag & ABORT_DEV_) { 25248c2ecf20Sopenharmony_ci /*srb->state = SRB_ABORT_SENT; */ 25258c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (!(srb->state & SRB_DISCONNECT)) 25298c2ecf20Sopenharmony_ci goto mingx0; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len); 25328c2ecf20Sopenharmony_ci srb->state |= dcb->active_srb->state; 25338c2ecf20Sopenharmony_ci srb->state |= SRB_DATA_XFER; 25348c2ecf20Sopenharmony_ci dcb->active_srb = srb; 25358c2ecf20Sopenharmony_ci /* How can we make the DORS happy? */ 25368c2ecf20Sopenharmony_ci return srb; 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci mingx0: 25398c2ecf20Sopenharmony_ci srb = acb->tmp_srb; 25408c2ecf20Sopenharmony_ci srb->state = SRB_UNEXPECT_RESEL; 25418c2ecf20Sopenharmony_ci dcb->active_srb = srb; 25428c2ecf20Sopenharmony_ci srb->msgout_buf[0] = MSG_ABORT_TAG; 25438c2ecf20Sopenharmony_ci srb->msg_count = 1; 25448c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 25458c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag); 25468c2ecf20Sopenharmony_ci return srb; 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistatic inline void reprogram_regs(struct AdapterCtlBlk *acb, 25518c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb) 25528c2ecf20Sopenharmony_ci{ 25538c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); 25548c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); 25558c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); 25568c2ecf20Sopenharmony_ci set_xfer_rate(acb, dcb); 25578c2ecf20Sopenharmony_ci} 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci/* set async transfer mode */ 25618c2ecf20Sopenharmony_cistatic void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) 25628c2ecf20Sopenharmony_ci{ 25638c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 25648c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n", 25658c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci dcb->sync_mode &= ~(SYNC_NEGO_ENABLE); 25688c2ecf20Sopenharmony_ci dcb->sync_mode |= SYNC_NEGO_DONE; 25698c2ecf20Sopenharmony_ci /*dcb->sync_period &= 0; */ 25708c2ecf20Sopenharmony_ci dcb->sync_offset = 0; 25718c2ecf20Sopenharmony_ci dcb->min_nego_period = 200 >> 2; /* 200ns <=> 5 MHz */ 25728c2ecf20Sopenharmony_ci srb->state &= ~SRB_DO_SYNC_NEGO; 25738c2ecf20Sopenharmony_ci reprogram_regs(acb, dcb); 25748c2ecf20Sopenharmony_ci if ((dcb->sync_mode & WIDE_NEGO_ENABLE) 25758c2ecf20Sopenharmony_ci && !(dcb->sync_mode & WIDE_NEGO_DONE)) { 25768c2ecf20Sopenharmony_ci build_wdtr(acb, dcb, srb); 25778c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 25788c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n"); 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci} 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci/* set sync transfer mode */ 25848c2ecf20Sopenharmony_cistatic void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) 25858c2ecf20Sopenharmony_ci{ 25868c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 25878c2ecf20Sopenharmony_ci u8 bval; 25888c2ecf20Sopenharmony_ci int fact; 25898c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins " 25908c2ecf20Sopenharmony_ci "(%02i.%01i MHz) Offset %i\n", 25918c2ecf20Sopenharmony_ci dcb->target_id, srb->msgin_buf[3] << 2, 25928c2ecf20Sopenharmony_ci (250 / srb->msgin_buf[3]), 25938c2ecf20Sopenharmony_ci ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], 25948c2ecf20Sopenharmony_ci srb->msgin_buf[4]); 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci if (srb->msgin_buf[4] > 15) 25978c2ecf20Sopenharmony_ci srb->msgin_buf[4] = 15; 25988c2ecf20Sopenharmony_ci if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) 25998c2ecf20Sopenharmony_ci dcb->sync_offset = 0; 26008c2ecf20Sopenharmony_ci else if (dcb->sync_offset == 0) 26018c2ecf20Sopenharmony_ci dcb->sync_offset = srb->msgin_buf[4]; 26028c2ecf20Sopenharmony_ci if (srb->msgin_buf[4] > dcb->sync_offset) 26038c2ecf20Sopenharmony_ci srb->msgin_buf[4] = dcb->sync_offset; 26048c2ecf20Sopenharmony_ci else 26058c2ecf20Sopenharmony_ci dcb->sync_offset = srb->msgin_buf[4]; 26068c2ecf20Sopenharmony_ci bval = 0; 26078c2ecf20Sopenharmony_ci while (bval < 7 && (srb->msgin_buf[3] > clock_period[bval] 26088c2ecf20Sopenharmony_ci || dcb->min_nego_period > 26098c2ecf20Sopenharmony_ci clock_period[bval])) 26108c2ecf20Sopenharmony_ci bval++; 26118c2ecf20Sopenharmony_ci if (srb->msgin_buf[3] < clock_period[bval]) 26128c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 26138c2ecf20Sopenharmony_ci "msgin_set_sync: Increase sync nego period to %ins\n", 26148c2ecf20Sopenharmony_ci clock_period[bval] << 2); 26158c2ecf20Sopenharmony_ci srb->msgin_buf[3] = clock_period[bval]; 26168c2ecf20Sopenharmony_ci dcb->sync_period &= 0xf0; 26178c2ecf20Sopenharmony_ci dcb->sync_period |= ALT_SYNC | bval; 26188c2ecf20Sopenharmony_ci dcb->min_nego_period = srb->msgin_buf[3]; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci if (dcb->sync_period & WIDE_SYNC) 26218c2ecf20Sopenharmony_ci fact = 500; 26228c2ecf20Sopenharmony_ci else 26238c2ecf20Sopenharmony_ci fact = 250; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, 26268c2ecf20Sopenharmony_ci "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", 26278c2ecf20Sopenharmony_ci dcb->target_id, (fact == 500) ? "Wide16" : "", 26288c2ecf20Sopenharmony_ci dcb->min_nego_period << 2, dcb->sync_offset, 26298c2ecf20Sopenharmony_ci (fact / dcb->min_nego_period), 26308c2ecf20Sopenharmony_ci ((fact % dcb->min_nego_period) * 10 + 26318c2ecf20Sopenharmony_ci dcb->min_nego_period / 2) / dcb->min_nego_period); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci if (!(srb->state & SRB_DO_SYNC_NEGO)) { 26348c2ecf20Sopenharmony_ci /* Reply with corrected SDTR Message */ 26358c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n", 26368c2ecf20Sopenharmony_ci srb->msgin_buf[3] << 2, srb->msgin_buf[4]); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci memcpy(srb->msgout_buf, srb->msgin_buf, 5); 26398c2ecf20Sopenharmony_ci srb->msg_count = 5; 26408c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 26418c2ecf20Sopenharmony_ci dcb->sync_mode |= SYNC_NEGO_DONE; 26428c2ecf20Sopenharmony_ci } else { 26438c2ecf20Sopenharmony_ci if ((dcb->sync_mode & WIDE_NEGO_ENABLE) 26448c2ecf20Sopenharmony_ci && !(dcb->sync_mode & WIDE_NEGO_DONE)) { 26458c2ecf20Sopenharmony_ci build_wdtr(acb, dcb, srb); 26468c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 26478c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n"); 26488c2ecf20Sopenharmony_ci } 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci srb->state &= ~SRB_DO_SYNC_NEGO; 26518c2ecf20Sopenharmony_ci dcb->sync_mode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE; 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci reprogram_regs(acb, dcb); 26548c2ecf20Sopenharmony_ci} 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic inline void msgin_set_nowide(struct AdapterCtlBlk *acb, 26588c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 26618c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci dcb->sync_period &= ~WIDE_SYNC; 26648c2ecf20Sopenharmony_ci dcb->sync_mode &= ~(WIDE_NEGO_ENABLE); 26658c2ecf20Sopenharmony_ci dcb->sync_mode |= WIDE_NEGO_DONE; 26668c2ecf20Sopenharmony_ci srb->state &= ~SRB_DO_WIDE_NEGO; 26678c2ecf20Sopenharmony_ci reprogram_regs(acb, dcb); 26688c2ecf20Sopenharmony_ci if ((dcb->sync_mode & SYNC_NEGO_ENABLE) 26698c2ecf20Sopenharmony_ci && !(dcb->sync_mode & SYNC_NEGO_DONE)) { 26708c2ecf20Sopenharmony_ci build_sdtr(acb, dcb, srb); 26718c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 26728c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n"); 26738c2ecf20Sopenharmony_ci } 26748c2ecf20Sopenharmony_ci} 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_cistatic void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) 26778c2ecf20Sopenharmony_ci{ 26788c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = srb->dcb; 26798c2ecf20Sopenharmony_ci u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO 26808c2ecf20Sopenharmony_ci && acb->config & HCC_WIDE_CARD) ? 1 : 0; 26818c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id); 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci if (srb->msgin_buf[3] > wide) 26848c2ecf20Sopenharmony_ci srb->msgin_buf[3] = wide; 26858c2ecf20Sopenharmony_ci /* Completed */ 26868c2ecf20Sopenharmony_ci if (!(srb->state & SRB_DO_WIDE_NEGO)) { 26878c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 26888c2ecf20Sopenharmony_ci "msgin_set_wide: Wide nego initiated <%02i>\n", 26898c2ecf20Sopenharmony_ci dcb->target_id); 26908c2ecf20Sopenharmony_ci memcpy(srb->msgout_buf, srb->msgin_buf, 4); 26918c2ecf20Sopenharmony_ci srb->msg_count = 4; 26928c2ecf20Sopenharmony_ci srb->state |= SRB_DO_WIDE_NEGO; 26938c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci dcb->sync_mode |= (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE); 26978c2ecf20Sopenharmony_ci if (srb->msgin_buf[3] > 0) 26988c2ecf20Sopenharmony_ci dcb->sync_period |= WIDE_SYNC; 26998c2ecf20Sopenharmony_ci else 27008c2ecf20Sopenharmony_ci dcb->sync_period &= ~WIDE_SYNC; 27018c2ecf20Sopenharmony_ci srb->state &= ~SRB_DO_WIDE_NEGO; 27028c2ecf20Sopenharmony_ci /*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ 27038c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, 27048c2ecf20Sopenharmony_ci "msgin_set_wide: Wide (%i bit) negotiated <%02i>\n", 27058c2ecf20Sopenharmony_ci (8 << srb->msgin_buf[3]), dcb->target_id); 27068c2ecf20Sopenharmony_ci reprogram_regs(acb, dcb); 27078c2ecf20Sopenharmony_ci if ((dcb->sync_mode & SYNC_NEGO_ENABLE) 27088c2ecf20Sopenharmony_ci && !(dcb->sync_mode & SYNC_NEGO_DONE)) { 27098c2ecf20Sopenharmony_ci build_sdtr(acb, dcb, srb); 27108c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 27118c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n"); 27128c2ecf20Sopenharmony_ci } 27138c2ecf20Sopenharmony_ci} 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci/* 27178c2ecf20Sopenharmony_ci * extended message codes: 27188c2ecf20Sopenharmony_ci * 27198c2ecf20Sopenharmony_ci * code description 27208c2ecf20Sopenharmony_ci * 27218c2ecf20Sopenharmony_ci * 02h Reserved 27228c2ecf20Sopenharmony_ci * 00h MODIFY DATA POINTER 27238c2ecf20Sopenharmony_ci * 01h SYNCHRONOUS DATA TRANSFER REQUEST 27248c2ecf20Sopenharmony_ci * 03h WIDE DATA TRANSFER REQUEST 27258c2ecf20Sopenharmony_ci * 04h - 7Fh Reserved 27268c2ecf20Sopenharmony_ci * 80h - FFh Vendor specific 27278c2ecf20Sopenharmony_ci */ 27288c2ecf20Sopenharmony_cistatic void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 27298c2ecf20Sopenharmony_ci u16 *pscsi_status) 27308c2ecf20Sopenharmony_ci{ 27318c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = acb->active_dcb; 27328c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd); 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); 27358c2ecf20Sopenharmony_ci if (msgin_completed(srb->msgin_buf, acb->msg_len)) { 27368c2ecf20Sopenharmony_ci /* Now eval the msg */ 27378c2ecf20Sopenharmony_ci switch (srb->msgin_buf[0]) { 27388c2ecf20Sopenharmony_ci case DISCONNECT: 27398c2ecf20Sopenharmony_ci srb->state = SRB_DISCONNECT; 27408c2ecf20Sopenharmony_ci break; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci case SIMPLE_QUEUE_TAG: 27438c2ecf20Sopenharmony_ci case HEAD_OF_QUEUE_TAG: 27448c2ecf20Sopenharmony_ci case ORDERED_QUEUE_TAG: 27458c2ecf20Sopenharmony_ci srb = 27468c2ecf20Sopenharmony_ci msgin_qtag(acb, dcb, 27478c2ecf20Sopenharmony_ci srb->msgin_buf[1]); 27488c2ecf20Sopenharmony_ci break; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci case MESSAGE_REJECT: 27518c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, 27528c2ecf20Sopenharmony_ci DO_CLRATN | DO_DATALATCH); 27538c2ecf20Sopenharmony_ci /* A sync nego message was rejected ! */ 27548c2ecf20Sopenharmony_ci if (srb->state & SRB_DO_SYNC_NEGO) { 27558c2ecf20Sopenharmony_ci msgin_set_async(acb, srb); 27568c2ecf20Sopenharmony_ci break; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci /* A wide nego message was rejected ! */ 27598c2ecf20Sopenharmony_ci if (srb->state & SRB_DO_WIDE_NEGO) { 27608c2ecf20Sopenharmony_ci msgin_set_nowide(acb, srb); 27618c2ecf20Sopenharmony_ci break; 27628c2ecf20Sopenharmony_ci } 27638c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 27648c2ecf20Sopenharmony_ci /*srb->state |= SRB_ABORT_SENT */ 27658c2ecf20Sopenharmony_ci break; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci case EXTENDED_MESSAGE: 27688c2ecf20Sopenharmony_ci /* SDTR */ 27698c2ecf20Sopenharmony_ci if (srb->msgin_buf[1] == 3 27708c2ecf20Sopenharmony_ci && srb->msgin_buf[2] == EXTENDED_SDTR) { 27718c2ecf20Sopenharmony_ci msgin_set_sync(acb, srb); 27728c2ecf20Sopenharmony_ci break; 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci /* WDTR */ 27758c2ecf20Sopenharmony_ci if (srb->msgin_buf[1] == 2 27768c2ecf20Sopenharmony_ci && srb->msgin_buf[2] == EXTENDED_WDTR 27778c2ecf20Sopenharmony_ci && srb->msgin_buf[3] <= 2) { /* sanity check ... */ 27788c2ecf20Sopenharmony_ci msgin_set_wide(acb, srb); 27798c2ecf20Sopenharmony_ci break; 27808c2ecf20Sopenharmony_ci } 27818c2ecf20Sopenharmony_ci msgin_reject(acb, srb); 27828c2ecf20Sopenharmony_ci break; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci case MSG_IGNOREWIDE: 27858c2ecf20Sopenharmony_ci /* Discard wide residual */ 27868c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n"); 27878c2ecf20Sopenharmony_ci break; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci case COMMAND_COMPLETE: 27908c2ecf20Sopenharmony_ci /* nothing has to be done */ 27918c2ecf20Sopenharmony_ci break; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci case SAVE_POINTERS: 27948c2ecf20Sopenharmony_ci /* 27958c2ecf20Sopenharmony_ci * SAVE POINTER may be ignored as we have the struct 27968c2ecf20Sopenharmony_ci * ScsiReqBlk* associated with the scsi command. 27978c2ecf20Sopenharmony_ci */ 27988c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " 27998c2ecf20Sopenharmony_ci "SAVE POINTER rem=%i Ignore\n", 28008c2ecf20Sopenharmony_ci srb->cmd, srb->total_xfer_length); 28018c2ecf20Sopenharmony_ci break; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci case RESTORE_POINTERS: 28048c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n"); 28058c2ecf20Sopenharmony_ci break; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci case ABORT: 28088c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " 28098c2ecf20Sopenharmony_ci "<%02i-%i> ABORT msg\n", 28108c2ecf20Sopenharmony_ci srb->cmd, dcb->target_id, 28118c2ecf20Sopenharmony_ci dcb->target_lun); 28128c2ecf20Sopenharmony_ci dcb->flag |= ABORT_DEV_; 28138c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 28148c2ecf20Sopenharmony_ci break; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci default: 28178c2ecf20Sopenharmony_ci /* reject unknown messages */ 28188c2ecf20Sopenharmony_ci if (srb->msgin_buf[0] & IDENTIFY_BASE) { 28198c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n"); 28208c2ecf20Sopenharmony_ci srb->msg_count = 1; 28218c2ecf20Sopenharmony_ci srb->msgout_buf[0] = dcb->identify_msg; 28228c2ecf20Sopenharmony_ci DC395x_ENABLE_MSGOUT; 28238c2ecf20Sopenharmony_ci srb->state |= SRB_MSGOUT; 28248c2ecf20Sopenharmony_ci /*break; */ 28258c2ecf20Sopenharmony_ci } 28268c2ecf20Sopenharmony_ci msgin_reject(acb, srb); 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci /* Clear counter and MsgIn state */ 28308c2ecf20Sopenharmony_ci srb->state &= ~SRB_MSGIN; 28318c2ecf20Sopenharmony_ci acb->msg_len = 0; 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci *pscsi_status = PH_BUS_FREE; 28348c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important ... you know! */ 28358c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); 28368c2ecf20Sopenharmony_ci} 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_cistatic void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 28408c2ecf20Sopenharmony_ci u16 *pscsi_status) 28418c2ecf20Sopenharmony_ci{ 28428c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd); 28438c2ecf20Sopenharmony_ci clear_fifo(acb, "msgin_phase1"); 28448c2ecf20Sopenharmony_ci DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); 28458c2ecf20Sopenharmony_ci if (!(srb->state & SRB_MSGIN)) { 28468c2ecf20Sopenharmony_ci srb->state &= ~SRB_DISCONNECT; 28478c2ecf20Sopenharmony_ci srb->state |= SRB_MSGIN; 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 28508c2ecf20Sopenharmony_ci /* SCSI command */ 28518c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_cistatic void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 28568c2ecf20Sopenharmony_ci u16 *pscsi_status) 28578c2ecf20Sopenharmony_ci{ 28588c2ecf20Sopenharmony_ci} 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_cistatic void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 28628c2ecf20Sopenharmony_ci u16 *pscsi_status) 28638c2ecf20Sopenharmony_ci{ 28648c2ecf20Sopenharmony_ci} 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_cistatic void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) 28688c2ecf20Sopenharmony_ci{ 28698c2ecf20Sopenharmony_ci struct DeviceCtlBlk *i; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci /* set all lun device's period, offset */ 28728c2ecf20Sopenharmony_ci if (dcb->identify_msg & 0x07) 28738c2ecf20Sopenharmony_ci return; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (acb->scan_devices) { 28768c2ecf20Sopenharmony_ci current_sync_offset = dcb->sync_offset; 28778c2ecf20Sopenharmony_ci return; 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci list_for_each_entry(i, &acb->dcb_list, list) 28818c2ecf20Sopenharmony_ci if (i->target_id == dcb->target_id) { 28828c2ecf20Sopenharmony_ci i->sync_period = dcb->sync_period; 28838c2ecf20Sopenharmony_ci i->sync_offset = dcb->sync_offset; 28848c2ecf20Sopenharmony_ci i->sync_mode = dcb->sync_mode; 28858c2ecf20Sopenharmony_ci i->min_nego_period = dcb->min_nego_period; 28868c2ecf20Sopenharmony_ci } 28878c2ecf20Sopenharmony_ci} 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_cistatic void disconnect(struct AdapterCtlBlk *acb) 28918c2ecf20Sopenharmony_ci{ 28928c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = acb->active_dcb; 28938c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci if (!dcb) { 28968c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "disconnect: No such device\n"); 28978c2ecf20Sopenharmony_ci udelay(500); 28988c2ecf20Sopenharmony_ci /* Suspend queue for a while */ 28998c2ecf20Sopenharmony_ci acb->last_reset = 29008c2ecf20Sopenharmony_ci jiffies + HZ / 2 + 29018c2ecf20Sopenharmony_ci HZ * acb->eeprom.delay_time; 29028c2ecf20Sopenharmony_ci clear_fifo(acb, "disconnectEx"); 29038c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); 29048c2ecf20Sopenharmony_ci return; 29058c2ecf20Sopenharmony_ci } 29068c2ecf20Sopenharmony_ci srb = dcb->active_srb; 29078c2ecf20Sopenharmony_ci acb->active_dcb = NULL; 29088c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd); 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci srb->scsi_phase = PH_BUS_FREE; /* initial phase */ 29118c2ecf20Sopenharmony_ci clear_fifo(acb, "disconnect"); 29128c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); 29138c2ecf20Sopenharmony_ci if (srb->state & SRB_UNEXPECT_RESEL) { 29148c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, 29158c2ecf20Sopenharmony_ci "disconnect: Unexpected reselection <%02i-%i>\n", 29168c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 29178c2ecf20Sopenharmony_ci srb->state = 0; 29188c2ecf20Sopenharmony_ci waiting_process_next(acb); 29198c2ecf20Sopenharmony_ci } else if (srb->state & SRB_ABORT_SENT) { 29208c2ecf20Sopenharmony_ci dcb->flag &= ~ABORT_DEV_; 29218c2ecf20Sopenharmony_ci acb->last_reset = jiffies + HZ / 2 + 1; 29228c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); 29238c2ecf20Sopenharmony_ci doing_srb_done(acb, DID_ABORT, srb->cmd, 1); 29248c2ecf20Sopenharmony_ci waiting_process_next(acb); 29258c2ecf20Sopenharmony_ci } else { 29268c2ecf20Sopenharmony_ci if ((srb->state & (SRB_START_ + SRB_MSGOUT)) 29278c2ecf20Sopenharmony_ci || !(srb-> 29288c2ecf20Sopenharmony_ci state & (SRB_DISCONNECT + SRB_COMPLETED))) { 29298c2ecf20Sopenharmony_ci /* 29308c2ecf20Sopenharmony_ci * Selection time out 29318c2ecf20Sopenharmony_ci * SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED) 29328c2ecf20Sopenharmony_ci */ 29338c2ecf20Sopenharmony_ci /* Unexp. Disc / Sel Timeout */ 29348c2ecf20Sopenharmony_ci if (srb->state != SRB_START_ 29358c2ecf20Sopenharmony_ci && srb->state != SRB_MSGOUT) { 29368c2ecf20Sopenharmony_ci srb->state = SRB_READY; 29378c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 29388c2ecf20Sopenharmony_ci "disconnect: (0x%p) Unexpected\n", 29398c2ecf20Sopenharmony_ci srb->cmd); 29408c2ecf20Sopenharmony_ci srb->target_status = SCSI_STAT_SEL_TIMEOUT; 29418c2ecf20Sopenharmony_ci goto disc1; 29428c2ecf20Sopenharmony_ci } else { 29438c2ecf20Sopenharmony_ci /* Normal selection timeout */ 29448c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "disconnect: (0x%p) " 29458c2ecf20Sopenharmony_ci "<%02i-%i> SelTO\n", srb->cmd, 29468c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 29478c2ecf20Sopenharmony_ci if (srb->retry_count++ > DC395x_MAX_RETRIES 29488c2ecf20Sopenharmony_ci || acb->scan_devices) { 29498c2ecf20Sopenharmony_ci srb->target_status = 29508c2ecf20Sopenharmony_ci SCSI_STAT_SEL_TIMEOUT; 29518c2ecf20Sopenharmony_ci goto disc1; 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci free_tag(dcb, srb); 29548c2ecf20Sopenharmony_ci list_move(&srb->list, &dcb->srb_waiting_list); 29558c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, 29568c2ecf20Sopenharmony_ci "disconnect: (0x%p) Retry\n", 29578c2ecf20Sopenharmony_ci srb->cmd); 29588c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ / 20); 29598c2ecf20Sopenharmony_ci } 29608c2ecf20Sopenharmony_ci } else if (srb->state & SRB_DISCONNECT) { 29618c2ecf20Sopenharmony_ci u8 bval = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); 29628c2ecf20Sopenharmony_ci /* 29638c2ecf20Sopenharmony_ci * SRB_DISCONNECT (This is what we expect!) 29648c2ecf20Sopenharmony_ci */ 29658c2ecf20Sopenharmony_ci if (bval & 0x40) { 29668c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "disconnect: SCSI bus stat " 29678c2ecf20Sopenharmony_ci " 0x%02x: ACK set! Other controllers?\n", 29688c2ecf20Sopenharmony_ci bval); 29698c2ecf20Sopenharmony_ci /* It could come from another initiator, therefore don't do much ! */ 29708c2ecf20Sopenharmony_ci } else 29718c2ecf20Sopenharmony_ci waiting_process_next(acb); 29728c2ecf20Sopenharmony_ci } else if (srb->state & SRB_COMPLETED) { 29738c2ecf20Sopenharmony_ci disc1: 29748c2ecf20Sopenharmony_ci /* 29758c2ecf20Sopenharmony_ci ** SRB_COMPLETED 29768c2ecf20Sopenharmony_ci */ 29778c2ecf20Sopenharmony_ci free_tag(dcb, srb); 29788c2ecf20Sopenharmony_ci dcb->active_srb = NULL; 29798c2ecf20Sopenharmony_ci srb->state = SRB_FREE; 29808c2ecf20Sopenharmony_ci srb_done(acb, dcb, srb); 29818c2ecf20Sopenharmony_ci } 29828c2ecf20Sopenharmony_ci } 29838c2ecf20Sopenharmony_ci} 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_cistatic void reselect(struct AdapterCtlBlk *acb) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = acb->active_dcb; 29898c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb = NULL; 29908c2ecf20Sopenharmony_ci u16 rsel_tar_lun_id; 29918c2ecf20Sopenharmony_ci u8 id, lun; 29928c2ecf20Sopenharmony_ci u8 arblostflag = 0; 29938c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci clear_fifo(acb, "reselect"); 29968c2ecf20Sopenharmony_ci /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ 29978c2ecf20Sopenharmony_ci /* Read Reselected Target ID and LUN */ 29988c2ecf20Sopenharmony_ci rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID); 29998c2ecf20Sopenharmony_ci if (dcb) { /* Arbitration lost but Reselection win */ 30008c2ecf20Sopenharmony_ci srb = dcb->active_srb; 30018c2ecf20Sopenharmony_ci if (!srb) { 30028c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, " 30038c2ecf20Sopenharmony_ci "but active_srb == NULL\n"); 30048c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 30058c2ecf20Sopenharmony_ci return; 30068c2ecf20Sopenharmony_ci } 30078c2ecf20Sopenharmony_ci /* Why the if ? */ 30088c2ecf20Sopenharmony_ci if (!acb->scan_devices) { 30098c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> " 30108c2ecf20Sopenharmony_ci "Arb lost but Resel win rsel=%i stat=0x%04x\n", 30118c2ecf20Sopenharmony_ci srb->cmd, dcb->target_id, 30128c2ecf20Sopenharmony_ci dcb->target_lun, rsel_tar_lun_id, 30138c2ecf20Sopenharmony_ci DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); 30148c2ecf20Sopenharmony_ci arblostflag = 1; 30158c2ecf20Sopenharmony_ci /*srb->state |= SRB_DISCONNECT; */ 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci srb->state = SRB_READY; 30188c2ecf20Sopenharmony_ci free_tag(dcb, srb); 30198c2ecf20Sopenharmony_ci list_move(&srb->list, &dcb->srb_waiting_list); 30208c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ / 20); 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci /* return; */ 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci /* Read Reselected Target Id and LUN */ 30268c2ecf20Sopenharmony_ci if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8))) 30278c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "reselect: Expects identify msg. " 30288c2ecf20Sopenharmony_ci "Got %i!\n", rsel_tar_lun_id); 30298c2ecf20Sopenharmony_ci id = rsel_tar_lun_id & 0xff; 30308c2ecf20Sopenharmony_ci lun = (rsel_tar_lun_id >> 8) & 7; 30318c2ecf20Sopenharmony_ci dcb = find_dcb(acb, id, lun); 30328c2ecf20Sopenharmony_ci if (!dcb) { 30338c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "reselect: From non existent device " 30348c2ecf20Sopenharmony_ci "<%02i-%i>\n", id, lun); 30358c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 30368c2ecf20Sopenharmony_ci return; 30378c2ecf20Sopenharmony_ci } 30388c2ecf20Sopenharmony_ci acb->active_dcb = dcb; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (!(dcb->dev_mode & NTC_DO_DISCONNECT)) 30418c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "reselect: in spite of forbidden " 30428c2ecf20Sopenharmony_ci "disconnection? <%02i-%i>\n", 30438c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) { 30468c2ecf20Sopenharmony_ci srb = acb->tmp_srb; 30478c2ecf20Sopenharmony_ci dcb->active_srb = srb; 30488c2ecf20Sopenharmony_ci } else { 30498c2ecf20Sopenharmony_ci /* There can be only one! */ 30508c2ecf20Sopenharmony_ci srb = dcb->active_srb; 30518c2ecf20Sopenharmony_ci if (!srb || !(srb->state & SRB_DISCONNECT)) { 30528c2ecf20Sopenharmony_ci /* 30538c2ecf20Sopenharmony_ci * abort command 30548c2ecf20Sopenharmony_ci */ 30558c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 30568c2ecf20Sopenharmony_ci "reselect: w/o disconnected cmds <%02i-%i>\n", 30578c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 30588c2ecf20Sopenharmony_ci srb = acb->tmp_srb; 30598c2ecf20Sopenharmony_ci srb->state = SRB_UNEXPECT_RESEL; 30608c2ecf20Sopenharmony_ci dcb->active_srb = srb; 30618c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 30628c2ecf20Sopenharmony_ci } else { 30638c2ecf20Sopenharmony_ci if (dcb->flag & ABORT_DEV_) { 30648c2ecf20Sopenharmony_ci /*srb->state = SRB_ABORT_SENT; */ 30658c2ecf20Sopenharmony_ci enable_msgout_abort(acb, srb); 30668c2ecf20Sopenharmony_ci } else 30678c2ecf20Sopenharmony_ci srb->state = SRB_DATA_XFER; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci } 30708c2ecf20Sopenharmony_ci } 30718c2ecf20Sopenharmony_ci srb->scsi_phase = PH_BUS_FREE; /* initial phase */ 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci /* Program HA ID, target ID, period and offset */ 30748c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id); 30758c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); /* host ID */ 30768c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); /* target ID */ 30778c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); /* offset */ 30788c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); /* sync period, wide */ 30798c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ 30808c2ecf20Sopenharmony_ci /* SCSI command */ 30818c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); 30828c2ecf20Sopenharmony_ci} 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_cistatic inline u8 tagq_blacklist(char *name) 30868c2ecf20Sopenharmony_ci{ 30878c2ecf20Sopenharmony_ci#ifndef DC395x_NO_TAGQ 30888c2ecf20Sopenharmony_ci#if 0 30898c2ecf20Sopenharmony_ci u8 i; 30908c2ecf20Sopenharmony_ci for (i = 0; i < BADDEVCNT; i++) 30918c2ecf20Sopenharmony_ci if (memcmp(name, DC395x_baddevname1[i], 28) == 0) 30928c2ecf20Sopenharmony_ci return 1; 30938c2ecf20Sopenharmony_ci#endif 30948c2ecf20Sopenharmony_ci return 0; 30958c2ecf20Sopenharmony_ci#else 30968c2ecf20Sopenharmony_ci return 1; 30978c2ecf20Sopenharmony_ci#endif 30988c2ecf20Sopenharmony_ci} 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_cistatic void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) 31028c2ecf20Sopenharmony_ci{ 31038c2ecf20Sopenharmony_ci /* Check for SCSI format (ANSI and Response data format) */ 31048c2ecf20Sopenharmony_ci if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { 31058c2ecf20Sopenharmony_ci if ((ptr->Flags & SCSI_INQ_CMDQUEUE) 31068c2ecf20Sopenharmony_ci && (dcb->dev_mode & NTC_DO_TAG_QUEUEING) && 31078c2ecf20Sopenharmony_ci /*(dcb->dev_mode & NTC_DO_DISCONNECT) */ 31088c2ecf20Sopenharmony_ci /* ((dcb->dev_type == TYPE_DISK) 31098c2ecf20Sopenharmony_ci || (dcb->dev_type == TYPE_MOD)) && */ 31108c2ecf20Sopenharmony_ci !tagq_blacklist(((char *)ptr) + 8)) { 31118c2ecf20Sopenharmony_ci if (dcb->max_command == 1) 31128c2ecf20Sopenharmony_ci dcb->max_command = 31138c2ecf20Sopenharmony_ci dcb->acb->tag_max_num; 31148c2ecf20Sopenharmony_ci dcb->sync_mode |= EN_TAG_QUEUEING; 31158c2ecf20Sopenharmony_ci /*dcb->tag_mask = 0; */ 31168c2ecf20Sopenharmony_ci } else 31178c2ecf20Sopenharmony_ci dcb->max_command = 1; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci} 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_cistatic void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 31238c2ecf20Sopenharmony_ci struct ScsiInqData *ptr) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci u8 bval1 = ptr->DevType & SCSI_DEVTYPE; 31268c2ecf20Sopenharmony_ci dcb->dev_type = bval1; 31278c2ecf20Sopenharmony_ci /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ 31288c2ecf20Sopenharmony_ci disc_tagq_set(dcb, ptr); 31298c2ecf20Sopenharmony_ci} 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci/* unmap mapped pci regions from SRB */ 31338c2ecf20Sopenharmony_cistatic void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 31368c2ecf20Sopenharmony_ci enum dma_data_direction dir = cmd->sc_data_direction; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd) && dir != DMA_NONE) { 31398c2ecf20Sopenharmony_ci /* unmap DC395x SG list */ 31408c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", 31418c2ecf20Sopenharmony_ci srb->sg_bus_addr, SEGMENTX_LEN); 31428c2ecf20Sopenharmony_ci dma_unmap_single(&acb->dev->dev, srb->sg_bus_addr, SEGMENTX_LEN, 31438c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 31448c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", 31458c2ecf20Sopenharmony_ci scsi_sg_count(cmd), scsi_bufflen(cmd)); 31468c2ecf20Sopenharmony_ci /* unmap the sg segments */ 31478c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci} 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci/* unmap mapped pci sense buffer from SRB */ 31538c2ecf20Sopenharmony_cistatic void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, 31548c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 31558c2ecf20Sopenharmony_ci{ 31568c2ecf20Sopenharmony_ci if (!(srb->flag & AUTO_REQSENSE)) 31578c2ecf20Sopenharmony_ci return; 31588c2ecf20Sopenharmony_ci /* Unmap sense buffer */ 31598c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", 31608c2ecf20Sopenharmony_ci srb->segment_x[0].address); 31618c2ecf20Sopenharmony_ci dma_unmap_single(&acb->dev->dev, srb->segment_x[0].address, 31628c2ecf20Sopenharmony_ci srb->segment_x[0].length, DMA_FROM_DEVICE); 31638c2ecf20Sopenharmony_ci /* Restore SG stuff */ 31648c2ecf20Sopenharmony_ci srb->total_xfer_length = srb->xferred; 31658c2ecf20Sopenharmony_ci srb->segment_x[0].address = 31668c2ecf20Sopenharmony_ci srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; 31678c2ecf20Sopenharmony_ci srb->segment_x[0].length = 31688c2ecf20Sopenharmony_ci srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length; 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci/* 31738c2ecf20Sopenharmony_ci * Complete execution of a SCSI command 31748c2ecf20Sopenharmony_ci * Signal completion to the generic SCSI driver 31758c2ecf20Sopenharmony_ci */ 31768c2ecf20Sopenharmony_cistatic void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 31778c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 31788c2ecf20Sopenharmony_ci{ 31798c2ecf20Sopenharmony_ci u8 tempcnt, status; 31808c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 31818c2ecf20Sopenharmony_ci enum dma_data_direction dir = cmd->sc_data_direction; 31828c2ecf20Sopenharmony_ci int ckc_only = 1; 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd, 31858c2ecf20Sopenharmony_ci srb->cmd->device->id, (u8)srb->cmd->device->lun); 31868c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", 31878c2ecf20Sopenharmony_ci srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, 31888c2ecf20Sopenharmony_ci scsi_sgtalbe(cmd)); 31898c2ecf20Sopenharmony_ci status = srb->target_status; 31908c2ecf20Sopenharmony_ci if (srb->flag & AUTO_REQSENSE) { 31918c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); 31928c2ecf20Sopenharmony_ci pci_unmap_srb_sense(acb, srb); 31938c2ecf20Sopenharmony_ci /* 31948c2ecf20Sopenharmony_ci ** target status.......................... 31958c2ecf20Sopenharmony_ci */ 31968c2ecf20Sopenharmony_ci srb->flag &= ~AUTO_REQSENSE; 31978c2ecf20Sopenharmony_ci srb->adapter_status = 0; 31988c2ecf20Sopenharmony_ci srb->target_status = CHECK_CONDITION << 1; 31998c2ecf20Sopenharmony_ci if (debug_enabled(DBG_1)) { 32008c2ecf20Sopenharmony_ci switch (cmd->sense_buffer[2] & 0x0f) { 32018c2ecf20Sopenharmony_ci case NOT_READY: 32028c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 32038c2ecf20Sopenharmony_ci "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", 32048c2ecf20Sopenharmony_ci cmd->cmnd[0], dcb->target_id, 32058c2ecf20Sopenharmony_ci dcb->target_lun, status, acb->scan_devices); 32068c2ecf20Sopenharmony_ci break; 32078c2ecf20Sopenharmony_ci case UNIT_ATTENTION: 32088c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 32098c2ecf20Sopenharmony_ci "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", 32108c2ecf20Sopenharmony_ci cmd->cmnd[0], dcb->target_id, 32118c2ecf20Sopenharmony_ci dcb->target_lun, status, acb->scan_devices); 32128c2ecf20Sopenharmony_ci break; 32138c2ecf20Sopenharmony_ci case ILLEGAL_REQUEST: 32148c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 32158c2ecf20Sopenharmony_ci "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", 32168c2ecf20Sopenharmony_ci cmd->cmnd[0], dcb->target_id, 32178c2ecf20Sopenharmony_ci dcb->target_lun, status, acb->scan_devices); 32188c2ecf20Sopenharmony_ci break; 32198c2ecf20Sopenharmony_ci case MEDIUM_ERROR: 32208c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 32218c2ecf20Sopenharmony_ci "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", 32228c2ecf20Sopenharmony_ci cmd->cmnd[0], dcb->target_id, 32238c2ecf20Sopenharmony_ci dcb->target_lun, status, acb->scan_devices); 32248c2ecf20Sopenharmony_ci break; 32258c2ecf20Sopenharmony_ci case HARDWARE_ERROR: 32268c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 32278c2ecf20Sopenharmony_ci "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", 32288c2ecf20Sopenharmony_ci cmd->cmnd[0], dcb->target_id, 32298c2ecf20Sopenharmony_ci dcb->target_lun, status, acb->scan_devices); 32308c2ecf20Sopenharmony_ci break; 32318c2ecf20Sopenharmony_ci } 32328c2ecf20Sopenharmony_ci if (cmd->sense_buffer[7] >= 6) 32338c2ecf20Sopenharmony_ci printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x " 32348c2ecf20Sopenharmony_ci "(0x%08x 0x%08x)\n", 32358c2ecf20Sopenharmony_ci cmd->sense_buffer[2], cmd->sense_buffer[12], 32368c2ecf20Sopenharmony_ci cmd->sense_buffer[13], 32378c2ecf20Sopenharmony_ci *((unsigned int *)(cmd->sense_buffer + 3)), 32388c2ecf20Sopenharmony_ci *((unsigned int *)(cmd->sense_buffer + 8))); 32398c2ecf20Sopenharmony_ci else 32408c2ecf20Sopenharmony_ci printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n", 32418c2ecf20Sopenharmony_ci cmd->sense_buffer[2], 32428c2ecf20Sopenharmony_ci *((unsigned int *)(cmd->sense_buffer + 3))); 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci if (status == (CHECK_CONDITION << 1)) { 32468c2ecf20Sopenharmony_ci cmd->result = DID_BAD_TARGET << 16; 32478c2ecf20Sopenharmony_ci goto ckc_e; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n"); 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci if (srb->total_xfer_length 32528c2ecf20Sopenharmony_ci && srb->total_xfer_length >= cmd->underflow) 32538c2ecf20Sopenharmony_ci cmd->result = 32548c2ecf20Sopenharmony_ci MK_RES_LNX(DRIVER_SENSE, DID_OK, 32558c2ecf20Sopenharmony_ci srb->end_message, CHECK_CONDITION); 32568c2ecf20Sopenharmony_ci /*SET_RES_DID(cmd->result,DID_OK) */ 32578c2ecf20Sopenharmony_ci else 32588c2ecf20Sopenharmony_ci cmd->result = 32598c2ecf20Sopenharmony_ci MK_RES_LNX(DRIVER_SENSE, DID_OK, 32608c2ecf20Sopenharmony_ci srb->end_message, CHECK_CONDITION); 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_ci goto ckc_e; 32638c2ecf20Sopenharmony_ci } 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci/*************************************************************/ 32668c2ecf20Sopenharmony_ci if (status) { 32678c2ecf20Sopenharmony_ci /* 32688c2ecf20Sopenharmony_ci * target status.......................... 32698c2ecf20Sopenharmony_ci */ 32708c2ecf20Sopenharmony_ci if (status_byte(status) == CHECK_CONDITION) { 32718c2ecf20Sopenharmony_ci request_sense(acb, dcb, srb); 32728c2ecf20Sopenharmony_ci return; 32738c2ecf20Sopenharmony_ci } else if (status_byte(status) == QUEUE_FULL) { 32748c2ecf20Sopenharmony_ci tempcnt = (u8)list_size(&dcb->srb_going_list); 32758c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n", 32768c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, tempcnt); 32778c2ecf20Sopenharmony_ci if (tempcnt > 1) 32788c2ecf20Sopenharmony_ci tempcnt--; 32798c2ecf20Sopenharmony_ci dcb->max_command = tempcnt; 32808c2ecf20Sopenharmony_ci free_tag(dcb, srb); 32818c2ecf20Sopenharmony_ci list_move(&srb->list, &dcb->srb_waiting_list); 32828c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ / 20); 32838c2ecf20Sopenharmony_ci srb->adapter_status = 0; 32848c2ecf20Sopenharmony_ci srb->target_status = 0; 32858c2ecf20Sopenharmony_ci return; 32868c2ecf20Sopenharmony_ci } else if (status == SCSI_STAT_SEL_TIMEOUT) { 32878c2ecf20Sopenharmony_ci srb->adapter_status = H_SEL_TIMEOUT; 32888c2ecf20Sopenharmony_ci srb->target_status = 0; 32898c2ecf20Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 32908c2ecf20Sopenharmony_ci } else { 32918c2ecf20Sopenharmony_ci srb->adapter_status = 0; 32928c2ecf20Sopenharmony_ci SET_RES_DID(cmd->result, DID_ERROR); 32938c2ecf20Sopenharmony_ci SET_RES_MSG(cmd->result, srb->end_message); 32948c2ecf20Sopenharmony_ci SET_RES_TARGET(cmd->result, status); 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci } else { 32988c2ecf20Sopenharmony_ci /* 32998c2ecf20Sopenharmony_ci ** process initiator status.......................... 33008c2ecf20Sopenharmony_ci */ 33018c2ecf20Sopenharmony_ci status = srb->adapter_status; 33028c2ecf20Sopenharmony_ci if (status & H_OVER_UNDER_RUN) { 33038c2ecf20Sopenharmony_ci srb->target_status = 0; 33048c2ecf20Sopenharmony_ci SET_RES_DID(cmd->result, DID_OK); 33058c2ecf20Sopenharmony_ci SET_RES_MSG(cmd->result, srb->end_message); 33068c2ecf20Sopenharmony_ci } else if (srb->status & PARITY_ERROR) { 33078c2ecf20Sopenharmony_ci SET_RES_DID(cmd->result, DID_PARITY); 33088c2ecf20Sopenharmony_ci SET_RES_MSG(cmd->result, srb->end_message); 33098c2ecf20Sopenharmony_ci } else { /* No error */ 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci srb->adapter_status = 0; 33128c2ecf20Sopenharmony_ci srb->target_status = 0; 33138c2ecf20Sopenharmony_ci SET_RES_DID(cmd->result, DID_OK); 33148c2ecf20Sopenharmony_ci } 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci ckc_only = 0; 33188c2ecf20Sopenharmony_ci/* Check Error Conditions */ 33198c2ecf20Sopenharmony_ci ckc_e: 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci pci_unmap_srb(acb, srb); 33228c2ecf20Sopenharmony_ci 33238c2ecf20Sopenharmony_ci if (cmd->cmnd[0] == INQUIRY) { 33248c2ecf20Sopenharmony_ci unsigned char *base = NULL; 33258c2ecf20Sopenharmony_ci struct ScsiInqData *ptr; 33268c2ecf20Sopenharmony_ci unsigned long flags = 0; 33278c2ecf20Sopenharmony_ci struct scatterlist* sg = scsi_sglist(cmd); 33288c2ecf20Sopenharmony_ci size_t offset = 0, len = sizeof(struct ScsiInqData); 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci local_irq_save(flags); 33318c2ecf20Sopenharmony_ci base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len); 33328c2ecf20Sopenharmony_ci ptr = (struct ScsiInqData *)(base + offset); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci if (!ckc_only && (cmd->result & RES_DID) == 0 33358c2ecf20Sopenharmony_ci && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8 33368c2ecf20Sopenharmony_ci && dir != DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2) 33378c2ecf20Sopenharmony_ci dcb->inquiry7 = ptr->Flags; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci /*if( srb->cmd->cmnd[0] == INQUIRY && */ 33408c2ecf20Sopenharmony_ci /* (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */ 33418c2ecf20Sopenharmony_ci if ((cmd->result == (DID_OK << 16) || 33428c2ecf20Sopenharmony_ci status_byte(cmd->result) == CHECK_CONDITION)) { 33438c2ecf20Sopenharmony_ci if (!dcb->init_tcq_flag) { 33448c2ecf20Sopenharmony_ci add_dev(acb, dcb, ptr); 33458c2ecf20Sopenharmony_ci dcb->init_tcq_flag = 1; 33468c2ecf20Sopenharmony_ci } 33478c2ecf20Sopenharmony_ci } 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci scsi_kunmap_atomic_sg(base); 33508c2ecf20Sopenharmony_ci local_irq_restore(flags); 33518c2ecf20Sopenharmony_ci } 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci /* Here is the info for Doug Gilbert's sg3 ... */ 33548c2ecf20Sopenharmony_ci scsi_set_resid(cmd, srb->total_xfer_length); 33558c2ecf20Sopenharmony_ci /* This may be interpreted by sb. or not ... */ 33568c2ecf20Sopenharmony_ci cmd->SCp.this_residual = srb->total_xfer_length; 33578c2ecf20Sopenharmony_ci cmd->SCp.buffers_residual = 0; 33588c2ecf20Sopenharmony_ci if (debug_enabled(DBG_KG)) { 33598c2ecf20Sopenharmony_ci if (srb->total_xfer_length) 33608c2ecf20Sopenharmony_ci dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> " 33618c2ecf20Sopenharmony_ci "cmnd=0x%02x Missed %i bytes\n", 33628c2ecf20Sopenharmony_ci cmd, cmd->device->id, (u8)cmd->device->lun, 33638c2ecf20Sopenharmony_ci cmd->cmnd[0], srb->total_xfer_length); 33648c2ecf20Sopenharmony_ci } 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci if (srb != acb->tmp_srb) { 33678c2ecf20Sopenharmony_ci /* Add to free list */ 33688c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", 33698c2ecf20Sopenharmony_ci cmd, cmd->result); 33708c2ecf20Sopenharmony_ci list_move_tail(&srb->list, &acb->srb_free_list); 33718c2ecf20Sopenharmony_ci } else { 33728c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); 33738c2ecf20Sopenharmony_ci } 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 33768c2ecf20Sopenharmony_ci waiting_process_next(acb); 33778c2ecf20Sopenharmony_ci} 33788c2ecf20Sopenharmony_ci 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci/* abort all cmds in our queues */ 33818c2ecf20Sopenharmony_cistatic void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, 33828c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd, u8 force) 33838c2ecf20Sopenharmony_ci{ 33848c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 33858c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "doing_srb_done: pids "); 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci list_for_each_entry(dcb, &acb->dcb_list, list) { 33888c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 33898c2ecf20Sopenharmony_ci struct ScsiReqBlk *tmp; 33908c2ecf20Sopenharmony_ci struct scsi_cmnd *p; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) { 33938c2ecf20Sopenharmony_ci enum dma_data_direction dir; 33948c2ecf20Sopenharmony_ci int result; 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci p = srb->cmd; 33978c2ecf20Sopenharmony_ci dir = p->sc_data_direction; 33988c2ecf20Sopenharmony_ci result = MK_RES(0, did_flag, 0, 0); 33998c2ecf20Sopenharmony_ci printk("G:%p(%02i-%i) ", p, 34008c2ecf20Sopenharmony_ci p->device->id, (u8)p->device->lun); 34018c2ecf20Sopenharmony_ci list_del(&srb->list); 34028c2ecf20Sopenharmony_ci free_tag(dcb, srb); 34038c2ecf20Sopenharmony_ci list_add_tail(&srb->list, &acb->srb_free_list); 34048c2ecf20Sopenharmony_ci p->result = result; 34058c2ecf20Sopenharmony_ci pci_unmap_srb_sense(acb, srb); 34068c2ecf20Sopenharmony_ci pci_unmap_srb(acb, srb); 34078c2ecf20Sopenharmony_ci if (force) { 34088c2ecf20Sopenharmony_ci /* For new EH, we normally don't need to give commands back, 34098c2ecf20Sopenharmony_ci * as they all complete or all time out */ 34108c2ecf20Sopenharmony_ci p->scsi_done(p); 34118c2ecf20Sopenharmony_ci } 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_going_list)) 34148c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 34158c2ecf20Sopenharmony_ci "How could the ML send cmnds to the Going queue? <%02i-%i>\n", 34168c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 34178c2ecf20Sopenharmony_ci if (dcb->tag_mask) 34188c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 34198c2ecf20Sopenharmony_ci "tag_mask for <%02i-%i> should be empty, is %08x!\n", 34208c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, 34218c2ecf20Sopenharmony_ci dcb->tag_mask); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci /* Waiting queue */ 34248c2ecf20Sopenharmony_ci list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) { 34258c2ecf20Sopenharmony_ci int result; 34268c2ecf20Sopenharmony_ci p = srb->cmd; 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci result = MK_RES(0, did_flag, 0, 0); 34298c2ecf20Sopenharmony_ci printk("W:%p<%02i-%i>", p, p->device->id, 34308c2ecf20Sopenharmony_ci (u8)p->device->lun); 34318c2ecf20Sopenharmony_ci list_move_tail(&srb->list, &acb->srb_free_list); 34328c2ecf20Sopenharmony_ci p->result = result; 34338c2ecf20Sopenharmony_ci pci_unmap_srb_sense(acb, srb); 34348c2ecf20Sopenharmony_ci pci_unmap_srb(acb, srb); 34358c2ecf20Sopenharmony_ci if (force) { 34368c2ecf20Sopenharmony_ci /* For new EH, we normally don't need to give commands back, 34378c2ecf20Sopenharmony_ci * as they all complete or all time out */ 34388c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci } 34418c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_waiting_list)) 34428c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n", 34438c2ecf20Sopenharmony_ci list_size(&dcb->srb_waiting_list), dcb->target_id, 34448c2ecf20Sopenharmony_ci dcb->target_lun); 34458c2ecf20Sopenharmony_ci dcb->flag &= ~ABORT_DEV_; 34468c2ecf20Sopenharmony_ci } 34478c2ecf20Sopenharmony_ci printk("\n"); 34488c2ecf20Sopenharmony_ci} 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_cistatic void reset_scsi_bus(struct AdapterCtlBlk *acb) 34528c2ecf20Sopenharmony_ci{ 34538c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb); 34548c2ecf20Sopenharmony_ci acb->acb_flag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ 34558c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)) 34588c2ecf20Sopenharmony_ci /* nothing */; 34598c2ecf20Sopenharmony_ci} 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_cistatic void set_basic_config(struct AdapterCtlBlk *acb) 34638c2ecf20Sopenharmony_ci{ 34648c2ecf20Sopenharmony_ci u8 bval; 34658c2ecf20Sopenharmony_ci u16 wval; 34668c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_TIMEOUT, acb->sel_timeout); 34678c2ecf20Sopenharmony_ci if (acb->config & HCC_PARITY) 34688c2ecf20Sopenharmony_ci bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK; 34698c2ecf20Sopenharmony_ci else 34708c2ecf20Sopenharmony_ci bval = PHASELATCH | INITIATOR | BLOCKRST; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG0, bval); 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci /* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */ 34758c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONFIG1, 0x03); /* was 0x13: default */ 34768c2ecf20Sopenharmony_ci /* program Host ID */ 34778c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); 34788c2ecf20Sopenharmony_ci /* set ansynchronous transfer */ 34798c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, 0x00); 34808c2ecf20Sopenharmony_ci /* Turn LED control off */ 34818c2ecf20Sopenharmony_ci wval = DC395x_read16(acb, TRM_S1040_GEN_CONTROL) & 0x7F; 34828c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_GEN_CONTROL, wval); 34838c2ecf20Sopenharmony_ci /* DMA config */ 34848c2ecf20Sopenharmony_ci wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL; 34858c2ecf20Sopenharmony_ci wval |= 34868c2ecf20Sopenharmony_ci DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ; 34878c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval); 34888c2ecf20Sopenharmony_ci /* Clear pending interrupt status */ 34898c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); 34908c2ecf20Sopenharmony_ci /* Enable SCSI interrupt */ 34918c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x7F); 34928c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR 34938c2ecf20Sopenharmony_ci /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */ 34948c2ecf20Sopenharmony_ci ); 34958c2ecf20Sopenharmony_ci} 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_cistatic void scsi_reset_detect(struct AdapterCtlBlk *acb) 34998c2ecf20Sopenharmony_ci{ 35008c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb); 35018c2ecf20Sopenharmony_ci /* delay half a second */ 35028c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 35038c2ecf20Sopenharmony_ci del_timer(&acb->waiting_timer); 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); 35068c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); 35078c2ecf20Sopenharmony_ci /*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */ 35088c2ecf20Sopenharmony_ci udelay(500); 35098c2ecf20Sopenharmony_ci /* Maybe we locked up the bus? Then lets wait even longer ... */ 35108c2ecf20Sopenharmony_ci acb->last_reset = 35118c2ecf20Sopenharmony_ci jiffies + 5 * HZ / 2 + 35128c2ecf20Sopenharmony_ci HZ * acb->eeprom.delay_time; 35138c2ecf20Sopenharmony_ci 35148c2ecf20Sopenharmony_ci clear_fifo(acb, "scsi_reset_detect"); 35158c2ecf20Sopenharmony_ci set_basic_config(acb); 35168c2ecf20Sopenharmony_ci /*1.25 */ 35178c2ecf20Sopenharmony_ci /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */ 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci if (acb->acb_flag & RESET_DEV) { /* RESET_DETECT, RESET_DONE, RESET_DEV */ 35208c2ecf20Sopenharmony_ci acb->acb_flag |= RESET_DONE; 35218c2ecf20Sopenharmony_ci } else { 35228c2ecf20Sopenharmony_ci acb->acb_flag |= RESET_DETECT; 35238c2ecf20Sopenharmony_ci reset_dev_param(acb); 35248c2ecf20Sopenharmony_ci doing_srb_done(acb, DID_RESET, NULL, 1); 35258c2ecf20Sopenharmony_ci /*DC395x_RecoverSRB( acb ); */ 35268c2ecf20Sopenharmony_ci acb->active_dcb = NULL; 35278c2ecf20Sopenharmony_ci acb->acb_flag = 0; 35288c2ecf20Sopenharmony_ci waiting_process_next(acb); 35298c2ecf20Sopenharmony_ci } 35308c2ecf20Sopenharmony_ci} 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_cistatic void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, 35348c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb) 35358c2ecf20Sopenharmony_ci{ 35368c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 35378c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n", 35388c2ecf20Sopenharmony_ci cmd, cmd->device->id, (u8)cmd->device->lun); 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci srb->flag |= AUTO_REQSENSE; 35418c2ecf20Sopenharmony_ci srb->adapter_status = 0; 35428c2ecf20Sopenharmony_ci srb->target_status = 0; 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci /* KG: Can this prevent crap sense data ? */ 35458c2ecf20Sopenharmony_ci memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci /* Save some data */ 35488c2ecf20Sopenharmony_ci srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address = 35498c2ecf20Sopenharmony_ci srb->segment_x[0].address; 35508c2ecf20Sopenharmony_ci srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length = 35518c2ecf20Sopenharmony_ci srb->segment_x[0].length; 35528c2ecf20Sopenharmony_ci srb->xferred = srb->total_xfer_length; 35538c2ecf20Sopenharmony_ci /* srb->segment_x : a one entry of S/G list table */ 35548c2ecf20Sopenharmony_ci srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE; 35558c2ecf20Sopenharmony_ci srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE; 35568c2ecf20Sopenharmony_ci /* Map sense buffer */ 35578c2ecf20Sopenharmony_ci srb->segment_x[0].address = dma_map_single(&acb->dev->dev, 35588c2ecf20Sopenharmony_ci cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, 35598c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 35608c2ecf20Sopenharmony_ci dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", 35618c2ecf20Sopenharmony_ci cmd->sense_buffer, srb->segment_x[0].address, 35628c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE); 35638c2ecf20Sopenharmony_ci srb->sg_count = 1; 35648c2ecf20Sopenharmony_ci srb->sg_index = 0; 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_ci if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ 35678c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, 35688c2ecf20Sopenharmony_ci "request_sense: (0x%p) failed <%02i-%i>\n", 35698c2ecf20Sopenharmony_ci srb->cmd, dcb->target_id, dcb->target_lun); 35708c2ecf20Sopenharmony_ci list_move(&srb->list, &dcb->srb_waiting_list); 35718c2ecf20Sopenharmony_ci waiting_set_timer(acb, HZ / 100); 35728c2ecf20Sopenharmony_ci } 35738c2ecf20Sopenharmony_ci} 35748c2ecf20Sopenharmony_ci 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci/** 35778c2ecf20Sopenharmony_ci * device_alloc - Allocate a new device instance. This create the 35788c2ecf20Sopenharmony_ci * devices instance and sets up all the data items. The adapter 35798c2ecf20Sopenharmony_ci * instance is required to obtain confiuration information for this 35808c2ecf20Sopenharmony_ci * device. This does *not* add this device to the adapters device 35818c2ecf20Sopenharmony_ci * list. 35828c2ecf20Sopenharmony_ci * 35838c2ecf20Sopenharmony_ci * @acb: The adapter to obtain configuration information from. 35848c2ecf20Sopenharmony_ci * @target: The target for the new device. 35858c2ecf20Sopenharmony_ci * @lun: The lun for the new device. 35868c2ecf20Sopenharmony_ci * 35878c2ecf20Sopenharmony_ci * Return the new device if successful or NULL on failure. 35888c2ecf20Sopenharmony_ci **/ 35898c2ecf20Sopenharmony_cistatic struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, 35908c2ecf20Sopenharmony_ci u8 target, u8 lun) 35918c2ecf20Sopenharmony_ci{ 35928c2ecf20Sopenharmony_ci struct NvRamType *eeprom = &acb->eeprom; 35938c2ecf20Sopenharmony_ci u8 period_index = eeprom->target[target].period & 0x07; 35948c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); 35978c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun); 35988c2ecf20Sopenharmony_ci if (!dcb) 35998c2ecf20Sopenharmony_ci return NULL; 36008c2ecf20Sopenharmony_ci dcb->acb = NULL; 36018c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcb->srb_going_list); 36028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dcb->srb_waiting_list); 36038c2ecf20Sopenharmony_ci dcb->active_srb = NULL; 36048c2ecf20Sopenharmony_ci dcb->tag_mask = 0; 36058c2ecf20Sopenharmony_ci dcb->max_command = 1; 36068c2ecf20Sopenharmony_ci dcb->target_id = target; 36078c2ecf20Sopenharmony_ci dcb->target_lun = lun; 36088c2ecf20Sopenharmony_ci dcb->dev_mode = eeprom->target[target].cfg0; 36098c2ecf20Sopenharmony_ci#ifndef DC395x_NO_DISCONNECT 36108c2ecf20Sopenharmony_ci dcb->identify_msg = 36118c2ecf20Sopenharmony_ci IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun); 36128c2ecf20Sopenharmony_ci#else 36138c2ecf20Sopenharmony_ci dcb->identify_msg = IDENTIFY(0, lun); 36148c2ecf20Sopenharmony_ci#endif 36158c2ecf20Sopenharmony_ci dcb->inquiry7 = 0; 36168c2ecf20Sopenharmony_ci dcb->sync_mode = 0; 36178c2ecf20Sopenharmony_ci dcb->min_nego_period = clock_period[period_index]; 36188c2ecf20Sopenharmony_ci dcb->sync_period = 0; 36198c2ecf20Sopenharmony_ci dcb->sync_offset = 0; 36208c2ecf20Sopenharmony_ci dcb->flag = 0; 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci#ifndef DC395x_NO_WIDE 36238c2ecf20Sopenharmony_ci if ((dcb->dev_mode & NTC_DO_WIDE_NEGO) 36248c2ecf20Sopenharmony_ci && (acb->config & HCC_WIDE_CARD)) 36258c2ecf20Sopenharmony_ci dcb->sync_mode |= WIDE_NEGO_ENABLE; 36268c2ecf20Sopenharmony_ci#endif 36278c2ecf20Sopenharmony_ci#ifndef DC395x_NO_SYNC 36288c2ecf20Sopenharmony_ci if (dcb->dev_mode & NTC_DO_SYNC_NEGO) 36298c2ecf20Sopenharmony_ci if (!(lun) || current_sync_offset) 36308c2ecf20Sopenharmony_ci dcb->sync_mode |= SYNC_NEGO_ENABLE; 36318c2ecf20Sopenharmony_ci#endif 36328c2ecf20Sopenharmony_ci if (dcb->target_lun != 0) { 36338c2ecf20Sopenharmony_ci /* Copy settings */ 36348c2ecf20Sopenharmony_ci struct DeviceCtlBlk *p = NULL, *iter; 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci list_for_each_entry(iter, &acb->dcb_list, list) 36378c2ecf20Sopenharmony_ci if (iter->target_id == dcb->target_id) { 36388c2ecf20Sopenharmony_ci p = iter; 36398c2ecf20Sopenharmony_ci break; 36408c2ecf20Sopenharmony_ci } 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci if (!p) { 36438c2ecf20Sopenharmony_ci kfree(dcb); 36448c2ecf20Sopenharmony_ci return NULL; 36458c2ecf20Sopenharmony_ci } 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, 36488c2ecf20Sopenharmony_ci "device_alloc: <%02i-%i> copy from <%02i-%i>\n", 36498c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, 36508c2ecf20Sopenharmony_ci p->target_id, p->target_lun); 36518c2ecf20Sopenharmony_ci dcb->sync_mode = p->sync_mode; 36528c2ecf20Sopenharmony_ci dcb->sync_period = p->sync_period; 36538c2ecf20Sopenharmony_ci dcb->min_nego_period = p->min_nego_period; 36548c2ecf20Sopenharmony_ci dcb->sync_offset = p->sync_offset; 36558c2ecf20Sopenharmony_ci dcb->inquiry7 = p->inquiry7; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci return dcb; 36588c2ecf20Sopenharmony_ci} 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci/** 36628c2ecf20Sopenharmony_ci * adapter_add_device - Adds the device instance to the adaptor instance. 36638c2ecf20Sopenharmony_ci * 36648c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated 36658c2ecf20Sopenharmony_ci * @dcb: A newly created and initialised device instance to add. 36668c2ecf20Sopenharmony_ci **/ 36678c2ecf20Sopenharmony_cistatic void adapter_add_device(struct AdapterCtlBlk *acb, 36688c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb) 36698c2ecf20Sopenharmony_ci{ 36708c2ecf20Sopenharmony_ci /* backpointer to adapter */ 36718c2ecf20Sopenharmony_ci dcb->acb = acb; 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci /* set run_robin to this device if it is currently empty */ 36748c2ecf20Sopenharmony_ci if (list_empty(&acb->dcb_list)) 36758c2ecf20Sopenharmony_ci acb->dcb_run_robin = dcb; 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci /* add device to list */ 36788c2ecf20Sopenharmony_ci list_add_tail(&dcb->list, &acb->dcb_list); 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci /* update device maps */ 36818c2ecf20Sopenharmony_ci acb->dcb_map[dcb->target_id] |= (1 << dcb->target_lun); 36828c2ecf20Sopenharmony_ci acb->children[dcb->target_id][dcb->target_lun] = dcb; 36838c2ecf20Sopenharmony_ci} 36848c2ecf20Sopenharmony_ci 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci/** 36878c2ecf20Sopenharmony_ci * adapter_remove_device - Removes the device instance from the adaptor 36888c2ecf20Sopenharmony_ci * instance. The device instance is not check in any way or freed by this. 36898c2ecf20Sopenharmony_ci * The caller is expected to take care of that. This will simply remove the 36908c2ecf20Sopenharmony_ci * device from the adapters data strcutures. 36918c2ecf20Sopenharmony_ci * 36928c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated 36938c2ecf20Sopenharmony_ci * @dcb: A device that has previously been added to the adapter. 36948c2ecf20Sopenharmony_ci **/ 36958c2ecf20Sopenharmony_cistatic void adapter_remove_device(struct AdapterCtlBlk *acb, 36968c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb) 36978c2ecf20Sopenharmony_ci{ 36988c2ecf20Sopenharmony_ci struct DeviceCtlBlk *i; 36998c2ecf20Sopenharmony_ci struct DeviceCtlBlk *tmp; 37008c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n", 37018c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun); 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci /* fix up any pointers to this device that we have in the adapter */ 37048c2ecf20Sopenharmony_ci if (acb->active_dcb == dcb) 37058c2ecf20Sopenharmony_ci acb->active_dcb = NULL; 37068c2ecf20Sopenharmony_ci if (acb->dcb_run_robin == dcb) 37078c2ecf20Sopenharmony_ci acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb); 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci /* unlink from list */ 37108c2ecf20Sopenharmony_ci list_for_each_entry_safe(i, tmp, &acb->dcb_list, list) 37118c2ecf20Sopenharmony_ci if (dcb == i) { 37128c2ecf20Sopenharmony_ci list_del(&i->list); 37138c2ecf20Sopenharmony_ci break; 37148c2ecf20Sopenharmony_ci } 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci /* clear map and children */ 37178c2ecf20Sopenharmony_ci acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun); 37188c2ecf20Sopenharmony_ci acb->children[dcb->target_id][dcb->target_lun] = NULL; 37198c2ecf20Sopenharmony_ci dcb->acb = NULL; 37208c2ecf20Sopenharmony_ci} 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci/** 37248c2ecf20Sopenharmony_ci * adapter_remove_and_free_device - Removes a single device from the adapter 37258c2ecf20Sopenharmony_ci * and then frees the device information. 37268c2ecf20Sopenharmony_ci * 37278c2ecf20Sopenharmony_ci * @acb: The adapter device to be updated 37288c2ecf20Sopenharmony_ci * @dcb: A device that has previously been added to the adapter. 37298c2ecf20Sopenharmony_ci */ 37308c2ecf20Sopenharmony_cistatic void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, 37318c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb) 37328c2ecf20Sopenharmony_ci{ 37338c2ecf20Sopenharmony_ci if (list_size(&dcb->srb_going_list) > 1) { 37348c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> " 37358c2ecf20Sopenharmony_ci "Won't remove because of %i active requests.\n", 37368c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, 37378c2ecf20Sopenharmony_ci list_size(&dcb->srb_going_list)); 37388c2ecf20Sopenharmony_ci return; 37398c2ecf20Sopenharmony_ci } 37408c2ecf20Sopenharmony_ci adapter_remove_device(acb, dcb); 37418c2ecf20Sopenharmony_ci kfree(dcb); 37428c2ecf20Sopenharmony_ci} 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci/** 37468c2ecf20Sopenharmony_ci * adapter_remove_and_free_all_devices - Removes and frees all of the 37478c2ecf20Sopenharmony_ci * devices associated with the specified adapter. 37488c2ecf20Sopenharmony_ci * 37498c2ecf20Sopenharmony_ci * @acb: The adapter from which all devices should be removed. 37508c2ecf20Sopenharmony_ci **/ 37518c2ecf20Sopenharmony_cistatic void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) 37528c2ecf20Sopenharmony_ci{ 37538c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 37548c2ecf20Sopenharmony_ci struct DeviceCtlBlk *tmp; 37558c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n", 37568c2ecf20Sopenharmony_ci list_size(&acb->dcb_list)); 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) 37598c2ecf20Sopenharmony_ci adapter_remove_and_free_device(acb, dcb); 37608c2ecf20Sopenharmony_ci} 37618c2ecf20Sopenharmony_ci 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci/** 37648c2ecf20Sopenharmony_ci * dc395x_slave_alloc - Called by the scsi mid layer to tell us about a new 37658c2ecf20Sopenharmony_ci * scsi device that we need to deal with. We allocate a new device and then 37668c2ecf20Sopenharmony_ci * insert that device into the adapters device list. 37678c2ecf20Sopenharmony_ci * 37688c2ecf20Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle. 37698c2ecf20Sopenharmony_ci **/ 37708c2ecf20Sopenharmony_cistatic int dc395x_slave_alloc(struct scsi_device *scsi_device) 37718c2ecf20Sopenharmony_ci{ 37728c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; 37738c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_ci dcb = device_alloc(acb, scsi_device->id, scsi_device->lun); 37768c2ecf20Sopenharmony_ci if (!dcb) 37778c2ecf20Sopenharmony_ci return -ENOMEM; 37788c2ecf20Sopenharmony_ci adapter_add_device(acb, dcb); 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci return 0; 37818c2ecf20Sopenharmony_ci} 37828c2ecf20Sopenharmony_ci 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci/** 37858c2ecf20Sopenharmony_ci * dc395x_slave_destroy - Called by the scsi mid layer to tell us about a 37868c2ecf20Sopenharmony_ci * device that is going away. 37878c2ecf20Sopenharmony_ci * 37888c2ecf20Sopenharmony_ci * @scsi_device: The new scsi device that we need to handle. 37898c2ecf20Sopenharmony_ci **/ 37908c2ecf20Sopenharmony_cistatic void dc395x_slave_destroy(struct scsi_device *scsi_device) 37918c2ecf20Sopenharmony_ci{ 37928c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; 37938c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun); 37948c2ecf20Sopenharmony_ci if (dcb) 37958c2ecf20Sopenharmony_ci adapter_remove_and_free_device(acb, dcb); 37968c2ecf20Sopenharmony_ci} 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci/** 38028c2ecf20Sopenharmony_ci * trms1040_wait_30us: wait for 30 us 38038c2ecf20Sopenharmony_ci * 38048c2ecf20Sopenharmony_ci * Waits for 30us (using the chip by the looks of it..) 38058c2ecf20Sopenharmony_ci * 38068c2ecf20Sopenharmony_ci * @io_port: base I/O address 38078c2ecf20Sopenharmony_ci **/ 38088c2ecf20Sopenharmony_cistatic void trms1040_wait_30us(unsigned long io_port) 38098c2ecf20Sopenharmony_ci{ 38108c2ecf20Sopenharmony_ci /* ScsiPortStallExecution(30); wait 30 us */ 38118c2ecf20Sopenharmony_ci outb(5, io_port + TRM_S1040_GEN_TIMER); 38128c2ecf20Sopenharmony_ci while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT)) 38138c2ecf20Sopenharmony_ci /* nothing */ ; 38148c2ecf20Sopenharmony_ci} 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci/** 38188c2ecf20Sopenharmony_ci * trms1040_write_cmd - write the secified command and address to 38198c2ecf20Sopenharmony_ci * chip 38208c2ecf20Sopenharmony_ci * 38218c2ecf20Sopenharmony_ci * @io_port: base I/O address 38228c2ecf20Sopenharmony_ci * @cmd: SB + op code (command) to send 38238c2ecf20Sopenharmony_ci * @addr: address to send 38248c2ecf20Sopenharmony_ci **/ 38258c2ecf20Sopenharmony_cistatic void trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr) 38268c2ecf20Sopenharmony_ci{ 38278c2ecf20Sopenharmony_ci int i; 38288c2ecf20Sopenharmony_ci u8 send_data; 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci /* program SB + OP code */ 38318c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++, cmd <<= 1) { 38328c2ecf20Sopenharmony_ci send_data = NVR_SELECT; 38338c2ecf20Sopenharmony_ci if (cmd & 0x04) /* Start from bit 2 */ 38348c2ecf20Sopenharmony_ci send_data |= NVR_BITOUT; 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci outb(send_data, io_port + TRM_S1040_GEN_NVRAM); 38378c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38388c2ecf20Sopenharmony_ci outb((send_data | NVR_CLOCK), 38398c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_NVRAM); 38408c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38418c2ecf20Sopenharmony_ci } 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci /* send address */ 38448c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++, addr <<= 1) { 38458c2ecf20Sopenharmony_ci send_data = NVR_SELECT; 38468c2ecf20Sopenharmony_ci if (addr & 0x40) /* Start from bit 6 */ 38478c2ecf20Sopenharmony_ci send_data |= NVR_BITOUT; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci outb(send_data, io_port + TRM_S1040_GEN_NVRAM); 38508c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38518c2ecf20Sopenharmony_ci outb((send_data | NVR_CLOCK), 38528c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_NVRAM); 38538c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38548c2ecf20Sopenharmony_ci } 38558c2ecf20Sopenharmony_ci outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); 38568c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38578c2ecf20Sopenharmony_ci} 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci/** 38618c2ecf20Sopenharmony_ci * trms1040_set_data - store a single byte in the eeprom 38628c2ecf20Sopenharmony_ci * 38638c2ecf20Sopenharmony_ci * Called from write all to write a single byte into the SSEEPROM 38648c2ecf20Sopenharmony_ci * Which is done one bit at a time. 38658c2ecf20Sopenharmony_ci * 38668c2ecf20Sopenharmony_ci * @io_port: base I/O address 38678c2ecf20Sopenharmony_ci * @addr: offset into EEPROM 38688c2ecf20Sopenharmony_ci * @byte: bytes to write 38698c2ecf20Sopenharmony_ci **/ 38708c2ecf20Sopenharmony_cistatic void trms1040_set_data(unsigned long io_port, u8 addr, u8 byte) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci int i; 38738c2ecf20Sopenharmony_ci u8 send_data; 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_ci /* Send write command & address */ 38768c2ecf20Sopenharmony_ci trms1040_write_cmd(io_port, 0x05, addr); 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci /* Write data */ 38798c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++, byte <<= 1) { 38808c2ecf20Sopenharmony_ci send_data = NVR_SELECT; 38818c2ecf20Sopenharmony_ci if (byte & 0x80) /* Start from bit 7 */ 38828c2ecf20Sopenharmony_ci send_data |= NVR_BITOUT; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci outb(send_data, io_port + TRM_S1040_GEN_NVRAM); 38858c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38868c2ecf20Sopenharmony_ci outb((send_data | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); 38878c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38888c2ecf20Sopenharmony_ci } 38898c2ecf20Sopenharmony_ci outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); 38908c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci /* Disable chip select */ 38938c2ecf20Sopenharmony_ci outb(0, io_port + TRM_S1040_GEN_NVRAM); 38948c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); 38978c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci /* Wait for write ready */ 39008c2ecf20Sopenharmony_ci while (1) { 39018c2ecf20Sopenharmony_ci outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); 39028c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); 39058c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci if (inb(io_port + TRM_S1040_GEN_NVRAM) & NVR_BITIN) 39088c2ecf20Sopenharmony_ci break; 39098c2ecf20Sopenharmony_ci } 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci /* Disable chip select */ 39128c2ecf20Sopenharmony_ci outb(0, io_port + TRM_S1040_GEN_NVRAM); 39138c2ecf20Sopenharmony_ci} 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci/** 39178c2ecf20Sopenharmony_ci * trms1040_write_all - write 128 bytes to the eeprom 39188c2ecf20Sopenharmony_ci * 39198c2ecf20Sopenharmony_ci * Write the supplied 128 bytes to the chips SEEPROM 39208c2ecf20Sopenharmony_ci * 39218c2ecf20Sopenharmony_ci * @eeprom: the data to write 39228c2ecf20Sopenharmony_ci * @io_port: the base io port 39238c2ecf20Sopenharmony_ci **/ 39248c2ecf20Sopenharmony_cistatic void trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port) 39258c2ecf20Sopenharmony_ci{ 39268c2ecf20Sopenharmony_ci u8 *b_eeprom = (u8 *)eeprom; 39278c2ecf20Sopenharmony_ci u8 addr; 39288c2ecf20Sopenharmony_ci 39298c2ecf20Sopenharmony_ci /* Enable SEEPROM */ 39308c2ecf20Sopenharmony_ci outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM), 39318c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_CONTROL); 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci /* write enable */ 39348c2ecf20Sopenharmony_ci trms1040_write_cmd(io_port, 0x04, 0xFF); 39358c2ecf20Sopenharmony_ci outb(0, io_port + TRM_S1040_GEN_NVRAM); 39368c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci /* write */ 39398c2ecf20Sopenharmony_ci for (addr = 0; addr < 128; addr++, b_eeprom++) 39408c2ecf20Sopenharmony_ci trms1040_set_data(io_port, addr, *b_eeprom); 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci /* write disable */ 39438c2ecf20Sopenharmony_ci trms1040_write_cmd(io_port, 0x04, 0x00); 39448c2ecf20Sopenharmony_ci outb(0, io_port + TRM_S1040_GEN_NVRAM); 39458c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39468c2ecf20Sopenharmony_ci 39478c2ecf20Sopenharmony_ci /* Disable SEEPROM */ 39488c2ecf20Sopenharmony_ci outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), 39498c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_CONTROL); 39508c2ecf20Sopenharmony_ci} 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci/** 39548c2ecf20Sopenharmony_ci * trms1040_get_data - get a single byte from the eeprom 39558c2ecf20Sopenharmony_ci * 39568c2ecf20Sopenharmony_ci * Called from read all to read a single byte into the SSEEPROM 39578c2ecf20Sopenharmony_ci * Which is done one bit at a time. 39588c2ecf20Sopenharmony_ci * 39598c2ecf20Sopenharmony_ci * @io_port: base I/O address 39608c2ecf20Sopenharmony_ci * @addr: offset into SEEPROM 39618c2ecf20Sopenharmony_ci * 39628c2ecf20Sopenharmony_ci * Returns the byte read. 39638c2ecf20Sopenharmony_ci **/ 39648c2ecf20Sopenharmony_cistatic u8 trms1040_get_data(unsigned long io_port, u8 addr) 39658c2ecf20Sopenharmony_ci{ 39668c2ecf20Sopenharmony_ci int i; 39678c2ecf20Sopenharmony_ci u8 read_byte; 39688c2ecf20Sopenharmony_ci u8 result = 0; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci /* Send read command & address */ 39718c2ecf20Sopenharmony_ci trms1040_write_cmd(io_port, 0x06, addr); 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci /* read data */ 39748c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 39758c2ecf20Sopenharmony_ci outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); 39768c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39778c2ecf20Sopenharmony_ci outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci /* Get data bit while falling edge */ 39808c2ecf20Sopenharmony_ci read_byte = inb(io_port + TRM_S1040_GEN_NVRAM); 39818c2ecf20Sopenharmony_ci result <<= 1; 39828c2ecf20Sopenharmony_ci if (read_byte & NVR_BITIN) 39838c2ecf20Sopenharmony_ci result |= 1; 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci trms1040_wait_30us(io_port); 39868c2ecf20Sopenharmony_ci } 39878c2ecf20Sopenharmony_ci 39888c2ecf20Sopenharmony_ci /* Disable chip select */ 39898c2ecf20Sopenharmony_ci outb(0, io_port + TRM_S1040_GEN_NVRAM); 39908c2ecf20Sopenharmony_ci return result; 39918c2ecf20Sopenharmony_ci} 39928c2ecf20Sopenharmony_ci 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci/** 39958c2ecf20Sopenharmony_ci * trms1040_read_all - read all bytes from the eeprom 39968c2ecf20Sopenharmony_ci * 39978c2ecf20Sopenharmony_ci * Read the 128 bytes from the SEEPROM. 39988c2ecf20Sopenharmony_ci * 39998c2ecf20Sopenharmony_ci * @eeprom: where to store the data 40008c2ecf20Sopenharmony_ci * @io_port: the base io port 40018c2ecf20Sopenharmony_ci **/ 40028c2ecf20Sopenharmony_cistatic void trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port) 40038c2ecf20Sopenharmony_ci{ 40048c2ecf20Sopenharmony_ci u8 *b_eeprom = (u8 *)eeprom; 40058c2ecf20Sopenharmony_ci u8 addr; 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci /* Enable SEEPROM */ 40088c2ecf20Sopenharmony_ci outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM), 40098c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_CONTROL); 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_ci /* read details */ 40128c2ecf20Sopenharmony_ci for (addr = 0; addr < 128; addr++, b_eeprom++) 40138c2ecf20Sopenharmony_ci *b_eeprom = trms1040_get_data(io_port, addr); 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci /* Disable SEEPROM */ 40168c2ecf20Sopenharmony_ci outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), 40178c2ecf20Sopenharmony_ci io_port + TRM_S1040_GEN_CONTROL); 40188c2ecf20Sopenharmony_ci} 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci/** 40238c2ecf20Sopenharmony_ci * check_eeprom - get and check contents of the eeprom 40248c2ecf20Sopenharmony_ci * 40258c2ecf20Sopenharmony_ci * Read seeprom 128 bytes into the memory provider in eeprom. 40268c2ecf20Sopenharmony_ci * Checks the checksum and if it's not correct it uses a set of default 40278c2ecf20Sopenharmony_ci * values. 40288c2ecf20Sopenharmony_ci * 40298c2ecf20Sopenharmony_ci * @eeprom: caller allocated strcuture to read the eeprom data into 40308c2ecf20Sopenharmony_ci * @io_port: io port to read from 40318c2ecf20Sopenharmony_ci **/ 40328c2ecf20Sopenharmony_cistatic void check_eeprom(struct NvRamType *eeprom, unsigned long io_port) 40338c2ecf20Sopenharmony_ci{ 40348c2ecf20Sopenharmony_ci u16 *w_eeprom = (u16 *)eeprom; 40358c2ecf20Sopenharmony_ci u16 w_addr; 40368c2ecf20Sopenharmony_ci u16 cksum; 40378c2ecf20Sopenharmony_ci u32 d_addr; 40388c2ecf20Sopenharmony_ci u32 *d_eeprom; 40398c2ecf20Sopenharmony_ci 40408c2ecf20Sopenharmony_ci trms1040_read_all(eeprom, io_port); /* read eeprom */ 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci cksum = 0; 40438c2ecf20Sopenharmony_ci for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64; 40448c2ecf20Sopenharmony_ci w_addr++, w_eeprom++) 40458c2ecf20Sopenharmony_ci cksum += *w_eeprom; 40468c2ecf20Sopenharmony_ci if (cksum != 0x1234) { 40478c2ecf20Sopenharmony_ci /* 40488c2ecf20Sopenharmony_ci * Checksum is wrong. 40498c2ecf20Sopenharmony_ci * Load a set of defaults into the eeprom buffer 40508c2ecf20Sopenharmony_ci */ 40518c2ecf20Sopenharmony_ci dprintkl(KERN_WARNING, 40528c2ecf20Sopenharmony_ci "EEProm checksum error: using default values and options.\n"); 40538c2ecf20Sopenharmony_ci eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; 40548c2ecf20Sopenharmony_ci eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); 40558c2ecf20Sopenharmony_ci eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; 40568c2ecf20Sopenharmony_ci eeprom->sub_sys_id[1] = 40578c2ecf20Sopenharmony_ci (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); 40588c2ecf20Sopenharmony_ci eeprom->sub_class = 0x00; 40598c2ecf20Sopenharmony_ci eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; 40608c2ecf20Sopenharmony_ci eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); 40618c2ecf20Sopenharmony_ci eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; 40628c2ecf20Sopenharmony_ci eeprom->device_id[1] = 40638c2ecf20Sopenharmony_ci (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); 40648c2ecf20Sopenharmony_ci eeprom->reserved = 0x00; 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci for (d_addr = 0, d_eeprom = (u32 *)eeprom->target; 40678c2ecf20Sopenharmony_ci d_addr < 16; d_addr++, d_eeprom++) 40688c2ecf20Sopenharmony_ci *d_eeprom = 0x00000077; /* cfg3,cfg2,period,cfg0 */ 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci *d_eeprom++ = 0x04000F07; /* max_tag,delay_time,channel_cfg,scsi_id */ 40718c2ecf20Sopenharmony_ci *d_eeprom++ = 0x00000015; /* reserved1,boot_lun,boot_target,reserved0 */ 40728c2ecf20Sopenharmony_ci for (d_addr = 0; d_addr < 12; d_addr++, d_eeprom++) 40738c2ecf20Sopenharmony_ci *d_eeprom = 0x00; 40748c2ecf20Sopenharmony_ci 40758c2ecf20Sopenharmony_ci /* Now load defaults (maybe set by boot/module params) */ 40768c2ecf20Sopenharmony_ci set_safe_settings(); 40778c2ecf20Sopenharmony_ci fix_settings(); 40788c2ecf20Sopenharmony_ci eeprom_override(eeprom); 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci eeprom->cksum = 0x00; 40818c2ecf20Sopenharmony_ci for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom; 40828c2ecf20Sopenharmony_ci w_addr < 63; w_addr++, w_eeprom++) 40838c2ecf20Sopenharmony_ci cksum += *w_eeprom; 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_ci *w_eeprom = 0x1234 - cksum; 40868c2ecf20Sopenharmony_ci trms1040_write_all(eeprom, io_port); 40878c2ecf20Sopenharmony_ci eeprom->delay_time = cfg_data[CFG_RESET_DELAY].value; 40888c2ecf20Sopenharmony_ci } else { 40898c2ecf20Sopenharmony_ci set_safe_settings(); 40908c2ecf20Sopenharmony_ci eeprom_index_to_delay(eeprom); 40918c2ecf20Sopenharmony_ci eeprom_override(eeprom); 40928c2ecf20Sopenharmony_ci } 40938c2ecf20Sopenharmony_ci} 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci/** 40978c2ecf20Sopenharmony_ci * print_eeprom_settings - output the eeprom settings 40988c2ecf20Sopenharmony_ci * to the kernel log so people can see what they were. 40998c2ecf20Sopenharmony_ci * 41008c2ecf20Sopenharmony_ci * @eeprom: The eeprom data strucutre to show details for. 41018c2ecf20Sopenharmony_ci **/ 41028c2ecf20Sopenharmony_cistatic void print_eeprom_settings(struct NvRamType *eeprom) 41038c2ecf20Sopenharmony_ci{ 41048c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n", 41058c2ecf20Sopenharmony_ci eeprom->scsi_id, 41068c2ecf20Sopenharmony_ci eeprom->target[0].period, 41078c2ecf20Sopenharmony_ci clock_speed[eeprom->target[0].period] / 10, 41088c2ecf20Sopenharmony_ci clock_speed[eeprom->target[0].period] % 10, 41098c2ecf20Sopenharmony_ci eeprom->target[0].cfg0); 41108c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", 41118c2ecf20Sopenharmony_ci eeprom->channel_cfg, eeprom->max_tag, 41128c2ecf20Sopenharmony_ci 1 << eeprom->max_tag, eeprom->delay_time); 41138c2ecf20Sopenharmony_ci} 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci 41168c2ecf20Sopenharmony_ci/* Free SG tables */ 41178c2ecf20Sopenharmony_cistatic void adapter_sg_tables_free(struct AdapterCtlBlk *acb) 41188c2ecf20Sopenharmony_ci{ 41198c2ecf20Sopenharmony_ci int i; 41208c2ecf20Sopenharmony_ci const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page) 41238c2ecf20Sopenharmony_ci kfree(acb->srb_array[i].segment_x); 41248c2ecf20Sopenharmony_ci} 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci/* 41288c2ecf20Sopenharmony_ci * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*) 41298c2ecf20Sopenharmony_ci * should never cross a page boundary */ 41308c2ecf20Sopenharmony_cistatic int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) 41318c2ecf20Sopenharmony_ci{ 41328c2ecf20Sopenharmony_ci const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1) 41338c2ecf20Sopenharmony_ci *SEGMENTX_LEN; 41348c2ecf20Sopenharmony_ci int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE; 41358c2ecf20Sopenharmony_ci const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; 41368c2ecf20Sopenharmony_ci int srb_idx = 0; 41378c2ecf20Sopenharmony_ci unsigned i = 0; 41388c2ecf20Sopenharmony_ci struct SGentry *ptr; 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci for (i = 0; i < DC395x_MAX_SRB_CNT; i++) 41418c2ecf20Sopenharmony_ci acb->srb_array[i].segment_x = NULL; 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages); 41448c2ecf20Sopenharmony_ci while (pages--) { 41458c2ecf20Sopenharmony_ci ptr = kmalloc(PAGE_SIZE, GFP_KERNEL); 41468c2ecf20Sopenharmony_ci if (!ptr) { 41478c2ecf20Sopenharmony_ci adapter_sg_tables_free(acb); 41488c2ecf20Sopenharmony_ci return 1; 41498c2ecf20Sopenharmony_ci } 41508c2ecf20Sopenharmony_ci dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n", 41518c2ecf20Sopenharmony_ci PAGE_SIZE, ptr, srb_idx); 41528c2ecf20Sopenharmony_ci i = 0; 41538c2ecf20Sopenharmony_ci while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT) 41548c2ecf20Sopenharmony_ci acb->srb_array[srb_idx++].segment_x = 41558c2ecf20Sopenharmony_ci ptr + (i++ * DC395x_MAX_SG_LISTENTRY); 41568c2ecf20Sopenharmony_ci } 41578c2ecf20Sopenharmony_ci if (i < srbs_per_page) 41588c2ecf20Sopenharmony_ci acb->srb.segment_x = 41598c2ecf20Sopenharmony_ci ptr + (i * DC395x_MAX_SG_LISTENTRY); 41608c2ecf20Sopenharmony_ci else 41618c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n"); 41628c2ecf20Sopenharmony_ci return 0; 41638c2ecf20Sopenharmony_ci} 41648c2ecf20Sopenharmony_ci 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ci/** 41688c2ecf20Sopenharmony_ci * adapter_print_config - print adapter connection and termination 41698c2ecf20Sopenharmony_ci * config 41708c2ecf20Sopenharmony_ci * 41718c2ecf20Sopenharmony_ci * The io port in the adapter needs to have been set before calling 41728c2ecf20Sopenharmony_ci * this function. 41738c2ecf20Sopenharmony_ci * 41748c2ecf20Sopenharmony_ci * @acb: The adapter to print the information for. 41758c2ecf20Sopenharmony_ci **/ 41768c2ecf20Sopenharmony_cistatic void adapter_print_config(struct AdapterCtlBlk *acb) 41778c2ecf20Sopenharmony_ci{ 41788c2ecf20Sopenharmony_ci u8 bval; 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS); 41818c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "%sConnectors: ", 41828c2ecf20Sopenharmony_ci ((bval & WIDESCSI) ? "(Wide) " : "")); 41838c2ecf20Sopenharmony_ci if (!(bval & CON5068)) 41848c2ecf20Sopenharmony_ci printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); 41858c2ecf20Sopenharmony_ci if (!(bval & CON68)) 41868c2ecf20Sopenharmony_ci printk("int68%s ", !(bval & INT68HIGH) ? "" : "(50)"); 41878c2ecf20Sopenharmony_ci if (!(bval & CON50)) 41888c2ecf20Sopenharmony_ci printk("int50 "); 41898c2ecf20Sopenharmony_ci if ((bval & (CON5068 | CON50 | CON68)) == 41908c2ecf20Sopenharmony_ci 0 /*(CON5068 | CON50 | CON68) */ ) 41918c2ecf20Sopenharmony_ci printk(" Oops! (All 3?) "); 41928c2ecf20Sopenharmony_ci bval = DC395x_read8(acb, TRM_S1040_GEN_CONTROL); 41938c2ecf20Sopenharmony_ci printk(" Termination: "); 41948c2ecf20Sopenharmony_ci if (bval & DIS_TERM) 41958c2ecf20Sopenharmony_ci printk("Disabled\n"); 41968c2ecf20Sopenharmony_ci else { 41978c2ecf20Sopenharmony_ci if (bval & AUTOTERM) 41988c2ecf20Sopenharmony_ci printk("Auto "); 41998c2ecf20Sopenharmony_ci if (bval & LOW8TERM) 42008c2ecf20Sopenharmony_ci printk("Low "); 42018c2ecf20Sopenharmony_ci if (bval & UP8TERM) 42028c2ecf20Sopenharmony_ci printk("High "); 42038c2ecf20Sopenharmony_ci printk("\n"); 42048c2ecf20Sopenharmony_ci } 42058c2ecf20Sopenharmony_ci} 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci/** 42098c2ecf20Sopenharmony_ci * adapter_init_params - Initialize the various parameters in the 42108c2ecf20Sopenharmony_ci * adapter structure. Note that the pointer to the scsi_host is set 42118c2ecf20Sopenharmony_ci * early (when this instance is created) and the io_port and irq 42128c2ecf20Sopenharmony_ci * values are set later after they have been reserved. This just gets 42138c2ecf20Sopenharmony_ci * everything set to a good starting position. 42148c2ecf20Sopenharmony_ci * 42158c2ecf20Sopenharmony_ci * The eeprom structure in the adapter needs to have been set before 42168c2ecf20Sopenharmony_ci * calling this function. 42178c2ecf20Sopenharmony_ci * 42188c2ecf20Sopenharmony_ci * @acb: The adapter to initialize. 42198c2ecf20Sopenharmony_ci **/ 42208c2ecf20Sopenharmony_cistatic void adapter_init_params(struct AdapterCtlBlk *acb) 42218c2ecf20Sopenharmony_ci{ 42228c2ecf20Sopenharmony_ci struct NvRamType *eeprom = &acb->eeprom; 42238c2ecf20Sopenharmony_ci int i; 42248c2ecf20Sopenharmony_ci 42258c2ecf20Sopenharmony_ci /* NOTE: acb->scsi_host is set at scsi_host/acb creation time */ 42268c2ecf20Sopenharmony_ci /* NOTE: acb->io_port_base is set at port registration time */ 42278c2ecf20Sopenharmony_ci /* NOTE: acb->io_port_len is set at port registration time */ 42288c2ecf20Sopenharmony_ci 42298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&acb->dcb_list); 42308c2ecf20Sopenharmony_ci acb->dcb_run_robin = NULL; 42318c2ecf20Sopenharmony_ci acb->active_dcb = NULL; 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&acb->srb_free_list); 42348c2ecf20Sopenharmony_ci /* temp SRB for Q tag used or abort command used */ 42358c2ecf20Sopenharmony_ci acb->tmp_srb = &acb->srb; 42368c2ecf20Sopenharmony_ci timer_setup(&acb->waiting_timer, waiting_timeout, 0); 42378c2ecf20Sopenharmony_ci timer_setup(&acb->selto_timer, NULL, 0); 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci acb->srb_count = DC395x_MAX_SRB_CNT; 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci acb->sel_timeout = DC395x_SEL_TIMEOUT; /* timeout=250ms */ 42428c2ecf20Sopenharmony_ci /* NOTE: acb->irq_level is set at IRQ registration time */ 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci acb->tag_max_num = 1 << eeprom->max_tag; 42458c2ecf20Sopenharmony_ci if (acb->tag_max_num > 30) 42468c2ecf20Sopenharmony_ci acb->tag_max_num = 30; 42478c2ecf20Sopenharmony_ci 42488c2ecf20Sopenharmony_ci acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE, RESET_DEV */ 42498c2ecf20Sopenharmony_ci acb->gmode2 = eeprom->channel_cfg; 42508c2ecf20Sopenharmony_ci acb->config = 0; /* NOTE: actually set in adapter_init_chip */ 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci if (eeprom->channel_cfg & NAC_SCANLUN) 42538c2ecf20Sopenharmony_ci acb->lun_chk = 1; 42548c2ecf20Sopenharmony_ci acb->scan_devices = 1; 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci acb->scsi_host->this_id = eeprom->scsi_id; 42578c2ecf20Sopenharmony_ci acb->hostid_bit = (1 << acb->scsi_host->this_id); 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci for (i = 0; i < DC395x_MAX_SCSI_ID; i++) 42608c2ecf20Sopenharmony_ci acb->dcb_map[i] = 0; 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci acb->msg_len = 0; 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci /* link static array of srbs into the srb free list */ 42658c2ecf20Sopenharmony_ci for (i = 0; i < acb->srb_count - 1; i++) 42668c2ecf20Sopenharmony_ci list_add_tail(&acb->srb_array[i].list, &acb->srb_free_list); 42678c2ecf20Sopenharmony_ci} 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci/** 42718c2ecf20Sopenharmony_ci * adapter_init_host - Initialize the scsi host instance based on 42728c2ecf20Sopenharmony_ci * values that we have already stored in the adapter instance. There's 42738c2ecf20Sopenharmony_ci * some mention that a lot of these are deprecated, so we won't use 42748c2ecf20Sopenharmony_ci * them (we'll use the ones in the adapter instance) but we'll fill 42758c2ecf20Sopenharmony_ci * them in in case something else needs them. 42768c2ecf20Sopenharmony_ci * 42778c2ecf20Sopenharmony_ci * The eeprom structure, irq and io ports in the adapter need to have 42788c2ecf20Sopenharmony_ci * been set before calling this function. 42798c2ecf20Sopenharmony_ci * 42808c2ecf20Sopenharmony_ci * @host: The scsi host instance to fill in the values for. 42818c2ecf20Sopenharmony_ci **/ 42828c2ecf20Sopenharmony_cistatic void adapter_init_scsi_host(struct Scsi_Host *host) 42838c2ecf20Sopenharmony_ci{ 42848c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; 42858c2ecf20Sopenharmony_ci struct NvRamType *eeprom = &acb->eeprom; 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci host->max_cmd_len = 24; 42888c2ecf20Sopenharmony_ci host->can_queue = DC395x_MAX_CMD_QUEUE; 42898c2ecf20Sopenharmony_ci host->cmd_per_lun = DC395x_MAX_CMD_PER_LUN; 42908c2ecf20Sopenharmony_ci host->this_id = (int)eeprom->scsi_id; 42918c2ecf20Sopenharmony_ci host->io_port = acb->io_port_base; 42928c2ecf20Sopenharmony_ci host->n_io_port = acb->io_port_len; 42938c2ecf20Sopenharmony_ci host->dma_channel = -1; 42948c2ecf20Sopenharmony_ci host->unique_id = acb->io_port_base; 42958c2ecf20Sopenharmony_ci host->irq = acb->irq_level; 42968c2ecf20Sopenharmony_ci acb->last_reset = jiffies; 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci host->max_id = 16; 42998c2ecf20Sopenharmony_ci if (host->max_id - 1 == eeprom->scsi_id) 43008c2ecf20Sopenharmony_ci host->max_id--; 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci if (eeprom->channel_cfg & NAC_SCANLUN) 43038c2ecf20Sopenharmony_ci host->max_lun = 8; 43048c2ecf20Sopenharmony_ci else 43058c2ecf20Sopenharmony_ci host->max_lun = 1; 43068c2ecf20Sopenharmony_ci} 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_ci/** 43108c2ecf20Sopenharmony_ci * adapter_init_chip - Get the chip into a know state and figure out 43118c2ecf20Sopenharmony_ci * some of the settings that apply to this adapter. 43128c2ecf20Sopenharmony_ci * 43138c2ecf20Sopenharmony_ci * The io port in the adapter needs to have been set before calling 43148c2ecf20Sopenharmony_ci * this function. The config will be configured correctly on return. 43158c2ecf20Sopenharmony_ci * 43168c2ecf20Sopenharmony_ci * @acb: The adapter which we are to init. 43178c2ecf20Sopenharmony_ci **/ 43188c2ecf20Sopenharmony_cistatic void adapter_init_chip(struct AdapterCtlBlk *acb) 43198c2ecf20Sopenharmony_ci{ 43208c2ecf20Sopenharmony_ci struct NvRamType *eeprom = &acb->eeprom; 43218c2ecf20Sopenharmony_ci 43228c2ecf20Sopenharmony_ci /* Mask all the interrupt */ 43238c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00); 43248c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00); 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_ci /* Reset SCSI module */ 43278c2ecf20Sopenharmony_ci DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci /* Reset PCI/DMA module */ 43308c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); 43318c2ecf20Sopenharmony_ci udelay(20); 43328c2ecf20Sopenharmony_ci 43338c2ecf20Sopenharmony_ci /* program configuration 0 */ 43348c2ecf20Sopenharmony_ci acb->config = HCC_AUTOTERM | HCC_PARITY; 43358c2ecf20Sopenharmony_ci if (DC395x_read8(acb, TRM_S1040_GEN_STATUS) & WIDESCSI) 43368c2ecf20Sopenharmony_ci acb->config |= HCC_WIDE_CARD; 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET) 43398c2ecf20Sopenharmony_ci acb->config |= HCC_SCSI_RESET; 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci if (acb->config & HCC_SCSI_RESET) { 43428c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n"); 43438c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci /*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */ 43468c2ecf20Sopenharmony_ci /*spin_unlock_irq (&io_request_lock); */ 43478c2ecf20Sopenharmony_ci udelay(500); 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci acb->last_reset = 43508c2ecf20Sopenharmony_ci jiffies + HZ / 2 + 43518c2ecf20Sopenharmony_ci HZ * acb->eeprom.delay_time; 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci /*spin_lock_irq (&io_request_lock); */ 43548c2ecf20Sopenharmony_ci } 43558c2ecf20Sopenharmony_ci} 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci/** 43598c2ecf20Sopenharmony_ci * init_adapter - Grab the resource for the card, setup the adapter 43608c2ecf20Sopenharmony_ci * information, set the card into a known state, create the various 43618c2ecf20Sopenharmony_ci * tables etc etc. This basically gets all adapter information all up 43628c2ecf20Sopenharmony_ci * to date, initialised and gets the chip in sync with it. 43638c2ecf20Sopenharmony_ci * 43648c2ecf20Sopenharmony_ci * @host: This hosts adapter structure 43658c2ecf20Sopenharmony_ci * @io_port: The base I/O port 43668c2ecf20Sopenharmony_ci * @irq: IRQ 43678c2ecf20Sopenharmony_ci * 43688c2ecf20Sopenharmony_ci * Returns 0 if the initialization succeeds, any other value on 43698c2ecf20Sopenharmony_ci * failure. 43708c2ecf20Sopenharmony_ci **/ 43718c2ecf20Sopenharmony_cistatic int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port, 43728c2ecf20Sopenharmony_ci u32 io_port_len, unsigned int irq) 43738c2ecf20Sopenharmony_ci{ 43748c2ecf20Sopenharmony_ci if (!request_region(io_port, io_port_len, DC395X_NAME)) { 43758c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port); 43768c2ecf20Sopenharmony_ci goto failed; 43778c2ecf20Sopenharmony_ci } 43788c2ecf20Sopenharmony_ci /* store port base to indicate we have registered it */ 43798c2ecf20Sopenharmony_ci acb->io_port_base = io_port; 43808c2ecf20Sopenharmony_ci acb->io_port_len = io_port_len; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) { 43838c2ecf20Sopenharmony_ci /* release the region we just claimed */ 43848c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "Failed to register IRQ\n"); 43858c2ecf20Sopenharmony_ci goto failed; 43868c2ecf20Sopenharmony_ci } 43878c2ecf20Sopenharmony_ci /* store irq to indicate we have registered it */ 43888c2ecf20Sopenharmony_ci acb->irq_level = irq; 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci /* get eeprom configuration information and command line settings etc */ 43918c2ecf20Sopenharmony_ci check_eeprom(&acb->eeprom, io_port); 43928c2ecf20Sopenharmony_ci print_eeprom_settings(&acb->eeprom); 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci /* setup adapter control block */ 43958c2ecf20Sopenharmony_ci adapter_init_params(acb); 43968c2ecf20Sopenharmony_ci 43978c2ecf20Sopenharmony_ci /* display card connectors/termination settings */ 43988c2ecf20Sopenharmony_ci adapter_print_config(acb); 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci if (adapter_sg_tables_alloc(acb)) { 44018c2ecf20Sopenharmony_ci dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n"); 44028c2ecf20Sopenharmony_ci goto failed; 44038c2ecf20Sopenharmony_ci } 44048c2ecf20Sopenharmony_ci adapter_init_scsi_host(acb->scsi_host); 44058c2ecf20Sopenharmony_ci adapter_init_chip(acb); 44068c2ecf20Sopenharmony_ci set_basic_config(acb); 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, 44098c2ecf20Sopenharmony_ci "adapter_init: acb=%p, pdcb_map=%p psrb_array=%p " 44108c2ecf20Sopenharmony_ci "size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n", 44118c2ecf20Sopenharmony_ci acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), 44128c2ecf20Sopenharmony_ci sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); 44138c2ecf20Sopenharmony_ci return 0; 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_cifailed: 44168c2ecf20Sopenharmony_ci if (acb->irq_level) 44178c2ecf20Sopenharmony_ci free_irq(acb->irq_level, acb); 44188c2ecf20Sopenharmony_ci if (acb->io_port_base) 44198c2ecf20Sopenharmony_ci release_region(acb->io_port_base, acb->io_port_len); 44208c2ecf20Sopenharmony_ci adapter_sg_tables_free(acb); 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci return 1; 44238c2ecf20Sopenharmony_ci} 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ci/** 44278c2ecf20Sopenharmony_ci * adapter_uninit_chip - cleanly shut down the scsi controller chip, 44288c2ecf20Sopenharmony_ci * stopping all operations and disabling interrupt generation on the 44298c2ecf20Sopenharmony_ci * card. 44308c2ecf20Sopenharmony_ci * 44318c2ecf20Sopenharmony_ci * @acb: The adapter which we are to shutdown. 44328c2ecf20Sopenharmony_ci **/ 44338c2ecf20Sopenharmony_cistatic void adapter_uninit_chip(struct AdapterCtlBlk *acb) 44348c2ecf20Sopenharmony_ci{ 44358c2ecf20Sopenharmony_ci /* disable interrupts */ 44368c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0); 44378c2ecf20Sopenharmony_ci DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0); 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci /* reset the scsi bus */ 44408c2ecf20Sopenharmony_ci if (acb->config & HCC_SCSI_RESET) 44418c2ecf20Sopenharmony_ci reset_scsi_bus(acb); 44428c2ecf20Sopenharmony_ci 44438c2ecf20Sopenharmony_ci /* clear any pending interrupt state */ 44448c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); 44458c2ecf20Sopenharmony_ci} 44468c2ecf20Sopenharmony_ci 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci/** 44508c2ecf20Sopenharmony_ci * adapter_uninit - Shut down the chip and release any resources that 44518c2ecf20Sopenharmony_ci * we had allocated. Once this returns the adapter should not be used 44528c2ecf20Sopenharmony_ci * anymore. 44538c2ecf20Sopenharmony_ci * 44548c2ecf20Sopenharmony_ci * @acb: The adapter which we are to un-initialize. 44558c2ecf20Sopenharmony_ci **/ 44568c2ecf20Sopenharmony_cistatic void adapter_uninit(struct AdapterCtlBlk *acb) 44578c2ecf20Sopenharmony_ci{ 44588c2ecf20Sopenharmony_ci unsigned long flags; 44598c2ecf20Sopenharmony_ci DC395x_LOCK_IO(acb->scsi_host, flags); 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci /* remove timers */ 44628c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 44638c2ecf20Sopenharmony_ci del_timer(&acb->waiting_timer); 44648c2ecf20Sopenharmony_ci if (timer_pending(&acb->selto_timer)) 44658c2ecf20Sopenharmony_ci del_timer(&acb->selto_timer); 44668c2ecf20Sopenharmony_ci 44678c2ecf20Sopenharmony_ci adapter_uninit_chip(acb); 44688c2ecf20Sopenharmony_ci adapter_remove_and_free_all_devices(acb); 44698c2ecf20Sopenharmony_ci DC395x_UNLOCK_IO(acb->scsi_host, flags); 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci if (acb->irq_level) 44728c2ecf20Sopenharmony_ci free_irq(acb->irq_level, acb); 44738c2ecf20Sopenharmony_ci if (acb->io_port_base) 44748c2ecf20Sopenharmony_ci release_region(acb->io_port_base, acb->io_port_len); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci adapter_sg_tables_free(acb); 44778c2ecf20Sopenharmony_ci} 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci 44808c2ecf20Sopenharmony_ci#undef YESNO 44818c2ecf20Sopenharmony_ci#define YESNO(YN) \ 44828c2ecf20Sopenharmony_ci if (YN) seq_printf(m, " Yes ");\ 44838c2ecf20Sopenharmony_ci else seq_printf(m, " No ") 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_cistatic int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host) 44868c2ecf20Sopenharmony_ci{ 44878c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; 44888c2ecf20Sopenharmony_ci int spd, spd1; 44898c2ecf20Sopenharmony_ci struct DeviceCtlBlk *dcb; 44908c2ecf20Sopenharmony_ci unsigned long flags; 44918c2ecf20Sopenharmony_ci int dev; 44928c2ecf20Sopenharmony_ci 44938c2ecf20Sopenharmony_ci seq_puts(m, DC395X_BANNER " PCI SCSI Host Adapter\n" 44948c2ecf20Sopenharmony_ci " Driver Version " DC395X_VERSION "\n"); 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci DC395x_LOCK_IO(acb->scsi_host, flags); 44978c2ecf20Sopenharmony_ci 44988c2ecf20Sopenharmony_ci seq_printf(m, "SCSI Host Nr %i, ", host->host_no); 44998c2ecf20Sopenharmony_ci seq_printf(m, "DC395U/UW/F DC315/U %s\n", 45008c2ecf20Sopenharmony_ci (acb->config & HCC_WIDE_CARD) ? "Wide" : ""); 45018c2ecf20Sopenharmony_ci seq_printf(m, "io_port_base 0x%04lx, ", acb->io_port_base); 45028c2ecf20Sopenharmony_ci seq_printf(m, "irq_level 0x%04x, ", acb->irq_level); 45038c2ecf20Sopenharmony_ci seq_printf(m, " SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000); 45048c2ecf20Sopenharmony_ci 45058c2ecf20Sopenharmony_ci seq_printf(m, "MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun); 45068c2ecf20Sopenharmony_ci seq_printf(m, "AdapterID %i\n", host->this_id); 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci seq_printf(m, "tag_max_num %i", acb->tag_max_num); 45098c2ecf20Sopenharmony_ci /*seq_printf(m, ", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */ 45108c2ecf20Sopenharmony_ci seq_printf(m, ", FilterCfg 0x%02x", 45118c2ecf20Sopenharmony_ci DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1)); 45128c2ecf20Sopenharmony_ci seq_printf(m, ", DelayReset %is\n", acb->eeprom.delay_time); 45138c2ecf20Sopenharmony_ci /*seq_printf(m, "\n"); */ 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci seq_printf(m, "Nr of DCBs: %i\n", list_size(&acb->dcb_list)); 45168c2ecf20Sopenharmony_ci seq_printf(m, "Map of attached LUNs: %8ph\n", &acb->dcb_map[0]); 45178c2ecf20Sopenharmony_ci seq_printf(m, " %8ph\n", &acb->dcb_map[8]); 45188c2ecf20Sopenharmony_ci 45198c2ecf20Sopenharmony_ci seq_puts(m, 45208c2ecf20Sopenharmony_ci "Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n"); 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci dev = 0; 45238c2ecf20Sopenharmony_ci list_for_each_entry(dcb, &acb->dcb_list, list) { 45248c2ecf20Sopenharmony_ci int nego_period; 45258c2ecf20Sopenharmony_ci seq_printf(m, "%02i %02i %02i ", dev, dcb->target_id, 45268c2ecf20Sopenharmony_ci dcb->target_lun); 45278c2ecf20Sopenharmony_ci YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK); 45288c2ecf20Sopenharmony_ci YESNO(dcb->sync_offset); 45298c2ecf20Sopenharmony_ci YESNO(dcb->sync_period & WIDE_SYNC); 45308c2ecf20Sopenharmony_ci YESNO(dcb->dev_mode & NTC_DO_DISCONNECT); 45318c2ecf20Sopenharmony_ci YESNO(dcb->dev_mode & NTC_DO_SEND_START); 45328c2ecf20Sopenharmony_ci YESNO(dcb->sync_mode & EN_TAG_QUEUEING); 45338c2ecf20Sopenharmony_ci nego_period = clock_period[dcb->sync_period & 0x07] << 2; 45348c2ecf20Sopenharmony_ci if (dcb->sync_offset) 45358c2ecf20Sopenharmony_ci seq_printf(m, " %03i ns ", nego_period); 45368c2ecf20Sopenharmony_ci else 45378c2ecf20Sopenharmony_ci seq_printf(m, " (%03i ns)", (dcb->min_nego_period << 2)); 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci if (dcb->sync_offset & 0x0f) { 45408c2ecf20Sopenharmony_ci spd = 1000 / (nego_period); 45418c2ecf20Sopenharmony_ci spd1 = 1000 % (nego_period); 45428c2ecf20Sopenharmony_ci spd1 = (spd1 * 10 + nego_period / 2) / (nego_period); 45438c2ecf20Sopenharmony_ci seq_printf(m, " %2i.%1i M %02i ", spd, spd1, 45448c2ecf20Sopenharmony_ci (dcb->sync_offset & 0x0f)); 45458c2ecf20Sopenharmony_ci } else 45468c2ecf20Sopenharmony_ci seq_puts(m, " "); 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci /* Add more info ... */ 45498c2ecf20Sopenharmony_ci seq_printf(m, " %02i\n", dcb->max_command); 45508c2ecf20Sopenharmony_ci dev++; 45518c2ecf20Sopenharmony_ci } 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci if (timer_pending(&acb->waiting_timer)) 45548c2ecf20Sopenharmony_ci seq_puts(m, "Waiting queue timer running\n"); 45558c2ecf20Sopenharmony_ci else 45568c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci list_for_each_entry(dcb, &acb->dcb_list, list) { 45598c2ecf20Sopenharmony_ci struct ScsiReqBlk *srb; 45608c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_waiting_list)) 45618c2ecf20Sopenharmony_ci seq_printf(m, "DCB (%02i-%i): Waiting: %i:", 45628c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, 45638c2ecf20Sopenharmony_ci list_size(&dcb->srb_waiting_list)); 45648c2ecf20Sopenharmony_ci list_for_each_entry(srb, &dcb->srb_waiting_list, list) 45658c2ecf20Sopenharmony_ci seq_printf(m, " %p", srb->cmd); 45668c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_going_list)) 45678c2ecf20Sopenharmony_ci seq_printf(m, "\nDCB (%02i-%i): Going : %i:", 45688c2ecf20Sopenharmony_ci dcb->target_id, dcb->target_lun, 45698c2ecf20Sopenharmony_ci list_size(&dcb->srb_going_list)); 45708c2ecf20Sopenharmony_ci list_for_each_entry(srb, &dcb->srb_going_list, list) 45718c2ecf20Sopenharmony_ci seq_printf(m, " %p", srb->cmd); 45728c2ecf20Sopenharmony_ci if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) 45738c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 45748c2ecf20Sopenharmony_ci } 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci if (debug_enabled(DBG_1)) { 45778c2ecf20Sopenharmony_ci seq_printf(m, "DCB list for ACB %p:\n", acb); 45788c2ecf20Sopenharmony_ci list_for_each_entry(dcb, &acb->dcb_list, list) { 45798c2ecf20Sopenharmony_ci seq_printf(m, "%p -> ", dcb); 45808c2ecf20Sopenharmony_ci } 45818c2ecf20Sopenharmony_ci seq_puts(m, "END\n"); 45828c2ecf20Sopenharmony_ci } 45838c2ecf20Sopenharmony_ci 45848c2ecf20Sopenharmony_ci DC395x_UNLOCK_IO(acb->scsi_host, flags); 45858c2ecf20Sopenharmony_ci return 0; 45868c2ecf20Sopenharmony_ci} 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_cistatic struct scsi_host_template dc395x_driver_template = { 45908c2ecf20Sopenharmony_ci .module = THIS_MODULE, 45918c2ecf20Sopenharmony_ci .proc_name = DC395X_NAME, 45928c2ecf20Sopenharmony_ci .show_info = dc395x_show_info, 45938c2ecf20Sopenharmony_ci .name = DC395X_BANNER " " DC395X_VERSION, 45948c2ecf20Sopenharmony_ci .queuecommand = dc395x_queue_command, 45958c2ecf20Sopenharmony_ci .slave_alloc = dc395x_slave_alloc, 45968c2ecf20Sopenharmony_ci .slave_destroy = dc395x_slave_destroy, 45978c2ecf20Sopenharmony_ci .can_queue = DC395x_MAX_CAN_QUEUE, 45988c2ecf20Sopenharmony_ci .this_id = 7, 45998c2ecf20Sopenharmony_ci .sg_tablesize = DC395x_MAX_SG_TABLESIZE, 46008c2ecf20Sopenharmony_ci .cmd_per_lun = DC395x_MAX_CMD_PER_LUN, 46018c2ecf20Sopenharmony_ci .eh_abort_handler = dc395x_eh_abort, 46028c2ecf20Sopenharmony_ci .eh_bus_reset_handler = dc395x_eh_bus_reset, 46038c2ecf20Sopenharmony_ci .dma_boundary = PAGE_SIZE - 1, 46048c2ecf20Sopenharmony_ci}; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci 46078c2ecf20Sopenharmony_ci/** 46088c2ecf20Sopenharmony_ci * banner_display - Display banner on first instance of driver 46098c2ecf20Sopenharmony_ci * initialized. 46108c2ecf20Sopenharmony_ci **/ 46118c2ecf20Sopenharmony_cistatic void banner_display(void) 46128c2ecf20Sopenharmony_ci{ 46138c2ecf20Sopenharmony_ci static int banner_done = 0; 46148c2ecf20Sopenharmony_ci if (!banner_done) 46158c2ecf20Sopenharmony_ci { 46168c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION); 46178c2ecf20Sopenharmony_ci banner_done = 1; 46188c2ecf20Sopenharmony_ci } 46198c2ecf20Sopenharmony_ci} 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci/** 46238c2ecf20Sopenharmony_ci * dc395x_init_one - Initialise a single instance of the adapter. 46248c2ecf20Sopenharmony_ci * 46258c2ecf20Sopenharmony_ci * The PCI layer will call this once for each instance of the adapter 46268c2ecf20Sopenharmony_ci * that it finds in the system. The pci_dev strcuture indicates which 46278c2ecf20Sopenharmony_ci * instance we are being called from. 46288c2ecf20Sopenharmony_ci * 46298c2ecf20Sopenharmony_ci * @dev: The PCI device to initialize. 46308c2ecf20Sopenharmony_ci * @id: Looks like a pointer to the entry in our pci device table 46318c2ecf20Sopenharmony_ci * that was actually matched by the PCI subsystem. 46328c2ecf20Sopenharmony_ci * 46338c2ecf20Sopenharmony_ci * Returns 0 on success, or an error code (-ve) on failure. 46348c2ecf20Sopenharmony_ci **/ 46358c2ecf20Sopenharmony_cistatic int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id) 46368c2ecf20Sopenharmony_ci{ 46378c2ecf20Sopenharmony_ci struct Scsi_Host *scsi_host = NULL; 46388c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = NULL; 46398c2ecf20Sopenharmony_ci unsigned long io_port_base; 46408c2ecf20Sopenharmony_ci unsigned int io_port_len; 46418c2ecf20Sopenharmony_ci unsigned int irq; 46428c2ecf20Sopenharmony_ci 46438c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev)); 46448c2ecf20Sopenharmony_ci banner_display(); 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci if (pci_enable_device(dev)) 46478c2ecf20Sopenharmony_ci { 46488c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "PCI Enable device failed.\n"); 46498c2ecf20Sopenharmony_ci return -ENODEV; 46508c2ecf20Sopenharmony_ci } 46518c2ecf20Sopenharmony_ci io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK; 46528c2ecf20Sopenharmony_ci io_port_len = pci_resource_len(dev, 0); 46538c2ecf20Sopenharmony_ci irq = dev->irq; 46548c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq); 46558c2ecf20Sopenharmony_ci 46568c2ecf20Sopenharmony_ci /* allocate scsi host information (includes out adapter) */ 46578c2ecf20Sopenharmony_ci scsi_host = scsi_host_alloc(&dc395x_driver_template, 46588c2ecf20Sopenharmony_ci sizeof(struct AdapterCtlBlk)); 46598c2ecf20Sopenharmony_ci if (!scsi_host) { 46608c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "scsi_host_alloc failed\n"); 46618c2ecf20Sopenharmony_ci goto fail; 46628c2ecf20Sopenharmony_ci } 46638c2ecf20Sopenharmony_ci acb = (struct AdapterCtlBlk*)scsi_host->hostdata; 46648c2ecf20Sopenharmony_ci acb->scsi_host = scsi_host; 46658c2ecf20Sopenharmony_ci acb->dev = dev; 46668c2ecf20Sopenharmony_ci 46678c2ecf20Sopenharmony_ci /* initialise the adapter and everything we need */ 46688c2ecf20Sopenharmony_ci if (adapter_init(acb, io_port_base, io_port_len, irq)) { 46698c2ecf20Sopenharmony_ci dprintkl(KERN_INFO, "adapter init failed\n"); 46708c2ecf20Sopenharmony_ci acb = NULL; 46718c2ecf20Sopenharmony_ci goto fail; 46728c2ecf20Sopenharmony_ci } 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_ci pci_set_master(dev); 46758c2ecf20Sopenharmony_ci 46768c2ecf20Sopenharmony_ci /* get the scsi mid level to scan for new devices on the bus */ 46778c2ecf20Sopenharmony_ci if (scsi_add_host(scsi_host, &dev->dev)) { 46788c2ecf20Sopenharmony_ci dprintkl(KERN_ERR, "scsi_add_host failed\n"); 46798c2ecf20Sopenharmony_ci goto fail; 46808c2ecf20Sopenharmony_ci } 46818c2ecf20Sopenharmony_ci pci_set_drvdata(dev, scsi_host); 46828c2ecf20Sopenharmony_ci scsi_scan_host(scsi_host); 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_ci return 0; 46858c2ecf20Sopenharmony_ci 46868c2ecf20Sopenharmony_cifail: 46878c2ecf20Sopenharmony_ci if (acb != NULL) 46888c2ecf20Sopenharmony_ci adapter_uninit(acb); 46898c2ecf20Sopenharmony_ci if (scsi_host != NULL) 46908c2ecf20Sopenharmony_ci scsi_host_put(scsi_host); 46918c2ecf20Sopenharmony_ci pci_disable_device(dev); 46928c2ecf20Sopenharmony_ci return -ENODEV; 46938c2ecf20Sopenharmony_ci} 46948c2ecf20Sopenharmony_ci 46958c2ecf20Sopenharmony_ci 46968c2ecf20Sopenharmony_ci/** 46978c2ecf20Sopenharmony_ci * dc395x_remove_one - Called to remove a single instance of the 46988c2ecf20Sopenharmony_ci * adapter. 46998c2ecf20Sopenharmony_ci * 47008c2ecf20Sopenharmony_ci * @dev: The PCI device to initialize. 47018c2ecf20Sopenharmony_ci **/ 47028c2ecf20Sopenharmony_cistatic void dc395x_remove_one(struct pci_dev *dev) 47038c2ecf20Sopenharmony_ci{ 47048c2ecf20Sopenharmony_ci struct Scsi_Host *scsi_host = pci_get_drvdata(dev); 47058c2ecf20Sopenharmony_ci struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata); 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ci dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb); 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ci scsi_remove_host(scsi_host); 47108c2ecf20Sopenharmony_ci adapter_uninit(acb); 47118c2ecf20Sopenharmony_ci pci_disable_device(dev); 47128c2ecf20Sopenharmony_ci scsi_host_put(scsi_host); 47138c2ecf20Sopenharmony_ci} 47148c2ecf20Sopenharmony_ci 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_cistatic struct pci_device_id dc395x_pci_table[] = { 47178c2ecf20Sopenharmony_ci { 47188c2ecf20Sopenharmony_ci .vendor = PCI_VENDOR_ID_TEKRAM, 47198c2ecf20Sopenharmony_ci .device = PCI_DEVICE_ID_TEKRAM_TRMS1040, 47208c2ecf20Sopenharmony_ci .subvendor = PCI_ANY_ID, 47218c2ecf20Sopenharmony_ci .subdevice = PCI_ANY_ID, 47228c2ecf20Sopenharmony_ci }, 47238c2ecf20Sopenharmony_ci {} /* Terminating entry */ 47248c2ecf20Sopenharmony_ci}; 47258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dc395x_pci_table); 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_cistatic struct pci_driver dc395x_driver = { 47298c2ecf20Sopenharmony_ci .name = DC395X_NAME, 47308c2ecf20Sopenharmony_ci .id_table = dc395x_pci_table, 47318c2ecf20Sopenharmony_ci .probe = dc395x_init_one, 47328c2ecf20Sopenharmony_ci .remove = dc395x_remove_one, 47338c2ecf20Sopenharmony_ci}; 47348c2ecf20Sopenharmony_cimodule_pci_driver(dc395x_driver); 47358c2ecf20Sopenharmony_ci 47368c2ecf20Sopenharmony_ciMODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff"); 47378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series"); 47388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4739