18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci The author respectfully requests that any modifications to this software be 118c2ecf20Sopenharmony_ci sent directly to him for evaluation and testing. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose 148c2ecf20Sopenharmony_ci advice has been invaluable, to David Gentzel, for writing the original Linux 158c2ecf20Sopenharmony_ci BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site. 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB 188c2ecf20Sopenharmony_ci Manager available as freely redistributable source code. 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci*/ 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define blogic_drvr_version "2.1.17" 238c2ecf20Sopenharmony_ci#define blogic_drvr_date "12 September 2013" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/types.h> 298c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 308c2ecf20Sopenharmony_ci#include <linux/delay.h> 318c2ecf20Sopenharmony_ci#include <linux/ioport.h> 328c2ecf20Sopenharmony_ci#include <linux/mm.h> 338c2ecf20Sopenharmony_ci#include <linux/stat.h> 348c2ecf20Sopenharmony_ci#include <linux/pci.h> 358c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 368c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 378c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/msdos_partition.h> 408c2ecf20Sopenharmony_ci#include <scsi/scsicam.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <asm/dma.h> 438c2ecf20Sopenharmony_ci#include <asm/io.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 468c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 478c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 488c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 498c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 508c2ecf20Sopenharmony_ci#include "BusLogic.h" 518c2ecf20Sopenharmony_ci#include "FlashPoint.c" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#ifndef FAILURE 548c2ecf20Sopenharmony_ci#define FAILURE (-1) 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct scsi_host_template blogic_template; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci blogic_drvr_options_count is a count of the number of BusLogic Driver 618c2ecf20Sopenharmony_ci Options specifications provided via the Linux Kernel Command Line or via 628c2ecf20Sopenharmony_ci the Loadable Kernel Module Installation Facility. 638c2ecf20Sopenharmony_ci*/ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int blogic_drvr_options_count; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci blogic_drvr_options is an array of Driver Options structures representing 708c2ecf20Sopenharmony_ci BusLogic Driver Options specifications provided via the Linux Kernel Command 718c2ecf20Sopenharmony_ci Line or via the Loadable Kernel Module Installation Facility. 728c2ecf20Sopenharmony_ci*/ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct blogic_drvr_options blogic_drvr_options[BLOGIC_MAX_ADAPTERS]; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci BusLogic can be assigned a string by insmod. 798c2ecf20Sopenharmony_ci*/ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 828c2ecf20Sopenharmony_ci#ifdef MODULE 838c2ecf20Sopenharmony_cistatic char *BusLogic; 848c2ecf20Sopenharmony_cimodule_param(BusLogic, charp, 0); 858c2ecf20Sopenharmony_ci#endif 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci blogic_probe_options is a set of Probe Options to be applied across 908c2ecf20Sopenharmony_ci all BusLogic Host Adapters. 918c2ecf20Sopenharmony_ci*/ 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic struct blogic_probe_options blogic_probe_options; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci blogic_global_options is a set of Global Options to be applied across 988c2ecf20Sopenharmony_ci all BusLogic Host Adapters. 998c2ecf20Sopenharmony_ci*/ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct blogic_global_options blogic_global_options; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic LIST_HEAD(blogic_host_list); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci blogic_probeinfo_count is the number of entries in blogic_probeinfo_list. 1078c2ecf20Sopenharmony_ci*/ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int blogic_probeinfo_count; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* 1138c2ecf20Sopenharmony_ci blogic_probeinfo_list is the list of I/O Addresses and Bus Probe Information 1148c2ecf20Sopenharmony_ci to be checked for potential BusLogic Host Adapters. It is initialized by 1158c2ecf20Sopenharmony_ci interrogating the PCI Configuration Space on PCI machines as well as from the 1168c2ecf20Sopenharmony_ci list of standard BusLogic I/O Addresses. 1178c2ecf20Sopenharmony_ci*/ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct blogic_probeinfo *blogic_probeinfo_list; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 1238c2ecf20Sopenharmony_ci blogic_cmd_failure_reason holds a string identifying the reason why a 1248c2ecf20Sopenharmony_ci call to blogic_cmd failed. It is only non-NULL when blogic_cmd 1258c2ecf20Sopenharmony_ci returns a failure code. 1268c2ecf20Sopenharmony_ci*/ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic char *blogic_cmd_failure_reason; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci blogic_announce_drvr announces the Driver Version and Date, Author's 1328c2ecf20Sopenharmony_ci Name, Copyright Notice, and Electronic Mail Address. 1338c2ecf20Sopenharmony_ci*/ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void blogic_announce_drvr(struct blogic_adapter *adapter) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci blogic_announce("***** BusLogic SCSI Driver Version " blogic_drvr_version " of " blogic_drvr_date " *****\n", adapter); 1388c2ecf20Sopenharmony_ci blogic_announce("Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>\n", adapter); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci blogic_drvr_info returns the Host Adapter Name to identify this SCSI 1448c2ecf20Sopenharmony_ci Driver and Host Adapter. 1458c2ecf20Sopenharmony_ci*/ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic const char *blogic_drvr_info(struct Scsi_Host *host) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 1508c2ecf20Sopenharmony_ci (struct blogic_adapter *) host->hostdata; 1518c2ecf20Sopenharmony_ci return adapter->full_model; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci blogic_init_ccbs initializes a group of Command Control Blocks (CCBs) 1568c2ecf20Sopenharmony_ci for Host Adapter from the blk_size bytes located at blk_pointer. The newly 1578c2ecf20Sopenharmony_ci created CCBs are added to Host Adapter's free list. 1588c2ecf20Sopenharmony_ci*/ 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic void blogic_init_ccbs(struct blogic_adapter *adapter, void *blk_pointer, 1618c2ecf20Sopenharmony_ci int blk_size, dma_addr_t blkp) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct blogic_ccb *ccb = (struct blogic_ccb *) blk_pointer; 1648c2ecf20Sopenharmony_ci unsigned int offset = 0; 1658c2ecf20Sopenharmony_ci memset(blk_pointer, 0, blk_size); 1668c2ecf20Sopenharmony_ci ccb->allocgrp_head = blkp; 1678c2ecf20Sopenharmony_ci ccb->allocgrp_size = blk_size; 1688c2ecf20Sopenharmony_ci while ((blk_size -= sizeof(struct blogic_ccb)) >= 0) { 1698c2ecf20Sopenharmony_ci ccb->status = BLOGIC_CCB_FREE; 1708c2ecf20Sopenharmony_ci ccb->adapter = adapter; 1718c2ecf20Sopenharmony_ci ccb->dma_handle = (u32) blkp + offset; 1728c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) { 1738c2ecf20Sopenharmony_ci ccb->callback = blogic_qcompleted_ccb; 1748c2ecf20Sopenharmony_ci ccb->base_addr = adapter->fpinfo.base_addr; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci ccb->next = adapter->free_ccbs; 1778c2ecf20Sopenharmony_ci ccb->next_all = adapter->all_ccbs; 1788c2ecf20Sopenharmony_ci adapter->free_ccbs = ccb; 1798c2ecf20Sopenharmony_ci adapter->all_ccbs = ccb; 1808c2ecf20Sopenharmony_ci adapter->alloc_ccbs++; 1818c2ecf20Sopenharmony_ci ccb++; 1828c2ecf20Sopenharmony_ci offset += sizeof(struct blogic_ccb); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci blogic_create_initccbs allocates the initial CCBs for Host Adapter. 1898c2ecf20Sopenharmony_ci*/ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic bool __init blogic_create_initccbs(struct blogic_adapter *adapter) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci int blk_size = BLOGIC_CCB_GRP_ALLOCSIZE * sizeof(struct blogic_ccb); 1948c2ecf20Sopenharmony_ci void *blk_pointer; 1958c2ecf20Sopenharmony_ci dma_addr_t blkp; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci while (adapter->alloc_ccbs < adapter->initccbs) { 1988c2ecf20Sopenharmony_ci blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev, 1998c2ecf20Sopenharmony_ci blk_size, &blkp, GFP_KERNEL); 2008c2ecf20Sopenharmony_ci if (blk_pointer == NULL) { 2018c2ecf20Sopenharmony_ci blogic_err("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", 2028c2ecf20Sopenharmony_ci adapter); 2038c2ecf20Sopenharmony_ci return false; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci return true; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* 2128c2ecf20Sopenharmony_ci blogic_destroy_ccbs deallocates the CCBs for Host Adapter. 2138c2ecf20Sopenharmony_ci*/ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void blogic_destroy_ccbs(struct blogic_adapter *adapter) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct blogic_ccb *next_ccb = adapter->all_ccbs, *ccb, *lastccb = NULL; 2188c2ecf20Sopenharmony_ci adapter->all_ccbs = NULL; 2198c2ecf20Sopenharmony_ci adapter->free_ccbs = NULL; 2208c2ecf20Sopenharmony_ci while ((ccb = next_ccb) != NULL) { 2218c2ecf20Sopenharmony_ci next_ccb = ccb->next_all; 2228c2ecf20Sopenharmony_ci if (ccb->allocgrp_head) { 2238c2ecf20Sopenharmony_ci if (lastccb) 2248c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pci_device->dev, 2258c2ecf20Sopenharmony_ci lastccb->allocgrp_size, lastccb, 2268c2ecf20Sopenharmony_ci lastccb->allocgrp_head); 2278c2ecf20Sopenharmony_ci lastccb = ccb; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci if (lastccb) 2318c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pci_device->dev, 2328c2ecf20Sopenharmony_ci lastccb->allocgrp_size, lastccb, 2338c2ecf20Sopenharmony_ci lastccb->allocgrp_head); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci blogic_create_addlccbs allocates Additional CCBs for Host Adapter. If 2398c2ecf20Sopenharmony_ci allocation fails and there are no remaining CCBs available, the Driver Queue 2408c2ecf20Sopenharmony_ci Depth is decreased to a known safe value to avoid potential deadlocks when 2418c2ecf20Sopenharmony_ci multiple host adapters share the same IRQ Channel. 2428c2ecf20Sopenharmony_ci*/ 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void blogic_create_addlccbs(struct blogic_adapter *adapter, 2458c2ecf20Sopenharmony_ci int addl_ccbs, bool print_success) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int blk_size = BLOGIC_CCB_GRP_ALLOCSIZE * sizeof(struct blogic_ccb); 2488c2ecf20Sopenharmony_ci int prev_alloc = adapter->alloc_ccbs; 2498c2ecf20Sopenharmony_ci void *blk_pointer; 2508c2ecf20Sopenharmony_ci dma_addr_t blkp; 2518c2ecf20Sopenharmony_ci if (addl_ccbs <= 0) 2528c2ecf20Sopenharmony_ci return; 2538c2ecf20Sopenharmony_ci while (adapter->alloc_ccbs - prev_alloc < addl_ccbs) { 2548c2ecf20Sopenharmony_ci blk_pointer = dma_alloc_coherent(&adapter->pci_device->dev, 2558c2ecf20Sopenharmony_ci blk_size, &blkp, GFP_KERNEL); 2568c2ecf20Sopenharmony_ci if (blk_pointer == NULL) 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci blogic_init_ccbs(adapter, blk_pointer, blk_size, blkp); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci if (adapter->alloc_ccbs > prev_alloc) { 2618c2ecf20Sopenharmony_ci if (print_success) 2628c2ecf20Sopenharmony_ci blogic_notice("Allocated %d additional CCBs (total now %d)\n", adapter, adapter->alloc_ccbs - prev_alloc, adapter->alloc_ccbs); 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci blogic_notice("Failed to allocate additional CCBs\n", adapter); 2668c2ecf20Sopenharmony_ci if (adapter->drvr_qdepth > adapter->alloc_ccbs - adapter->tgt_count) { 2678c2ecf20Sopenharmony_ci adapter->drvr_qdepth = adapter->alloc_ccbs - adapter->tgt_count; 2688c2ecf20Sopenharmony_ci adapter->scsi_host->can_queue = adapter->drvr_qdepth; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* 2738c2ecf20Sopenharmony_ci blogic_alloc_ccb allocates a CCB from Host Adapter's free list, 2748c2ecf20Sopenharmony_ci allocating more memory from the Kernel if necessary. The Host Adapter's 2758c2ecf20Sopenharmony_ci Lock should already have been acquired by the caller. 2768c2ecf20Sopenharmony_ci*/ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic struct blogic_ccb *blogic_alloc_ccb(struct blogic_adapter *adapter) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci static unsigned long serial; 2818c2ecf20Sopenharmony_ci struct blogic_ccb *ccb; 2828c2ecf20Sopenharmony_ci ccb = adapter->free_ccbs; 2838c2ecf20Sopenharmony_ci if (ccb != NULL) { 2848c2ecf20Sopenharmony_ci ccb->serial = ++serial; 2858c2ecf20Sopenharmony_ci adapter->free_ccbs = ccb->next; 2868c2ecf20Sopenharmony_ci ccb->next = NULL; 2878c2ecf20Sopenharmony_ci if (adapter->free_ccbs == NULL) 2888c2ecf20Sopenharmony_ci blogic_create_addlccbs(adapter, adapter->inc_ccbs, 2898c2ecf20Sopenharmony_ci true); 2908c2ecf20Sopenharmony_ci return ccb; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci blogic_create_addlccbs(adapter, adapter->inc_ccbs, true); 2938c2ecf20Sopenharmony_ci ccb = adapter->free_ccbs; 2948c2ecf20Sopenharmony_ci if (ccb == NULL) 2958c2ecf20Sopenharmony_ci return NULL; 2968c2ecf20Sopenharmony_ci ccb->serial = ++serial; 2978c2ecf20Sopenharmony_ci adapter->free_ccbs = ccb->next; 2988c2ecf20Sopenharmony_ci ccb->next = NULL; 2998c2ecf20Sopenharmony_ci return ccb; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci blogic_dealloc_ccb deallocates a CCB, returning it to the Host Adapter's 3058c2ecf20Sopenharmony_ci free list. The Host Adapter's Lock should already have been acquired by the 3068c2ecf20Sopenharmony_ci caller. 3078c2ecf20Sopenharmony_ci*/ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void blogic_dealloc_ccb(struct blogic_ccb *ccb, int dma_unmap) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = ccb->adapter; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (ccb->command != NULL) 3148c2ecf20Sopenharmony_ci scsi_dma_unmap(ccb->command); 3158c2ecf20Sopenharmony_ci if (dma_unmap) 3168c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->pci_device->dev, ccb->sensedata, 3178c2ecf20Sopenharmony_ci ccb->sense_datalen, DMA_FROM_DEVICE); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci ccb->command = NULL; 3208c2ecf20Sopenharmony_ci ccb->status = BLOGIC_CCB_FREE; 3218c2ecf20Sopenharmony_ci ccb->next = adapter->free_ccbs; 3228c2ecf20Sopenharmony_ci adapter->free_ccbs = ccb; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/* 3278c2ecf20Sopenharmony_ci blogic_cmd sends the command opcode to adapter, optionally 3288c2ecf20Sopenharmony_ci providing paramlen bytes of param and receiving at most 3298c2ecf20Sopenharmony_ci replylen bytes of reply; any excess reply data is received but 3308c2ecf20Sopenharmony_ci discarded. 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci On success, this function returns the number of reply bytes read from 3338c2ecf20Sopenharmony_ci the Host Adapter (including any discarded data); on failure, it returns 3348c2ecf20Sopenharmony_ci -1 if the command was invalid, or -2 if a timeout occurred. 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci blogic_cmd is called exclusively during host adapter detection and 3378c2ecf20Sopenharmony_ci initialization, so performance and latency are not critical, and exclusive 3388c2ecf20Sopenharmony_ci access to the Host Adapter hardware is assumed. Once the host adapter and 3398c2ecf20Sopenharmony_ci driver are initialized, the only Host Adapter command that is issued is the 3408c2ecf20Sopenharmony_ci single byte Execute Mailbox Command operation code, which does not require 3418c2ecf20Sopenharmony_ci waiting for the Host Adapter Ready bit to be set in the Status Register. 3428c2ecf20Sopenharmony_ci*/ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int blogic_cmd(struct blogic_adapter *adapter, enum blogic_opcode opcode, 3458c2ecf20Sopenharmony_ci void *param, int paramlen, void *reply, int replylen) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci unsigned char *param_p = (unsigned char *) param; 3488c2ecf20Sopenharmony_ci unsigned char *reply_p = (unsigned char *) reply; 3498c2ecf20Sopenharmony_ci union blogic_stat_reg statusreg; 3508c2ecf20Sopenharmony_ci union blogic_int_reg intreg; 3518c2ecf20Sopenharmony_ci unsigned long processor_flag = 0; 3528c2ecf20Sopenharmony_ci int reply_b = 0, result; 3538c2ecf20Sopenharmony_ci long timeout; 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci Clear out the Reply Data if provided. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci if (replylen > 0) 3588c2ecf20Sopenharmony_ci memset(reply, 0, replylen); 3598c2ecf20Sopenharmony_ci /* 3608c2ecf20Sopenharmony_ci If the IRQ Channel has not yet been acquired, then interrupts 3618c2ecf20Sopenharmony_ci must be disabled while issuing host adapter commands since a 3628c2ecf20Sopenharmony_ci Command Complete interrupt could occur if the IRQ Channel was 3638c2ecf20Sopenharmony_ci previously enabled by another BusLogic Host Adapter or another 3648c2ecf20Sopenharmony_ci driver sharing the same IRQ Channel. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci if (!adapter->irq_acquired) 3678c2ecf20Sopenharmony_ci local_irq_save(processor_flag); 3688c2ecf20Sopenharmony_ci /* 3698c2ecf20Sopenharmony_ci Wait for the Host Adapter Ready bit to be set and the 3708c2ecf20Sopenharmony_ci Command/Parameter Register Busy bit to be reset in the Status 3718c2ecf20Sopenharmony_ci Register. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci timeout = 10000; 3748c2ecf20Sopenharmony_ci while (--timeout >= 0) { 3758c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 3768c2ecf20Sopenharmony_ci if (statusreg.sr.adapter_ready && !statusreg.sr.cmd_param_busy) 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci udelay(100); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci if (timeout < 0) { 3818c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = 3828c2ecf20Sopenharmony_ci "Timeout waiting for Host Adapter Ready"; 3838c2ecf20Sopenharmony_ci result = -2; 3848c2ecf20Sopenharmony_ci goto done; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci Write the opcode to the Command/Parameter Register. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci adapter->adapter_cmd_complete = false; 3908c2ecf20Sopenharmony_ci blogic_setcmdparam(adapter, opcode); 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci Write any additional Parameter Bytes. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci timeout = 10000; 3958c2ecf20Sopenharmony_ci while (paramlen > 0 && --timeout >= 0) { 3968c2ecf20Sopenharmony_ci /* 3978c2ecf20Sopenharmony_ci Wait 100 microseconds to give the Host Adapter enough 3988c2ecf20Sopenharmony_ci time to determine whether the last value written to the 3998c2ecf20Sopenharmony_ci Command/Parameter Register was valid or not. If the 4008c2ecf20Sopenharmony_ci Command Complete bit is set in the Interrupt Register, 4018c2ecf20Sopenharmony_ci then the Command Invalid bit in the Status Register will 4028c2ecf20Sopenharmony_ci be reset if the Operation Code or Parameter was valid 4038c2ecf20Sopenharmony_ci and the command has completed, or set if the Operation 4048c2ecf20Sopenharmony_ci Code or Parameter was invalid. If the Data In Register 4058c2ecf20Sopenharmony_ci Ready bit is set in the Status Register, then the 4068c2ecf20Sopenharmony_ci Operation Code was valid, and data is waiting to be read 4078c2ecf20Sopenharmony_ci back from the Host Adapter. Otherwise, wait for the 4088c2ecf20Sopenharmony_ci Command/Parameter Register Busy bit in the Status 4098c2ecf20Sopenharmony_ci Register to be reset. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci udelay(100); 4128c2ecf20Sopenharmony_ci intreg.all = blogic_rdint(adapter); 4138c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 4148c2ecf20Sopenharmony_ci if (intreg.ir.cmd_complete) 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci if (adapter->adapter_cmd_complete) 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci if (statusreg.sr.datain_ready) 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci if (statusreg.sr.cmd_param_busy) 4218c2ecf20Sopenharmony_ci continue; 4228c2ecf20Sopenharmony_ci blogic_setcmdparam(adapter, *param_p++); 4238c2ecf20Sopenharmony_ci paramlen--; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci if (timeout < 0) { 4268c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = 4278c2ecf20Sopenharmony_ci "Timeout waiting for Parameter Acceptance"; 4288c2ecf20Sopenharmony_ci result = -2; 4298c2ecf20Sopenharmony_ci goto done; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci /* 4328c2ecf20Sopenharmony_ci The Modify I/O Address command does not cause a Command Complete 4338c2ecf20Sopenharmony_ci Interrupt. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci if (opcode == BLOGIC_MOD_IOADDR) { 4368c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 4378c2ecf20Sopenharmony_ci if (statusreg.sr.cmd_invalid) { 4388c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = 4398c2ecf20Sopenharmony_ci "Modify I/O Address Invalid"; 4408c2ecf20Sopenharmony_ci result = -1; 4418c2ecf20Sopenharmony_ci goto done; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci if (blogic_global_options.trace_config) 4448c2ecf20Sopenharmony_ci blogic_notice("blogic_cmd(%02X) Status = %02X: (Modify I/O Address)\n", adapter, opcode, statusreg.all); 4458c2ecf20Sopenharmony_ci result = 0; 4468c2ecf20Sopenharmony_ci goto done; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci /* 4498c2ecf20Sopenharmony_ci Select an appropriate timeout value for awaiting command completion. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci switch (opcode) { 4528c2ecf20Sopenharmony_ci case BLOGIC_INQ_DEV0TO7: 4538c2ecf20Sopenharmony_ci case BLOGIC_INQ_DEV8TO15: 4548c2ecf20Sopenharmony_ci case BLOGIC_INQ_DEV: 4558c2ecf20Sopenharmony_ci /* Approximately 60 seconds. */ 4568c2ecf20Sopenharmony_ci timeout = 60 * 10000; 4578c2ecf20Sopenharmony_ci break; 4588c2ecf20Sopenharmony_ci default: 4598c2ecf20Sopenharmony_ci /* Approximately 1 second. */ 4608c2ecf20Sopenharmony_ci timeout = 10000; 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci Receive any Reply Bytes, waiting for either the Command 4658c2ecf20Sopenharmony_ci Complete bit to be set in the Interrupt Register, or for the 4668c2ecf20Sopenharmony_ci Interrupt Handler to set the Host Adapter Command Completed 4678c2ecf20Sopenharmony_ci bit in the Host Adapter structure. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci while (--timeout >= 0) { 4708c2ecf20Sopenharmony_ci intreg.all = blogic_rdint(adapter); 4718c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 4728c2ecf20Sopenharmony_ci if (intreg.ir.cmd_complete) 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci if (adapter->adapter_cmd_complete) 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci if (statusreg.sr.datain_ready) { 4778c2ecf20Sopenharmony_ci if (++reply_b <= replylen) 4788c2ecf20Sopenharmony_ci *reply_p++ = blogic_rddatain(adapter); 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci blogic_rddatain(adapter); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci if (opcode == BLOGIC_FETCH_LOCALRAM && 4838c2ecf20Sopenharmony_ci statusreg.sr.adapter_ready) 4848c2ecf20Sopenharmony_ci break; 4858c2ecf20Sopenharmony_ci udelay(100); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if (timeout < 0) { 4888c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = 4898c2ecf20Sopenharmony_ci "Timeout waiting for Command Complete"; 4908c2ecf20Sopenharmony_ci result = -2; 4918c2ecf20Sopenharmony_ci goto done; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci /* 4948c2ecf20Sopenharmony_ci Clear any pending Command Complete Interrupt. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci blogic_intreset(adapter); 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci Provide tracing information if requested. 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_ci if (blogic_global_options.trace_config) { 5018c2ecf20Sopenharmony_ci int i; 5028c2ecf20Sopenharmony_ci blogic_notice("blogic_cmd(%02X) Status = %02X: %2d ==> %2d:", 5038c2ecf20Sopenharmony_ci adapter, opcode, statusreg.all, replylen, 5048c2ecf20Sopenharmony_ci reply_b); 5058c2ecf20Sopenharmony_ci if (replylen > reply_b) 5068c2ecf20Sopenharmony_ci replylen = reply_b; 5078c2ecf20Sopenharmony_ci for (i = 0; i < replylen; i++) 5088c2ecf20Sopenharmony_ci blogic_notice(" %02X", adapter, 5098c2ecf20Sopenharmony_ci ((unsigned char *) reply)[i]); 5108c2ecf20Sopenharmony_ci blogic_notice("\n", adapter); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci /* 5138c2ecf20Sopenharmony_ci Process Command Invalid conditions. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci if (statusreg.sr.cmd_invalid) { 5168c2ecf20Sopenharmony_ci /* 5178c2ecf20Sopenharmony_ci Some early BusLogic Host Adapters may not recover 5188c2ecf20Sopenharmony_ci properly from a Command Invalid condition, so if this 5198c2ecf20Sopenharmony_ci appears to be the case, a Soft Reset is issued to the 5208c2ecf20Sopenharmony_ci Host Adapter. Potentially invalid commands are never 5218c2ecf20Sopenharmony_ci attempted after Mailbox Initialization is performed, 5228c2ecf20Sopenharmony_ci so there should be no Host Adapter state lost by a 5238c2ecf20Sopenharmony_ci Soft Reset in response to a Command Invalid condition. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci udelay(1000); 5268c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 5278c2ecf20Sopenharmony_ci if (statusreg.sr.cmd_invalid || statusreg.sr.rsvd || 5288c2ecf20Sopenharmony_ci statusreg.sr.datain_ready || 5298c2ecf20Sopenharmony_ci statusreg.sr.cmd_param_busy || 5308c2ecf20Sopenharmony_ci !statusreg.sr.adapter_ready || 5318c2ecf20Sopenharmony_ci !statusreg.sr.init_reqd || 5328c2ecf20Sopenharmony_ci statusreg.sr.diag_active || 5338c2ecf20Sopenharmony_ci statusreg.sr.diag_failed) { 5348c2ecf20Sopenharmony_ci blogic_softreset(adapter); 5358c2ecf20Sopenharmony_ci udelay(1000); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = "Command Invalid"; 5388c2ecf20Sopenharmony_ci result = -1; 5398c2ecf20Sopenharmony_ci goto done; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci /* 5428c2ecf20Sopenharmony_ci Handle Excess Parameters Supplied conditions. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci if (paramlen > 0) { 5458c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = "Excess Parameters Supplied"; 5468c2ecf20Sopenharmony_ci result = -1; 5478c2ecf20Sopenharmony_ci goto done; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci Indicate the command completed successfully. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = NULL; 5538c2ecf20Sopenharmony_ci result = reply_b; 5548c2ecf20Sopenharmony_ci /* 5558c2ecf20Sopenharmony_ci Restore the interrupt status if necessary and return. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_cidone: 5588c2ecf20Sopenharmony_ci if (!adapter->irq_acquired) 5598c2ecf20Sopenharmony_ci local_irq_restore(processor_flag); 5608c2ecf20Sopenharmony_ci return result; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci/* 5658c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa appends a single ISA I/O Address to the list 5668c2ecf20Sopenharmony_ci of I/O Address and Bus Probe Information to be checked for potential BusLogic 5678c2ecf20Sopenharmony_ci Host Adapters. 5688c2ecf20Sopenharmony_ci*/ 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void __init blogic_add_probeaddr_isa(unsigned long io_addr) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo; 5738c2ecf20Sopenharmony_ci if (blogic_probeinfo_count >= BLOGIC_MAX_ADAPTERS) 5748c2ecf20Sopenharmony_ci return; 5758c2ecf20Sopenharmony_ci probeinfo = &blogic_probeinfo_list[blogic_probeinfo_count++]; 5768c2ecf20Sopenharmony_ci probeinfo->adapter_type = BLOGIC_MULTIMASTER; 5778c2ecf20Sopenharmony_ci probeinfo->adapter_bus_type = BLOGIC_ISA_BUS; 5788c2ecf20Sopenharmony_ci probeinfo->io_addr = io_addr; 5798c2ecf20Sopenharmony_ci probeinfo->pci_device = NULL; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* 5848c2ecf20Sopenharmony_ci blogic_init_probeinfo_isa initializes the list of I/O Address and 5858c2ecf20Sopenharmony_ci Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters 5868c2ecf20Sopenharmony_ci only from the list of standard BusLogic MultiMaster ISA I/O Addresses. 5878c2ecf20Sopenharmony_ci*/ 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic void __init blogic_init_probeinfo_isa(struct blogic_adapter *adapter) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci /* 5928c2ecf20Sopenharmony_ci If BusLogic Driver Options specifications requested that ISA 5938c2ecf20Sopenharmony_ci Bus Probes be inhibited, do not proceed further. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci if (blogic_probe_options.noprobe_isa) 5968c2ecf20Sopenharmony_ci return; 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci Append the list of standard BusLogic MultiMaster ISA I/O Addresses. 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe330) 6018c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x330); 6028c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe334) 6038c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x334); 6048c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe230) 6058c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x230); 6068c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe234) 6078c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x234); 6088c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe130) 6098c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x130); 6108c2ecf20Sopenharmony_ci if (!blogic_probe_options.limited_isa || blogic_probe_options.probe134) 6118c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x134); 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci blogic_sort_probeinfo sorts a section of blogic_probeinfo_list in order 6208c2ecf20Sopenharmony_ci of increasing PCI Bus and Device Number. 6218c2ecf20Sopenharmony_ci*/ 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void __init blogic_sort_probeinfo(struct blogic_probeinfo 6248c2ecf20Sopenharmony_ci *probeinfo_list, int probeinfo_cnt) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci int last_exchange = probeinfo_cnt - 1, bound, j; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci while (last_exchange > 0) { 6298c2ecf20Sopenharmony_ci bound = last_exchange; 6308c2ecf20Sopenharmony_ci last_exchange = 0; 6318c2ecf20Sopenharmony_ci for (j = 0; j < bound; j++) { 6328c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo1 = 6338c2ecf20Sopenharmony_ci &probeinfo_list[j]; 6348c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo2 = 6358c2ecf20Sopenharmony_ci &probeinfo_list[j + 1]; 6368c2ecf20Sopenharmony_ci if (probeinfo1->bus > probeinfo2->bus || 6378c2ecf20Sopenharmony_ci (probeinfo1->bus == probeinfo2->bus && 6388c2ecf20Sopenharmony_ci (probeinfo1->dev > probeinfo2->dev))) { 6398c2ecf20Sopenharmony_ci struct blogic_probeinfo tmp_probeinfo; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci memcpy(&tmp_probeinfo, probeinfo1, 6428c2ecf20Sopenharmony_ci sizeof(struct blogic_probeinfo)); 6438c2ecf20Sopenharmony_ci memcpy(probeinfo1, probeinfo2, 6448c2ecf20Sopenharmony_ci sizeof(struct blogic_probeinfo)); 6458c2ecf20Sopenharmony_ci memcpy(probeinfo2, &tmp_probeinfo, 6468c2ecf20Sopenharmony_ci sizeof(struct blogic_probeinfo)); 6478c2ecf20Sopenharmony_ci last_exchange = j; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/* 6558c2ecf20Sopenharmony_ci blogic_init_mm_probeinfo initializes the list of I/O Address 6568c2ecf20Sopenharmony_ci and Bus Probe Information to be checked for potential BusLogic MultiMaster 6578c2ecf20Sopenharmony_ci SCSI Host Adapters by interrogating the PCI Configuration Space on PCI 6588c2ecf20Sopenharmony_ci machines as well as from the list of standard BusLogic MultiMaster ISA 6598c2ecf20Sopenharmony_ci I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found. 6608c2ecf20Sopenharmony_ci*/ 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int __init blogic_init_mm_probeinfo(struct blogic_adapter *adapter) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct blogic_probeinfo *pr_probeinfo = 6658c2ecf20Sopenharmony_ci &blogic_probeinfo_list[blogic_probeinfo_count]; 6668c2ecf20Sopenharmony_ci int nonpr_mmindex = blogic_probeinfo_count + 1; 6678c2ecf20Sopenharmony_ci int nonpr_mmcount = 0, mmcount = 0; 6688c2ecf20Sopenharmony_ci bool force_scan_order = false; 6698c2ecf20Sopenharmony_ci bool force_scan_order_checked = false; 6708c2ecf20Sopenharmony_ci bool addr_seen[6]; 6718c2ecf20Sopenharmony_ci struct pci_dev *pci_device = NULL; 6728c2ecf20Sopenharmony_ci int i; 6738c2ecf20Sopenharmony_ci if (blogic_probeinfo_count >= BLOGIC_MAX_ADAPTERS) 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci blogic_probeinfo_count++; 6768c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 6778c2ecf20Sopenharmony_ci addr_seen[i] = false; 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci Iterate over the MultiMaster PCI Host Adapters. For each 6808c2ecf20Sopenharmony_ci enumerated host adapter, determine whether its ISA Compatible 6818c2ecf20Sopenharmony_ci I/O Port is enabled and if so, whether it is assigned the 6828c2ecf20Sopenharmony_ci Primary I/O Address. A host adapter that is assigned the 6838c2ecf20Sopenharmony_ci Primary I/O Address will always be the preferred boot device. 6848c2ecf20Sopenharmony_ci The MultiMaster BIOS will first recognize a host adapter at 6858c2ecf20Sopenharmony_ci the Primary I/O Address, then any other PCI host adapters, 6868c2ecf20Sopenharmony_ci and finally any host adapters located at the remaining 6878c2ecf20Sopenharmony_ci standard ISA I/O Addresses. When a PCI host adapter is found 6888c2ecf20Sopenharmony_ci with its ISA Compatible I/O Port enabled, a command is issued 6898c2ecf20Sopenharmony_ci to disable the ISA Compatible I/O Port, and it is noted that the 6908c2ecf20Sopenharmony_ci particular standard ISA I/O Address need not be probed. 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci pr_probeinfo->io_addr = 0; 6938c2ecf20Sopenharmony_ci while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, 6948c2ecf20Sopenharmony_ci PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, 6958c2ecf20Sopenharmony_ci pci_device)) != NULL) { 6968c2ecf20Sopenharmony_ci struct blogic_adapter *host_adapter = adapter; 6978c2ecf20Sopenharmony_ci struct blogic_adapter_info adapter_info; 6988c2ecf20Sopenharmony_ci enum blogic_isa_ioport mod_ioaddr_req; 6998c2ecf20Sopenharmony_ci unsigned char bus; 7008c2ecf20Sopenharmony_ci unsigned char device; 7018c2ecf20Sopenharmony_ci unsigned int irq_ch; 7028c2ecf20Sopenharmony_ci unsigned long base_addr0; 7038c2ecf20Sopenharmony_ci unsigned long base_addr1; 7048c2ecf20Sopenharmony_ci unsigned long io_addr; 7058c2ecf20Sopenharmony_ci unsigned long pci_addr; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (pci_enable_device(pci_device)) 7088c2ecf20Sopenharmony_ci continue; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) 7118c2ecf20Sopenharmony_ci continue; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci bus = pci_device->bus->number; 7148c2ecf20Sopenharmony_ci device = pci_device->devfn >> 3; 7158c2ecf20Sopenharmony_ci irq_ch = pci_device->irq; 7168c2ecf20Sopenharmony_ci io_addr = base_addr0 = pci_resource_start(pci_device, 0); 7178c2ecf20Sopenharmony_ci pci_addr = base_addr1 = pci_resource_start(pci_device, 1); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) { 7208c2ecf20Sopenharmony_ci blogic_err("BusLogic: Base Address0 0x%lX not I/O for MultiMaster Host Adapter\n", NULL, base_addr0); 7218c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr); 7228c2ecf20Sopenharmony_ci continue; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) { 7258c2ecf20Sopenharmony_ci blogic_err("BusLogic: Base Address1 0x%lX not Memory for MultiMaster Host Adapter\n", NULL, base_addr1); 7268c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr); 7278c2ecf20Sopenharmony_ci continue; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci if (irq_ch == 0) { 7308c2ecf20Sopenharmony_ci blogic_err("BusLogic: IRQ Channel %d invalid for MultiMaster Host Adapter\n", NULL, irq_ch); 7318c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr); 7328c2ecf20Sopenharmony_ci continue; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci if (blogic_global_options.trace_probe) { 7358c2ecf20Sopenharmony_ci blogic_notice("BusLogic: PCI MultiMaster Host Adapter detected at\n", NULL); 7368c2ecf20Sopenharmony_ci blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX\n", NULL, bus, device, io_addr, pci_addr); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci /* 7398c2ecf20Sopenharmony_ci Issue the Inquire PCI Host Adapter Information command to determine 7408c2ecf20Sopenharmony_ci the ISA Compatible I/O Port. If the ISA Compatible I/O Port is 7418c2ecf20Sopenharmony_ci known and enabled, note that the particular Standard ISA I/O 7428c2ecf20Sopenharmony_ci Address should not be probed. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci host_adapter->io_addr = io_addr; 7458c2ecf20Sopenharmony_ci blogic_intreset(host_adapter); 7468c2ecf20Sopenharmony_ci if (blogic_cmd(host_adapter, BLOGIC_INQ_PCI_INFO, NULL, 0, 7478c2ecf20Sopenharmony_ci &adapter_info, sizeof(adapter_info)) == 7488c2ecf20Sopenharmony_ci sizeof(adapter_info)) { 7498c2ecf20Sopenharmony_ci if (adapter_info.isa_port < 6) 7508c2ecf20Sopenharmony_ci addr_seen[adapter_info.isa_port] = true; 7518c2ecf20Sopenharmony_ci } else 7528c2ecf20Sopenharmony_ci adapter_info.isa_port = BLOGIC_IO_DISABLE; 7538c2ecf20Sopenharmony_ci /* 7548c2ecf20Sopenharmony_ci Issue the Modify I/O Address command to disable the 7558c2ecf20Sopenharmony_ci ISA Compatible I/O Port. On PCI Host Adapters, the 7568c2ecf20Sopenharmony_ci Modify I/O Address command allows modification of the 7578c2ecf20Sopenharmony_ci ISA compatible I/O Address that the Host Adapter 7588c2ecf20Sopenharmony_ci responds to; it does not affect the PCI compliant 7598c2ecf20Sopenharmony_ci I/O Address assigned at system initialization. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci mod_ioaddr_req = BLOGIC_IO_DISABLE; 7628c2ecf20Sopenharmony_ci blogic_cmd(host_adapter, BLOGIC_MOD_IOADDR, &mod_ioaddr_req, 7638c2ecf20Sopenharmony_ci sizeof(mod_ioaddr_req), NULL, 0); 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci For the first MultiMaster Host Adapter enumerated, 7668c2ecf20Sopenharmony_ci issue the Fetch Host Adapter Local RAM command to read 7678c2ecf20Sopenharmony_ci byte 45 of the AutoSCSI area, for the setting of the 7688c2ecf20Sopenharmony_ci "Use Bus And Device # For PCI Scanning Seq." option. 7698c2ecf20Sopenharmony_ci Issue the Inquire Board ID command since this option is 7708c2ecf20Sopenharmony_ci only valid for the BT-948/958/958D. 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (!force_scan_order_checked) { 7738c2ecf20Sopenharmony_ci struct blogic_fetch_localram fetch_localram; 7748c2ecf20Sopenharmony_ci struct blogic_autoscsi_byte45 autoscsi_byte45; 7758c2ecf20Sopenharmony_ci struct blogic_board_id id; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci fetch_localram.offset = BLOGIC_AUTOSCSI_BASE + 45; 7788c2ecf20Sopenharmony_ci fetch_localram.count = sizeof(autoscsi_byte45); 7798c2ecf20Sopenharmony_ci blogic_cmd(host_adapter, BLOGIC_FETCH_LOCALRAM, 7808c2ecf20Sopenharmony_ci &fetch_localram, sizeof(fetch_localram), 7818c2ecf20Sopenharmony_ci &autoscsi_byte45, 7828c2ecf20Sopenharmony_ci sizeof(autoscsi_byte45)); 7838c2ecf20Sopenharmony_ci blogic_cmd(host_adapter, BLOGIC_GET_BOARD_ID, NULL, 0, 7848c2ecf20Sopenharmony_ci &id, sizeof(id)); 7858c2ecf20Sopenharmony_ci if (id.fw_ver_digit1 == '5') 7868c2ecf20Sopenharmony_ci force_scan_order = 7878c2ecf20Sopenharmony_ci autoscsi_byte45.force_scan_order; 7888c2ecf20Sopenharmony_ci force_scan_order_checked = true; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci /* 7918c2ecf20Sopenharmony_ci Determine whether this MultiMaster Host Adapter has its 7928c2ecf20Sopenharmony_ci ISA Compatible I/O Port enabled and is assigned the 7938c2ecf20Sopenharmony_ci Primary I/O Address. If it does, then it is the Primary 7948c2ecf20Sopenharmony_ci MultiMaster Host Adapter and must be recognized first. 7958c2ecf20Sopenharmony_ci If it does not, then it is added to the list for probing 7968c2ecf20Sopenharmony_ci after any Primary MultiMaster Host Adapter is probed. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci if (adapter_info.isa_port == BLOGIC_IO_330) { 7998c2ecf20Sopenharmony_ci pr_probeinfo->adapter_type = BLOGIC_MULTIMASTER; 8008c2ecf20Sopenharmony_ci pr_probeinfo->adapter_bus_type = BLOGIC_PCI_BUS; 8018c2ecf20Sopenharmony_ci pr_probeinfo->io_addr = io_addr; 8028c2ecf20Sopenharmony_ci pr_probeinfo->pci_addr = pci_addr; 8038c2ecf20Sopenharmony_ci pr_probeinfo->bus = bus; 8048c2ecf20Sopenharmony_ci pr_probeinfo->dev = device; 8058c2ecf20Sopenharmony_ci pr_probeinfo->irq_ch = irq_ch; 8068c2ecf20Sopenharmony_ci pr_probeinfo->pci_device = pci_dev_get(pci_device); 8078c2ecf20Sopenharmony_ci mmcount++; 8088c2ecf20Sopenharmony_ci } else if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) { 8098c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo = 8108c2ecf20Sopenharmony_ci &blogic_probeinfo_list[blogic_probeinfo_count++]; 8118c2ecf20Sopenharmony_ci probeinfo->adapter_type = BLOGIC_MULTIMASTER; 8128c2ecf20Sopenharmony_ci probeinfo->adapter_bus_type = BLOGIC_PCI_BUS; 8138c2ecf20Sopenharmony_ci probeinfo->io_addr = io_addr; 8148c2ecf20Sopenharmony_ci probeinfo->pci_addr = pci_addr; 8158c2ecf20Sopenharmony_ci probeinfo->bus = bus; 8168c2ecf20Sopenharmony_ci probeinfo->dev = device; 8178c2ecf20Sopenharmony_ci probeinfo->irq_ch = irq_ch; 8188c2ecf20Sopenharmony_ci probeinfo->pci_device = pci_dev_get(pci_device); 8198c2ecf20Sopenharmony_ci nonpr_mmcount++; 8208c2ecf20Sopenharmony_ci mmcount++; 8218c2ecf20Sopenharmony_ci } else 8228c2ecf20Sopenharmony_ci blogic_warn("BusLogic: Too many Host Adapters detected\n", NULL); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci /* 8258c2ecf20Sopenharmony_ci If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." 8268c2ecf20Sopenharmony_ci option is ON for the first enumerated MultiMaster Host Adapter, 8278c2ecf20Sopenharmony_ci and if that host adapter is a BT-948/958/958D, then the 8288c2ecf20Sopenharmony_ci MultiMaster BIOS will recognize MultiMaster Host Adapters in 8298c2ecf20Sopenharmony_ci the order of increasing PCI Bus and Device Number. In that case, 8308c2ecf20Sopenharmony_ci sort the probe information into the same order the BIOS uses. 8318c2ecf20Sopenharmony_ci If this option is OFF, then the MultiMaster BIOS will recognize 8328c2ecf20Sopenharmony_ci MultiMaster Host Adapters in the order they are enumerated by 8338c2ecf20Sopenharmony_ci the PCI BIOS, and hence no sorting is necessary. 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ci if (force_scan_order) 8368c2ecf20Sopenharmony_ci blogic_sort_probeinfo(&blogic_probeinfo_list[nonpr_mmindex], 8378c2ecf20Sopenharmony_ci nonpr_mmcount); 8388c2ecf20Sopenharmony_ci /* 8398c2ecf20Sopenharmony_ci If no PCI MultiMaster Host Adapter is assigned the Primary 8408c2ecf20Sopenharmony_ci I/O Address, then the Primary I/O Address must be probed 8418c2ecf20Sopenharmony_ci explicitly before any PCI host adapters are probed. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci if (!blogic_probe_options.noprobe_isa) 8448c2ecf20Sopenharmony_ci if (pr_probeinfo->io_addr == 0 && 8458c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8468c2ecf20Sopenharmony_ci blogic_probe_options.probe330)) { 8478c2ecf20Sopenharmony_ci pr_probeinfo->adapter_type = BLOGIC_MULTIMASTER; 8488c2ecf20Sopenharmony_ci pr_probeinfo->adapter_bus_type = BLOGIC_ISA_BUS; 8498c2ecf20Sopenharmony_ci pr_probeinfo->io_addr = 0x330; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci Append the list of standard BusLogic MultiMaster ISA I/O Addresses, 8538c2ecf20Sopenharmony_ci omitting the Primary I/O Address which has already been handled. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci if (!blogic_probe_options.noprobe_isa) { 8568c2ecf20Sopenharmony_ci if (!addr_seen[1] && 8578c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8588c2ecf20Sopenharmony_ci blogic_probe_options.probe334)) 8598c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x334); 8608c2ecf20Sopenharmony_ci if (!addr_seen[2] && 8618c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8628c2ecf20Sopenharmony_ci blogic_probe_options.probe230)) 8638c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x230); 8648c2ecf20Sopenharmony_ci if (!addr_seen[3] && 8658c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8668c2ecf20Sopenharmony_ci blogic_probe_options.probe234)) 8678c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x234); 8688c2ecf20Sopenharmony_ci if (!addr_seen[4] && 8698c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8708c2ecf20Sopenharmony_ci blogic_probe_options.probe130)) 8718c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x130); 8728c2ecf20Sopenharmony_ci if (!addr_seen[5] && 8738c2ecf20Sopenharmony_ci (!blogic_probe_options.limited_isa || 8748c2ecf20Sopenharmony_ci blogic_probe_options.probe134)) 8758c2ecf20Sopenharmony_ci blogic_add_probeaddr_isa(0x134); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci /* 8788c2ecf20Sopenharmony_ci Iterate over the older non-compliant MultiMaster PCI Host Adapters, 8798c2ecf20Sopenharmony_ci noting the PCI bus location and assigned IRQ Channel. 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_ci pci_device = NULL; 8828c2ecf20Sopenharmony_ci while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, 8838c2ecf20Sopenharmony_ci PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, 8848c2ecf20Sopenharmony_ci pci_device)) != NULL) { 8858c2ecf20Sopenharmony_ci unsigned char bus; 8868c2ecf20Sopenharmony_ci unsigned char device; 8878c2ecf20Sopenharmony_ci unsigned int irq_ch; 8888c2ecf20Sopenharmony_ci unsigned long io_addr; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (pci_enable_device(pci_device)) 8918c2ecf20Sopenharmony_ci continue; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) 8948c2ecf20Sopenharmony_ci continue; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci bus = pci_device->bus->number; 8978c2ecf20Sopenharmony_ci device = pci_device->devfn >> 3; 8988c2ecf20Sopenharmony_ci irq_ch = pci_device->irq; 8998c2ecf20Sopenharmony_ci io_addr = pci_resource_start(pci_device, 0); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (io_addr == 0 || irq_ch == 0) 9028c2ecf20Sopenharmony_ci continue; 9038c2ecf20Sopenharmony_ci for (i = 0; i < blogic_probeinfo_count; i++) { 9048c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo = 9058c2ecf20Sopenharmony_ci &blogic_probeinfo_list[i]; 9068c2ecf20Sopenharmony_ci if (probeinfo->io_addr == io_addr && 9078c2ecf20Sopenharmony_ci probeinfo->adapter_type == BLOGIC_MULTIMASTER) { 9088c2ecf20Sopenharmony_ci probeinfo->adapter_bus_type = BLOGIC_PCI_BUS; 9098c2ecf20Sopenharmony_ci probeinfo->pci_addr = 0; 9108c2ecf20Sopenharmony_ci probeinfo->bus = bus; 9118c2ecf20Sopenharmony_ci probeinfo->dev = device; 9128c2ecf20Sopenharmony_ci probeinfo->irq_ch = irq_ch; 9138c2ecf20Sopenharmony_ci probeinfo->pci_device = pci_dev_get(pci_device); 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci return mmcount; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci blogic_init_fp_probeinfo initializes the list of I/O Address 9248c2ecf20Sopenharmony_ci and Bus Probe Information to be checked for potential BusLogic FlashPoint 9258c2ecf20Sopenharmony_ci Host Adapters by interrogating the PCI Configuration Space. It returns the 9268c2ecf20Sopenharmony_ci number of FlashPoint Host Adapters found. 9278c2ecf20Sopenharmony_ci*/ 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic int __init blogic_init_fp_probeinfo(struct blogic_adapter *adapter) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci int fpindex = blogic_probeinfo_count, fpcount = 0; 9328c2ecf20Sopenharmony_ci struct pci_dev *pci_device = NULL; 9338c2ecf20Sopenharmony_ci /* 9348c2ecf20Sopenharmony_ci Interrogate PCI Configuration Space for any FlashPoint Host Adapters. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci while ((pci_device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, 9378c2ecf20Sopenharmony_ci PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, 9388c2ecf20Sopenharmony_ci pci_device)) != NULL) { 9398c2ecf20Sopenharmony_ci unsigned char bus; 9408c2ecf20Sopenharmony_ci unsigned char device; 9418c2ecf20Sopenharmony_ci unsigned int irq_ch; 9428c2ecf20Sopenharmony_ci unsigned long base_addr0; 9438c2ecf20Sopenharmony_ci unsigned long base_addr1; 9448c2ecf20Sopenharmony_ci unsigned long io_addr; 9458c2ecf20Sopenharmony_ci unsigned long pci_addr; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (pci_enable_device(pci_device)) 9488c2ecf20Sopenharmony_ci continue; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (dma_set_mask(&pci_device->dev, DMA_BIT_MASK(32))) 9518c2ecf20Sopenharmony_ci continue; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci bus = pci_device->bus->number; 9548c2ecf20Sopenharmony_ci device = pci_device->devfn >> 3; 9558c2ecf20Sopenharmony_ci irq_ch = pci_device->irq; 9568c2ecf20Sopenharmony_ci io_addr = base_addr0 = pci_resource_start(pci_device, 0); 9578c2ecf20Sopenharmony_ci pci_addr = base_addr1 = pci_resource_start(pci_device, 1); 9588c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI_FLASHPOINT 9598c2ecf20Sopenharmony_ci if (pci_resource_flags(pci_device, 0) & IORESOURCE_MEM) { 9608c2ecf20Sopenharmony_ci blogic_err("BusLogic: Base Address0 0x%lX not I/O for FlashPoint Host Adapter\n", NULL, base_addr0); 9618c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr); 9628c2ecf20Sopenharmony_ci continue; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci if (pci_resource_flags(pci_device, 1) & IORESOURCE_IO) { 9658c2ecf20Sopenharmony_ci blogic_err("BusLogic: Base Address1 0x%lX not Memory for FlashPoint Host Adapter\n", NULL, base_addr1); 9668c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d PCI Address 0x%lX\n", NULL, bus, device, pci_addr); 9678c2ecf20Sopenharmony_ci continue; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci if (irq_ch == 0) { 9708c2ecf20Sopenharmony_ci blogic_err("BusLogic: IRQ Channel %d invalid for FlashPoint Host Adapter\n", NULL, irq_ch); 9718c2ecf20Sopenharmony_ci blogic_err("at PCI Bus %d Device %d I/O Address 0x%lX\n", NULL, bus, device, io_addr); 9728c2ecf20Sopenharmony_ci continue; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci if (blogic_global_options.trace_probe) { 9758c2ecf20Sopenharmony_ci blogic_notice("BusLogic: FlashPoint Host Adapter detected at\n", NULL); 9768c2ecf20Sopenharmony_ci blogic_notice("BusLogic: PCI Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX\n", NULL, bus, device, io_addr, pci_addr); 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci if (blogic_probeinfo_count < BLOGIC_MAX_ADAPTERS) { 9798c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo = 9808c2ecf20Sopenharmony_ci &blogic_probeinfo_list[blogic_probeinfo_count++]; 9818c2ecf20Sopenharmony_ci probeinfo->adapter_type = BLOGIC_FLASHPOINT; 9828c2ecf20Sopenharmony_ci probeinfo->adapter_bus_type = BLOGIC_PCI_BUS; 9838c2ecf20Sopenharmony_ci probeinfo->io_addr = io_addr; 9848c2ecf20Sopenharmony_ci probeinfo->pci_addr = pci_addr; 9858c2ecf20Sopenharmony_ci probeinfo->bus = bus; 9868c2ecf20Sopenharmony_ci probeinfo->dev = device; 9878c2ecf20Sopenharmony_ci probeinfo->irq_ch = irq_ch; 9888c2ecf20Sopenharmony_ci probeinfo->pci_device = pci_dev_get(pci_device); 9898c2ecf20Sopenharmony_ci fpcount++; 9908c2ecf20Sopenharmony_ci } else 9918c2ecf20Sopenharmony_ci blogic_warn("BusLogic: Too many Host Adapters detected\n", NULL); 9928c2ecf20Sopenharmony_ci#else 9938c2ecf20Sopenharmony_ci blogic_err("BusLogic: FlashPoint Host Adapter detected at PCI Bus %d Device %d\n", NULL, bus, device); 9948c2ecf20Sopenharmony_ci blogic_err("BusLogic: I/O Address 0x%lX PCI Address 0x%lX, irq %d, but FlashPoint\n", NULL, io_addr, pci_addr, irq_ch); 9958c2ecf20Sopenharmony_ci blogic_err("BusLogic: support was omitted in this kernel configuration.\n", NULL); 9968c2ecf20Sopenharmony_ci#endif 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci /* 9998c2ecf20Sopenharmony_ci The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of 10008c2ecf20Sopenharmony_ci increasing PCI Bus and Device Number, so sort the probe information into 10018c2ecf20Sopenharmony_ci the same order the BIOS uses. 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci blogic_sort_probeinfo(&blogic_probeinfo_list[fpindex], fpcount); 10048c2ecf20Sopenharmony_ci return fpcount; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci/* 10098c2ecf20Sopenharmony_ci blogic_init_probeinfo_list initializes the list of I/O Address and Bus 10108c2ecf20Sopenharmony_ci Probe Information to be checked for potential BusLogic SCSI Host Adapters by 10118c2ecf20Sopenharmony_ci interrogating the PCI Configuration Space on PCI machines as well as from the 10128c2ecf20Sopenharmony_ci list of standard BusLogic MultiMaster ISA I/O Addresses. By default, if both 10138c2ecf20Sopenharmony_ci FlashPoint and PCI MultiMaster Host Adapters are present, this driver will 10148c2ecf20Sopenharmony_ci probe for FlashPoint Host Adapters first unless the BIOS primary disk is 10158c2ecf20Sopenharmony_ci controlled by the first PCI MultiMaster Host Adapter, in which case 10168c2ecf20Sopenharmony_ci MultiMaster Host Adapters will be probed first. The BusLogic Driver Options 10178c2ecf20Sopenharmony_ci specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force 10188c2ecf20Sopenharmony_ci a particular probe order. 10198c2ecf20Sopenharmony_ci*/ 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic void __init blogic_init_probeinfo_list(struct blogic_adapter *adapter) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci /* 10248c2ecf20Sopenharmony_ci If a PCI BIOS is present, interrogate it for MultiMaster and 10258c2ecf20Sopenharmony_ci FlashPoint Host Adapters; otherwise, default to the standard 10268c2ecf20Sopenharmony_ci ISA MultiMaster probe. 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ci if (!blogic_probe_options.noprobe_pci) { 10298c2ecf20Sopenharmony_ci if (blogic_probe_options.multimaster_first) { 10308c2ecf20Sopenharmony_ci blogic_init_mm_probeinfo(adapter); 10318c2ecf20Sopenharmony_ci blogic_init_fp_probeinfo(adapter); 10328c2ecf20Sopenharmony_ci } else if (blogic_probe_options.flashpoint_first) { 10338c2ecf20Sopenharmony_ci blogic_init_fp_probeinfo(adapter); 10348c2ecf20Sopenharmony_ci blogic_init_mm_probeinfo(adapter); 10358c2ecf20Sopenharmony_ci } else { 10368c2ecf20Sopenharmony_ci int fpcount = blogic_init_fp_probeinfo(adapter); 10378c2ecf20Sopenharmony_ci int mmcount = blogic_init_mm_probeinfo(adapter); 10388c2ecf20Sopenharmony_ci if (fpcount > 0 && mmcount > 0) { 10398c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo = 10408c2ecf20Sopenharmony_ci &blogic_probeinfo_list[fpcount]; 10418c2ecf20Sopenharmony_ci struct blogic_adapter *myadapter = adapter; 10428c2ecf20Sopenharmony_ci struct blogic_fetch_localram fetch_localram; 10438c2ecf20Sopenharmony_ci struct blogic_bios_drvmap d0_mapbyte; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci while (probeinfo->adapter_bus_type != 10468c2ecf20Sopenharmony_ci BLOGIC_PCI_BUS) 10478c2ecf20Sopenharmony_ci probeinfo++; 10488c2ecf20Sopenharmony_ci myadapter->io_addr = probeinfo->io_addr; 10498c2ecf20Sopenharmony_ci fetch_localram.offset = 10508c2ecf20Sopenharmony_ci BLOGIC_BIOS_BASE + BLOGIC_BIOS_DRVMAP; 10518c2ecf20Sopenharmony_ci fetch_localram.count = sizeof(d0_mapbyte); 10528c2ecf20Sopenharmony_ci blogic_cmd(myadapter, BLOGIC_FETCH_LOCALRAM, 10538c2ecf20Sopenharmony_ci &fetch_localram, 10548c2ecf20Sopenharmony_ci sizeof(fetch_localram), 10558c2ecf20Sopenharmony_ci &d0_mapbyte, 10568c2ecf20Sopenharmony_ci sizeof(d0_mapbyte)); 10578c2ecf20Sopenharmony_ci /* 10588c2ecf20Sopenharmony_ci If the Map Byte for BIOS Drive 0 indicates 10598c2ecf20Sopenharmony_ci that BIOS Drive 0 is controlled by this 10608c2ecf20Sopenharmony_ci PCI MultiMaster Host Adapter, then reverse 10618c2ecf20Sopenharmony_ci the probe order so that MultiMaster Host 10628c2ecf20Sopenharmony_ci Adapters are probed before FlashPoint Host 10638c2ecf20Sopenharmony_ci Adapters. 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci if (d0_mapbyte.diskgeom != BLOGIC_BIOS_NODISK) { 10668c2ecf20Sopenharmony_ci struct blogic_probeinfo saved_probeinfo[BLOGIC_MAX_ADAPTERS]; 10678c2ecf20Sopenharmony_ci int mmcount = blogic_probeinfo_count - fpcount; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci memcpy(saved_probeinfo, 10708c2ecf20Sopenharmony_ci blogic_probeinfo_list, 10718c2ecf20Sopenharmony_ci blogic_probeinfo_count * sizeof(struct blogic_probeinfo)); 10728c2ecf20Sopenharmony_ci memcpy(&blogic_probeinfo_list[0], 10738c2ecf20Sopenharmony_ci &saved_probeinfo[fpcount], 10748c2ecf20Sopenharmony_ci mmcount * sizeof(struct blogic_probeinfo)); 10758c2ecf20Sopenharmony_ci memcpy(&blogic_probeinfo_list[mmcount], 10768c2ecf20Sopenharmony_ci &saved_probeinfo[0], 10778c2ecf20Sopenharmony_ci fpcount * sizeof(struct blogic_probeinfo)); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci } else { 10828c2ecf20Sopenharmony_ci blogic_init_probeinfo_isa(adapter); 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci#else 10888c2ecf20Sopenharmony_ci#define blogic_init_probeinfo_list(adapter) \ 10898c2ecf20Sopenharmony_ci blogic_init_probeinfo_isa(adapter) 10908c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci/* 10948c2ecf20Sopenharmony_ci blogic_failure prints a standardized error message, and then returns false. 10958c2ecf20Sopenharmony_ci*/ 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic bool blogic_failure(struct blogic_adapter *adapter, char *msg) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci blogic_announce_drvr(adapter); 11008c2ecf20Sopenharmony_ci if (adapter->adapter_bus_type == BLOGIC_PCI_BUS) { 11018c2ecf20Sopenharmony_ci blogic_err("While configuring BusLogic PCI Host Adapter at\n", 11028c2ecf20Sopenharmony_ci adapter); 11038c2ecf20Sopenharmony_ci blogic_err("Bus %d Device %d I/O Address 0x%lX PCI Address 0x%lX:\n", adapter, adapter->bus, adapter->dev, adapter->io_addr, adapter->pci_addr); 11048c2ecf20Sopenharmony_ci } else 11058c2ecf20Sopenharmony_ci blogic_err("While configuring BusLogic Host Adapter at I/O Address 0x%lX:\n", adapter, adapter->io_addr); 11068c2ecf20Sopenharmony_ci blogic_err("%s FAILED - DETACHING\n", adapter, msg); 11078c2ecf20Sopenharmony_ci if (blogic_cmd_failure_reason != NULL) 11088c2ecf20Sopenharmony_ci blogic_err("ADDITIONAL FAILURE INFO - %s\n", adapter, 11098c2ecf20Sopenharmony_ci blogic_cmd_failure_reason); 11108c2ecf20Sopenharmony_ci return false; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci/* 11158c2ecf20Sopenharmony_ci blogic_probe probes for a BusLogic Host Adapter. 11168c2ecf20Sopenharmony_ci*/ 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic bool __init blogic_probe(struct blogic_adapter *adapter) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci union blogic_stat_reg statusreg; 11218c2ecf20Sopenharmony_ci union blogic_int_reg intreg; 11228c2ecf20Sopenharmony_ci union blogic_geo_reg georeg; 11238c2ecf20Sopenharmony_ci /* 11248c2ecf20Sopenharmony_ci FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) { 11278c2ecf20Sopenharmony_ci struct fpoint_info *fpinfo = &adapter->fpinfo; 11288c2ecf20Sopenharmony_ci fpinfo->base_addr = (u32) adapter->io_addr; 11298c2ecf20Sopenharmony_ci fpinfo->irq_ch = adapter->irq_ch; 11308c2ecf20Sopenharmony_ci fpinfo->present = false; 11318c2ecf20Sopenharmony_ci if (!(FlashPoint_ProbeHostAdapter(fpinfo) == 0 && 11328c2ecf20Sopenharmony_ci fpinfo->present)) { 11338c2ecf20Sopenharmony_ci blogic_err("BusLogic: FlashPoint Host Adapter detected at PCI Bus %d Device %d\n", adapter, adapter->bus, adapter->dev); 11348c2ecf20Sopenharmony_ci blogic_err("BusLogic: I/O Address 0x%lX PCI Address 0x%lX, but FlashPoint\n", adapter, adapter->io_addr, adapter->pci_addr); 11358c2ecf20Sopenharmony_ci blogic_err("BusLogic: Probe Function failed to validate it.\n", adapter); 11368c2ecf20Sopenharmony_ci return false; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci if (blogic_global_options.trace_probe) 11398c2ecf20Sopenharmony_ci blogic_notice("BusLogic_Probe(0x%lX): FlashPoint Found\n", adapter, adapter->io_addr); 11408c2ecf20Sopenharmony_ci /* 11418c2ecf20Sopenharmony_ci Indicate the Host Adapter Probe completed successfully. 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ci return true; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci Read the Status, Interrupt, and Geometry Registers to test if there are I/O 11478c2ecf20Sopenharmony_ci ports that respond, and to check the values to determine if they are from a 11488c2ecf20Sopenharmony_ci BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which 11498c2ecf20Sopenharmony_ci case there is definitely no BusLogic Host Adapter at this base I/O Address. 11508c2ecf20Sopenharmony_ci The test here is a subset of that used by the BusLogic Host Adapter BIOS. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 11538c2ecf20Sopenharmony_ci intreg.all = blogic_rdint(adapter); 11548c2ecf20Sopenharmony_ci georeg.all = blogic_rdgeom(adapter); 11558c2ecf20Sopenharmony_ci if (blogic_global_options.trace_probe) 11568c2ecf20Sopenharmony_ci blogic_notice("BusLogic_Probe(0x%lX): Status 0x%02X, Interrupt 0x%02X, Geometry 0x%02X\n", adapter, adapter->io_addr, statusreg.all, intreg.all, georeg.all); 11578c2ecf20Sopenharmony_ci if (statusreg.all == 0 || statusreg.sr.diag_active || 11588c2ecf20Sopenharmony_ci statusreg.sr.cmd_param_busy || statusreg.sr.rsvd || 11598c2ecf20Sopenharmony_ci statusreg.sr.cmd_invalid || intreg.ir.rsvd != 0) 11608c2ecf20Sopenharmony_ci return false; 11618c2ecf20Sopenharmony_ci /* 11628c2ecf20Sopenharmony_ci Check the undocumented Geometry Register to test if there is 11638c2ecf20Sopenharmony_ci an I/O port that responded. Adaptec Host Adapters do not 11648c2ecf20Sopenharmony_ci implement the Geometry Register, so this test helps serve to 11658c2ecf20Sopenharmony_ci avoid incorrectly recognizing an Adaptec 1542A or 1542B as a 11668c2ecf20Sopenharmony_ci BusLogic. Unfortunately, the Adaptec 1542C series does respond 11678c2ecf20Sopenharmony_ci to the Geometry Register I/O port, but it will be rejected 11688c2ecf20Sopenharmony_ci later when the Inquire Extended Setup Information command is 11698c2ecf20Sopenharmony_ci issued in blogic_checkadapter. The AMI FastDisk Host Adapter 11708c2ecf20Sopenharmony_ci is a BusLogic clone that implements the same interface as 11718c2ecf20Sopenharmony_ci earlier BusLogic Host Adapters, including the undocumented 11728c2ecf20Sopenharmony_ci commands, and is therefore supported by this driver. However, 11738c2ecf20Sopenharmony_ci the AMI FastDisk always returns 0x00 upon reading the Geometry 11748c2ecf20Sopenharmony_ci Register, so the extended translation option should always be 11758c2ecf20Sopenharmony_ci left disabled on the AMI FastDisk. 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_ci if (georeg.all == 0xFF) 11788c2ecf20Sopenharmony_ci return false; 11798c2ecf20Sopenharmony_ci /* 11808c2ecf20Sopenharmony_ci Indicate the Host Adapter Probe completed successfully. 11818c2ecf20Sopenharmony_ci */ 11828c2ecf20Sopenharmony_ci return true; 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci/* 11878c2ecf20Sopenharmony_ci blogic_hwreset issues a Hardware Reset to the Host Adapter 11888c2ecf20Sopenharmony_ci and waits for Host Adapter Diagnostics to complete. If hard_reset is true, a 11898c2ecf20Sopenharmony_ci Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a 11908c2ecf20Sopenharmony_ci Soft Reset is performed which only resets the Host Adapter without forcing a 11918c2ecf20Sopenharmony_ci SCSI Bus Reset. 11928c2ecf20Sopenharmony_ci*/ 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic bool blogic_hwreset(struct blogic_adapter *adapter, bool hard_reset) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci union blogic_stat_reg statusreg; 11978c2ecf20Sopenharmony_ci int timeout; 11988c2ecf20Sopenharmony_ci /* 11998c2ecf20Sopenharmony_ci FlashPoint Host Adapters are Hard Reset by the FlashPoint 12008c2ecf20Sopenharmony_ci SCCB Manager. 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) { 12038c2ecf20Sopenharmony_ci struct fpoint_info *fpinfo = &adapter->fpinfo; 12048c2ecf20Sopenharmony_ci fpinfo->softreset = !hard_reset; 12058c2ecf20Sopenharmony_ci fpinfo->report_underrun = true; 12068c2ecf20Sopenharmony_ci adapter->cardhandle = 12078c2ecf20Sopenharmony_ci FlashPoint_HardwareResetHostAdapter(fpinfo); 12088c2ecf20Sopenharmony_ci if (adapter->cardhandle == (void *)FPOINT_BADCARD_HANDLE) 12098c2ecf20Sopenharmony_ci return false; 12108c2ecf20Sopenharmony_ci /* 12118c2ecf20Sopenharmony_ci Indicate the Host Adapter Hard Reset completed successfully. 12128c2ecf20Sopenharmony_ci */ 12138c2ecf20Sopenharmony_ci return true; 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci /* 12168c2ecf20Sopenharmony_ci Issue a Hard Reset or Soft Reset Command to the Host Adapter. 12178c2ecf20Sopenharmony_ci The Host Adapter should respond by setting Diagnostic Active in 12188c2ecf20Sopenharmony_ci the Status Register. 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ci if (hard_reset) 12218c2ecf20Sopenharmony_ci blogic_hardreset(adapter); 12228c2ecf20Sopenharmony_ci else 12238c2ecf20Sopenharmony_ci blogic_softreset(adapter); 12248c2ecf20Sopenharmony_ci /* 12258c2ecf20Sopenharmony_ci Wait until Diagnostic Active is set in the Status Register. 12268c2ecf20Sopenharmony_ci */ 12278c2ecf20Sopenharmony_ci timeout = 5 * 10000; 12288c2ecf20Sopenharmony_ci while (--timeout >= 0) { 12298c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 12308c2ecf20Sopenharmony_ci if (statusreg.sr.diag_active) 12318c2ecf20Sopenharmony_ci break; 12328c2ecf20Sopenharmony_ci udelay(100); 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci if (blogic_global_options.trace_hw_reset) 12358c2ecf20Sopenharmony_ci blogic_notice("BusLogic_HardwareReset(0x%lX): Diagnostic Active, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all); 12368c2ecf20Sopenharmony_ci if (timeout < 0) 12378c2ecf20Sopenharmony_ci return false; 12388c2ecf20Sopenharmony_ci /* 12398c2ecf20Sopenharmony_ci Wait 100 microseconds to allow completion of any initial diagnostic 12408c2ecf20Sopenharmony_ci activity which might leave the contents of the Status Register 12418c2ecf20Sopenharmony_ci unpredictable. 12428c2ecf20Sopenharmony_ci */ 12438c2ecf20Sopenharmony_ci udelay(100); 12448c2ecf20Sopenharmony_ci /* 12458c2ecf20Sopenharmony_ci Wait until Diagnostic Active is reset in the Status Register. 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci timeout = 10 * 10000; 12488c2ecf20Sopenharmony_ci while (--timeout >= 0) { 12498c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 12508c2ecf20Sopenharmony_ci if (!statusreg.sr.diag_active) 12518c2ecf20Sopenharmony_ci break; 12528c2ecf20Sopenharmony_ci udelay(100); 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci if (blogic_global_options.trace_hw_reset) 12558c2ecf20Sopenharmony_ci blogic_notice("BusLogic_HardwareReset(0x%lX): Diagnostic Completed, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all); 12568c2ecf20Sopenharmony_ci if (timeout < 0) 12578c2ecf20Sopenharmony_ci return false; 12588c2ecf20Sopenharmony_ci /* 12598c2ecf20Sopenharmony_ci Wait until at least one of the Diagnostic Failure, Host Adapter 12608c2ecf20Sopenharmony_ci Ready, or Data In Register Ready bits is set in the Status Register. 12618c2ecf20Sopenharmony_ci */ 12628c2ecf20Sopenharmony_ci timeout = 10000; 12638c2ecf20Sopenharmony_ci while (--timeout >= 0) { 12648c2ecf20Sopenharmony_ci statusreg.all = blogic_rdstatus(adapter); 12658c2ecf20Sopenharmony_ci if (statusreg.sr.diag_failed || statusreg.sr.adapter_ready || 12668c2ecf20Sopenharmony_ci statusreg.sr.datain_ready) 12678c2ecf20Sopenharmony_ci break; 12688c2ecf20Sopenharmony_ci udelay(100); 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci if (blogic_global_options.trace_hw_reset) 12718c2ecf20Sopenharmony_ci blogic_notice("BusLogic_HardwareReset(0x%lX): Host Adapter Ready, Status 0x%02X\n", adapter, adapter->io_addr, statusreg.all); 12728c2ecf20Sopenharmony_ci if (timeout < 0) 12738c2ecf20Sopenharmony_ci return false; 12748c2ecf20Sopenharmony_ci /* 12758c2ecf20Sopenharmony_ci If Diagnostic Failure is set or Host Adapter Ready is reset, 12768c2ecf20Sopenharmony_ci then an error occurred during the Host Adapter diagnostics. 12778c2ecf20Sopenharmony_ci If Data In Register Ready is set, then there is an Error Code 12788c2ecf20Sopenharmony_ci available. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci if (statusreg.sr.diag_failed || !statusreg.sr.adapter_ready) { 12818c2ecf20Sopenharmony_ci blogic_cmd_failure_reason = NULL; 12828c2ecf20Sopenharmony_ci blogic_failure(adapter, "HARD RESET DIAGNOSTICS"); 12838c2ecf20Sopenharmony_ci blogic_err("HOST ADAPTER STATUS REGISTER = %02X\n", adapter, 12848c2ecf20Sopenharmony_ci statusreg.all); 12858c2ecf20Sopenharmony_ci if (statusreg.sr.datain_ready) 12868c2ecf20Sopenharmony_ci blogic_err("HOST ADAPTER ERROR CODE = %d\n", adapter, 12878c2ecf20Sopenharmony_ci blogic_rddatain(adapter)); 12888c2ecf20Sopenharmony_ci return false; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci /* 12918c2ecf20Sopenharmony_ci Indicate the Host Adapter Hard Reset completed successfully. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci return true; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci/* 12988c2ecf20Sopenharmony_ci blogic_checkadapter checks to be sure this really is a BusLogic 12998c2ecf20Sopenharmony_ci Host Adapter. 13008c2ecf20Sopenharmony_ci*/ 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic bool __init blogic_checkadapter(struct blogic_adapter *adapter) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci struct blogic_ext_setup ext_setupinfo; 13058c2ecf20Sopenharmony_ci unsigned char req_replylen; 13068c2ecf20Sopenharmony_ci bool result = true; 13078c2ecf20Sopenharmony_ci /* 13088c2ecf20Sopenharmony_ci FlashPoint Host Adapters do not require this protection. 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) 13118c2ecf20Sopenharmony_ci return true; 13128c2ecf20Sopenharmony_ci /* 13138c2ecf20Sopenharmony_ci Issue the Inquire Extended Setup Information command. Only genuine 13148c2ecf20Sopenharmony_ci BusLogic Host Adapters and true clones support this command. 13158c2ecf20Sopenharmony_ci Adaptec 1542C series Host Adapters that respond to the Geometry 13168c2ecf20Sopenharmony_ci Register I/O port will fail this command. 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci req_replylen = sizeof(ext_setupinfo); 13198c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_EXTSETUP, &req_replylen, 13208c2ecf20Sopenharmony_ci sizeof(req_replylen), &ext_setupinfo, 13218c2ecf20Sopenharmony_ci sizeof(ext_setupinfo)) != sizeof(ext_setupinfo)) 13228c2ecf20Sopenharmony_ci result = false; 13238c2ecf20Sopenharmony_ci /* 13248c2ecf20Sopenharmony_ci Provide tracing information if requested and return. 13258c2ecf20Sopenharmony_ci */ 13268c2ecf20Sopenharmony_ci if (blogic_global_options.trace_probe) 13278c2ecf20Sopenharmony_ci blogic_notice("BusLogic_Check(0x%lX): MultiMaster %s\n", adapter, 13288c2ecf20Sopenharmony_ci adapter->io_addr, 13298c2ecf20Sopenharmony_ci (result ? "Found" : "Not Found")); 13308c2ecf20Sopenharmony_ci return result; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci/* 13358c2ecf20Sopenharmony_ci blogic_rdconfig reads the Configuration Information 13368c2ecf20Sopenharmony_ci from Host Adapter and initializes the Host Adapter structure. 13378c2ecf20Sopenharmony_ci*/ 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic bool __init blogic_rdconfig(struct blogic_adapter *adapter) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci struct blogic_board_id id; 13428c2ecf20Sopenharmony_ci struct blogic_config config; 13438c2ecf20Sopenharmony_ci struct blogic_setup_info setupinfo; 13448c2ecf20Sopenharmony_ci struct blogic_ext_setup ext_setupinfo; 13458c2ecf20Sopenharmony_ci unsigned char model[5]; 13468c2ecf20Sopenharmony_ci unsigned char fw_ver_digit3; 13478c2ecf20Sopenharmony_ci unsigned char fw_ver_letter; 13488c2ecf20Sopenharmony_ci struct blogic_adapter_info adapter_info; 13498c2ecf20Sopenharmony_ci struct blogic_fetch_localram fetch_localram; 13508c2ecf20Sopenharmony_ci struct blogic_autoscsi autoscsi; 13518c2ecf20Sopenharmony_ci union blogic_geo_reg georeg; 13528c2ecf20Sopenharmony_ci unsigned char req_replylen; 13538c2ecf20Sopenharmony_ci unsigned char *tgt, ch; 13548c2ecf20Sopenharmony_ci int tgt_id, i; 13558c2ecf20Sopenharmony_ci /* 13568c2ecf20Sopenharmony_ci Configuration Information for FlashPoint Host Adapters is 13578c2ecf20Sopenharmony_ci provided in the fpoint_info structure by the FlashPoint 13588c2ecf20Sopenharmony_ci SCCB Manager's Probe Function. Initialize fields in the 13598c2ecf20Sopenharmony_ci Host Adapter structure from the fpoint_info structure. 13608c2ecf20Sopenharmony_ci */ 13618c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) { 13628c2ecf20Sopenharmony_ci struct fpoint_info *fpinfo = &adapter->fpinfo; 13638c2ecf20Sopenharmony_ci tgt = adapter->model; 13648c2ecf20Sopenharmony_ci *tgt++ = 'B'; 13658c2ecf20Sopenharmony_ci *tgt++ = 'T'; 13668c2ecf20Sopenharmony_ci *tgt++ = '-'; 13678c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(fpinfo->model); i++) 13688c2ecf20Sopenharmony_ci *tgt++ = fpinfo->model[i]; 13698c2ecf20Sopenharmony_ci *tgt++ = '\0'; 13708c2ecf20Sopenharmony_ci strcpy(adapter->fw_ver, FLASHPOINT_FW_VER); 13718c2ecf20Sopenharmony_ci adapter->scsi_id = fpinfo->scsi_id; 13728c2ecf20Sopenharmony_ci adapter->ext_trans_enable = fpinfo->ext_trans_enable; 13738c2ecf20Sopenharmony_ci adapter->parity = fpinfo->parity; 13748c2ecf20Sopenharmony_ci adapter->reset_enabled = !fpinfo->softreset; 13758c2ecf20Sopenharmony_ci adapter->level_int = true; 13768c2ecf20Sopenharmony_ci adapter->wide = fpinfo->wide; 13778c2ecf20Sopenharmony_ci adapter->differential = false; 13788c2ecf20Sopenharmony_ci adapter->scam = true; 13798c2ecf20Sopenharmony_ci adapter->ultra = true; 13808c2ecf20Sopenharmony_ci adapter->ext_lun = true; 13818c2ecf20Sopenharmony_ci adapter->terminfo_valid = true; 13828c2ecf20Sopenharmony_ci adapter->low_term = fpinfo->low_term; 13838c2ecf20Sopenharmony_ci adapter->high_term = fpinfo->high_term; 13848c2ecf20Sopenharmony_ci adapter->scam_enabled = fpinfo->scam_enabled; 13858c2ecf20Sopenharmony_ci adapter->scam_lev2 = fpinfo->scam_lev2; 13868c2ecf20Sopenharmony_ci adapter->drvr_sglimit = BLOGIC_SG_LIMIT; 13878c2ecf20Sopenharmony_ci adapter->maxdev = (adapter->wide ? 16 : 8); 13888c2ecf20Sopenharmony_ci adapter->maxlun = 32; 13898c2ecf20Sopenharmony_ci adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE; 13908c2ecf20Sopenharmony_ci adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE; 13918c2ecf20Sopenharmony_ci adapter->drvr_qdepth = 255; 13928c2ecf20Sopenharmony_ci adapter->adapter_qdepth = adapter->drvr_qdepth; 13938c2ecf20Sopenharmony_ci adapter->sync_ok = fpinfo->sync_ok; 13948c2ecf20Sopenharmony_ci adapter->fast_ok = fpinfo->fast_ok; 13958c2ecf20Sopenharmony_ci adapter->ultra_ok = fpinfo->ultra_ok; 13968c2ecf20Sopenharmony_ci adapter->wide_ok = fpinfo->wide_ok; 13978c2ecf20Sopenharmony_ci adapter->discon_ok = fpinfo->discon_ok; 13988c2ecf20Sopenharmony_ci adapter->tagq_ok = 0xFFFF; 13998c2ecf20Sopenharmony_ci goto common; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci /* 14028c2ecf20Sopenharmony_ci Issue the Inquire Board ID command. 14038c2ecf20Sopenharmony_ci */ 14048c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_GET_BOARD_ID, NULL, 0, &id, 14058c2ecf20Sopenharmony_ci sizeof(id)) != sizeof(id)) 14068c2ecf20Sopenharmony_ci return blogic_failure(adapter, "INQUIRE BOARD ID"); 14078c2ecf20Sopenharmony_ci /* 14088c2ecf20Sopenharmony_ci Issue the Inquire Configuration command. 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_CONFIG, NULL, 0, &config, 14118c2ecf20Sopenharmony_ci sizeof(config)) 14128c2ecf20Sopenharmony_ci != sizeof(config)) 14138c2ecf20Sopenharmony_ci return blogic_failure(adapter, "INQUIRE CONFIGURATION"); 14148c2ecf20Sopenharmony_ci /* 14158c2ecf20Sopenharmony_ci Issue the Inquire Setup Information command. 14168c2ecf20Sopenharmony_ci */ 14178c2ecf20Sopenharmony_ci req_replylen = sizeof(setupinfo); 14188c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_SETUPINFO, &req_replylen, 14198c2ecf20Sopenharmony_ci sizeof(req_replylen), &setupinfo, 14208c2ecf20Sopenharmony_ci sizeof(setupinfo)) != sizeof(setupinfo)) 14218c2ecf20Sopenharmony_ci return blogic_failure(adapter, "INQUIRE SETUP INFORMATION"); 14228c2ecf20Sopenharmony_ci /* 14238c2ecf20Sopenharmony_ci Issue the Inquire Extended Setup Information command. 14248c2ecf20Sopenharmony_ci */ 14258c2ecf20Sopenharmony_ci req_replylen = sizeof(ext_setupinfo); 14268c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_EXTSETUP, &req_replylen, 14278c2ecf20Sopenharmony_ci sizeof(req_replylen), &ext_setupinfo, 14288c2ecf20Sopenharmony_ci sizeof(ext_setupinfo)) != sizeof(ext_setupinfo)) 14298c2ecf20Sopenharmony_ci return blogic_failure(adapter, 14308c2ecf20Sopenharmony_ci "INQUIRE EXTENDED SETUP INFORMATION"); 14318c2ecf20Sopenharmony_ci /* 14328c2ecf20Sopenharmony_ci Issue the Inquire Firmware Version 3rd Digit command. 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci fw_ver_digit3 = '\0'; 14358c2ecf20Sopenharmony_ci if (id.fw_ver_digit1 > '0') 14368c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_D3, NULL, 0, 14378c2ecf20Sopenharmony_ci &fw_ver_digit3, 14388c2ecf20Sopenharmony_ci sizeof(fw_ver_digit3)) != sizeof(fw_ver_digit3)) 14398c2ecf20Sopenharmony_ci return blogic_failure(adapter, 14408c2ecf20Sopenharmony_ci "INQUIRE FIRMWARE 3RD DIGIT"); 14418c2ecf20Sopenharmony_ci /* 14428c2ecf20Sopenharmony_ci Issue the Inquire Host Adapter Model Number command. 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci if (ext_setupinfo.bus_type == 'A' && id.fw_ver_digit1 == '2') 14458c2ecf20Sopenharmony_ci /* BusLogic BT-542B ISA 2.xx */ 14468c2ecf20Sopenharmony_ci strcpy(model, "542B"); 14478c2ecf20Sopenharmony_ci else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '2' && 14488c2ecf20Sopenharmony_ci (id.fw_ver_digit2 <= '1' || (id.fw_ver_digit2 == '2' && 14498c2ecf20Sopenharmony_ci fw_ver_digit3 == '0'))) 14508c2ecf20Sopenharmony_ci /* BusLogic BT-742A EISA 2.1x or 2.20 */ 14518c2ecf20Sopenharmony_ci strcpy(model, "742A"); 14528c2ecf20Sopenharmony_ci else if (ext_setupinfo.bus_type == 'E' && id.fw_ver_digit1 == '0') 14538c2ecf20Sopenharmony_ci /* AMI FastDisk EISA Series 441 0.x */ 14548c2ecf20Sopenharmony_ci strcpy(model, "747A"); 14558c2ecf20Sopenharmony_ci else { 14568c2ecf20Sopenharmony_ci req_replylen = sizeof(model); 14578c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_MODELNO, &req_replylen, 14588c2ecf20Sopenharmony_ci sizeof(req_replylen), &model, 14598c2ecf20Sopenharmony_ci sizeof(model)) != sizeof(model)) 14608c2ecf20Sopenharmony_ci return blogic_failure(adapter, 14618c2ecf20Sopenharmony_ci "INQUIRE HOST ADAPTER MODEL NUMBER"); 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci /* 14648c2ecf20Sopenharmony_ci BusLogic MultiMaster Host Adapters can be identified by their 14658c2ecf20Sopenharmony_ci model number and the major version number of their firmware 14668c2ecf20Sopenharmony_ci as follows: 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci 5.xx BusLogic "W" Series Host Adapters: 14698c2ecf20Sopenharmony_ci BT-948/958/958D 14708c2ecf20Sopenharmony_ci 4.xx BusLogic "C" Series Host Adapters: 14718c2ecf20Sopenharmony_ci BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF 14728c2ecf20Sopenharmony_ci 3.xx BusLogic "S" Series Host Adapters: 14738c2ecf20Sopenharmony_ci BT-747S/747D/757S/757D/445S/545S/542D 14748c2ecf20Sopenharmony_ci BT-542B/742A (revision H) 14758c2ecf20Sopenharmony_ci 2.xx BusLogic "A" Series Host Adapters: 14768c2ecf20Sopenharmony_ci BT-542B/742A (revision G and below) 14778c2ecf20Sopenharmony_ci 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter 14788c2ecf20Sopenharmony_ci */ 14798c2ecf20Sopenharmony_ci /* 14808c2ecf20Sopenharmony_ci Save the Model Name and Host Adapter Name in the Host Adapter 14818c2ecf20Sopenharmony_ci structure. 14828c2ecf20Sopenharmony_ci */ 14838c2ecf20Sopenharmony_ci tgt = adapter->model; 14848c2ecf20Sopenharmony_ci *tgt++ = 'B'; 14858c2ecf20Sopenharmony_ci *tgt++ = 'T'; 14868c2ecf20Sopenharmony_ci *tgt++ = '-'; 14878c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(model); i++) { 14888c2ecf20Sopenharmony_ci ch = model[i]; 14898c2ecf20Sopenharmony_ci if (ch == ' ' || ch == '\0') 14908c2ecf20Sopenharmony_ci break; 14918c2ecf20Sopenharmony_ci *tgt++ = ch; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci *tgt++ = '\0'; 14948c2ecf20Sopenharmony_ci /* 14958c2ecf20Sopenharmony_ci Save the Firmware Version in the Host Adapter structure. 14968c2ecf20Sopenharmony_ci */ 14978c2ecf20Sopenharmony_ci tgt = adapter->fw_ver; 14988c2ecf20Sopenharmony_ci *tgt++ = id.fw_ver_digit1; 14998c2ecf20Sopenharmony_ci *tgt++ = '.'; 15008c2ecf20Sopenharmony_ci *tgt++ = id.fw_ver_digit2; 15018c2ecf20Sopenharmony_ci if (fw_ver_digit3 != ' ' && fw_ver_digit3 != '\0') 15028c2ecf20Sopenharmony_ci *tgt++ = fw_ver_digit3; 15038c2ecf20Sopenharmony_ci *tgt = '\0'; 15048c2ecf20Sopenharmony_ci /* 15058c2ecf20Sopenharmony_ci Issue the Inquire Firmware Version Letter command. 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "3.3") >= 0) { 15088c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_FWVER_LETTER, NULL, 0, 15098c2ecf20Sopenharmony_ci &fw_ver_letter, 15108c2ecf20Sopenharmony_ci sizeof(fw_ver_letter)) != sizeof(fw_ver_letter)) 15118c2ecf20Sopenharmony_ci return blogic_failure(adapter, 15128c2ecf20Sopenharmony_ci "INQUIRE FIRMWARE VERSION LETTER"); 15138c2ecf20Sopenharmony_ci if (fw_ver_letter != ' ' && fw_ver_letter != '\0') 15148c2ecf20Sopenharmony_ci *tgt++ = fw_ver_letter; 15158c2ecf20Sopenharmony_ci *tgt = '\0'; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci /* 15188c2ecf20Sopenharmony_ci Save the Host Adapter SCSI ID in the Host Adapter structure. 15198c2ecf20Sopenharmony_ci */ 15208c2ecf20Sopenharmony_ci adapter->scsi_id = config.id; 15218c2ecf20Sopenharmony_ci /* 15228c2ecf20Sopenharmony_ci Determine the Bus Type and save it in the Host Adapter structure, 15238c2ecf20Sopenharmony_ci determine and save the IRQ Channel if necessary, and determine 15248c2ecf20Sopenharmony_ci and save the DMA Channel for ISA Host Adapters. 15258c2ecf20Sopenharmony_ci */ 15268c2ecf20Sopenharmony_ci adapter->adapter_bus_type = 15278c2ecf20Sopenharmony_ci blogic_adater_bus_types[adapter->model[3] - '4']; 15288c2ecf20Sopenharmony_ci if (adapter->irq_ch == 0) { 15298c2ecf20Sopenharmony_ci if (config.irq_ch9) 15308c2ecf20Sopenharmony_ci adapter->irq_ch = 9; 15318c2ecf20Sopenharmony_ci else if (config.irq_ch10) 15328c2ecf20Sopenharmony_ci adapter->irq_ch = 10; 15338c2ecf20Sopenharmony_ci else if (config.irq_ch11) 15348c2ecf20Sopenharmony_ci adapter->irq_ch = 11; 15358c2ecf20Sopenharmony_ci else if (config.irq_ch12) 15368c2ecf20Sopenharmony_ci adapter->irq_ch = 12; 15378c2ecf20Sopenharmony_ci else if (config.irq_ch14) 15388c2ecf20Sopenharmony_ci adapter->irq_ch = 14; 15398c2ecf20Sopenharmony_ci else if (config.irq_ch15) 15408c2ecf20Sopenharmony_ci adapter->irq_ch = 15; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci if (adapter->adapter_bus_type == BLOGIC_ISA_BUS) { 15438c2ecf20Sopenharmony_ci if (config.dma_ch5) 15448c2ecf20Sopenharmony_ci adapter->dma_ch = 5; 15458c2ecf20Sopenharmony_ci else if (config.dma_ch6) 15468c2ecf20Sopenharmony_ci adapter->dma_ch = 6; 15478c2ecf20Sopenharmony_ci else if (config.dma_ch7) 15488c2ecf20Sopenharmony_ci adapter->dma_ch = 7; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci /* 15518c2ecf20Sopenharmony_ci Determine whether Extended Translation is enabled and save it in 15528c2ecf20Sopenharmony_ci the Host Adapter structure. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci georeg.all = blogic_rdgeom(adapter); 15558c2ecf20Sopenharmony_ci adapter->ext_trans_enable = georeg.gr.ext_trans_enable; 15568c2ecf20Sopenharmony_ci /* 15578c2ecf20Sopenharmony_ci Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide 15588c2ecf20Sopenharmony_ci SCSI flag, Differential SCSI flag, SCAM Supported flag, and 15598c2ecf20Sopenharmony_ci Ultra SCSI flag in the Host Adapter structure. 15608c2ecf20Sopenharmony_ci */ 15618c2ecf20Sopenharmony_ci adapter->adapter_sglimit = ext_setupinfo.sg_limit; 15628c2ecf20Sopenharmony_ci adapter->drvr_sglimit = adapter->adapter_sglimit; 15638c2ecf20Sopenharmony_ci if (adapter->adapter_sglimit > BLOGIC_SG_LIMIT) 15648c2ecf20Sopenharmony_ci adapter->drvr_sglimit = BLOGIC_SG_LIMIT; 15658c2ecf20Sopenharmony_ci if (ext_setupinfo.misc.level_int) 15668c2ecf20Sopenharmony_ci adapter->level_int = true; 15678c2ecf20Sopenharmony_ci adapter->wide = ext_setupinfo.wide; 15688c2ecf20Sopenharmony_ci adapter->differential = ext_setupinfo.differential; 15698c2ecf20Sopenharmony_ci adapter->scam = ext_setupinfo.scam; 15708c2ecf20Sopenharmony_ci adapter->ultra = ext_setupinfo.ultra; 15718c2ecf20Sopenharmony_ci /* 15728c2ecf20Sopenharmony_ci Determine whether Extended LUN Format CCBs are supported and save the 15738c2ecf20Sopenharmony_ci information in the Host Adapter structure. 15748c2ecf20Sopenharmony_ci */ 15758c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] == '5' || (adapter->fw_ver[0] == '4' && 15768c2ecf20Sopenharmony_ci adapter->wide)) 15778c2ecf20Sopenharmony_ci adapter->ext_lun = true; 15788c2ecf20Sopenharmony_ci /* 15798c2ecf20Sopenharmony_ci Issue the Inquire PCI Host Adapter Information command to read the 15808c2ecf20Sopenharmony_ci Termination Information from "W" series MultiMaster Host Adapters. 15818c2ecf20Sopenharmony_ci */ 15828c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] == '5') { 15838c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_PCI_INFO, NULL, 0, 15848c2ecf20Sopenharmony_ci &adapter_info, 15858c2ecf20Sopenharmony_ci sizeof(adapter_info)) != sizeof(adapter_info)) 15868c2ecf20Sopenharmony_ci return blogic_failure(adapter, 15878c2ecf20Sopenharmony_ci "INQUIRE PCI HOST ADAPTER INFORMATION"); 15888c2ecf20Sopenharmony_ci /* 15898c2ecf20Sopenharmony_ci Save the Termination Information in the Host Adapter 15908c2ecf20Sopenharmony_ci structure. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_ci if (adapter_info.genericinfo_valid) { 15938c2ecf20Sopenharmony_ci adapter->terminfo_valid = true; 15948c2ecf20Sopenharmony_ci adapter->low_term = adapter_info.low_term; 15958c2ecf20Sopenharmony_ci adapter->high_term = adapter_info.high_term; 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci /* 15998c2ecf20Sopenharmony_ci Issue the Fetch Host Adapter Local RAM command to read the 16008c2ecf20Sopenharmony_ci AutoSCSI data from "W" and "C" series MultiMaster Host Adapters. 16018c2ecf20Sopenharmony_ci */ 16028c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] >= '4') { 16038c2ecf20Sopenharmony_ci fetch_localram.offset = BLOGIC_AUTOSCSI_BASE; 16048c2ecf20Sopenharmony_ci fetch_localram.count = sizeof(autoscsi); 16058c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_FETCH_LOCALRAM, &fetch_localram, 16068c2ecf20Sopenharmony_ci sizeof(fetch_localram), &autoscsi, 16078c2ecf20Sopenharmony_ci sizeof(autoscsi)) != sizeof(autoscsi)) 16088c2ecf20Sopenharmony_ci return blogic_failure(adapter, 16098c2ecf20Sopenharmony_ci "FETCH HOST ADAPTER LOCAL RAM"); 16108c2ecf20Sopenharmony_ci /* 16118c2ecf20Sopenharmony_ci Save the Parity Checking Enabled, Bus Reset Enabled, 16128c2ecf20Sopenharmony_ci and Termination Information in the Host Adapter structure. 16138c2ecf20Sopenharmony_ci */ 16148c2ecf20Sopenharmony_ci adapter->parity = autoscsi.parity; 16158c2ecf20Sopenharmony_ci adapter->reset_enabled = autoscsi.reset_enabled; 16168c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] == '4') { 16178c2ecf20Sopenharmony_ci adapter->terminfo_valid = true; 16188c2ecf20Sopenharmony_ci adapter->low_term = autoscsi.low_term; 16198c2ecf20Sopenharmony_ci adapter->high_term = autoscsi.high_term; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci /* 16228c2ecf20Sopenharmony_ci Save the Wide Permitted, Fast Permitted, Synchronous 16238c2ecf20Sopenharmony_ci Permitted, Disconnect Permitted, Ultra Permitted, and 16248c2ecf20Sopenharmony_ci SCAM Information in the Host Adapter structure. 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ci adapter->wide_ok = autoscsi.wide_ok; 16278c2ecf20Sopenharmony_ci adapter->fast_ok = autoscsi.fast_ok; 16288c2ecf20Sopenharmony_ci adapter->sync_ok = autoscsi.sync_ok; 16298c2ecf20Sopenharmony_ci adapter->discon_ok = autoscsi.discon_ok; 16308c2ecf20Sopenharmony_ci if (adapter->ultra) 16318c2ecf20Sopenharmony_ci adapter->ultra_ok = autoscsi.ultra_ok; 16328c2ecf20Sopenharmony_ci if (adapter->scam) { 16338c2ecf20Sopenharmony_ci adapter->scam_enabled = autoscsi.scam_enabled; 16348c2ecf20Sopenharmony_ci adapter->scam_lev2 = autoscsi.scam_lev2; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci /* 16388c2ecf20Sopenharmony_ci Initialize fields in the Host Adapter structure for "S" and "A" 16398c2ecf20Sopenharmony_ci series MultiMaster Host Adapters. 16408c2ecf20Sopenharmony_ci */ 16418c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] < '4') { 16428c2ecf20Sopenharmony_ci if (setupinfo.sync) { 16438c2ecf20Sopenharmony_ci adapter->sync_ok = 0xFF; 16448c2ecf20Sopenharmony_ci if (adapter->adapter_bus_type == BLOGIC_EISA_BUS) { 16458c2ecf20Sopenharmony_ci if (ext_setupinfo.misc.fast_on_eisa) 16468c2ecf20Sopenharmony_ci adapter->fast_ok = 0xFF; 16478c2ecf20Sopenharmony_ci if (strcmp(adapter->model, "BT-757") == 0) 16488c2ecf20Sopenharmony_ci adapter->wide_ok = 0xFF; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci adapter->discon_ok = 0xFF; 16528c2ecf20Sopenharmony_ci adapter->parity = setupinfo.parity; 16538c2ecf20Sopenharmony_ci adapter->reset_enabled = true; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci /* 16568c2ecf20Sopenharmony_ci Determine the maximum number of Target IDs and Logical Units 16578c2ecf20Sopenharmony_ci supported by this driver for Wide and Narrow Host Adapters. 16588c2ecf20Sopenharmony_ci */ 16598c2ecf20Sopenharmony_ci adapter->maxdev = (adapter->wide ? 16 : 8); 16608c2ecf20Sopenharmony_ci adapter->maxlun = (adapter->ext_lun ? 32 : 8); 16618c2ecf20Sopenharmony_ci /* 16628c2ecf20Sopenharmony_ci Select appropriate values for the Mailbox Count, Driver Queue Depth, 16638c2ecf20Sopenharmony_ci Initial CCBs, and Incremental CCBs variables based on whether 16648c2ecf20Sopenharmony_ci or not Strict Round Robin Mode is supported. If Strict Round 16658c2ecf20Sopenharmony_ci Robin Mode is supported, then there is no performance degradation 16668c2ecf20Sopenharmony_ci in using the maximum possible number of Outgoing and Incoming 16678c2ecf20Sopenharmony_ci Mailboxes and allowing the Tagged and Untagged Queue Depths to 16688c2ecf20Sopenharmony_ci determine the actual utilization. If Strict Round Robin Mode is 16698c2ecf20Sopenharmony_ci not supported, then the Host Adapter must scan all the Outgoing 16708c2ecf20Sopenharmony_ci Mailboxes whenever an Outgoing Mailbox entry is made, which can 16718c2ecf20Sopenharmony_ci cause a substantial performance penalty. The host adapters 16728c2ecf20Sopenharmony_ci actually have room to store the following number of CCBs 16738c2ecf20Sopenharmony_ci internally; that is, they can internally queue and manage this 16748c2ecf20Sopenharmony_ci many active commands on the SCSI bus simultaneously. Performance 16758c2ecf20Sopenharmony_ci measurements demonstrate that the Driver Queue Depth should be 16768c2ecf20Sopenharmony_ci set to the Mailbox Count, rather than the Host Adapter Queue 16778c2ecf20Sopenharmony_ci Depth (internal CCB capacity), as it is more efficient to have the 16788c2ecf20Sopenharmony_ci queued commands waiting in Outgoing Mailboxes if necessary than 16798c2ecf20Sopenharmony_ci to block the process in the higher levels of the SCSI Subsystem. 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci 192 BT-948/958/958D 16828c2ecf20Sopenharmony_ci 100 BT-946C/956C/956CD/747C/757C/757CD/445C 16838c2ecf20Sopenharmony_ci 50 BT-545C/540CF 16848c2ecf20Sopenharmony_ci 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] == '5') 16878c2ecf20Sopenharmony_ci adapter->adapter_qdepth = 192; 16888c2ecf20Sopenharmony_ci else if (adapter->fw_ver[0] == '4') 16898c2ecf20Sopenharmony_ci adapter->adapter_qdepth = (adapter->adapter_bus_type != 16908c2ecf20Sopenharmony_ci BLOGIC_ISA_BUS ? 100 : 50); 16918c2ecf20Sopenharmony_ci else 16928c2ecf20Sopenharmony_ci adapter->adapter_qdepth = 30; 16938c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "3.31") >= 0) { 16948c2ecf20Sopenharmony_ci adapter->strict_rr = true; 16958c2ecf20Sopenharmony_ci adapter->mbox_count = BLOGIC_MAX_MAILBOX; 16968c2ecf20Sopenharmony_ci } else { 16978c2ecf20Sopenharmony_ci adapter->strict_rr = false; 16988c2ecf20Sopenharmony_ci adapter->mbox_count = 32; 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci adapter->drvr_qdepth = adapter->mbox_count; 17018c2ecf20Sopenharmony_ci adapter->initccbs = 4 * BLOGIC_CCB_GRP_ALLOCSIZE; 17028c2ecf20Sopenharmony_ci adapter->inc_ccbs = BLOGIC_CCB_GRP_ALLOCSIZE; 17038c2ecf20Sopenharmony_ci /* 17048c2ecf20Sopenharmony_ci Tagged Queuing support is available and operates properly on 17058c2ecf20Sopenharmony_ci all "W" series MultiMaster Host Adapters, on "C" series 17068c2ecf20Sopenharmony_ci MultiMaster Host Adapters with firmware version 4.22 and above, 17078c2ecf20Sopenharmony_ci and on "S" series MultiMaster Host Adapters with firmware version 17088c2ecf20Sopenharmony_ci 3.35 and above. 17098c2ecf20Sopenharmony_ci */ 17108c2ecf20Sopenharmony_ci adapter->tagq_ok = 0; 17118c2ecf20Sopenharmony_ci switch (adapter->fw_ver[0]) { 17128c2ecf20Sopenharmony_ci case '5': 17138c2ecf20Sopenharmony_ci adapter->tagq_ok = 0xFFFF; 17148c2ecf20Sopenharmony_ci break; 17158c2ecf20Sopenharmony_ci case '4': 17168c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "4.22") >= 0) 17178c2ecf20Sopenharmony_ci adapter->tagq_ok = 0xFFFF; 17188c2ecf20Sopenharmony_ci break; 17198c2ecf20Sopenharmony_ci case '3': 17208c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "3.35") >= 0) 17218c2ecf20Sopenharmony_ci adapter->tagq_ok = 0xFFFF; 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci /* 17258c2ecf20Sopenharmony_ci Determine the Host Adapter BIOS Address if the BIOS is enabled and 17268c2ecf20Sopenharmony_ci save it in the Host Adapter structure. The BIOS is disabled if the 17278c2ecf20Sopenharmony_ci bios_addr is 0. 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_ci adapter->bios_addr = ext_setupinfo.bios_addr << 12; 17308c2ecf20Sopenharmony_ci /* 17318c2ecf20Sopenharmony_ci ISA Host Adapters require Bounce Buffers if there is more than 17328c2ecf20Sopenharmony_ci 16MB memory. 17338c2ecf20Sopenharmony_ci */ 17348c2ecf20Sopenharmony_ci if (adapter->adapter_bus_type == BLOGIC_ISA_BUS && 17358c2ecf20Sopenharmony_ci (void *) high_memory > (void *) MAX_DMA_ADDRESS) 17368c2ecf20Sopenharmony_ci adapter->need_bouncebuf = true; 17378c2ecf20Sopenharmony_ci /* 17388c2ecf20Sopenharmony_ci BusLogic BT-445S Host Adapters prior to board revision E have a 17398c2ecf20Sopenharmony_ci hardware bug whereby when the BIOS is enabled, transfers to/from 17408c2ecf20Sopenharmony_ci the same address range the BIOS occupies modulo 16MB are handled 17418c2ecf20Sopenharmony_ci incorrectly. Only properly functioning BT-445S Host Adapters 17428c2ecf20Sopenharmony_ci have firmware version 3.37, so require that ISA Bounce Buffers 17438c2ecf20Sopenharmony_ci be used for the buggy BT-445S models if there is more than 16MB 17448c2ecf20Sopenharmony_ci memory. 17458c2ecf20Sopenharmony_ci */ 17468c2ecf20Sopenharmony_ci if (adapter->bios_addr > 0 && strcmp(adapter->model, "BT-445S") == 0 && 17478c2ecf20Sopenharmony_ci strcmp(adapter->fw_ver, "3.37") < 0 && 17488c2ecf20Sopenharmony_ci (void *) high_memory > (void *) MAX_DMA_ADDRESS) 17498c2ecf20Sopenharmony_ci adapter->need_bouncebuf = true; 17508c2ecf20Sopenharmony_ci /* 17518c2ecf20Sopenharmony_ci Initialize parameters common to MultiMaster and FlashPoint 17528c2ecf20Sopenharmony_ci Host Adapters. 17538c2ecf20Sopenharmony_ci */ 17548c2ecf20Sopenharmony_cicommon: 17558c2ecf20Sopenharmony_ci /* 17568c2ecf20Sopenharmony_ci Initialize the Host Adapter Full Model Name from the Model Name. 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci strcpy(adapter->full_model, "BusLogic "); 17598c2ecf20Sopenharmony_ci strcat(adapter->full_model, adapter->model); 17608c2ecf20Sopenharmony_ci /* 17618c2ecf20Sopenharmony_ci Select an appropriate value for the Tagged Queue Depth either from a 17628c2ecf20Sopenharmony_ci BusLogic Driver Options specification, or based on whether this Host 17638c2ecf20Sopenharmony_ci Adapter requires that ISA Bounce Buffers be used. The Tagged Queue 17648c2ecf20Sopenharmony_ci Depth is left at 0 for automatic determination in 17658c2ecf20Sopenharmony_ci BusLogic_SelectQueueDepths. Initialize the Untagged Queue Depth. 17668c2ecf20Sopenharmony_ci */ 17678c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) { 17688c2ecf20Sopenharmony_ci unsigned char qdepth = 0; 17698c2ecf20Sopenharmony_ci if (adapter->drvr_opts != NULL && 17708c2ecf20Sopenharmony_ci adapter->drvr_opts->qdepth[tgt_id] > 0) 17718c2ecf20Sopenharmony_ci qdepth = adapter->drvr_opts->qdepth[tgt_id]; 17728c2ecf20Sopenharmony_ci else if (adapter->need_bouncebuf) 17738c2ecf20Sopenharmony_ci qdepth = BLOGIC_TAG_DEPTH_BB; 17748c2ecf20Sopenharmony_ci adapter->qdepth[tgt_id] = qdepth; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci if (adapter->need_bouncebuf) 17778c2ecf20Sopenharmony_ci adapter->untag_qdepth = BLOGIC_UNTAG_DEPTH_BB; 17788c2ecf20Sopenharmony_ci else 17798c2ecf20Sopenharmony_ci adapter->untag_qdepth = BLOGIC_UNTAG_DEPTH; 17808c2ecf20Sopenharmony_ci if (adapter->drvr_opts != NULL) 17818c2ecf20Sopenharmony_ci adapter->common_qdepth = adapter->drvr_opts->common_qdepth; 17828c2ecf20Sopenharmony_ci if (adapter->common_qdepth > 0 && 17838c2ecf20Sopenharmony_ci adapter->common_qdepth < adapter->untag_qdepth) 17848c2ecf20Sopenharmony_ci adapter->untag_qdepth = adapter->common_qdepth; 17858c2ecf20Sopenharmony_ci /* 17868c2ecf20Sopenharmony_ci Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. 17878c2ecf20Sopenharmony_ci Therefore, mask the Tagged Queuing Permitted Default bits with the 17888c2ecf20Sopenharmony_ci Disconnect/Reconnect Permitted bits. 17898c2ecf20Sopenharmony_ci */ 17908c2ecf20Sopenharmony_ci adapter->tagq_ok &= adapter->discon_ok; 17918c2ecf20Sopenharmony_ci /* 17928c2ecf20Sopenharmony_ci Combine the default Tagged Queuing Permitted bits with any 17938c2ecf20Sopenharmony_ci BusLogic Driver Options Tagged Queuing specification. 17948c2ecf20Sopenharmony_ci */ 17958c2ecf20Sopenharmony_ci if (adapter->drvr_opts != NULL) 17968c2ecf20Sopenharmony_ci adapter->tagq_ok = (adapter->drvr_opts->tagq_ok & 17978c2ecf20Sopenharmony_ci adapter->drvr_opts->tagq_ok_mask) | 17988c2ecf20Sopenharmony_ci (adapter->tagq_ok & ~adapter->drvr_opts->tagq_ok_mask); 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci /* 18018c2ecf20Sopenharmony_ci Select an appropriate value for Bus Settle Time either from a 18028c2ecf20Sopenharmony_ci BusLogic Driver Options specification, or from 18038c2ecf20Sopenharmony_ci BLOGIC_BUS_SETTLE_TIME. 18048c2ecf20Sopenharmony_ci */ 18058c2ecf20Sopenharmony_ci if (adapter->drvr_opts != NULL && 18068c2ecf20Sopenharmony_ci adapter->drvr_opts->bus_settle_time > 0) 18078c2ecf20Sopenharmony_ci adapter->bus_settle_time = adapter->drvr_opts->bus_settle_time; 18088c2ecf20Sopenharmony_ci else 18098c2ecf20Sopenharmony_ci adapter->bus_settle_time = BLOGIC_BUS_SETTLE_TIME; 18108c2ecf20Sopenharmony_ci /* 18118c2ecf20Sopenharmony_ci Indicate reading the Host Adapter Configuration completed 18128c2ecf20Sopenharmony_ci successfully. 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_ci return true; 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci/* 18198c2ecf20Sopenharmony_ci blogic_reportconfig reports the configuration of Host Adapter. 18208c2ecf20Sopenharmony_ci*/ 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic bool __init blogic_reportconfig(struct blogic_adapter *adapter) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci unsigned short alltgt_mask = (1 << adapter->maxdev) - 1; 18258c2ecf20Sopenharmony_ci unsigned short sync_ok, fast_ok; 18268c2ecf20Sopenharmony_ci unsigned short ultra_ok, wide_ok; 18278c2ecf20Sopenharmony_ci unsigned short discon_ok, tagq_ok; 18288c2ecf20Sopenharmony_ci bool common_syncneg, common_tagq_depth; 18298c2ecf20Sopenharmony_ci char syncstr[BLOGIC_MAXDEV + 1]; 18308c2ecf20Sopenharmony_ci char widestr[BLOGIC_MAXDEV + 1]; 18318c2ecf20Sopenharmony_ci char discon_str[BLOGIC_MAXDEV + 1]; 18328c2ecf20Sopenharmony_ci char tagq_str[BLOGIC_MAXDEV + 1]; 18338c2ecf20Sopenharmony_ci char *syncmsg = syncstr; 18348c2ecf20Sopenharmony_ci char *widemsg = widestr; 18358c2ecf20Sopenharmony_ci char *discon_msg = discon_str; 18368c2ecf20Sopenharmony_ci char *tagq_msg = tagq_str; 18378c2ecf20Sopenharmony_ci int tgt_id; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci blogic_info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", adapter, adapter->model, blogic_adapter_busnames[adapter->adapter_bus_type], (adapter->wide ? " Wide" : ""), (adapter->differential ? " Differential" : ""), (adapter->ultra ? " Ultra" : "")); 18408c2ecf20Sopenharmony_ci blogic_info(" Firmware Version: %s, I/O Address: 0x%lX, IRQ Channel: %d/%s\n", adapter, adapter->fw_ver, adapter->io_addr, adapter->irq_ch, (adapter->level_int ? "Level" : "Edge")); 18418c2ecf20Sopenharmony_ci if (adapter->adapter_bus_type != BLOGIC_PCI_BUS) { 18428c2ecf20Sopenharmony_ci blogic_info(" DMA Channel: ", adapter); 18438c2ecf20Sopenharmony_ci if (adapter->dma_ch > 0) 18448c2ecf20Sopenharmony_ci blogic_info("%d, ", adapter, adapter->dma_ch); 18458c2ecf20Sopenharmony_ci else 18468c2ecf20Sopenharmony_ci blogic_info("None, ", adapter); 18478c2ecf20Sopenharmony_ci if (adapter->bios_addr > 0) 18488c2ecf20Sopenharmony_ci blogic_info("BIOS Address: 0x%X, ", adapter, 18498c2ecf20Sopenharmony_ci adapter->bios_addr); 18508c2ecf20Sopenharmony_ci else 18518c2ecf20Sopenharmony_ci blogic_info("BIOS Address: None, ", adapter); 18528c2ecf20Sopenharmony_ci } else { 18538c2ecf20Sopenharmony_ci blogic_info(" PCI Bus: %d, Device: %d, Address: ", adapter, 18548c2ecf20Sopenharmony_ci adapter->bus, adapter->dev); 18558c2ecf20Sopenharmony_ci if (adapter->pci_addr > 0) 18568c2ecf20Sopenharmony_ci blogic_info("0x%lX, ", adapter, adapter->pci_addr); 18578c2ecf20Sopenharmony_ci else 18588c2ecf20Sopenharmony_ci blogic_info("Unassigned, ", adapter); 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci blogic_info("Host Adapter SCSI ID: %d\n", adapter, adapter->scsi_id); 18618c2ecf20Sopenharmony_ci blogic_info(" Parity Checking: %s, Extended Translation: %s\n", 18628c2ecf20Sopenharmony_ci adapter, (adapter->parity ? "Enabled" : "Disabled"), 18638c2ecf20Sopenharmony_ci (adapter->ext_trans_enable ? "Enabled" : "Disabled")); 18648c2ecf20Sopenharmony_ci alltgt_mask &= ~(1 << adapter->scsi_id); 18658c2ecf20Sopenharmony_ci sync_ok = adapter->sync_ok & alltgt_mask; 18668c2ecf20Sopenharmony_ci fast_ok = adapter->fast_ok & alltgt_mask; 18678c2ecf20Sopenharmony_ci ultra_ok = adapter->ultra_ok & alltgt_mask; 18688c2ecf20Sopenharmony_ci if ((blogic_multimaster_type(adapter) && 18698c2ecf20Sopenharmony_ci (adapter->fw_ver[0] >= '4' || 18708c2ecf20Sopenharmony_ci adapter->adapter_bus_type == BLOGIC_EISA_BUS)) || 18718c2ecf20Sopenharmony_ci blogic_flashpoint_type(adapter)) { 18728c2ecf20Sopenharmony_ci common_syncneg = false; 18738c2ecf20Sopenharmony_ci if (sync_ok == 0) { 18748c2ecf20Sopenharmony_ci syncmsg = "Disabled"; 18758c2ecf20Sopenharmony_ci common_syncneg = true; 18768c2ecf20Sopenharmony_ci } else if (sync_ok == alltgt_mask) { 18778c2ecf20Sopenharmony_ci if (fast_ok == 0) { 18788c2ecf20Sopenharmony_ci syncmsg = "Slow"; 18798c2ecf20Sopenharmony_ci common_syncneg = true; 18808c2ecf20Sopenharmony_ci } else if (fast_ok == alltgt_mask) { 18818c2ecf20Sopenharmony_ci if (ultra_ok == 0) { 18828c2ecf20Sopenharmony_ci syncmsg = "Fast"; 18838c2ecf20Sopenharmony_ci common_syncneg = true; 18848c2ecf20Sopenharmony_ci } else if (ultra_ok == alltgt_mask) { 18858c2ecf20Sopenharmony_ci syncmsg = "Ultra"; 18868c2ecf20Sopenharmony_ci common_syncneg = true; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci if (!common_syncneg) { 18918c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 18928c2ecf20Sopenharmony_ci syncstr[tgt_id] = ((!(sync_ok & (1 << tgt_id))) ? 'N' : (!(fast_ok & (1 << tgt_id)) ? 'S' : (!(ultra_ok & (1 << tgt_id)) ? 'F' : 'U'))); 18938c2ecf20Sopenharmony_ci syncstr[adapter->scsi_id] = '#'; 18948c2ecf20Sopenharmony_ci syncstr[adapter->maxdev] = '\0'; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci } else 18978c2ecf20Sopenharmony_ci syncmsg = (sync_ok == 0 ? "Disabled" : "Enabled"); 18988c2ecf20Sopenharmony_ci wide_ok = adapter->wide_ok & alltgt_mask; 18998c2ecf20Sopenharmony_ci if (wide_ok == 0) 19008c2ecf20Sopenharmony_ci widemsg = "Disabled"; 19018c2ecf20Sopenharmony_ci else if (wide_ok == alltgt_mask) 19028c2ecf20Sopenharmony_ci widemsg = "Enabled"; 19038c2ecf20Sopenharmony_ci else { 19048c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 19058c2ecf20Sopenharmony_ci widestr[tgt_id] = ((wide_ok & (1 << tgt_id)) ? 'Y' : 'N'); 19068c2ecf20Sopenharmony_ci widestr[adapter->scsi_id] = '#'; 19078c2ecf20Sopenharmony_ci widestr[adapter->maxdev] = '\0'; 19088c2ecf20Sopenharmony_ci } 19098c2ecf20Sopenharmony_ci discon_ok = adapter->discon_ok & alltgt_mask; 19108c2ecf20Sopenharmony_ci if (discon_ok == 0) 19118c2ecf20Sopenharmony_ci discon_msg = "Disabled"; 19128c2ecf20Sopenharmony_ci else if (discon_ok == alltgt_mask) 19138c2ecf20Sopenharmony_ci discon_msg = "Enabled"; 19148c2ecf20Sopenharmony_ci else { 19158c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 19168c2ecf20Sopenharmony_ci discon_str[tgt_id] = ((discon_ok & (1 << tgt_id)) ? 'Y' : 'N'); 19178c2ecf20Sopenharmony_ci discon_str[adapter->scsi_id] = '#'; 19188c2ecf20Sopenharmony_ci discon_str[adapter->maxdev] = '\0'; 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci tagq_ok = adapter->tagq_ok & alltgt_mask; 19218c2ecf20Sopenharmony_ci if (tagq_ok == 0) 19228c2ecf20Sopenharmony_ci tagq_msg = "Disabled"; 19238c2ecf20Sopenharmony_ci else if (tagq_ok == alltgt_mask) 19248c2ecf20Sopenharmony_ci tagq_msg = "Enabled"; 19258c2ecf20Sopenharmony_ci else { 19268c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 19278c2ecf20Sopenharmony_ci tagq_str[tgt_id] = ((tagq_ok & (1 << tgt_id)) ? 'Y' : 'N'); 19288c2ecf20Sopenharmony_ci tagq_str[adapter->scsi_id] = '#'; 19298c2ecf20Sopenharmony_ci tagq_str[adapter->maxdev] = '\0'; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci blogic_info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", 19328c2ecf20Sopenharmony_ci adapter, syncmsg, widemsg); 19338c2ecf20Sopenharmony_ci blogic_info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", adapter, 19348c2ecf20Sopenharmony_ci discon_msg, tagq_msg); 19358c2ecf20Sopenharmony_ci if (blogic_multimaster_type(adapter)) { 19368c2ecf20Sopenharmony_ci blogic_info(" Scatter/Gather Limit: %d of %d segments, Mailboxes: %d\n", adapter, adapter->drvr_sglimit, adapter->adapter_sglimit, adapter->mbox_count); 19378c2ecf20Sopenharmony_ci blogic_info(" Driver Queue Depth: %d, Host Adapter Queue Depth: %d\n", adapter, adapter->drvr_qdepth, adapter->adapter_qdepth); 19388c2ecf20Sopenharmony_ci } else 19398c2ecf20Sopenharmony_ci blogic_info(" Driver Queue Depth: %d, Scatter/Gather Limit: %d segments\n", adapter, adapter->drvr_qdepth, adapter->drvr_sglimit); 19408c2ecf20Sopenharmony_ci blogic_info(" Tagged Queue Depth: ", adapter); 19418c2ecf20Sopenharmony_ci common_tagq_depth = true; 19428c2ecf20Sopenharmony_ci for (tgt_id = 1; tgt_id < adapter->maxdev; tgt_id++) 19438c2ecf20Sopenharmony_ci if (adapter->qdepth[tgt_id] != adapter->qdepth[0]) { 19448c2ecf20Sopenharmony_ci common_tagq_depth = false; 19458c2ecf20Sopenharmony_ci break; 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci if (common_tagq_depth) { 19488c2ecf20Sopenharmony_ci if (adapter->qdepth[0] > 0) 19498c2ecf20Sopenharmony_ci blogic_info("%d", adapter, adapter->qdepth[0]); 19508c2ecf20Sopenharmony_ci else 19518c2ecf20Sopenharmony_ci blogic_info("Automatic", adapter); 19528c2ecf20Sopenharmony_ci } else 19538c2ecf20Sopenharmony_ci blogic_info("Individual", adapter); 19548c2ecf20Sopenharmony_ci blogic_info(", Untagged Queue Depth: %d\n", adapter, 19558c2ecf20Sopenharmony_ci adapter->untag_qdepth); 19568c2ecf20Sopenharmony_ci if (adapter->terminfo_valid) { 19578c2ecf20Sopenharmony_ci if (adapter->wide) 19588c2ecf20Sopenharmony_ci blogic_info(" SCSI Bus Termination: %s", adapter, 19598c2ecf20Sopenharmony_ci (adapter->low_term ? (adapter->high_term ? "Both Enabled" : "Low Enabled") : (adapter->high_term ? "High Enabled" : "Both Disabled"))); 19608c2ecf20Sopenharmony_ci else 19618c2ecf20Sopenharmony_ci blogic_info(" SCSI Bus Termination: %s", adapter, 19628c2ecf20Sopenharmony_ci (adapter->low_term ? "Enabled" : "Disabled")); 19638c2ecf20Sopenharmony_ci if (adapter->scam) 19648c2ecf20Sopenharmony_ci blogic_info(", SCAM: %s", adapter, 19658c2ecf20Sopenharmony_ci (adapter->scam_enabled ? (adapter->scam_lev2 ? "Enabled, Level 2" : "Enabled, Level 1") : "Disabled")); 19668c2ecf20Sopenharmony_ci blogic_info("\n", adapter); 19678c2ecf20Sopenharmony_ci } 19688c2ecf20Sopenharmony_ci /* 19698c2ecf20Sopenharmony_ci Indicate reporting the Host Adapter configuration completed 19708c2ecf20Sopenharmony_ci successfully. 19718c2ecf20Sopenharmony_ci */ 19728c2ecf20Sopenharmony_ci return true; 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci/* 19778c2ecf20Sopenharmony_ci blogic_getres acquires the system resources necessary to use 19788c2ecf20Sopenharmony_ci Host Adapter. 19798c2ecf20Sopenharmony_ci*/ 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_cistatic bool __init blogic_getres(struct blogic_adapter *adapter) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci if (adapter->irq_ch == 0) { 19848c2ecf20Sopenharmony_ci blogic_err("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", 19858c2ecf20Sopenharmony_ci adapter); 19868c2ecf20Sopenharmony_ci return false; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci /* 19898c2ecf20Sopenharmony_ci Acquire shared access to the IRQ Channel. 19908c2ecf20Sopenharmony_ci */ 19918c2ecf20Sopenharmony_ci if (request_irq(adapter->irq_ch, blogic_inthandler, IRQF_SHARED, 19928c2ecf20Sopenharmony_ci adapter->full_model, adapter) < 0) { 19938c2ecf20Sopenharmony_ci blogic_err("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", 19948c2ecf20Sopenharmony_ci adapter, adapter->irq_ch); 19958c2ecf20Sopenharmony_ci return false; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci adapter->irq_acquired = true; 19988c2ecf20Sopenharmony_ci /* 19998c2ecf20Sopenharmony_ci Acquire exclusive access to the DMA Channel. 20008c2ecf20Sopenharmony_ci */ 20018c2ecf20Sopenharmony_ci if (adapter->dma_ch > 0) { 20028c2ecf20Sopenharmony_ci if (request_dma(adapter->dma_ch, adapter->full_model) < 0) { 20038c2ecf20Sopenharmony_ci blogic_err("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", adapter, adapter->dma_ch); 20048c2ecf20Sopenharmony_ci return false; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci set_dma_mode(adapter->dma_ch, DMA_MODE_CASCADE); 20078c2ecf20Sopenharmony_ci enable_dma(adapter->dma_ch); 20088c2ecf20Sopenharmony_ci adapter->dma_chan_acquired = true; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci /* 20118c2ecf20Sopenharmony_ci Indicate the System Resource Acquisition completed successfully, 20128c2ecf20Sopenharmony_ci */ 20138c2ecf20Sopenharmony_ci return true; 20148c2ecf20Sopenharmony_ci} 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci/* 20188c2ecf20Sopenharmony_ci blogic_relres releases any system resources previously acquired 20198c2ecf20Sopenharmony_ci by blogic_getres. 20208c2ecf20Sopenharmony_ci*/ 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_cistatic void blogic_relres(struct blogic_adapter *adapter) 20238c2ecf20Sopenharmony_ci{ 20248c2ecf20Sopenharmony_ci /* 20258c2ecf20Sopenharmony_ci Release shared access to the IRQ Channel. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_ci if (adapter->irq_acquired) 20288c2ecf20Sopenharmony_ci free_irq(adapter->irq_ch, adapter); 20298c2ecf20Sopenharmony_ci /* 20308c2ecf20Sopenharmony_ci Release exclusive access to the DMA Channel. 20318c2ecf20Sopenharmony_ci */ 20328c2ecf20Sopenharmony_ci if (adapter->dma_chan_acquired) 20338c2ecf20Sopenharmony_ci free_dma(adapter->dma_ch); 20348c2ecf20Sopenharmony_ci /* 20358c2ecf20Sopenharmony_ci Release any allocated memory structs not released elsewhere 20368c2ecf20Sopenharmony_ci */ 20378c2ecf20Sopenharmony_ci if (adapter->mbox_space) 20388c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->pci_device->dev, adapter->mbox_sz, 20398c2ecf20Sopenharmony_ci adapter->mbox_space, adapter->mbox_space_handle); 20408c2ecf20Sopenharmony_ci pci_dev_put(adapter->pci_device); 20418c2ecf20Sopenharmony_ci adapter->mbox_space = NULL; 20428c2ecf20Sopenharmony_ci adapter->mbox_space_handle = 0; 20438c2ecf20Sopenharmony_ci adapter->mbox_sz = 0; 20448c2ecf20Sopenharmony_ci} 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci/* 20488c2ecf20Sopenharmony_ci blogic_initadapter initializes Host Adapter. This is the only 20498c2ecf20Sopenharmony_ci function called during SCSI Host Adapter detection which modifies the state 20508c2ecf20Sopenharmony_ci of the Host Adapter from its initial power on or hard reset state. 20518c2ecf20Sopenharmony_ci*/ 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic bool blogic_initadapter(struct blogic_adapter *adapter) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct blogic_extmbox_req extmbox_req; 20568c2ecf20Sopenharmony_ci enum blogic_rr_req rr_req; 20578c2ecf20Sopenharmony_ci enum blogic_setccb_fmt setccb_fmt; 20588c2ecf20Sopenharmony_ci int tgt_id; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci /* 20618c2ecf20Sopenharmony_ci Initialize the pointers to the first and last CCBs that are 20628c2ecf20Sopenharmony_ci queued for completion processing. 20638c2ecf20Sopenharmony_ci */ 20648c2ecf20Sopenharmony_ci adapter->firstccb = NULL; 20658c2ecf20Sopenharmony_ci adapter->lastccb = NULL; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* 20688c2ecf20Sopenharmony_ci Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, 20698c2ecf20Sopenharmony_ci Command Successful Flag, Active Commands, and Commands Since Reset 20708c2ecf20Sopenharmony_ci for each Target Device. 20718c2ecf20Sopenharmony_ci */ 20728c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) { 20738c2ecf20Sopenharmony_ci adapter->bdr_pend[tgt_id] = NULL; 20748c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].tagq_active = false; 20758c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].cmd_good = false; 20768c2ecf20Sopenharmony_ci adapter->active_cmds[tgt_id] = 0; 20778c2ecf20Sopenharmony_ci adapter->cmds_since_rst[tgt_id] = 0; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* 20818c2ecf20Sopenharmony_ci FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) 20848c2ecf20Sopenharmony_ci goto done; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* 20878c2ecf20Sopenharmony_ci Initialize the Outgoing and Incoming Mailbox pointers. 20888c2ecf20Sopenharmony_ci */ 20898c2ecf20Sopenharmony_ci adapter->mbox_sz = adapter->mbox_count * (sizeof(struct blogic_outbox) + sizeof(struct blogic_inbox)); 20908c2ecf20Sopenharmony_ci adapter->mbox_space = dma_alloc_coherent(&adapter->pci_device->dev, 20918c2ecf20Sopenharmony_ci adapter->mbox_sz, &adapter->mbox_space_handle, 20928c2ecf20Sopenharmony_ci GFP_KERNEL); 20938c2ecf20Sopenharmony_ci if (adapter->mbox_space == NULL) 20948c2ecf20Sopenharmony_ci return blogic_failure(adapter, "MAILBOX ALLOCATION"); 20958c2ecf20Sopenharmony_ci adapter->first_outbox = (struct blogic_outbox *) adapter->mbox_space; 20968c2ecf20Sopenharmony_ci adapter->last_outbox = adapter->first_outbox + adapter->mbox_count - 1; 20978c2ecf20Sopenharmony_ci adapter->next_outbox = adapter->first_outbox; 20988c2ecf20Sopenharmony_ci adapter->first_inbox = (struct blogic_inbox *) (adapter->last_outbox + 1); 20998c2ecf20Sopenharmony_ci adapter->last_inbox = adapter->first_inbox + adapter->mbox_count - 1; 21008c2ecf20Sopenharmony_ci adapter->next_inbox = adapter->first_inbox; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* 21038c2ecf20Sopenharmony_ci Initialize the Outgoing and Incoming Mailbox structures. 21048c2ecf20Sopenharmony_ci */ 21058c2ecf20Sopenharmony_ci memset(adapter->first_outbox, 0, 21068c2ecf20Sopenharmony_ci adapter->mbox_count * sizeof(struct blogic_outbox)); 21078c2ecf20Sopenharmony_ci memset(adapter->first_inbox, 0, 21088c2ecf20Sopenharmony_ci adapter->mbox_count * sizeof(struct blogic_inbox)); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci /* 21118c2ecf20Sopenharmony_ci Initialize the Host Adapter's Pointer to the Outgoing/Incoming 21128c2ecf20Sopenharmony_ci Mailboxes. 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_ci extmbox_req.mbox_count = adapter->mbox_count; 21158c2ecf20Sopenharmony_ci extmbox_req.base_mbox_addr = (u32) adapter->mbox_space_handle; 21168c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INIT_EXT_MBOX, &extmbox_req, 21178c2ecf20Sopenharmony_ci sizeof(extmbox_req), NULL, 0) < 0) 21188c2ecf20Sopenharmony_ci return blogic_failure(adapter, "MAILBOX INITIALIZATION"); 21198c2ecf20Sopenharmony_ci /* 21208c2ecf20Sopenharmony_ci Enable Strict Round Robin Mode if supported by the Host Adapter. In 21218c2ecf20Sopenharmony_ci Strict Round Robin Mode, the Host Adapter only looks at the next 21228c2ecf20Sopenharmony_ci Outgoing Mailbox for each new command, rather than scanning 21238c2ecf20Sopenharmony_ci through all the Outgoing Mailboxes to find any that have new 21248c2ecf20Sopenharmony_ci commands in them. Strict Round Robin Mode is significantly more 21258c2ecf20Sopenharmony_ci efficient. 21268c2ecf20Sopenharmony_ci */ 21278c2ecf20Sopenharmony_ci if (adapter->strict_rr) { 21288c2ecf20Sopenharmony_ci rr_req = BLOGIC_STRICT_RR_MODE; 21298c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_STRICT_RR, &rr_req, 21308c2ecf20Sopenharmony_ci sizeof(rr_req), NULL, 0) < 0) 21318c2ecf20Sopenharmony_ci return blogic_failure(adapter, 21328c2ecf20Sopenharmony_ci "ENABLE STRICT ROUND ROBIN MODE"); 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci /* 21368c2ecf20Sopenharmony_ci For Host Adapters that support Extended LUN Format CCBs, issue the 21378c2ecf20Sopenharmony_ci Set CCB Format command to allow 32 Logical Units per Target Device. 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_ci if (adapter->ext_lun) { 21408c2ecf20Sopenharmony_ci setccb_fmt = BLOGIC_EXT_LUN_CCB; 21418c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_SETCCB_FMT, &setccb_fmt, 21428c2ecf20Sopenharmony_ci sizeof(setccb_fmt), NULL, 0) < 0) 21438c2ecf20Sopenharmony_ci return blogic_failure(adapter, "SET CCB FORMAT"); 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci /* 21478c2ecf20Sopenharmony_ci Announce Successful Initialization. 21488c2ecf20Sopenharmony_ci */ 21498c2ecf20Sopenharmony_cidone: 21508c2ecf20Sopenharmony_ci if (!adapter->adapter_initd) { 21518c2ecf20Sopenharmony_ci blogic_info("*** %s Initialized Successfully ***\n", adapter, 21528c2ecf20Sopenharmony_ci adapter->full_model); 21538c2ecf20Sopenharmony_ci blogic_info("\n", adapter); 21548c2ecf20Sopenharmony_ci } else 21558c2ecf20Sopenharmony_ci blogic_warn("*** %s Initialized Successfully ***\n", adapter, 21568c2ecf20Sopenharmony_ci adapter->full_model); 21578c2ecf20Sopenharmony_ci adapter->adapter_initd = true; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* 21608c2ecf20Sopenharmony_ci Indicate the Host Adapter Initialization completed successfully. 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_ci return true; 21638c2ecf20Sopenharmony_ci} 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci/* 21678c2ecf20Sopenharmony_ci blogic_inquiry inquires about the Target Devices accessible 21688c2ecf20Sopenharmony_ci through Host Adapter. 21698c2ecf20Sopenharmony_ci*/ 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_cistatic bool __init blogic_inquiry(struct blogic_adapter *adapter) 21728c2ecf20Sopenharmony_ci{ 21738c2ecf20Sopenharmony_ci u16 installed_devs; 21748c2ecf20Sopenharmony_ci u8 installed_devs0to7[8]; 21758c2ecf20Sopenharmony_ci struct blogic_setup_info setupinfo; 21768c2ecf20Sopenharmony_ci u8 sync_period[BLOGIC_MAXDEV]; 21778c2ecf20Sopenharmony_ci unsigned char req_replylen; 21788c2ecf20Sopenharmony_ci int tgt_id; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci /* 21818c2ecf20Sopenharmony_ci Wait a few seconds between the Host Adapter Hard Reset which 21828c2ecf20Sopenharmony_ci initiates a SCSI Bus Reset and issuing any SCSI Commands. Some 21838c2ecf20Sopenharmony_ci SCSI devices get confused if they receive SCSI Commands too soon 21848c2ecf20Sopenharmony_ci after a SCSI Bus Reset. 21858c2ecf20Sopenharmony_ci */ 21868c2ecf20Sopenharmony_ci blogic_delay(adapter->bus_settle_time); 21878c2ecf20Sopenharmony_ci /* 21888c2ecf20Sopenharmony_ci FlashPoint Host Adapters do not provide for Target Device Inquiry. 21898c2ecf20Sopenharmony_ci */ 21908c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) 21918c2ecf20Sopenharmony_ci return true; 21928c2ecf20Sopenharmony_ci /* 21938c2ecf20Sopenharmony_ci Inhibit the Target Device Inquiry if requested. 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_ci if (adapter->drvr_opts != NULL && adapter->drvr_opts->stop_tgt_inquiry) 21968c2ecf20Sopenharmony_ci return true; 21978c2ecf20Sopenharmony_ci /* 21988c2ecf20Sopenharmony_ci Issue the Inquire Target Devices command for host adapters with 21998c2ecf20Sopenharmony_ci firmware version 4.25 or later, or the Inquire Installed Devices 22008c2ecf20Sopenharmony_ci ID 0 to 7 command for older host adapters. This is necessary to 22018c2ecf20Sopenharmony_ci force Synchronous Transfer Negotiation so that the Inquire Setup 22028c2ecf20Sopenharmony_ci Information and Inquire Synchronous Period commands will return 22038c2ecf20Sopenharmony_ci valid data. The Inquire Target Devices command is preferable to 22048c2ecf20Sopenharmony_ci Inquire Installed Devices ID 0 to 7 since it only probes Logical 22058c2ecf20Sopenharmony_ci Unit 0 of each Target Device. 22068c2ecf20Sopenharmony_ci */ 22078c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "4.25") >= 0) { 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci /* 22108c2ecf20Sopenharmony_ci Issue a Inquire Target Devices command. Inquire Target 22118c2ecf20Sopenharmony_ci Devices only tests Logical Unit 0 of each Target Device 22128c2ecf20Sopenharmony_ci unlike the Inquire Installed Devices commands which test 22138c2ecf20Sopenharmony_ci Logical Units 0 - 7. Two bytes are returned, where byte 22148c2ecf20Sopenharmony_ci 0 bit 0 set indicates that Target Device 0 exists, and so on. 22158c2ecf20Sopenharmony_ci */ 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_DEV, NULL, 0, 22188c2ecf20Sopenharmony_ci &installed_devs, sizeof(installed_devs)) 22198c2ecf20Sopenharmony_ci != sizeof(installed_devs)) 22208c2ecf20Sopenharmony_ci return blogic_failure(adapter, "INQUIRE TARGET DEVICES"); 22218c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 22228c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].tgt_exists = 22238c2ecf20Sopenharmony_ci (installed_devs & (1 << tgt_id) ? true : false); 22248c2ecf20Sopenharmony_ci } else { 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* 22278c2ecf20Sopenharmony_ci Issue an Inquire Installed Devices command. For each 22288c2ecf20Sopenharmony_ci Target Device, a byte is returned where bit 0 set 22298c2ecf20Sopenharmony_ci indicates that Logical Unit 0 * exists, bit 1 set 22308c2ecf20Sopenharmony_ci indicates that Logical Unit 1 exists, and so on. 22318c2ecf20Sopenharmony_ci */ 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_DEV0TO7, NULL, 0, 22348c2ecf20Sopenharmony_ci &installed_devs0to7, sizeof(installed_devs0to7)) 22358c2ecf20Sopenharmony_ci != sizeof(installed_devs0to7)) 22368c2ecf20Sopenharmony_ci return blogic_failure(adapter, 22378c2ecf20Sopenharmony_ci "INQUIRE INSTALLED DEVICES ID 0 TO 7"); 22388c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < 8; tgt_id++) 22398c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].tgt_exists = 22408c2ecf20Sopenharmony_ci installed_devs0to7[tgt_id] != 0; 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci /* 22438c2ecf20Sopenharmony_ci Issue the Inquire Setup Information command. 22448c2ecf20Sopenharmony_ci */ 22458c2ecf20Sopenharmony_ci req_replylen = sizeof(setupinfo); 22468c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_SETUPINFO, &req_replylen, 22478c2ecf20Sopenharmony_ci sizeof(req_replylen), &setupinfo, sizeof(setupinfo)) 22488c2ecf20Sopenharmony_ci != sizeof(setupinfo)) 22498c2ecf20Sopenharmony_ci return blogic_failure(adapter, "INQUIRE SETUP INFORMATION"); 22508c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 22518c2ecf20Sopenharmony_ci adapter->sync_offset[tgt_id] = (tgt_id < 8 ? setupinfo.sync0to7[tgt_id].offset : setupinfo.sync8to15[tgt_id - 8].offset); 22528c2ecf20Sopenharmony_ci if (strcmp(adapter->fw_ver, "5.06L") >= 0) 22538c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 22548c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].wide_active = (tgt_id < 8 ? (setupinfo.wide_tx_active0to7 & (1 << tgt_id) ? true : false) : (setupinfo.wide_tx_active8to15 & (1 << (tgt_id - 8)) ? true : false)); 22558c2ecf20Sopenharmony_ci /* 22568c2ecf20Sopenharmony_ci Issue the Inquire Synchronous Period command. 22578c2ecf20Sopenharmony_ci */ 22588c2ecf20Sopenharmony_ci if (adapter->fw_ver[0] >= '3') { 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci /* Issue a Inquire Synchronous Period command. For each 22618c2ecf20Sopenharmony_ci Target Device, a byte is returned which represents the 22628c2ecf20Sopenharmony_ci Synchronous Transfer Period in units of 10 nanoseconds. 22638c2ecf20Sopenharmony_ci */ 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci req_replylen = sizeof(sync_period); 22668c2ecf20Sopenharmony_ci if (blogic_cmd(adapter, BLOGIC_INQ_SYNC_PERIOD, &req_replylen, 22678c2ecf20Sopenharmony_ci sizeof(req_replylen), &sync_period, 22688c2ecf20Sopenharmony_ci sizeof(sync_period)) != sizeof(sync_period)) 22698c2ecf20Sopenharmony_ci return blogic_failure(adapter, 22708c2ecf20Sopenharmony_ci "INQUIRE SYNCHRONOUS PERIOD"); 22718c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 22728c2ecf20Sopenharmony_ci adapter->sync_period[tgt_id] = sync_period[tgt_id]; 22738c2ecf20Sopenharmony_ci } else 22748c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 22758c2ecf20Sopenharmony_ci if (setupinfo.sync0to7[tgt_id].offset > 0) 22768c2ecf20Sopenharmony_ci adapter->sync_period[tgt_id] = 20 + 5 * setupinfo.sync0to7[tgt_id].tx_period; 22778c2ecf20Sopenharmony_ci /* 22788c2ecf20Sopenharmony_ci Indicate the Target Device Inquiry completed successfully. 22798c2ecf20Sopenharmony_ci */ 22808c2ecf20Sopenharmony_ci return true; 22818c2ecf20Sopenharmony_ci} 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci/* 22848c2ecf20Sopenharmony_ci blogic_inithoststruct initializes the fields in the SCSI Host 22858c2ecf20Sopenharmony_ci structure. The base, io_port, n_io_ports, irq, and dma_channel fields in the 22868c2ecf20Sopenharmony_ci SCSI Host structure are intentionally left uninitialized, as this driver 22878c2ecf20Sopenharmony_ci handles acquisition and release of these resources explicitly, as well as 22888c2ecf20Sopenharmony_ci ensuring exclusive access to the Host Adapter hardware and data structures 22898c2ecf20Sopenharmony_ci through explicit acquisition and release of the Host Adapter's Lock. 22908c2ecf20Sopenharmony_ci*/ 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_cistatic void __init blogic_inithoststruct(struct blogic_adapter *adapter, 22938c2ecf20Sopenharmony_ci struct Scsi_Host *host) 22948c2ecf20Sopenharmony_ci{ 22958c2ecf20Sopenharmony_ci host->max_id = adapter->maxdev; 22968c2ecf20Sopenharmony_ci host->max_lun = adapter->maxlun; 22978c2ecf20Sopenharmony_ci host->max_channel = 0; 22988c2ecf20Sopenharmony_ci host->unique_id = adapter->io_addr; 22998c2ecf20Sopenharmony_ci host->this_id = adapter->scsi_id; 23008c2ecf20Sopenharmony_ci host->can_queue = adapter->drvr_qdepth; 23018c2ecf20Sopenharmony_ci host->sg_tablesize = adapter->drvr_sglimit; 23028c2ecf20Sopenharmony_ci host->unchecked_isa_dma = adapter->need_bouncebuf; 23038c2ecf20Sopenharmony_ci host->cmd_per_lun = adapter->untag_qdepth; 23048c2ecf20Sopenharmony_ci} 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci/* 23078c2ecf20Sopenharmony_ci blogic_slaveconfig will actually set the queue depth on individual 23088c2ecf20Sopenharmony_ci scsi devices as they are permanently added to the device chain. We 23098c2ecf20Sopenharmony_ci shamelessly rip off the SelectQueueDepths code to make this work mostly 23108c2ecf20Sopenharmony_ci like it used to. Since we don't get called once at the end of the scan 23118c2ecf20Sopenharmony_ci but instead get called for each device, we have to do things a bit 23128c2ecf20Sopenharmony_ci differently. 23138c2ecf20Sopenharmony_ci*/ 23148c2ecf20Sopenharmony_cistatic int blogic_slaveconfig(struct scsi_device *dev) 23158c2ecf20Sopenharmony_ci{ 23168c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 23178c2ecf20Sopenharmony_ci (struct blogic_adapter *) dev->host->hostdata; 23188c2ecf20Sopenharmony_ci int tgt_id = dev->id; 23198c2ecf20Sopenharmony_ci int qdepth = adapter->qdepth[tgt_id]; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (adapter->tgt_flags[tgt_id].tagq_ok && 23228c2ecf20Sopenharmony_ci (adapter->tagq_ok & (1 << tgt_id))) { 23238c2ecf20Sopenharmony_ci if (qdepth == 0) 23248c2ecf20Sopenharmony_ci qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH; 23258c2ecf20Sopenharmony_ci adapter->qdepth[tgt_id] = qdepth; 23268c2ecf20Sopenharmony_ci scsi_change_queue_depth(dev, qdepth); 23278c2ecf20Sopenharmony_ci } else { 23288c2ecf20Sopenharmony_ci adapter->tagq_ok &= ~(1 << tgt_id); 23298c2ecf20Sopenharmony_ci qdepth = adapter->untag_qdepth; 23308c2ecf20Sopenharmony_ci adapter->qdepth[tgt_id] = qdepth; 23318c2ecf20Sopenharmony_ci scsi_change_queue_depth(dev, qdepth); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci qdepth = 0; 23348c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) 23358c2ecf20Sopenharmony_ci if (adapter->tgt_flags[tgt_id].tgt_exists) 23368c2ecf20Sopenharmony_ci qdepth += adapter->qdepth[tgt_id]; 23378c2ecf20Sopenharmony_ci if (qdepth > adapter->alloc_ccbs) 23388c2ecf20Sopenharmony_ci blogic_create_addlccbs(adapter, qdepth - adapter->alloc_ccbs, 23398c2ecf20Sopenharmony_ci false); 23408c2ecf20Sopenharmony_ci return 0; 23418c2ecf20Sopenharmony_ci} 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci/* 23448c2ecf20Sopenharmony_ci blogic_init probes for BusLogic Host Adapters at the standard 23458c2ecf20Sopenharmony_ci I/O Addresses where they may be located, initializing, registering, and 23468c2ecf20Sopenharmony_ci reporting the configuration of each BusLogic Host Adapter it finds. It 23478c2ecf20Sopenharmony_ci returns the number of BusLogic Host Adapters successfully initialized and 23488c2ecf20Sopenharmony_ci registered. 23498c2ecf20Sopenharmony_ci*/ 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_cistatic int __init blogic_init(void) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci int adapter_count = 0, drvr_optindex = 0, probeindex; 23548c2ecf20Sopenharmony_ci struct blogic_adapter *adapter; 23558c2ecf20Sopenharmony_ci int ret = 0; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci#ifdef MODULE 23588c2ecf20Sopenharmony_ci if (BusLogic) 23598c2ecf20Sopenharmony_ci blogic_setup(BusLogic); 23608c2ecf20Sopenharmony_ci#endif 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci if (blogic_probe_options.noprobe) 23638c2ecf20Sopenharmony_ci return -ENODEV; 23648c2ecf20Sopenharmony_ci blogic_probeinfo_list = 23658c2ecf20Sopenharmony_ci kcalloc(BLOGIC_MAX_ADAPTERS, sizeof(struct blogic_probeinfo), 23668c2ecf20Sopenharmony_ci GFP_KERNEL); 23678c2ecf20Sopenharmony_ci if (blogic_probeinfo_list == NULL) { 23688c2ecf20Sopenharmony_ci blogic_err("BusLogic: Unable to allocate Probe Info List\n", 23698c2ecf20Sopenharmony_ci NULL); 23708c2ecf20Sopenharmony_ci return -ENOMEM; 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci adapter = kzalloc(sizeof(struct blogic_adapter), GFP_KERNEL); 23748c2ecf20Sopenharmony_ci if (adapter == NULL) { 23758c2ecf20Sopenharmony_ci kfree(blogic_probeinfo_list); 23768c2ecf20Sopenharmony_ci blogic_err("BusLogic: Unable to allocate Prototype Host Adapter\n", NULL); 23778c2ecf20Sopenharmony_ci return -ENOMEM; 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci#ifdef MODULE 23818c2ecf20Sopenharmony_ci if (BusLogic != NULL) 23828c2ecf20Sopenharmony_ci blogic_setup(BusLogic); 23838c2ecf20Sopenharmony_ci#endif 23848c2ecf20Sopenharmony_ci blogic_init_probeinfo_list(adapter); 23858c2ecf20Sopenharmony_ci for (probeindex = 0; probeindex < blogic_probeinfo_count; probeindex++) { 23868c2ecf20Sopenharmony_ci struct blogic_probeinfo *probeinfo = 23878c2ecf20Sopenharmony_ci &blogic_probeinfo_list[probeindex]; 23888c2ecf20Sopenharmony_ci struct blogic_adapter *myadapter = adapter; 23898c2ecf20Sopenharmony_ci struct Scsi_Host *host; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci if (probeinfo->io_addr == 0) 23928c2ecf20Sopenharmony_ci continue; 23938c2ecf20Sopenharmony_ci memset(myadapter, 0, sizeof(struct blogic_adapter)); 23948c2ecf20Sopenharmony_ci myadapter->adapter_type = probeinfo->adapter_type; 23958c2ecf20Sopenharmony_ci myadapter->adapter_bus_type = probeinfo->adapter_bus_type; 23968c2ecf20Sopenharmony_ci myadapter->io_addr = probeinfo->io_addr; 23978c2ecf20Sopenharmony_ci myadapter->pci_addr = probeinfo->pci_addr; 23988c2ecf20Sopenharmony_ci myadapter->bus = probeinfo->bus; 23998c2ecf20Sopenharmony_ci myadapter->dev = probeinfo->dev; 24008c2ecf20Sopenharmony_ci myadapter->pci_device = probeinfo->pci_device; 24018c2ecf20Sopenharmony_ci myadapter->irq_ch = probeinfo->irq_ch; 24028c2ecf20Sopenharmony_ci myadapter->addr_count = 24038c2ecf20Sopenharmony_ci blogic_adapter_addr_count[myadapter->adapter_type]; 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci /* 24068c2ecf20Sopenharmony_ci Make sure region is free prior to probing. 24078c2ecf20Sopenharmony_ci */ 24088c2ecf20Sopenharmony_ci if (!request_region(myadapter->io_addr, myadapter->addr_count, 24098c2ecf20Sopenharmony_ci "BusLogic")) 24108c2ecf20Sopenharmony_ci continue; 24118c2ecf20Sopenharmony_ci /* 24128c2ecf20Sopenharmony_ci Probe the Host Adapter. If unsuccessful, abort further 24138c2ecf20Sopenharmony_ci initialization. 24148c2ecf20Sopenharmony_ci */ 24158c2ecf20Sopenharmony_ci if (!blogic_probe(myadapter)) { 24168c2ecf20Sopenharmony_ci release_region(myadapter->io_addr, 24178c2ecf20Sopenharmony_ci myadapter->addr_count); 24188c2ecf20Sopenharmony_ci continue; 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci /* 24218c2ecf20Sopenharmony_ci Hard Reset the Host Adapter. If unsuccessful, abort further 24228c2ecf20Sopenharmony_ci initialization. 24238c2ecf20Sopenharmony_ci */ 24248c2ecf20Sopenharmony_ci if (!blogic_hwreset(myadapter, true)) { 24258c2ecf20Sopenharmony_ci release_region(myadapter->io_addr, 24268c2ecf20Sopenharmony_ci myadapter->addr_count); 24278c2ecf20Sopenharmony_ci continue; 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci /* 24308c2ecf20Sopenharmony_ci Check the Host Adapter. If unsuccessful, abort further 24318c2ecf20Sopenharmony_ci initialization. 24328c2ecf20Sopenharmony_ci */ 24338c2ecf20Sopenharmony_ci if (!blogic_checkadapter(myadapter)) { 24348c2ecf20Sopenharmony_ci release_region(myadapter->io_addr, 24358c2ecf20Sopenharmony_ci myadapter->addr_count); 24368c2ecf20Sopenharmony_ci continue; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci /* 24398c2ecf20Sopenharmony_ci Initialize the Driver Options field if provided. 24408c2ecf20Sopenharmony_ci */ 24418c2ecf20Sopenharmony_ci if (drvr_optindex < blogic_drvr_options_count) 24428c2ecf20Sopenharmony_ci myadapter->drvr_opts = 24438c2ecf20Sopenharmony_ci &blogic_drvr_options[drvr_optindex++]; 24448c2ecf20Sopenharmony_ci /* 24458c2ecf20Sopenharmony_ci Announce the Driver Version and Date, Author's Name, 24468c2ecf20Sopenharmony_ci Copyright Notice, and Electronic Mail Address. 24478c2ecf20Sopenharmony_ci */ 24488c2ecf20Sopenharmony_ci blogic_announce_drvr(myadapter); 24498c2ecf20Sopenharmony_ci /* 24508c2ecf20Sopenharmony_ci Register the SCSI Host structure. 24518c2ecf20Sopenharmony_ci */ 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci host = scsi_host_alloc(&blogic_template, 24548c2ecf20Sopenharmony_ci sizeof(struct blogic_adapter)); 24558c2ecf20Sopenharmony_ci if (host == NULL) { 24568c2ecf20Sopenharmony_ci release_region(myadapter->io_addr, 24578c2ecf20Sopenharmony_ci myadapter->addr_count); 24588c2ecf20Sopenharmony_ci continue; 24598c2ecf20Sopenharmony_ci } 24608c2ecf20Sopenharmony_ci myadapter = (struct blogic_adapter *) host->hostdata; 24618c2ecf20Sopenharmony_ci memcpy(myadapter, adapter, sizeof(struct blogic_adapter)); 24628c2ecf20Sopenharmony_ci myadapter->scsi_host = host; 24638c2ecf20Sopenharmony_ci myadapter->host_no = host->host_no; 24648c2ecf20Sopenharmony_ci /* 24658c2ecf20Sopenharmony_ci Add Host Adapter to the end of the list of registered 24668c2ecf20Sopenharmony_ci BusLogic Host Adapters. 24678c2ecf20Sopenharmony_ci */ 24688c2ecf20Sopenharmony_ci list_add_tail(&myadapter->host_list, &blogic_host_list); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci /* 24718c2ecf20Sopenharmony_ci Read the Host Adapter Configuration, Configure the Host 24728c2ecf20Sopenharmony_ci Adapter, Acquire the System Resources necessary to use 24738c2ecf20Sopenharmony_ci the Host Adapter, then Create the Initial CCBs, Initialize 24748c2ecf20Sopenharmony_ci the Host Adapter, and finally perform Target Device 24758c2ecf20Sopenharmony_ci Inquiry. From this point onward, any failure will be 24768c2ecf20Sopenharmony_ci assumed to be due to a problem with the Host Adapter, 24778c2ecf20Sopenharmony_ci rather than due to having mistakenly identified this port 24788c2ecf20Sopenharmony_ci as belonging to a BusLogic Host Adapter. The I/O Address 24798c2ecf20Sopenharmony_ci range will not be released, thereby preventing it from 24808c2ecf20Sopenharmony_ci being incorrectly identified as any other type of Host 24818c2ecf20Sopenharmony_ci Adapter. 24828c2ecf20Sopenharmony_ci */ 24838c2ecf20Sopenharmony_ci if (blogic_rdconfig(myadapter) && 24848c2ecf20Sopenharmony_ci blogic_reportconfig(myadapter) && 24858c2ecf20Sopenharmony_ci blogic_getres(myadapter) && 24868c2ecf20Sopenharmony_ci blogic_create_initccbs(myadapter) && 24878c2ecf20Sopenharmony_ci blogic_initadapter(myadapter) && 24888c2ecf20Sopenharmony_ci blogic_inquiry(myadapter)) { 24898c2ecf20Sopenharmony_ci /* 24908c2ecf20Sopenharmony_ci Initialization has been completed successfully. 24918c2ecf20Sopenharmony_ci Release and re-register usage of the I/O Address 24928c2ecf20Sopenharmony_ci range so that the Model Name of the Host Adapter 24938c2ecf20Sopenharmony_ci will appear, and initialize the SCSI Host structure. 24948c2ecf20Sopenharmony_ci */ 24958c2ecf20Sopenharmony_ci release_region(myadapter->io_addr, 24968c2ecf20Sopenharmony_ci myadapter->addr_count); 24978c2ecf20Sopenharmony_ci if (!request_region(myadapter->io_addr, 24988c2ecf20Sopenharmony_ci myadapter->addr_count, 24998c2ecf20Sopenharmony_ci myadapter->full_model)) { 25008c2ecf20Sopenharmony_ci printk(KERN_WARNING 25018c2ecf20Sopenharmony_ci "BusLogic: Release and re-register of " 25028c2ecf20Sopenharmony_ci "port 0x%04lx failed \n", 25038c2ecf20Sopenharmony_ci (unsigned long)myadapter->io_addr); 25048c2ecf20Sopenharmony_ci blogic_destroy_ccbs(myadapter); 25058c2ecf20Sopenharmony_ci blogic_relres(myadapter); 25068c2ecf20Sopenharmony_ci list_del(&myadapter->host_list); 25078c2ecf20Sopenharmony_ci scsi_host_put(host); 25088c2ecf20Sopenharmony_ci ret = -ENOMEM; 25098c2ecf20Sopenharmony_ci } else { 25108c2ecf20Sopenharmony_ci blogic_inithoststruct(myadapter, 25118c2ecf20Sopenharmony_ci host); 25128c2ecf20Sopenharmony_ci if (scsi_add_host(host, myadapter->pci_device 25138c2ecf20Sopenharmony_ci ? &myadapter->pci_device->dev 25148c2ecf20Sopenharmony_ci : NULL)) { 25158c2ecf20Sopenharmony_ci printk(KERN_WARNING 25168c2ecf20Sopenharmony_ci "BusLogic: scsi_add_host()" 25178c2ecf20Sopenharmony_ci "failed!\n"); 25188c2ecf20Sopenharmony_ci blogic_destroy_ccbs(myadapter); 25198c2ecf20Sopenharmony_ci blogic_relres(myadapter); 25208c2ecf20Sopenharmony_ci list_del(&myadapter->host_list); 25218c2ecf20Sopenharmony_ci scsi_host_put(host); 25228c2ecf20Sopenharmony_ci ret = -ENODEV; 25238c2ecf20Sopenharmony_ci } else { 25248c2ecf20Sopenharmony_ci scsi_scan_host(host); 25258c2ecf20Sopenharmony_ci adapter_count++; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci } 25288c2ecf20Sopenharmony_ci } else { 25298c2ecf20Sopenharmony_ci /* 25308c2ecf20Sopenharmony_ci An error occurred during Host Adapter Configuration 25318c2ecf20Sopenharmony_ci Querying, Host Adapter Configuration, Resource 25328c2ecf20Sopenharmony_ci Acquisition, CCB Creation, Host Adapter 25338c2ecf20Sopenharmony_ci Initialization, or Target Device Inquiry, so 25348c2ecf20Sopenharmony_ci remove Host Adapter from the list of registered 25358c2ecf20Sopenharmony_ci BusLogic Host Adapters, destroy the CCBs, Release 25368c2ecf20Sopenharmony_ci the System Resources, and Unregister the SCSI 25378c2ecf20Sopenharmony_ci Host. 25388c2ecf20Sopenharmony_ci */ 25398c2ecf20Sopenharmony_ci blogic_destroy_ccbs(myadapter); 25408c2ecf20Sopenharmony_ci blogic_relres(myadapter); 25418c2ecf20Sopenharmony_ci list_del(&myadapter->host_list); 25428c2ecf20Sopenharmony_ci scsi_host_put(host); 25438c2ecf20Sopenharmony_ci ret = -ENODEV; 25448c2ecf20Sopenharmony_ci } 25458c2ecf20Sopenharmony_ci } 25468c2ecf20Sopenharmony_ci kfree(adapter); 25478c2ecf20Sopenharmony_ci kfree(blogic_probeinfo_list); 25488c2ecf20Sopenharmony_ci blogic_probeinfo_list = NULL; 25498c2ecf20Sopenharmony_ci return ret; 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci/* 25548c2ecf20Sopenharmony_ci blogic_deladapter releases all resources previously acquired to 25558c2ecf20Sopenharmony_ci support a specific Host Adapter, including the I/O Address range, and 25568c2ecf20Sopenharmony_ci unregisters the BusLogic Host Adapter. 25578c2ecf20Sopenharmony_ci*/ 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic int __exit blogic_deladapter(struct blogic_adapter *adapter) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci struct Scsi_Host *host = adapter->scsi_host; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci scsi_remove_host(host); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci /* 25668c2ecf20Sopenharmony_ci FlashPoint Host Adapters must first be released by the FlashPoint 25678c2ecf20Sopenharmony_ci SCCB Manager. 25688c2ecf20Sopenharmony_ci */ 25698c2ecf20Sopenharmony_ci if (blogic_flashpoint_type(adapter)) 25708c2ecf20Sopenharmony_ci FlashPoint_ReleaseHostAdapter(adapter->cardhandle); 25718c2ecf20Sopenharmony_ci /* 25728c2ecf20Sopenharmony_ci Destroy the CCBs and release any system resources acquired to 25738c2ecf20Sopenharmony_ci support Host Adapter. 25748c2ecf20Sopenharmony_ci */ 25758c2ecf20Sopenharmony_ci blogic_destroy_ccbs(adapter); 25768c2ecf20Sopenharmony_ci blogic_relres(adapter); 25778c2ecf20Sopenharmony_ci /* 25788c2ecf20Sopenharmony_ci Release usage of the I/O Address range. 25798c2ecf20Sopenharmony_ci */ 25808c2ecf20Sopenharmony_ci release_region(adapter->io_addr, adapter->addr_count); 25818c2ecf20Sopenharmony_ci /* 25828c2ecf20Sopenharmony_ci Remove Host Adapter from the list of registered BusLogic 25838c2ecf20Sopenharmony_ci Host Adapters. 25848c2ecf20Sopenharmony_ci */ 25858c2ecf20Sopenharmony_ci list_del(&adapter->host_list); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci scsi_host_put(host); 25888c2ecf20Sopenharmony_ci return 0; 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci/* 25938c2ecf20Sopenharmony_ci blogic_qcompleted_ccb queues CCB for completion processing. 25948c2ecf20Sopenharmony_ci*/ 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_cistatic void blogic_qcompleted_ccb(struct blogic_ccb *ccb) 25978c2ecf20Sopenharmony_ci{ 25988c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = ccb->adapter; 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci ccb->status = BLOGIC_CCB_COMPLETE; 26018c2ecf20Sopenharmony_ci ccb->next = NULL; 26028c2ecf20Sopenharmony_ci if (adapter->firstccb == NULL) { 26038c2ecf20Sopenharmony_ci adapter->firstccb = ccb; 26048c2ecf20Sopenharmony_ci adapter->lastccb = ccb; 26058c2ecf20Sopenharmony_ci } else { 26068c2ecf20Sopenharmony_ci adapter->lastccb->next = ccb; 26078c2ecf20Sopenharmony_ci adapter->lastccb = ccb; 26088c2ecf20Sopenharmony_ci } 26098c2ecf20Sopenharmony_ci adapter->active_cmds[ccb->tgt_id]--; 26108c2ecf20Sopenharmony_ci} 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci/* 26148c2ecf20Sopenharmony_ci blogic_resultcode computes a SCSI Subsystem Result Code from 26158c2ecf20Sopenharmony_ci the Host Adapter Status and Target Device Status. 26168c2ecf20Sopenharmony_ci*/ 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_cistatic int blogic_resultcode(struct blogic_adapter *adapter, 26198c2ecf20Sopenharmony_ci enum blogic_adapter_status adapter_status, 26208c2ecf20Sopenharmony_ci enum blogic_tgt_status tgt_status) 26218c2ecf20Sopenharmony_ci{ 26228c2ecf20Sopenharmony_ci int hoststatus; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci switch (adapter_status) { 26258c2ecf20Sopenharmony_ci case BLOGIC_CMD_CMPLT_NORMAL: 26268c2ecf20Sopenharmony_ci case BLOGIC_LINK_CMD_CMPLT: 26278c2ecf20Sopenharmony_ci case BLOGIC_LINK_CMD_CMPLT_FLAG: 26288c2ecf20Sopenharmony_ci hoststatus = DID_OK; 26298c2ecf20Sopenharmony_ci break; 26308c2ecf20Sopenharmony_ci case BLOGIC_SELECT_TIMEOUT: 26318c2ecf20Sopenharmony_ci hoststatus = DID_TIME_OUT; 26328c2ecf20Sopenharmony_ci break; 26338c2ecf20Sopenharmony_ci case BLOGIC_INVALID_OUTBOX_CODE: 26348c2ecf20Sopenharmony_ci case BLOGIC_INVALID_CMD_CODE: 26358c2ecf20Sopenharmony_ci case BLOGIC_BAD_CMD_PARAM: 26368c2ecf20Sopenharmony_ci blogic_warn("BusLogic Driver Protocol Error 0x%02X\n", 26378c2ecf20Sopenharmony_ci adapter, adapter_status); 26388c2ecf20Sopenharmony_ci fallthrough; 26398c2ecf20Sopenharmony_ci case BLOGIC_DATA_UNDERRUN: 26408c2ecf20Sopenharmony_ci case BLOGIC_DATA_OVERRUN: 26418c2ecf20Sopenharmony_ci case BLOGIC_NOEXPECT_BUSFREE: 26428c2ecf20Sopenharmony_ci case BLOGIC_LINKCCB_BADLUN: 26438c2ecf20Sopenharmony_ci case BLOGIC_AUTOREQSENSE_FAIL: 26448c2ecf20Sopenharmony_ci case BLOGIC_TAGQUEUE_REJECT: 26458c2ecf20Sopenharmony_ci case BLOGIC_BAD_MSG_RCVD: 26468c2ecf20Sopenharmony_ci case BLOGIC_HW_FAIL: 26478c2ecf20Sopenharmony_ci case BLOGIC_BAD_RECONNECT: 26488c2ecf20Sopenharmony_ci case BLOGIC_ABRT_QUEUE: 26498c2ecf20Sopenharmony_ci case BLOGIC_ADAPTER_SW_ERROR: 26508c2ecf20Sopenharmony_ci case BLOGIC_HW_TIMEOUT: 26518c2ecf20Sopenharmony_ci case BLOGIC_PARITY_ERR: 26528c2ecf20Sopenharmony_ci hoststatus = DID_ERROR; 26538c2ecf20Sopenharmony_ci break; 26548c2ecf20Sopenharmony_ci case BLOGIC_INVALID_BUSPHASE: 26558c2ecf20Sopenharmony_ci case BLOGIC_NORESPONSE_TO_ATN: 26568c2ecf20Sopenharmony_ci case BLOGIC_HW_RESET: 26578c2ecf20Sopenharmony_ci case BLOGIC_RST_FROM_OTHERDEV: 26588c2ecf20Sopenharmony_ci case BLOGIC_HW_BDR: 26598c2ecf20Sopenharmony_ci hoststatus = DID_RESET; 26608c2ecf20Sopenharmony_ci break; 26618c2ecf20Sopenharmony_ci default: 26628c2ecf20Sopenharmony_ci blogic_warn("Unknown Host Adapter Status 0x%02X\n", adapter, 26638c2ecf20Sopenharmony_ci adapter_status); 26648c2ecf20Sopenharmony_ci hoststatus = DID_ERROR; 26658c2ecf20Sopenharmony_ci break; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci return (hoststatus << 16) | tgt_status; 26688c2ecf20Sopenharmony_ci} 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci/* 26728c2ecf20Sopenharmony_ci blogic_scan_inbox scans the Incoming Mailboxes saving any 26738c2ecf20Sopenharmony_ci Incoming Mailbox entries for completion processing. 26748c2ecf20Sopenharmony_ci*/ 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_cistatic void blogic_scan_inbox(struct blogic_adapter *adapter) 26778c2ecf20Sopenharmony_ci{ 26788c2ecf20Sopenharmony_ci /* 26798c2ecf20Sopenharmony_ci Scan through the Incoming Mailboxes in Strict Round Robin 26808c2ecf20Sopenharmony_ci fashion, saving any completed CCBs for further processing. It 26818c2ecf20Sopenharmony_ci is essential that for each CCB and SCSI Command issued, command 26828c2ecf20Sopenharmony_ci completion processing is performed exactly once. Therefore, 26838c2ecf20Sopenharmony_ci only Incoming Mailboxes with completion code Command Completed 26848c2ecf20Sopenharmony_ci Without Error, Command Completed With Error, or Command Aborted 26858c2ecf20Sopenharmony_ci At Host Request are saved for completion processing. When an 26868c2ecf20Sopenharmony_ci Incoming Mailbox has a completion code of Aborted Command Not 26878c2ecf20Sopenharmony_ci Found, the CCB had already completed or been aborted before the 26888c2ecf20Sopenharmony_ci current Abort request was processed, and so completion processing 26898c2ecf20Sopenharmony_ci has already occurred and no further action should be taken. 26908c2ecf20Sopenharmony_ci */ 26918c2ecf20Sopenharmony_ci struct blogic_inbox *next_inbox = adapter->next_inbox; 26928c2ecf20Sopenharmony_ci enum blogic_cmplt_code comp_code; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci while ((comp_code = next_inbox->comp_code) != BLOGIC_INBOX_FREE) { 26958c2ecf20Sopenharmony_ci /* 26968c2ecf20Sopenharmony_ci We are only allowed to do this because we limit our 26978c2ecf20Sopenharmony_ci architectures we run on to machines where bus_to_virt( 26988c2ecf20Sopenharmony_ci actually works. There *needs* to be a dma_addr_to_virt() 26998c2ecf20Sopenharmony_ci in the new PCI DMA mapping interface to replace 27008c2ecf20Sopenharmony_ci bus_to_virt() or else this code is going to become very 27018c2ecf20Sopenharmony_ci innefficient. 27028c2ecf20Sopenharmony_ci */ 27038c2ecf20Sopenharmony_ci struct blogic_ccb *ccb = 27048c2ecf20Sopenharmony_ci (struct blogic_ccb *) bus_to_virt(next_inbox->ccb); 27058c2ecf20Sopenharmony_ci if (comp_code != BLOGIC_CMD_NOTFOUND) { 27068c2ecf20Sopenharmony_ci if (ccb->status == BLOGIC_CCB_ACTIVE || 27078c2ecf20Sopenharmony_ci ccb->status == BLOGIC_CCB_RESET) { 27088c2ecf20Sopenharmony_ci /* 27098c2ecf20Sopenharmony_ci Save the Completion Code for this CCB and 27108c2ecf20Sopenharmony_ci queue the CCB for completion processing. 27118c2ecf20Sopenharmony_ci */ 27128c2ecf20Sopenharmony_ci ccb->comp_code = comp_code; 27138c2ecf20Sopenharmony_ci blogic_qcompleted_ccb(ccb); 27148c2ecf20Sopenharmony_ci } else { 27158c2ecf20Sopenharmony_ci /* 27168c2ecf20Sopenharmony_ci If a CCB ever appears in an Incoming Mailbox 27178c2ecf20Sopenharmony_ci and is not marked as status Active or Reset, 27188c2ecf20Sopenharmony_ci then there is most likely a bug in 27198c2ecf20Sopenharmony_ci the Host Adapter firmware. 27208c2ecf20Sopenharmony_ci */ 27218c2ecf20Sopenharmony_ci blogic_warn("Illegal CCB #%ld status %d in Incoming Mailbox\n", adapter, ccb->serial, ccb->status); 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci next_inbox->comp_code = BLOGIC_INBOX_FREE; 27258c2ecf20Sopenharmony_ci if (++next_inbox > adapter->last_inbox) 27268c2ecf20Sopenharmony_ci next_inbox = adapter->first_inbox; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci adapter->next_inbox = next_inbox; 27298c2ecf20Sopenharmony_ci} 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci/* 27338c2ecf20Sopenharmony_ci blogic_process_ccbs iterates over the completed CCBs for Host 27348c2ecf20Sopenharmony_ci Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and 27358c2ecf20Sopenharmony_ci calling the SCSI Subsystem Completion Routines. The Host Adapter's Lock 27368c2ecf20Sopenharmony_ci should already have been acquired by the caller. 27378c2ecf20Sopenharmony_ci*/ 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_cistatic void blogic_process_ccbs(struct blogic_adapter *adapter) 27408c2ecf20Sopenharmony_ci{ 27418c2ecf20Sopenharmony_ci if (adapter->processing_ccbs) 27428c2ecf20Sopenharmony_ci return; 27438c2ecf20Sopenharmony_ci adapter->processing_ccbs = true; 27448c2ecf20Sopenharmony_ci while (adapter->firstccb != NULL) { 27458c2ecf20Sopenharmony_ci struct blogic_ccb *ccb = adapter->firstccb; 27468c2ecf20Sopenharmony_ci struct scsi_cmnd *command = ccb->command; 27478c2ecf20Sopenharmony_ci adapter->firstccb = ccb->next; 27488c2ecf20Sopenharmony_ci if (adapter->firstccb == NULL) 27498c2ecf20Sopenharmony_ci adapter->lastccb = NULL; 27508c2ecf20Sopenharmony_ci /* 27518c2ecf20Sopenharmony_ci Process the Completed CCB. 27528c2ecf20Sopenharmony_ci */ 27538c2ecf20Sopenharmony_ci if (ccb->opcode == BLOGIC_BDR) { 27548c2ecf20Sopenharmony_ci int tgt_id = ccb->tgt_id; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci blogic_warn("Bus Device Reset CCB #%ld to Target %d Completed\n", adapter, ccb->serial, tgt_id); 27578c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->tgt_stats[tgt_id].bdr_done); 27588c2ecf20Sopenharmony_ci adapter->tgt_flags[tgt_id].tagq_active = false; 27598c2ecf20Sopenharmony_ci adapter->cmds_since_rst[tgt_id] = 0; 27608c2ecf20Sopenharmony_ci adapter->last_resetdone[tgt_id] = jiffies; 27618c2ecf20Sopenharmony_ci /* 27628c2ecf20Sopenharmony_ci Place CCB back on the Host Adapter's free list. 27638c2ecf20Sopenharmony_ci */ 27648c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 1); 27658c2ecf20Sopenharmony_ci#if 0 /* this needs to be redone different for new EH */ 27668c2ecf20Sopenharmony_ci /* 27678c2ecf20Sopenharmony_ci Bus Device Reset CCBs have the command field 27688c2ecf20Sopenharmony_ci non-NULL only when a Bus Device Reset was requested 27698c2ecf20Sopenharmony_ci for a command that did not have a currently active 27708c2ecf20Sopenharmony_ci CCB in the Host Adapter (i.e., a Synchronous Bus 27718c2ecf20Sopenharmony_ci Device Reset), and hence would not have its 27728c2ecf20Sopenharmony_ci Completion Routine called otherwise. 27738c2ecf20Sopenharmony_ci */ 27748c2ecf20Sopenharmony_ci while (command != NULL) { 27758c2ecf20Sopenharmony_ci struct scsi_cmnd *nxt_cmd = 27768c2ecf20Sopenharmony_ci command->reset_chain; 27778c2ecf20Sopenharmony_ci command->reset_chain = NULL; 27788c2ecf20Sopenharmony_ci command->result = DID_RESET << 16; 27798c2ecf20Sopenharmony_ci command->scsi_done(command); 27808c2ecf20Sopenharmony_ci command = nxt_cmd; 27818c2ecf20Sopenharmony_ci } 27828c2ecf20Sopenharmony_ci#endif 27838c2ecf20Sopenharmony_ci /* 27848c2ecf20Sopenharmony_ci Iterate over the CCBs for this Host Adapter 27858c2ecf20Sopenharmony_ci performing completion processing for any CCBs 27868c2ecf20Sopenharmony_ci marked as Reset for this Target. 27878c2ecf20Sopenharmony_ci */ 27888c2ecf20Sopenharmony_ci for (ccb = adapter->all_ccbs; ccb != NULL; 27898c2ecf20Sopenharmony_ci ccb = ccb->next_all) 27908c2ecf20Sopenharmony_ci if (ccb->status == BLOGIC_CCB_RESET && 27918c2ecf20Sopenharmony_ci ccb->tgt_id == tgt_id) { 27928c2ecf20Sopenharmony_ci command = ccb->command; 27938c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 1); 27948c2ecf20Sopenharmony_ci adapter->active_cmds[tgt_id]--; 27958c2ecf20Sopenharmony_ci command->result = DID_RESET << 16; 27968c2ecf20Sopenharmony_ci command->scsi_done(command); 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci adapter->bdr_pend[tgt_id] = NULL; 27998c2ecf20Sopenharmony_ci } else { 28008c2ecf20Sopenharmony_ci /* 28018c2ecf20Sopenharmony_ci Translate the Completion Code, Host Adapter Status, 28028c2ecf20Sopenharmony_ci and Target Device Status into a SCSI Subsystem 28038c2ecf20Sopenharmony_ci Result Code. 28048c2ecf20Sopenharmony_ci */ 28058c2ecf20Sopenharmony_ci switch (ccb->comp_code) { 28068c2ecf20Sopenharmony_ci case BLOGIC_INBOX_FREE: 28078c2ecf20Sopenharmony_ci case BLOGIC_CMD_NOTFOUND: 28088c2ecf20Sopenharmony_ci case BLOGIC_INVALID_CCB: 28098c2ecf20Sopenharmony_ci blogic_warn("CCB #%ld to Target %d Impossible State\n", adapter, ccb->serial, ccb->tgt_id); 28108c2ecf20Sopenharmony_ci break; 28118c2ecf20Sopenharmony_ci case BLOGIC_CMD_COMPLETE_GOOD: 28128c2ecf20Sopenharmony_ci adapter->tgt_stats[ccb->tgt_id] 28138c2ecf20Sopenharmony_ci .cmds_complete++; 28148c2ecf20Sopenharmony_ci adapter->tgt_flags[ccb->tgt_id] 28158c2ecf20Sopenharmony_ci .cmd_good = true; 28168c2ecf20Sopenharmony_ci command->result = DID_OK << 16; 28178c2ecf20Sopenharmony_ci break; 28188c2ecf20Sopenharmony_ci case BLOGIC_CMD_ABORT_BY_HOST: 28198c2ecf20Sopenharmony_ci blogic_warn("CCB #%ld to Target %d Aborted\n", 28208c2ecf20Sopenharmony_ci adapter, ccb->serial, ccb->tgt_id); 28218c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->tgt_stats[ccb->tgt_id].aborts_done); 28228c2ecf20Sopenharmony_ci command->result = DID_ABORT << 16; 28238c2ecf20Sopenharmony_ci break; 28248c2ecf20Sopenharmony_ci case BLOGIC_CMD_COMPLETE_ERROR: 28258c2ecf20Sopenharmony_ci command->result = blogic_resultcode(adapter, 28268c2ecf20Sopenharmony_ci ccb->adapter_status, ccb->tgt_status); 28278c2ecf20Sopenharmony_ci if (ccb->adapter_status != BLOGIC_SELECT_TIMEOUT) { 28288c2ecf20Sopenharmony_ci adapter->tgt_stats[ccb->tgt_id] 28298c2ecf20Sopenharmony_ci .cmds_complete++; 28308c2ecf20Sopenharmony_ci if (blogic_global_options.trace_err) { 28318c2ecf20Sopenharmony_ci int i; 28328c2ecf20Sopenharmony_ci blogic_notice("CCB #%ld Target %d: Result %X Host " 28338c2ecf20Sopenharmony_ci "Adapter Status %02X Target Status %02X\n", adapter, ccb->serial, ccb->tgt_id, command->result, ccb->adapter_status, ccb->tgt_status); 28348c2ecf20Sopenharmony_ci blogic_notice("CDB ", adapter); 28358c2ecf20Sopenharmony_ci for (i = 0; i < ccb->cdblen; i++) 28368c2ecf20Sopenharmony_ci blogic_notice(" %02X", adapter, ccb->cdb[i]); 28378c2ecf20Sopenharmony_ci blogic_notice("\n", adapter); 28388c2ecf20Sopenharmony_ci blogic_notice("Sense ", adapter); 28398c2ecf20Sopenharmony_ci for (i = 0; i < ccb->sense_datalen; i++) 28408c2ecf20Sopenharmony_ci blogic_notice(" %02X", adapter, command->sense_buffer[i]); 28418c2ecf20Sopenharmony_ci blogic_notice("\n", adapter); 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci break; 28458c2ecf20Sopenharmony_ci } 28468c2ecf20Sopenharmony_ci /* 28478c2ecf20Sopenharmony_ci When an INQUIRY command completes normally, save the 28488c2ecf20Sopenharmony_ci CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit 28498c2ecf20Sopenharmony_ci Wide Data Transfers Supported) bits. 28508c2ecf20Sopenharmony_ci */ 28518c2ecf20Sopenharmony_ci if (ccb->cdb[0] == INQUIRY && ccb->cdb[1] == 0 && 28528c2ecf20Sopenharmony_ci ccb->adapter_status == BLOGIC_CMD_CMPLT_NORMAL) { 28538c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = 28548c2ecf20Sopenharmony_ci &adapter->tgt_flags[ccb->tgt_id]; 28558c2ecf20Sopenharmony_ci struct scsi_inquiry *inquiry = 28568c2ecf20Sopenharmony_ci (struct scsi_inquiry *) scsi_sglist(command); 28578c2ecf20Sopenharmony_ci tgt_flags->tgt_exists = true; 28588c2ecf20Sopenharmony_ci tgt_flags->tagq_ok = inquiry->CmdQue; 28598c2ecf20Sopenharmony_ci tgt_flags->wide_ok = inquiry->WBus16; 28608c2ecf20Sopenharmony_ci } 28618c2ecf20Sopenharmony_ci /* 28628c2ecf20Sopenharmony_ci Place CCB back on the Host Adapter's free list. 28638c2ecf20Sopenharmony_ci */ 28648c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 1); 28658c2ecf20Sopenharmony_ci /* 28668c2ecf20Sopenharmony_ci Call the SCSI Command Completion Routine. 28678c2ecf20Sopenharmony_ci */ 28688c2ecf20Sopenharmony_ci command->scsi_done(command); 28698c2ecf20Sopenharmony_ci } 28708c2ecf20Sopenharmony_ci } 28718c2ecf20Sopenharmony_ci adapter->processing_ccbs = false; 28728c2ecf20Sopenharmony_ci} 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci/* 28768c2ecf20Sopenharmony_ci blogic_inthandler handles hardware interrupts from BusLogic Host 28778c2ecf20Sopenharmony_ci Adapters. 28788c2ecf20Sopenharmony_ci*/ 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_cistatic irqreturn_t blogic_inthandler(int irq_ch, void *devid) 28818c2ecf20Sopenharmony_ci{ 28828c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = (struct blogic_adapter *) devid; 28838c2ecf20Sopenharmony_ci unsigned long processor_flag; 28848c2ecf20Sopenharmony_ci /* 28858c2ecf20Sopenharmony_ci Acquire exclusive access to Host Adapter. 28868c2ecf20Sopenharmony_ci */ 28878c2ecf20Sopenharmony_ci spin_lock_irqsave(adapter->scsi_host->host_lock, processor_flag); 28888c2ecf20Sopenharmony_ci /* 28898c2ecf20Sopenharmony_ci Handle Interrupts appropriately for each Host Adapter type. 28908c2ecf20Sopenharmony_ci */ 28918c2ecf20Sopenharmony_ci if (blogic_multimaster_type(adapter)) { 28928c2ecf20Sopenharmony_ci union blogic_int_reg intreg; 28938c2ecf20Sopenharmony_ci /* 28948c2ecf20Sopenharmony_ci Read the Host Adapter Interrupt Register. 28958c2ecf20Sopenharmony_ci */ 28968c2ecf20Sopenharmony_ci intreg.all = blogic_rdint(adapter); 28978c2ecf20Sopenharmony_ci if (intreg.ir.int_valid) { 28988c2ecf20Sopenharmony_ci /* 28998c2ecf20Sopenharmony_ci Acknowledge the interrupt and reset the Host Adapter 29008c2ecf20Sopenharmony_ci Interrupt Register. 29018c2ecf20Sopenharmony_ci */ 29028c2ecf20Sopenharmony_ci blogic_intreset(adapter); 29038c2ecf20Sopenharmony_ci /* 29048c2ecf20Sopenharmony_ci Process valid External SCSI Bus Reset and Incoming 29058c2ecf20Sopenharmony_ci Mailbox Loaded Interrupts. Command Complete 29068c2ecf20Sopenharmony_ci Interrupts are noted, and Outgoing Mailbox Available 29078c2ecf20Sopenharmony_ci Interrupts are ignored, as they are never enabled. 29088c2ecf20Sopenharmony_ci */ 29098c2ecf20Sopenharmony_ci if (intreg.ir.ext_busreset) 29108c2ecf20Sopenharmony_ci adapter->adapter_extreset = true; 29118c2ecf20Sopenharmony_ci else if (intreg.ir.mailin_loaded) 29128c2ecf20Sopenharmony_ci blogic_scan_inbox(adapter); 29138c2ecf20Sopenharmony_ci else if (intreg.ir.cmd_complete) 29148c2ecf20Sopenharmony_ci adapter->adapter_cmd_complete = true; 29158c2ecf20Sopenharmony_ci } 29168c2ecf20Sopenharmony_ci } else { 29178c2ecf20Sopenharmony_ci /* 29188c2ecf20Sopenharmony_ci Check if there is a pending interrupt for this Host Adapter. 29198c2ecf20Sopenharmony_ci */ 29208c2ecf20Sopenharmony_ci if (FlashPoint_InterruptPending(adapter->cardhandle)) 29218c2ecf20Sopenharmony_ci switch (FlashPoint_HandleInterrupt(adapter->cardhandle)) { 29228c2ecf20Sopenharmony_ci case FPOINT_NORMAL_INT: 29238c2ecf20Sopenharmony_ci break; 29248c2ecf20Sopenharmony_ci case FPOINT_EXT_RESET: 29258c2ecf20Sopenharmony_ci adapter->adapter_extreset = true; 29268c2ecf20Sopenharmony_ci break; 29278c2ecf20Sopenharmony_ci case FPOINT_INTERN_ERR: 29288c2ecf20Sopenharmony_ci blogic_warn("Internal FlashPoint Error detected - Resetting Host Adapter\n", adapter); 29298c2ecf20Sopenharmony_ci adapter->adapter_intern_err = true; 29308c2ecf20Sopenharmony_ci break; 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci /* 29348c2ecf20Sopenharmony_ci Process any completed CCBs. 29358c2ecf20Sopenharmony_ci */ 29368c2ecf20Sopenharmony_ci if (adapter->firstccb != NULL) 29378c2ecf20Sopenharmony_ci blogic_process_ccbs(adapter); 29388c2ecf20Sopenharmony_ci /* 29398c2ecf20Sopenharmony_ci Reset the Host Adapter if requested. 29408c2ecf20Sopenharmony_ci */ 29418c2ecf20Sopenharmony_ci if (adapter->adapter_extreset) { 29428c2ecf20Sopenharmony_ci blogic_warn("Resetting %s due to External SCSI Bus Reset\n", adapter, adapter->full_model); 29438c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->ext_resets); 29448c2ecf20Sopenharmony_ci blogic_resetadapter(adapter, false); 29458c2ecf20Sopenharmony_ci adapter->adapter_extreset = false; 29468c2ecf20Sopenharmony_ci } else if (adapter->adapter_intern_err) { 29478c2ecf20Sopenharmony_ci blogic_warn("Resetting %s due to Host Adapter Internal Error\n", adapter, adapter->full_model); 29488c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->adapter_intern_errors); 29498c2ecf20Sopenharmony_ci blogic_resetadapter(adapter, true); 29508c2ecf20Sopenharmony_ci adapter->adapter_intern_err = false; 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci /* 29538c2ecf20Sopenharmony_ci Release exclusive access to Host Adapter. 29548c2ecf20Sopenharmony_ci */ 29558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(adapter->scsi_host->host_lock, processor_flag); 29568c2ecf20Sopenharmony_ci return IRQ_HANDLED; 29578c2ecf20Sopenharmony_ci} 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci/* 29618c2ecf20Sopenharmony_ci blogic_write_outbox places CCB and Action Code into an Outgoing 29628c2ecf20Sopenharmony_ci Mailbox for execution by Host Adapter. The Host Adapter's Lock should 29638c2ecf20Sopenharmony_ci already have been acquired by the caller. 29648c2ecf20Sopenharmony_ci*/ 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_cistatic bool blogic_write_outbox(struct blogic_adapter *adapter, 29678c2ecf20Sopenharmony_ci enum blogic_action action, struct blogic_ccb *ccb) 29688c2ecf20Sopenharmony_ci{ 29698c2ecf20Sopenharmony_ci struct blogic_outbox *next_outbox; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci next_outbox = adapter->next_outbox; 29728c2ecf20Sopenharmony_ci if (next_outbox->action == BLOGIC_OUTBOX_FREE) { 29738c2ecf20Sopenharmony_ci ccb->status = BLOGIC_CCB_ACTIVE; 29748c2ecf20Sopenharmony_ci /* 29758c2ecf20Sopenharmony_ci The CCB field must be written before the Action Code field 29768c2ecf20Sopenharmony_ci since the Host Adapter is operating asynchronously and the 29778c2ecf20Sopenharmony_ci locking code does not protect against simultaneous access 29788c2ecf20Sopenharmony_ci by the Host Adapter. 29798c2ecf20Sopenharmony_ci */ 29808c2ecf20Sopenharmony_ci next_outbox->ccb = ccb->dma_handle; 29818c2ecf20Sopenharmony_ci next_outbox->action = action; 29828c2ecf20Sopenharmony_ci blogic_execmbox(adapter); 29838c2ecf20Sopenharmony_ci if (++next_outbox > adapter->last_outbox) 29848c2ecf20Sopenharmony_ci next_outbox = adapter->first_outbox; 29858c2ecf20Sopenharmony_ci adapter->next_outbox = next_outbox; 29868c2ecf20Sopenharmony_ci if (action == BLOGIC_MBOX_START) { 29878c2ecf20Sopenharmony_ci adapter->active_cmds[ccb->tgt_id]++; 29888c2ecf20Sopenharmony_ci if (ccb->opcode != BLOGIC_BDR) 29898c2ecf20Sopenharmony_ci adapter->tgt_stats[ccb->tgt_id].cmds_tried++; 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci return true; 29928c2ecf20Sopenharmony_ci } 29938c2ecf20Sopenharmony_ci return false; 29948c2ecf20Sopenharmony_ci} 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci/* Error Handling (EH) support */ 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_cistatic int blogic_hostreset(struct scsi_cmnd *SCpnt) 29998c2ecf20Sopenharmony_ci{ 30008c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 30018c2ecf20Sopenharmony_ci (struct blogic_adapter *) SCpnt->device->host->hostdata; 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci unsigned int id = SCpnt->device->id; 30048c2ecf20Sopenharmony_ci struct blogic_tgt_stats *stats = &adapter->tgt_stats[id]; 30058c2ecf20Sopenharmony_ci int rc; 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci spin_lock_irq(SCpnt->device->host->host_lock); 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci blogic_inc_count(&stats->adapter_reset_req); 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci rc = blogic_resetadapter(adapter, false); 30128c2ecf20Sopenharmony_ci spin_unlock_irq(SCpnt->device->host->host_lock); 30138c2ecf20Sopenharmony_ci return rc; 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci/* 30178c2ecf20Sopenharmony_ci blogic_qcmd creates a CCB for Command and places it into an 30188c2ecf20Sopenharmony_ci Outgoing Mailbox for execution by the associated Host Adapter. 30198c2ecf20Sopenharmony_ci*/ 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_cistatic int blogic_qcmd_lck(struct scsi_cmnd *command, 30228c2ecf20Sopenharmony_ci void (*comp_cb) (struct scsi_cmnd *)) 30238c2ecf20Sopenharmony_ci{ 30248c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 30258c2ecf20Sopenharmony_ci (struct blogic_adapter *) command->device->host->hostdata; 30268c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = 30278c2ecf20Sopenharmony_ci &adapter->tgt_flags[command->device->id]; 30288c2ecf20Sopenharmony_ci struct blogic_tgt_stats *tgt_stats = adapter->tgt_stats; 30298c2ecf20Sopenharmony_ci unsigned char *cdb = command->cmnd; 30308c2ecf20Sopenharmony_ci int cdblen = command->cmd_len; 30318c2ecf20Sopenharmony_ci int tgt_id = command->device->id; 30328c2ecf20Sopenharmony_ci int lun = command->device->lun; 30338c2ecf20Sopenharmony_ci int buflen = scsi_bufflen(command); 30348c2ecf20Sopenharmony_ci int count; 30358c2ecf20Sopenharmony_ci struct blogic_ccb *ccb; 30368c2ecf20Sopenharmony_ci dma_addr_t sense_buf; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci /* 30398c2ecf20Sopenharmony_ci SCSI REQUEST_SENSE commands will be executed automatically by the 30408c2ecf20Sopenharmony_ci Host Adapter for any errors, so they should not be executed 30418c2ecf20Sopenharmony_ci explicitly unless the Sense Data is zero indicating that no error 30428c2ecf20Sopenharmony_ci occurred. 30438c2ecf20Sopenharmony_ci */ 30448c2ecf20Sopenharmony_ci if (cdb[0] == REQUEST_SENSE && command->sense_buffer[0] != 0) { 30458c2ecf20Sopenharmony_ci command->result = DID_OK << 16; 30468c2ecf20Sopenharmony_ci comp_cb(command); 30478c2ecf20Sopenharmony_ci return 0; 30488c2ecf20Sopenharmony_ci } 30498c2ecf20Sopenharmony_ci /* 30508c2ecf20Sopenharmony_ci Allocate a CCB from the Host Adapter's free list. In the unlikely 30518c2ecf20Sopenharmony_ci event that there are none available and memory allocation fails, 30528c2ecf20Sopenharmony_ci wait 1 second and try again. If that fails, the Host Adapter is 30538c2ecf20Sopenharmony_ci probably hung so signal an error as a Host Adapter Hard Reset 30548c2ecf20Sopenharmony_ci should be initiated soon. 30558c2ecf20Sopenharmony_ci */ 30568c2ecf20Sopenharmony_ci ccb = blogic_alloc_ccb(adapter); 30578c2ecf20Sopenharmony_ci if (ccb == NULL) { 30588c2ecf20Sopenharmony_ci spin_unlock_irq(adapter->scsi_host->host_lock); 30598c2ecf20Sopenharmony_ci blogic_delay(1); 30608c2ecf20Sopenharmony_ci spin_lock_irq(adapter->scsi_host->host_lock); 30618c2ecf20Sopenharmony_ci ccb = blogic_alloc_ccb(adapter); 30628c2ecf20Sopenharmony_ci if (ccb == NULL) { 30638c2ecf20Sopenharmony_ci command->result = DID_ERROR << 16; 30648c2ecf20Sopenharmony_ci comp_cb(command); 30658c2ecf20Sopenharmony_ci return 0; 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci } 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci /* 30708c2ecf20Sopenharmony_ci Initialize the fields in the BusLogic Command Control Block (CCB). 30718c2ecf20Sopenharmony_ci */ 30728c2ecf20Sopenharmony_ci count = scsi_dma_map(command); 30738c2ecf20Sopenharmony_ci BUG_ON(count < 0); 30748c2ecf20Sopenharmony_ci if (count) { 30758c2ecf20Sopenharmony_ci struct scatterlist *sg; 30768c2ecf20Sopenharmony_ci int i; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci ccb->opcode = BLOGIC_INITIATOR_CCB_SG; 30798c2ecf20Sopenharmony_ci ccb->datalen = count * sizeof(struct blogic_sg_seg); 30808c2ecf20Sopenharmony_ci if (blogic_multimaster_type(adapter)) 30818c2ecf20Sopenharmony_ci ccb->data = (unsigned int) ccb->dma_handle + 30828c2ecf20Sopenharmony_ci ((unsigned long) &ccb->sglist - 30838c2ecf20Sopenharmony_ci (unsigned long) ccb); 30848c2ecf20Sopenharmony_ci else 30858c2ecf20Sopenharmony_ci ccb->data = virt_to_32bit_virt(ccb->sglist); 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci scsi_for_each_sg(command, sg, count, i) { 30888c2ecf20Sopenharmony_ci ccb->sglist[i].segbytes = sg_dma_len(sg); 30898c2ecf20Sopenharmony_ci ccb->sglist[i].segdata = sg_dma_address(sg); 30908c2ecf20Sopenharmony_ci } 30918c2ecf20Sopenharmony_ci } else if (!count) { 30928c2ecf20Sopenharmony_ci ccb->opcode = BLOGIC_INITIATOR_CCB; 30938c2ecf20Sopenharmony_ci ccb->datalen = buflen; 30948c2ecf20Sopenharmony_ci ccb->data = 0; 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci switch (cdb[0]) { 30988c2ecf20Sopenharmony_ci case READ_6: 30998c2ecf20Sopenharmony_ci case READ_10: 31008c2ecf20Sopenharmony_ci ccb->datadir = BLOGIC_DATAIN_CHECKED; 31018c2ecf20Sopenharmony_ci tgt_stats[tgt_id].read_cmds++; 31028c2ecf20Sopenharmony_ci blogic_addcount(&tgt_stats[tgt_id].bytesread, buflen); 31038c2ecf20Sopenharmony_ci blogic_incszbucket(tgt_stats[tgt_id].read_sz_buckets, buflen); 31048c2ecf20Sopenharmony_ci break; 31058c2ecf20Sopenharmony_ci case WRITE_6: 31068c2ecf20Sopenharmony_ci case WRITE_10: 31078c2ecf20Sopenharmony_ci ccb->datadir = BLOGIC_DATAOUT_CHECKED; 31088c2ecf20Sopenharmony_ci tgt_stats[tgt_id].write_cmds++; 31098c2ecf20Sopenharmony_ci blogic_addcount(&tgt_stats[tgt_id].byteswritten, buflen); 31108c2ecf20Sopenharmony_ci blogic_incszbucket(tgt_stats[tgt_id].write_sz_buckets, buflen); 31118c2ecf20Sopenharmony_ci break; 31128c2ecf20Sopenharmony_ci default: 31138c2ecf20Sopenharmony_ci ccb->datadir = BLOGIC_UNCHECKED_TX; 31148c2ecf20Sopenharmony_ci break; 31158c2ecf20Sopenharmony_ci } 31168c2ecf20Sopenharmony_ci ccb->cdblen = cdblen; 31178c2ecf20Sopenharmony_ci ccb->adapter_status = 0; 31188c2ecf20Sopenharmony_ci ccb->tgt_status = 0; 31198c2ecf20Sopenharmony_ci ccb->tgt_id = tgt_id; 31208c2ecf20Sopenharmony_ci ccb->lun = lun; 31218c2ecf20Sopenharmony_ci ccb->tag_enable = false; 31228c2ecf20Sopenharmony_ci ccb->legacytag_enable = false; 31238c2ecf20Sopenharmony_ci /* 31248c2ecf20Sopenharmony_ci BusLogic recommends that after a Reset the first couple of 31258c2ecf20Sopenharmony_ci commands that are sent to a Target Device be sent in a non 31268c2ecf20Sopenharmony_ci Tagged Queue fashion so that the Host Adapter and Target Device 31278c2ecf20Sopenharmony_ci can establish Synchronous and Wide Transfer before Queue Tag 31288c2ecf20Sopenharmony_ci messages can interfere with the Synchronous and Wide Negotiation 31298c2ecf20Sopenharmony_ci messages. By waiting to enable Tagged Queuing until after the 31308c2ecf20Sopenharmony_ci first BLOGIC_MAX_TAG_DEPTH commands have been queued, it is 31318c2ecf20Sopenharmony_ci assured that after a Reset any pending commands are requeued 31328c2ecf20Sopenharmony_ci before Tagged Queuing is enabled and that the Tagged Queuing 31338c2ecf20Sopenharmony_ci message will not occur while the partition table is being printed. 31348c2ecf20Sopenharmony_ci In addition, some devices do not properly handle the transition 31358c2ecf20Sopenharmony_ci from non-tagged to tagged commands, so it is necessary to wait 31368c2ecf20Sopenharmony_ci until there are no pending commands for a target device 31378c2ecf20Sopenharmony_ci before queuing tagged commands. 31388c2ecf20Sopenharmony_ci */ 31398c2ecf20Sopenharmony_ci if (adapter->cmds_since_rst[tgt_id]++ >= BLOGIC_MAX_TAG_DEPTH && 31408c2ecf20Sopenharmony_ci !tgt_flags->tagq_active && 31418c2ecf20Sopenharmony_ci adapter->active_cmds[tgt_id] == 0 31428c2ecf20Sopenharmony_ci && tgt_flags->tagq_ok && 31438c2ecf20Sopenharmony_ci (adapter->tagq_ok & (1 << tgt_id))) { 31448c2ecf20Sopenharmony_ci tgt_flags->tagq_active = true; 31458c2ecf20Sopenharmony_ci blogic_notice("Tagged Queuing now active for Target %d\n", 31468c2ecf20Sopenharmony_ci adapter, tgt_id); 31478c2ecf20Sopenharmony_ci } 31488c2ecf20Sopenharmony_ci if (tgt_flags->tagq_active) { 31498c2ecf20Sopenharmony_ci enum blogic_queuetag queuetag = BLOGIC_SIMPLETAG; 31508c2ecf20Sopenharmony_ci /* 31518c2ecf20Sopenharmony_ci When using Tagged Queuing with Simple Queue Tags, it 31528c2ecf20Sopenharmony_ci appears that disk drive controllers do not guarantee that 31538c2ecf20Sopenharmony_ci a queued command will not remain in a disconnected state 31548c2ecf20Sopenharmony_ci indefinitely if commands that read or write nearer the 31558c2ecf20Sopenharmony_ci head position continue to arrive without interruption. 31568c2ecf20Sopenharmony_ci Therefore, for each Target Device this driver keeps track 31578c2ecf20Sopenharmony_ci of the last time either the queue was empty or an Ordered 31588c2ecf20Sopenharmony_ci Queue Tag was issued. If more than 4 seconds (one fifth 31598c2ecf20Sopenharmony_ci of the 20 second disk timeout) have elapsed since this 31608c2ecf20Sopenharmony_ci last sequence point, this command will be issued with an 31618c2ecf20Sopenharmony_ci Ordered Queue Tag rather than a Simple Queue Tag, which 31628c2ecf20Sopenharmony_ci forces the Target Device to complete all previously 31638c2ecf20Sopenharmony_ci queued commands before this command may be executed. 31648c2ecf20Sopenharmony_ci */ 31658c2ecf20Sopenharmony_ci if (adapter->active_cmds[tgt_id] == 0) 31668c2ecf20Sopenharmony_ci adapter->last_seqpoint[tgt_id] = jiffies; 31678c2ecf20Sopenharmony_ci else if (time_after(jiffies, 31688c2ecf20Sopenharmony_ci adapter->last_seqpoint[tgt_id] + 4 * HZ)) { 31698c2ecf20Sopenharmony_ci adapter->last_seqpoint[tgt_id] = jiffies; 31708c2ecf20Sopenharmony_ci queuetag = BLOGIC_ORDEREDTAG; 31718c2ecf20Sopenharmony_ci } 31728c2ecf20Sopenharmony_ci if (adapter->ext_lun) { 31738c2ecf20Sopenharmony_ci ccb->tag_enable = true; 31748c2ecf20Sopenharmony_ci ccb->queuetag = queuetag; 31758c2ecf20Sopenharmony_ci } else { 31768c2ecf20Sopenharmony_ci ccb->legacytag_enable = true; 31778c2ecf20Sopenharmony_ci ccb->legacy_tag = queuetag; 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci } 31808c2ecf20Sopenharmony_ci memcpy(ccb->cdb, cdb, cdblen); 31818c2ecf20Sopenharmony_ci ccb->sense_datalen = SCSI_SENSE_BUFFERSIZE; 31828c2ecf20Sopenharmony_ci ccb->command = command; 31838c2ecf20Sopenharmony_ci sense_buf = dma_map_single(&adapter->pci_device->dev, 31848c2ecf20Sopenharmony_ci command->sense_buffer, ccb->sense_datalen, 31858c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 31868c2ecf20Sopenharmony_ci if (dma_mapping_error(&adapter->pci_device->dev, sense_buf)) { 31878c2ecf20Sopenharmony_ci blogic_err("DMA mapping for sense data buffer failed\n", 31888c2ecf20Sopenharmony_ci adapter); 31898c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 0); 31908c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci ccb->sensedata = sense_buf; 31938c2ecf20Sopenharmony_ci command->scsi_done = comp_cb; 31948c2ecf20Sopenharmony_ci if (blogic_multimaster_type(adapter)) { 31958c2ecf20Sopenharmony_ci /* 31968c2ecf20Sopenharmony_ci Place the CCB in an Outgoing Mailbox. The higher levels 31978c2ecf20Sopenharmony_ci of the SCSI Subsystem should not attempt to queue more 31988c2ecf20Sopenharmony_ci commands than can be placed in Outgoing Mailboxes, so 31998c2ecf20Sopenharmony_ci there should always be one free. In the unlikely event 32008c2ecf20Sopenharmony_ci that there are none available, wait 1 second and try 32018c2ecf20Sopenharmony_ci again. If that fails, the Host Adapter is probably hung 32028c2ecf20Sopenharmony_ci so signal an error as a Host Adapter Hard Reset should 32038c2ecf20Sopenharmony_ci be initiated soon. 32048c2ecf20Sopenharmony_ci */ 32058c2ecf20Sopenharmony_ci if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, ccb)) { 32068c2ecf20Sopenharmony_ci spin_unlock_irq(adapter->scsi_host->host_lock); 32078c2ecf20Sopenharmony_ci blogic_warn("Unable to write Outgoing Mailbox - Pausing for 1 second\n", adapter); 32088c2ecf20Sopenharmony_ci blogic_delay(1); 32098c2ecf20Sopenharmony_ci spin_lock_irq(adapter->scsi_host->host_lock); 32108c2ecf20Sopenharmony_ci if (!blogic_write_outbox(adapter, BLOGIC_MBOX_START, 32118c2ecf20Sopenharmony_ci ccb)) { 32128c2ecf20Sopenharmony_ci blogic_warn("Still unable to write Outgoing Mailbox - Host Adapter Dead?\n", adapter); 32138c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 1); 32148c2ecf20Sopenharmony_ci command->result = DID_ERROR << 16; 32158c2ecf20Sopenharmony_ci command->scsi_done(command); 32168c2ecf20Sopenharmony_ci } 32178c2ecf20Sopenharmony_ci } 32188c2ecf20Sopenharmony_ci } else { 32198c2ecf20Sopenharmony_ci /* 32208c2ecf20Sopenharmony_ci Call the FlashPoint SCCB Manager to start execution of 32218c2ecf20Sopenharmony_ci the CCB. 32228c2ecf20Sopenharmony_ci */ 32238c2ecf20Sopenharmony_ci ccb->status = BLOGIC_CCB_ACTIVE; 32248c2ecf20Sopenharmony_ci adapter->active_cmds[tgt_id]++; 32258c2ecf20Sopenharmony_ci tgt_stats[tgt_id].cmds_tried++; 32268c2ecf20Sopenharmony_ci FlashPoint_StartCCB(adapter->cardhandle, ccb); 32278c2ecf20Sopenharmony_ci /* 32288c2ecf20Sopenharmony_ci The Command may have already completed and 32298c2ecf20Sopenharmony_ci blogic_qcompleted_ccb been called, or it may still be 32308c2ecf20Sopenharmony_ci pending. 32318c2ecf20Sopenharmony_ci */ 32328c2ecf20Sopenharmony_ci if (ccb->status == BLOGIC_CCB_COMPLETE) 32338c2ecf20Sopenharmony_ci blogic_process_ccbs(adapter); 32348c2ecf20Sopenharmony_ci } 32358c2ecf20Sopenharmony_ci return 0; 32368c2ecf20Sopenharmony_ci} 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(blogic_qcmd) 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci#if 0 32418c2ecf20Sopenharmony_ci/* 32428c2ecf20Sopenharmony_ci blogic_abort aborts Command if possible. 32438c2ecf20Sopenharmony_ci*/ 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_cistatic int blogic_abort(struct scsi_cmnd *command) 32468c2ecf20Sopenharmony_ci{ 32478c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 32488c2ecf20Sopenharmony_ci (struct blogic_adapter *) command->device->host->hostdata; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci int tgt_id = command->device->id; 32518c2ecf20Sopenharmony_ci struct blogic_ccb *ccb; 32528c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_request); 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci /* 32558c2ecf20Sopenharmony_ci Attempt to find an Active CCB for this Command. If no Active 32568c2ecf20Sopenharmony_ci CCB for this Command is found, then no Abort is necessary. 32578c2ecf20Sopenharmony_ci */ 32588c2ecf20Sopenharmony_ci for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all) 32598c2ecf20Sopenharmony_ci if (ccb->command == command) 32608c2ecf20Sopenharmony_ci break; 32618c2ecf20Sopenharmony_ci if (ccb == NULL) { 32628c2ecf20Sopenharmony_ci blogic_warn("Unable to Abort Command to Target %d - No CCB Found\n", adapter, tgt_id); 32638c2ecf20Sopenharmony_ci return SUCCESS; 32648c2ecf20Sopenharmony_ci } else if (ccb->status == BLOGIC_CCB_COMPLETE) { 32658c2ecf20Sopenharmony_ci blogic_warn("Unable to Abort Command to Target %d - CCB Completed\n", adapter, tgt_id); 32668c2ecf20Sopenharmony_ci return SUCCESS; 32678c2ecf20Sopenharmony_ci } else if (ccb->status == BLOGIC_CCB_RESET) { 32688c2ecf20Sopenharmony_ci blogic_warn("Unable to Abort Command to Target %d - CCB Reset\n", adapter, tgt_id); 32698c2ecf20Sopenharmony_ci return SUCCESS; 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci if (blogic_multimaster_type(adapter)) { 32728c2ecf20Sopenharmony_ci /* 32738c2ecf20Sopenharmony_ci Attempt to Abort this CCB. MultiMaster Firmware versions 32748c2ecf20Sopenharmony_ci prior to 5.xx do not generate Abort Tag messages, but only 32758c2ecf20Sopenharmony_ci generate the non-tagged Abort message. Since non-tagged 32768c2ecf20Sopenharmony_ci commands are not sent by the Host Adapter until the queue 32778c2ecf20Sopenharmony_ci of outstanding tagged commands has completed, and the 32788c2ecf20Sopenharmony_ci Abort message is treated as a non-tagged command, it is 32798c2ecf20Sopenharmony_ci effectively impossible to abort commands when Tagged 32808c2ecf20Sopenharmony_ci Queuing is active. Firmware version 5.xx does generate 32818c2ecf20Sopenharmony_ci Abort Tag messages, so it is possible to abort commands 32828c2ecf20Sopenharmony_ci when Tagged Queuing is active. 32838c2ecf20Sopenharmony_ci */ 32848c2ecf20Sopenharmony_ci if (adapter->tgt_flags[tgt_id].tagq_active && 32858c2ecf20Sopenharmony_ci adapter->fw_ver[0] < '5') { 32868c2ecf20Sopenharmony_ci blogic_warn("Unable to Abort CCB #%ld to Target %d - Abort Tag Not Supported\n", adapter, ccb->serial, tgt_id); 32878c2ecf20Sopenharmony_ci return FAILURE; 32888c2ecf20Sopenharmony_ci } else if (blogic_write_outbox(adapter, BLOGIC_MBOX_ABORT, 32898c2ecf20Sopenharmony_ci ccb)) { 32908c2ecf20Sopenharmony_ci blogic_warn("Aborting CCB #%ld to Target %d\n", 32918c2ecf20Sopenharmony_ci adapter, ccb->serial, tgt_id); 32928c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_tried); 32938c2ecf20Sopenharmony_ci return SUCCESS; 32948c2ecf20Sopenharmony_ci } else { 32958c2ecf20Sopenharmony_ci blogic_warn("Unable to Abort CCB #%ld to Target %d - No Outgoing Mailboxes\n", adapter, ccb->serial, tgt_id); 32968c2ecf20Sopenharmony_ci return FAILURE; 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci } else { 32998c2ecf20Sopenharmony_ci /* 33008c2ecf20Sopenharmony_ci Call the FlashPoint SCCB Manager to abort execution of 33018c2ecf20Sopenharmony_ci the CCB. 33028c2ecf20Sopenharmony_ci */ 33038c2ecf20Sopenharmony_ci blogic_warn("Aborting CCB #%ld to Target %d\n", adapter, 33048c2ecf20Sopenharmony_ci ccb->serial, tgt_id); 33058c2ecf20Sopenharmony_ci blogic_inc_count(&adapter->tgt_stats[tgt_id].aborts_tried); 33068c2ecf20Sopenharmony_ci FlashPoint_AbortCCB(adapter->cardhandle, ccb); 33078c2ecf20Sopenharmony_ci /* 33088c2ecf20Sopenharmony_ci The Abort may have already been completed and 33098c2ecf20Sopenharmony_ci blogic_qcompleted_ccb been called, or it 33108c2ecf20Sopenharmony_ci may still be pending. 33118c2ecf20Sopenharmony_ci */ 33128c2ecf20Sopenharmony_ci if (ccb->status == BLOGIC_CCB_COMPLETE) 33138c2ecf20Sopenharmony_ci blogic_process_ccbs(adapter); 33148c2ecf20Sopenharmony_ci return SUCCESS; 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci return SUCCESS; 33178c2ecf20Sopenharmony_ci} 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci#endif 33208c2ecf20Sopenharmony_ci/* 33218c2ecf20Sopenharmony_ci blogic_resetadapter resets Host Adapter if possible, marking all 33228c2ecf20Sopenharmony_ci currently executing SCSI Commands as having been Reset. 33238c2ecf20Sopenharmony_ci*/ 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_cistatic int blogic_resetadapter(struct blogic_adapter *adapter, bool hard_reset) 33268c2ecf20Sopenharmony_ci{ 33278c2ecf20Sopenharmony_ci struct blogic_ccb *ccb; 33288c2ecf20Sopenharmony_ci int tgt_id; 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci /* 33318c2ecf20Sopenharmony_ci * Attempt to Reset and Reinitialize the Host Adapter. 33328c2ecf20Sopenharmony_ci */ 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci if (!(blogic_hwreset(adapter, hard_reset) && 33358c2ecf20Sopenharmony_ci blogic_initadapter(adapter))) { 33368c2ecf20Sopenharmony_ci blogic_err("Resetting %s Failed\n", adapter, 33378c2ecf20Sopenharmony_ci adapter->full_model); 33388c2ecf20Sopenharmony_ci return FAILURE; 33398c2ecf20Sopenharmony_ci } 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci /* 33428c2ecf20Sopenharmony_ci * Deallocate all currently executing CCBs. 33438c2ecf20Sopenharmony_ci */ 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci for (ccb = adapter->all_ccbs; ccb != NULL; ccb = ccb->next_all) 33468c2ecf20Sopenharmony_ci if (ccb->status == BLOGIC_CCB_ACTIVE) 33478c2ecf20Sopenharmony_ci blogic_dealloc_ccb(ccb, 1); 33488c2ecf20Sopenharmony_ci /* 33498c2ecf20Sopenharmony_ci * Wait a few seconds between the Host Adapter Hard Reset which 33508c2ecf20Sopenharmony_ci * initiates a SCSI Bus Reset and issuing any SCSI Commands. Some 33518c2ecf20Sopenharmony_ci * SCSI devices get confused if they receive SCSI Commands too soon 33528c2ecf20Sopenharmony_ci * after a SCSI Bus Reset. 33538c2ecf20Sopenharmony_ci */ 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci if (hard_reset) { 33568c2ecf20Sopenharmony_ci spin_unlock_irq(adapter->scsi_host->host_lock); 33578c2ecf20Sopenharmony_ci blogic_delay(adapter->bus_settle_time); 33588c2ecf20Sopenharmony_ci spin_lock_irq(adapter->scsi_host->host_lock); 33598c2ecf20Sopenharmony_ci } 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++) { 33628c2ecf20Sopenharmony_ci adapter->last_resettried[tgt_id] = jiffies; 33638c2ecf20Sopenharmony_ci adapter->last_resetdone[tgt_id] = jiffies; 33648c2ecf20Sopenharmony_ci } 33658c2ecf20Sopenharmony_ci return SUCCESS; 33668c2ecf20Sopenharmony_ci} 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci/* 33698c2ecf20Sopenharmony_ci blogic_diskparam returns the Heads/Sectors/Cylinders BIOS Disk 33708c2ecf20Sopenharmony_ci Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, and 33718c2ecf20Sopenharmony_ci the appropriate number of cylinders so as not to exceed drive capacity. In 33728c2ecf20Sopenharmony_ci order for disks equal to or larger than 1 GB to be addressable by the BIOS 33738c2ecf20Sopenharmony_ci without exceeding the BIOS limitation of 1024 cylinders, Extended Translation 33748c2ecf20Sopenharmony_ci may be enabled in AutoSCSI on FlashPoint Host Adapters and on "W" and "C" 33758c2ecf20Sopenharmony_ci series MultiMaster Host Adapters, or by a dip switch setting on "S" and "A" 33768c2ecf20Sopenharmony_ci series MultiMaster Host Adapters. With Extended Translation enabled, drives 33778c2ecf20Sopenharmony_ci between 1 GB inclusive and 2 GB exclusive are given a disk geometry of 128 33788c2ecf20Sopenharmony_ci heads and 32 sectors, and drives above 2 GB inclusive are given a disk 33798c2ecf20Sopenharmony_ci geometry of 255 heads and 63 sectors. However, if the BIOS detects that the 33808c2ecf20Sopenharmony_ci Extended Translation setting does not match the geometry in the partition 33818c2ecf20Sopenharmony_ci table, then the translation inferred from the partition table will be used by 33828c2ecf20Sopenharmony_ci the BIOS, and a warning may be displayed. 33838c2ecf20Sopenharmony_ci*/ 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_cistatic int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev, 33868c2ecf20Sopenharmony_ci sector_t capacity, int *params) 33878c2ecf20Sopenharmony_ci{ 33888c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 33898c2ecf20Sopenharmony_ci (struct blogic_adapter *) sdev->host->hostdata; 33908c2ecf20Sopenharmony_ci struct bios_diskparam *diskparam = (struct bios_diskparam *) params; 33918c2ecf20Sopenharmony_ci unsigned char *buf; 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci if (adapter->ext_trans_enable && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */) { 33948c2ecf20Sopenharmony_ci if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */) { 33958c2ecf20Sopenharmony_ci diskparam->heads = 255; 33968c2ecf20Sopenharmony_ci diskparam->sectors = 63; 33978c2ecf20Sopenharmony_ci } else { 33988c2ecf20Sopenharmony_ci diskparam->heads = 128; 33998c2ecf20Sopenharmony_ci diskparam->sectors = 32; 34008c2ecf20Sopenharmony_ci } 34018c2ecf20Sopenharmony_ci } else { 34028c2ecf20Sopenharmony_ci diskparam->heads = 64; 34038c2ecf20Sopenharmony_ci diskparam->sectors = 32; 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors); 34068c2ecf20Sopenharmony_ci buf = scsi_bios_ptable(dev); 34078c2ecf20Sopenharmony_ci if (buf == NULL) 34088c2ecf20Sopenharmony_ci return 0; 34098c2ecf20Sopenharmony_ci /* 34108c2ecf20Sopenharmony_ci If the boot sector partition table flag is valid, search for 34118c2ecf20Sopenharmony_ci a partition table entry whose end_head matches one of the 34128c2ecf20Sopenharmony_ci standard BusLogic geometry translations (64/32, 128/32, or 255/63). 34138c2ecf20Sopenharmony_ci */ 34148c2ecf20Sopenharmony_ci if (*(unsigned short *) (buf + 64) == MSDOS_LABEL_MAGIC) { 34158c2ecf20Sopenharmony_ci struct msdos_partition *part1_entry = 34168c2ecf20Sopenharmony_ci (struct msdos_partition *)buf; 34178c2ecf20Sopenharmony_ci struct msdos_partition *part_entry = part1_entry; 34188c2ecf20Sopenharmony_ci int saved_cyl = diskparam->cylinders, part_no; 34198c2ecf20Sopenharmony_ci unsigned char part_end_head = 0, part_end_sector = 0; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci for (part_no = 0; part_no < 4; part_no++) { 34228c2ecf20Sopenharmony_ci part_end_head = part_entry->end_head; 34238c2ecf20Sopenharmony_ci part_end_sector = part_entry->end_sector & 0x3F; 34248c2ecf20Sopenharmony_ci if (part_end_head == 64 - 1) { 34258c2ecf20Sopenharmony_ci diskparam->heads = 64; 34268c2ecf20Sopenharmony_ci diskparam->sectors = 32; 34278c2ecf20Sopenharmony_ci break; 34288c2ecf20Sopenharmony_ci } else if (part_end_head == 128 - 1) { 34298c2ecf20Sopenharmony_ci diskparam->heads = 128; 34308c2ecf20Sopenharmony_ci diskparam->sectors = 32; 34318c2ecf20Sopenharmony_ci break; 34328c2ecf20Sopenharmony_ci } else if (part_end_head == 255 - 1) { 34338c2ecf20Sopenharmony_ci diskparam->heads = 255; 34348c2ecf20Sopenharmony_ci diskparam->sectors = 63; 34358c2ecf20Sopenharmony_ci break; 34368c2ecf20Sopenharmony_ci } 34378c2ecf20Sopenharmony_ci part_entry++; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci if (part_no == 4) { 34408c2ecf20Sopenharmony_ci part_end_head = part1_entry->end_head; 34418c2ecf20Sopenharmony_ci part_end_sector = part1_entry->end_sector & 0x3F; 34428c2ecf20Sopenharmony_ci } 34438c2ecf20Sopenharmony_ci diskparam->cylinders = (unsigned long) capacity / (diskparam->heads * diskparam->sectors); 34448c2ecf20Sopenharmony_ci if (part_no < 4 && part_end_sector == diskparam->sectors) { 34458c2ecf20Sopenharmony_ci if (diskparam->cylinders != saved_cyl) 34468c2ecf20Sopenharmony_ci blogic_warn("Adopting Geometry %d/%d from Partition Table\n", adapter, diskparam->heads, diskparam->sectors); 34478c2ecf20Sopenharmony_ci } else if (part_end_head > 0 || part_end_sector > 0) { 34488c2ecf20Sopenharmony_ci blogic_warn("Warning: Partition Table appears to have Geometry %d/%d which is\n", adapter, part_end_head + 1, part_end_sector); 34498c2ecf20Sopenharmony_ci blogic_warn("not compatible with current BusLogic Host Adapter Geometry %d/%d\n", adapter, diskparam->heads, diskparam->sectors); 34508c2ecf20Sopenharmony_ci } 34518c2ecf20Sopenharmony_ci } 34528c2ecf20Sopenharmony_ci kfree(buf); 34538c2ecf20Sopenharmony_ci return 0; 34548c2ecf20Sopenharmony_ci} 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci/* 34588c2ecf20Sopenharmony_ci BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>. 34598c2ecf20Sopenharmony_ci*/ 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_cistatic int blogic_write_info(struct Scsi_Host *shost, char *procbuf, 34628c2ecf20Sopenharmony_ci int bytes_avail) 34638c2ecf20Sopenharmony_ci{ 34648c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = 34658c2ecf20Sopenharmony_ci (struct blogic_adapter *) shost->hostdata; 34668c2ecf20Sopenharmony_ci struct blogic_tgt_stats *tgt_stats; 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci tgt_stats = adapter->tgt_stats; 34698c2ecf20Sopenharmony_ci adapter->ext_resets = 0; 34708c2ecf20Sopenharmony_ci adapter->adapter_intern_errors = 0; 34718c2ecf20Sopenharmony_ci memset(tgt_stats, 0, BLOGIC_MAXDEV * sizeof(struct blogic_tgt_stats)); 34728c2ecf20Sopenharmony_ci return 0; 34738c2ecf20Sopenharmony_ci} 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_cistatic int blogic_show_info(struct seq_file *m, struct Scsi_Host *shost) 34768c2ecf20Sopenharmony_ci{ 34778c2ecf20Sopenharmony_ci struct blogic_adapter *adapter = (struct blogic_adapter *) shost->hostdata; 34788c2ecf20Sopenharmony_ci struct blogic_tgt_stats *tgt_stats; 34798c2ecf20Sopenharmony_ci int tgt; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci tgt_stats = adapter->tgt_stats; 34828c2ecf20Sopenharmony_ci seq_write(m, adapter->msgbuf, adapter->msgbuflen); 34838c2ecf20Sopenharmony_ci seq_printf(m, "\n\ 34848c2ecf20Sopenharmony_ciCurrent Driver Queue Depth: %d\n\ 34858c2ecf20Sopenharmony_ciCurrently Allocated CCBs: %d\n", adapter->drvr_qdepth, adapter->alloc_ccbs); 34868c2ecf20Sopenharmony_ci seq_puts(m, "\n\n\ 34878c2ecf20Sopenharmony_ci DATA TRANSFER STATISTICS\n\ 34888c2ecf20Sopenharmony_ci\n\ 34898c2ecf20Sopenharmony_ciTarget Tagged Queuing Queue Depth Active Attempted Completed\n\ 34908c2ecf20Sopenharmony_ci====== ============== =========== ====== ========= =========\n"); 34918c2ecf20Sopenharmony_ci for (tgt = 0; tgt < adapter->maxdev; tgt++) { 34928c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; 34938c2ecf20Sopenharmony_ci if (!tgt_flags->tgt_exists) 34948c2ecf20Sopenharmony_ci continue; 34958c2ecf20Sopenharmony_ci seq_printf(m, " %2d %s", tgt, (tgt_flags->tagq_ok ? (tgt_flags->tagq_active ? " Active" : (adapter->tagq_ok & (1 << tgt) 34968c2ecf20Sopenharmony_ci ? " Permitted" : " Disabled")) 34978c2ecf20Sopenharmony_ci : "Not Supported")); 34988c2ecf20Sopenharmony_ci seq_printf(m, 34998c2ecf20Sopenharmony_ci " %3d %3u %9u %9u\n", adapter->qdepth[tgt], adapter->active_cmds[tgt], tgt_stats[tgt].cmds_tried, tgt_stats[tgt].cmds_complete); 35008c2ecf20Sopenharmony_ci } 35018c2ecf20Sopenharmony_ci seq_puts(m, "\n\ 35028c2ecf20Sopenharmony_ciTarget Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ 35038c2ecf20Sopenharmony_ci====== ============= ============== =================== ===================\n"); 35048c2ecf20Sopenharmony_ci for (tgt = 0; tgt < adapter->maxdev; tgt++) { 35058c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; 35068c2ecf20Sopenharmony_ci if (!tgt_flags->tgt_exists) 35078c2ecf20Sopenharmony_ci continue; 35088c2ecf20Sopenharmony_ci seq_printf(m, " %2d %9u %9u", tgt, tgt_stats[tgt].read_cmds, tgt_stats[tgt].write_cmds); 35098c2ecf20Sopenharmony_ci if (tgt_stats[tgt].bytesread.billions > 0) 35108c2ecf20Sopenharmony_ci seq_printf(m, " %9u%09u", tgt_stats[tgt].bytesread.billions, tgt_stats[tgt].bytesread.units); 35118c2ecf20Sopenharmony_ci else 35128c2ecf20Sopenharmony_ci seq_printf(m, " %9u", tgt_stats[tgt].bytesread.units); 35138c2ecf20Sopenharmony_ci if (tgt_stats[tgt].byteswritten.billions > 0) 35148c2ecf20Sopenharmony_ci seq_printf(m, " %9u%09u\n", tgt_stats[tgt].byteswritten.billions, tgt_stats[tgt].byteswritten.units); 35158c2ecf20Sopenharmony_ci else 35168c2ecf20Sopenharmony_ci seq_printf(m, " %9u\n", tgt_stats[tgt].byteswritten.units); 35178c2ecf20Sopenharmony_ci } 35188c2ecf20Sopenharmony_ci seq_puts(m, "\n\ 35198c2ecf20Sopenharmony_ciTarget Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ 35208c2ecf20Sopenharmony_ci====== ======= ========= ========= ========= ========= =========\n"); 35218c2ecf20Sopenharmony_ci for (tgt = 0; tgt < adapter->maxdev; tgt++) { 35228c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; 35238c2ecf20Sopenharmony_ci if (!tgt_flags->tgt_exists) 35248c2ecf20Sopenharmony_ci continue; 35258c2ecf20Sopenharmony_ci seq_printf(m, 35268c2ecf20Sopenharmony_ci " %2d Read %9u %9u %9u %9u %9u\n", tgt, 35278c2ecf20Sopenharmony_ci tgt_stats[tgt].read_sz_buckets[0], 35288c2ecf20Sopenharmony_ci tgt_stats[tgt].read_sz_buckets[1], tgt_stats[tgt].read_sz_buckets[2], tgt_stats[tgt].read_sz_buckets[3], tgt_stats[tgt].read_sz_buckets[4]); 35298c2ecf20Sopenharmony_ci seq_printf(m, 35308c2ecf20Sopenharmony_ci " %2d Write %9u %9u %9u %9u %9u\n", tgt, 35318c2ecf20Sopenharmony_ci tgt_stats[tgt].write_sz_buckets[0], 35328c2ecf20Sopenharmony_ci tgt_stats[tgt].write_sz_buckets[1], tgt_stats[tgt].write_sz_buckets[2], tgt_stats[tgt].write_sz_buckets[3], tgt_stats[tgt].write_sz_buckets[4]); 35338c2ecf20Sopenharmony_ci } 35348c2ecf20Sopenharmony_ci seq_puts(m, "\n\ 35358c2ecf20Sopenharmony_ciTarget Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ 35368c2ecf20Sopenharmony_ci====== ======= ========= ========= ========= ========= =========\n"); 35378c2ecf20Sopenharmony_ci for (tgt = 0; tgt < adapter->maxdev; tgt++) { 35388c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; 35398c2ecf20Sopenharmony_ci if (!tgt_flags->tgt_exists) 35408c2ecf20Sopenharmony_ci continue; 35418c2ecf20Sopenharmony_ci seq_printf(m, 35428c2ecf20Sopenharmony_ci " %2d Read %9u %9u %9u %9u %9u\n", tgt, 35438c2ecf20Sopenharmony_ci tgt_stats[tgt].read_sz_buckets[5], 35448c2ecf20Sopenharmony_ci tgt_stats[tgt].read_sz_buckets[6], tgt_stats[tgt].read_sz_buckets[7], tgt_stats[tgt].read_sz_buckets[8], tgt_stats[tgt].read_sz_buckets[9]); 35458c2ecf20Sopenharmony_ci seq_printf(m, 35468c2ecf20Sopenharmony_ci " %2d Write %9u %9u %9u %9u %9u\n", tgt, 35478c2ecf20Sopenharmony_ci tgt_stats[tgt].write_sz_buckets[5], 35488c2ecf20Sopenharmony_ci tgt_stats[tgt].write_sz_buckets[6], tgt_stats[tgt].write_sz_buckets[7], tgt_stats[tgt].write_sz_buckets[8], tgt_stats[tgt].write_sz_buckets[9]); 35498c2ecf20Sopenharmony_ci } 35508c2ecf20Sopenharmony_ci seq_puts(m, "\n\n\ 35518c2ecf20Sopenharmony_ci ERROR RECOVERY STATISTICS\n\ 35528c2ecf20Sopenharmony_ci\n\ 35538c2ecf20Sopenharmony_ci Command Aborts Bus Device Resets Host Adapter Resets\n\ 35548c2ecf20Sopenharmony_ciTarget Requested Completed Requested Completed Requested Completed\n\ 35558c2ecf20Sopenharmony_ci ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ 35568c2ecf20Sopenharmony_ci====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); 35578c2ecf20Sopenharmony_ci for (tgt = 0; tgt < adapter->maxdev; tgt++) { 35588c2ecf20Sopenharmony_ci struct blogic_tgt_flags *tgt_flags = &adapter->tgt_flags[tgt]; 35598c2ecf20Sopenharmony_ci if (!tgt_flags->tgt_exists) 35608c2ecf20Sopenharmony_ci continue; 35618c2ecf20Sopenharmony_ci seq_printf(m, " %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", 35628c2ecf20Sopenharmony_ci tgt, tgt_stats[tgt].aborts_request, 35638c2ecf20Sopenharmony_ci tgt_stats[tgt].aborts_tried, 35648c2ecf20Sopenharmony_ci tgt_stats[tgt].aborts_done, 35658c2ecf20Sopenharmony_ci tgt_stats[tgt].bdr_request, 35668c2ecf20Sopenharmony_ci tgt_stats[tgt].bdr_tried, 35678c2ecf20Sopenharmony_ci tgt_stats[tgt].bdr_done, 35688c2ecf20Sopenharmony_ci tgt_stats[tgt].adapter_reset_req, 35698c2ecf20Sopenharmony_ci tgt_stats[tgt].adapter_reset_attempt, 35708c2ecf20Sopenharmony_ci tgt_stats[tgt].adapter_reset_done); 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci seq_printf(m, "\nExternal Host Adapter Resets: %d\n", adapter->ext_resets); 35738c2ecf20Sopenharmony_ci seq_printf(m, "Host Adapter Internal Errors: %d\n", adapter->adapter_intern_errors); 35748c2ecf20Sopenharmony_ci return 0; 35758c2ecf20Sopenharmony_ci} 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci/* 35798c2ecf20Sopenharmony_ci blogic_msg prints Driver Messages. 35808c2ecf20Sopenharmony_ci*/ 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_cistatic void blogic_msg(enum blogic_msglevel msglevel, char *fmt, 35838c2ecf20Sopenharmony_ci struct blogic_adapter *adapter, ...) 35848c2ecf20Sopenharmony_ci{ 35858c2ecf20Sopenharmony_ci static char buf[BLOGIC_LINEBUF_SIZE]; 35868c2ecf20Sopenharmony_ci static bool begin = true; 35878c2ecf20Sopenharmony_ci va_list args; 35888c2ecf20Sopenharmony_ci int len = 0; 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci va_start(args, adapter); 35918c2ecf20Sopenharmony_ci len = vsprintf(buf, fmt, args); 35928c2ecf20Sopenharmony_ci va_end(args); 35938c2ecf20Sopenharmony_ci if (msglevel == BLOGIC_ANNOUNCE_LEVEL) { 35948c2ecf20Sopenharmony_ci static int msglines = 0; 35958c2ecf20Sopenharmony_ci strcpy(&adapter->msgbuf[adapter->msgbuflen], buf); 35968c2ecf20Sopenharmony_ci adapter->msgbuflen += len; 35978c2ecf20Sopenharmony_ci if (++msglines <= 2) 35988c2ecf20Sopenharmony_ci printk("%sscsi: %s", blogic_msglevelmap[msglevel], buf); 35998c2ecf20Sopenharmony_ci } else if (msglevel == BLOGIC_INFO_LEVEL) { 36008c2ecf20Sopenharmony_ci strcpy(&adapter->msgbuf[adapter->msgbuflen], buf); 36018c2ecf20Sopenharmony_ci adapter->msgbuflen += len; 36028c2ecf20Sopenharmony_ci if (begin) { 36038c2ecf20Sopenharmony_ci if (buf[0] != '\n' || len > 1) 36048c2ecf20Sopenharmony_ci printk("%sscsi%d: %s", blogic_msglevelmap[msglevel], adapter->host_no, buf); 36058c2ecf20Sopenharmony_ci } else 36068c2ecf20Sopenharmony_ci pr_cont("%s", buf); 36078c2ecf20Sopenharmony_ci } else { 36088c2ecf20Sopenharmony_ci if (begin) { 36098c2ecf20Sopenharmony_ci if (adapter != NULL && adapter->adapter_initd) 36108c2ecf20Sopenharmony_ci printk("%sscsi%d: %s", blogic_msglevelmap[msglevel], adapter->host_no, buf); 36118c2ecf20Sopenharmony_ci else 36128c2ecf20Sopenharmony_ci printk("%s%s", blogic_msglevelmap[msglevel], buf); 36138c2ecf20Sopenharmony_ci } else 36148c2ecf20Sopenharmony_ci pr_cont("%s", buf); 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci begin = (buf[len - 1] == '\n'); 36178c2ecf20Sopenharmony_ci} 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci/* 36218c2ecf20Sopenharmony_ci blogic_parse parses an individual option keyword. It returns true 36228c2ecf20Sopenharmony_ci and updates the pointer if the keyword is recognized and false otherwise. 36238c2ecf20Sopenharmony_ci*/ 36248c2ecf20Sopenharmony_ci 36258c2ecf20Sopenharmony_cistatic bool __init blogic_parse(char **str, char *keyword) 36268c2ecf20Sopenharmony_ci{ 36278c2ecf20Sopenharmony_ci char *pointer = *str; 36288c2ecf20Sopenharmony_ci while (*keyword != '\0') { 36298c2ecf20Sopenharmony_ci char strch = *pointer++; 36308c2ecf20Sopenharmony_ci char keywordch = *keyword++; 36318c2ecf20Sopenharmony_ci if (strch >= 'A' && strch <= 'Z') 36328c2ecf20Sopenharmony_ci strch += 'a' - 'Z'; 36338c2ecf20Sopenharmony_ci if (keywordch >= 'A' && keywordch <= 'Z') 36348c2ecf20Sopenharmony_ci keywordch += 'a' - 'Z'; 36358c2ecf20Sopenharmony_ci if (strch != keywordch) 36368c2ecf20Sopenharmony_ci return false; 36378c2ecf20Sopenharmony_ci } 36388c2ecf20Sopenharmony_ci *str = pointer; 36398c2ecf20Sopenharmony_ci return true; 36408c2ecf20Sopenharmony_ci} 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci/* 36448c2ecf20Sopenharmony_ci blogic_parseopts handles processing of BusLogic Driver Options 36458c2ecf20Sopenharmony_ci specifications. 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci BusLogic Driver Options may be specified either via the Linux Kernel Command 36488c2ecf20Sopenharmony_ci Line or via the Loadable Kernel Module Installation Facility. Driver Options 36498c2ecf20Sopenharmony_ci for multiple host adapters may be specified either by separating the option 36508c2ecf20Sopenharmony_ci strings by a semicolon, or by specifying multiple "BusLogic=" strings on the 36518c2ecf20Sopenharmony_ci command line. Individual option specifications for a single host adapter are 36528c2ecf20Sopenharmony_ci separated by commas. The Probing and Debugging Options apply to all host 36538c2ecf20Sopenharmony_ci adapters whereas the remaining options apply individually only to the 36548c2ecf20Sopenharmony_ci selected host adapter. 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci The BusLogic Driver Probing Options are described in 36578c2ecf20Sopenharmony_ci <file:Documentation/scsi/BusLogic.rst>. 36588c2ecf20Sopenharmony_ci*/ 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_cistatic int __init blogic_parseopts(char *options) 36618c2ecf20Sopenharmony_ci{ 36628c2ecf20Sopenharmony_ci while (true) { 36638c2ecf20Sopenharmony_ci struct blogic_drvr_options *drvr_opts = 36648c2ecf20Sopenharmony_ci &blogic_drvr_options[blogic_drvr_options_count++]; 36658c2ecf20Sopenharmony_ci int tgt_id; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci memset(drvr_opts, 0, sizeof(struct blogic_drvr_options)); 36688c2ecf20Sopenharmony_ci while (*options != '\0' && *options != ';') { 36698c2ecf20Sopenharmony_ci /* Probing Options. */ 36708c2ecf20Sopenharmony_ci if (blogic_parse(&options, "IO:")) { 36718c2ecf20Sopenharmony_ci unsigned long io_addr = simple_strtoul(options, 36728c2ecf20Sopenharmony_ci &options, 0); 36738c2ecf20Sopenharmony_ci blogic_probe_options.limited_isa = true; 36748c2ecf20Sopenharmony_ci switch (io_addr) { 36758c2ecf20Sopenharmony_ci case 0x330: 36768c2ecf20Sopenharmony_ci blogic_probe_options.probe330 = true; 36778c2ecf20Sopenharmony_ci break; 36788c2ecf20Sopenharmony_ci case 0x334: 36798c2ecf20Sopenharmony_ci blogic_probe_options.probe334 = true; 36808c2ecf20Sopenharmony_ci break; 36818c2ecf20Sopenharmony_ci case 0x230: 36828c2ecf20Sopenharmony_ci blogic_probe_options.probe230 = true; 36838c2ecf20Sopenharmony_ci break; 36848c2ecf20Sopenharmony_ci case 0x234: 36858c2ecf20Sopenharmony_ci blogic_probe_options.probe234 = true; 36868c2ecf20Sopenharmony_ci break; 36878c2ecf20Sopenharmony_ci case 0x130: 36888c2ecf20Sopenharmony_ci blogic_probe_options.probe130 = true; 36898c2ecf20Sopenharmony_ci break; 36908c2ecf20Sopenharmony_ci case 0x134: 36918c2ecf20Sopenharmony_ci blogic_probe_options.probe134 = true; 36928c2ecf20Sopenharmony_ci break; 36938c2ecf20Sopenharmony_ci default: 36948c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (invalid I/O Address 0x%lX)\n", NULL, io_addr); 36958c2ecf20Sopenharmony_ci return 0; 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, "NoProbeISA")) 36988c2ecf20Sopenharmony_ci blogic_probe_options.noprobe_isa = true; 36998c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "NoProbePCI")) 37008c2ecf20Sopenharmony_ci blogic_probe_options.noprobe_pci = true; 37018c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "NoProbe")) 37028c2ecf20Sopenharmony_ci blogic_probe_options.noprobe = true; 37038c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "NoSortPCI")) 37048c2ecf20Sopenharmony_ci blogic_probe_options.nosort_pci = true; 37058c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "MultiMasterFirst")) 37068c2ecf20Sopenharmony_ci blogic_probe_options.multimaster_first = true; 37078c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "FlashPointFirst")) 37088c2ecf20Sopenharmony_ci blogic_probe_options.flashpoint_first = true; 37098c2ecf20Sopenharmony_ci /* Tagged Queuing Options. */ 37108c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "QueueDepth:[") || 37118c2ecf20Sopenharmony_ci blogic_parse(&options, "QD:[")) { 37128c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) { 37138c2ecf20Sopenharmony_ci unsigned short qdepth = simple_strtoul(options, &options, 0); 37148c2ecf20Sopenharmony_ci if (qdepth > BLOGIC_MAX_TAG_DEPTH) { 37158c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (invalid Queue Depth %d)\n", NULL, qdepth); 37168c2ecf20Sopenharmony_ci return 0; 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci drvr_opts->qdepth[tgt_id] = qdepth; 37198c2ecf20Sopenharmony_ci if (*options == ',') 37208c2ecf20Sopenharmony_ci options++; 37218c2ecf20Sopenharmony_ci else if (*options == ']') 37228c2ecf20Sopenharmony_ci break; 37238c2ecf20Sopenharmony_ci else { 37248c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (',' or ']' expected at '%s')\n", NULL, options); 37258c2ecf20Sopenharmony_ci return 0; 37268c2ecf20Sopenharmony_ci } 37278c2ecf20Sopenharmony_ci } 37288c2ecf20Sopenharmony_ci if (*options != ']') { 37298c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (']' expected at '%s')\n", NULL, options); 37308c2ecf20Sopenharmony_ci return 0; 37318c2ecf20Sopenharmony_ci } else 37328c2ecf20Sopenharmony_ci options++; 37338c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, "QueueDepth:") || blogic_parse(&options, "QD:")) { 37348c2ecf20Sopenharmony_ci unsigned short qdepth = simple_strtoul(options, &options, 0); 37358c2ecf20Sopenharmony_ci if (qdepth == 0 || 37368c2ecf20Sopenharmony_ci qdepth > BLOGIC_MAX_TAG_DEPTH) { 37378c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (invalid Queue Depth %d)\n", NULL, qdepth); 37388c2ecf20Sopenharmony_ci return 0; 37398c2ecf20Sopenharmony_ci } 37408c2ecf20Sopenharmony_ci drvr_opts->common_qdepth = qdepth; 37418c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) 37428c2ecf20Sopenharmony_ci drvr_opts->qdepth[tgt_id] = qdepth; 37438c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, "TaggedQueuing:") || 37448c2ecf20Sopenharmony_ci blogic_parse(&options, "TQ:")) { 37458c2ecf20Sopenharmony_ci if (blogic_parse(&options, "Default")) { 37468c2ecf20Sopenharmony_ci drvr_opts->tagq_ok = 0x0000; 37478c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask = 0x0000; 37488c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, "Enable")) { 37498c2ecf20Sopenharmony_ci drvr_opts->tagq_ok = 0xFFFF; 37508c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask = 0xFFFF; 37518c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, "Disable")) { 37528c2ecf20Sopenharmony_ci drvr_opts->tagq_ok = 0x0000; 37538c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask = 0xFFFF; 37548c2ecf20Sopenharmony_ci } else { 37558c2ecf20Sopenharmony_ci unsigned short tgt_bit; 37568c2ecf20Sopenharmony_ci for (tgt_id = 0, tgt_bit = 1; 37578c2ecf20Sopenharmony_ci tgt_id < BLOGIC_MAXDEV; 37588c2ecf20Sopenharmony_ci tgt_id++, tgt_bit <<= 1) 37598c2ecf20Sopenharmony_ci switch (*options++) { 37608c2ecf20Sopenharmony_ci case 'Y': 37618c2ecf20Sopenharmony_ci drvr_opts->tagq_ok |= tgt_bit; 37628c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask |= tgt_bit; 37638c2ecf20Sopenharmony_ci break; 37648c2ecf20Sopenharmony_ci case 'N': 37658c2ecf20Sopenharmony_ci drvr_opts->tagq_ok &= ~tgt_bit; 37668c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask |= tgt_bit; 37678c2ecf20Sopenharmony_ci break; 37688c2ecf20Sopenharmony_ci case 'X': 37698c2ecf20Sopenharmony_ci break; 37708c2ecf20Sopenharmony_ci default: 37718c2ecf20Sopenharmony_ci options--; 37728c2ecf20Sopenharmony_ci tgt_id = BLOGIC_MAXDEV; 37738c2ecf20Sopenharmony_ci break; 37748c2ecf20Sopenharmony_ci } 37758c2ecf20Sopenharmony_ci } 37768c2ecf20Sopenharmony_ci } 37778c2ecf20Sopenharmony_ci /* Miscellaneous Options. */ 37788c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "BusSettleTime:") || 37798c2ecf20Sopenharmony_ci blogic_parse(&options, "BST:")) { 37808c2ecf20Sopenharmony_ci unsigned short bus_settle_time = 37818c2ecf20Sopenharmony_ci simple_strtoul(options, &options, 0); 37828c2ecf20Sopenharmony_ci if (bus_settle_time > 5 * 60) { 37838c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (invalid Bus Settle Time %d)\n", NULL, bus_settle_time); 37848c2ecf20Sopenharmony_ci return 0; 37858c2ecf20Sopenharmony_ci } 37868c2ecf20Sopenharmony_ci drvr_opts->bus_settle_time = bus_settle_time; 37878c2ecf20Sopenharmony_ci } else if (blogic_parse(&options, 37888c2ecf20Sopenharmony_ci "InhibitTargetInquiry")) 37898c2ecf20Sopenharmony_ci drvr_opts->stop_tgt_inquiry = true; 37908c2ecf20Sopenharmony_ci /* Debugging Options. */ 37918c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "TraceProbe")) 37928c2ecf20Sopenharmony_ci blogic_global_options.trace_probe = true; 37938c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "TraceHardwareReset")) 37948c2ecf20Sopenharmony_ci blogic_global_options.trace_hw_reset = true; 37958c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "TraceConfiguration")) 37968c2ecf20Sopenharmony_ci blogic_global_options.trace_config = true; 37978c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "TraceErrors")) 37988c2ecf20Sopenharmony_ci blogic_global_options.trace_err = true; 37998c2ecf20Sopenharmony_ci else if (blogic_parse(&options, "Debug")) { 38008c2ecf20Sopenharmony_ci blogic_global_options.trace_probe = true; 38018c2ecf20Sopenharmony_ci blogic_global_options.trace_hw_reset = true; 38028c2ecf20Sopenharmony_ci blogic_global_options.trace_config = true; 38038c2ecf20Sopenharmony_ci blogic_global_options.trace_err = true; 38048c2ecf20Sopenharmony_ci } 38058c2ecf20Sopenharmony_ci if (*options == ',') 38068c2ecf20Sopenharmony_ci options++; 38078c2ecf20Sopenharmony_ci else if (*options != ';' && *options != '\0') { 38088c2ecf20Sopenharmony_ci blogic_err("BusLogic: Unexpected Driver Option '%s' ignored\n", NULL, options); 38098c2ecf20Sopenharmony_ci *options = '\0'; 38108c2ecf20Sopenharmony_ci } 38118c2ecf20Sopenharmony_ci } 38128c2ecf20Sopenharmony_ci if (!(blogic_drvr_options_count == 0 || 38138c2ecf20Sopenharmony_ci blogic_probeinfo_count == 0 || 38148c2ecf20Sopenharmony_ci blogic_drvr_options_count == blogic_probeinfo_count)) { 38158c2ecf20Sopenharmony_ci blogic_err("BusLogic: Invalid Driver Options (all or no I/O Addresses must be specified)\n", NULL); 38168c2ecf20Sopenharmony_ci return 0; 38178c2ecf20Sopenharmony_ci } 38188c2ecf20Sopenharmony_ci /* 38198c2ecf20Sopenharmony_ci Tagged Queuing is disabled when the Queue Depth is 1 since queuing 38208c2ecf20Sopenharmony_ci multiple commands is not possible. 38218c2ecf20Sopenharmony_ci */ 38228c2ecf20Sopenharmony_ci for (tgt_id = 0; tgt_id < BLOGIC_MAXDEV; tgt_id++) 38238c2ecf20Sopenharmony_ci if (drvr_opts->qdepth[tgt_id] == 1) { 38248c2ecf20Sopenharmony_ci unsigned short tgt_bit = 1 << tgt_id; 38258c2ecf20Sopenharmony_ci drvr_opts->tagq_ok &= ~tgt_bit; 38268c2ecf20Sopenharmony_ci drvr_opts->tagq_ok_mask |= tgt_bit; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci if (*options == ';') 38298c2ecf20Sopenharmony_ci options++; 38308c2ecf20Sopenharmony_ci if (*options == '\0') 38318c2ecf20Sopenharmony_ci return 0; 38328c2ecf20Sopenharmony_ci } 38338c2ecf20Sopenharmony_ci return 1; 38348c2ecf20Sopenharmony_ci} 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci/* 38378c2ecf20Sopenharmony_ci Get it all started 38388c2ecf20Sopenharmony_ci*/ 38398c2ecf20Sopenharmony_ci 38408c2ecf20Sopenharmony_cistatic struct scsi_host_template blogic_template = { 38418c2ecf20Sopenharmony_ci .module = THIS_MODULE, 38428c2ecf20Sopenharmony_ci .proc_name = "BusLogic", 38438c2ecf20Sopenharmony_ci .write_info = blogic_write_info, 38448c2ecf20Sopenharmony_ci .show_info = blogic_show_info, 38458c2ecf20Sopenharmony_ci .name = "BusLogic", 38468c2ecf20Sopenharmony_ci .info = blogic_drvr_info, 38478c2ecf20Sopenharmony_ci .queuecommand = blogic_qcmd, 38488c2ecf20Sopenharmony_ci .slave_configure = blogic_slaveconfig, 38498c2ecf20Sopenharmony_ci .bios_param = blogic_diskparam, 38508c2ecf20Sopenharmony_ci .eh_host_reset_handler = blogic_hostreset, 38518c2ecf20Sopenharmony_ci#if 0 38528c2ecf20Sopenharmony_ci .eh_abort_handler = blogic_abort, 38538c2ecf20Sopenharmony_ci#endif 38548c2ecf20Sopenharmony_ci .unchecked_isa_dma = 1, 38558c2ecf20Sopenharmony_ci .max_sectors = 128, 38568c2ecf20Sopenharmony_ci}; 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_ci/* 38598c2ecf20Sopenharmony_ci blogic_setup handles processing of Kernel Command Line Arguments. 38608c2ecf20Sopenharmony_ci*/ 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_cistatic int __init blogic_setup(char *str) 38638c2ecf20Sopenharmony_ci{ 38648c2ecf20Sopenharmony_ci int ints[3]; 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci (void) get_options(str, ARRAY_SIZE(ints), ints); 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_ci if (ints[0] != 0) { 38698c2ecf20Sopenharmony_ci blogic_err("BusLogic: Obsolete Command Line Entry Format Ignored\n", NULL); 38708c2ecf20Sopenharmony_ci return 0; 38718c2ecf20Sopenharmony_ci } 38728c2ecf20Sopenharmony_ci if (str == NULL || *str == '\0') 38738c2ecf20Sopenharmony_ci return 0; 38748c2ecf20Sopenharmony_ci return blogic_parseopts(str); 38758c2ecf20Sopenharmony_ci} 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci/* 38788c2ecf20Sopenharmony_ci * Exit function. Deletes all hosts associated with this driver. 38798c2ecf20Sopenharmony_ci */ 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_cistatic void __exit blogic_exit(void) 38828c2ecf20Sopenharmony_ci{ 38838c2ecf20Sopenharmony_ci struct blogic_adapter *ha, *next; 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci list_for_each_entry_safe(ha, next, &blogic_host_list, host_list) 38868c2ecf20Sopenharmony_ci blogic_deladapter(ha); 38878c2ecf20Sopenharmony_ci} 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci__setup("BusLogic=", blogic_setup); 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci#ifdef MODULE 38928c2ecf20Sopenharmony_ci/*static struct pci_device_id blogic_pci_tbl[] = { 38938c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, 38948c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 38958c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, 38968c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 38978c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, 38988c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 38998c2ecf20Sopenharmony_ci { } 39008c2ecf20Sopenharmony_ci};*/ 39018c2ecf20Sopenharmony_cistatic const struct pci_device_id blogic_pci_tbl[] = { 39028c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER)}, 39038c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC)}, 39048c2ecf20Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT)}, 39058c2ecf20Sopenharmony_ci {0, }, 39068c2ecf20Sopenharmony_ci}; 39078c2ecf20Sopenharmony_ci#endif 39088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, blogic_pci_tbl); 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_cimodule_init(blogic_init); 39118c2ecf20Sopenharmony_cimodule_exit(blogic_exit); 3912