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