18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/*************************************************************************** 38c2ecf20Sopenharmony_ci dpti.c - description 48c2ecf20Sopenharmony_ci ------------------- 58c2ecf20Sopenharmony_ci begin : Thu Sep 7 2000 68c2ecf20Sopenharmony_ci copyright : (C) 2000 by Adaptec 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci July 30, 2001 First version being submitted 98c2ecf20Sopenharmony_ci for inclusion in the kernel. V2.4 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci See Documentation/scsi/dpti.rst for history, notes, license info 128c2ecf20Sopenharmony_ci and credits 138c2ecf20Sopenharmony_ci ***************************************************************************/ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/*************************************************************************** 168c2ecf20Sopenharmony_ci * * 178c2ecf20Sopenharmony_ci * * 188c2ecf20Sopenharmony_ci ***************************************************************************/ 198c2ecf20Sopenharmony_ci/*************************************************************************** 208c2ecf20Sopenharmony_ci * Sat Dec 20 2003 Go Taniguchi <go@turbolinux.co.jp> 218c2ecf20Sopenharmony_ci - Support 2.6 kernel and DMA-mapping 228c2ecf20Sopenharmony_ci - ioctl fix for raid tools 238c2ecf20Sopenharmony_ci - use schedule_timeout in long long loop 248c2ecf20Sopenharmony_ci **************************************************************************/ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/*#define DEBUG 1 */ 278c2ecf20Sopenharmony_ci/*#define UARTDELAY 1 */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn"); 338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Adaptec I2O RAID Driver"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci//////////////////////////////////////////////////////////////// 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/ioctl.h> /* For SCSI-Passthrough */ 388c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <linux/stat.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> /* for kmalloc() */ 428c2ecf20Sopenharmony_ci#include <linux/pci.h> /* for PCI support */ 438c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 448c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 458c2ecf20Sopenharmony_ci#include <linux/delay.h> /* for udelay */ 468c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 478c2ecf20Sopenharmony_ci#include <linux/kernel.h> /* for printk */ 488c2ecf20Sopenharmony_ci#include <linux/sched.h> 498c2ecf20Sopenharmony_ci#include <linux/reboot.h> 508c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 518c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#include <linux/timer.h> 548c2ecf20Sopenharmony_ci#include <linux/string.h> 558c2ecf20Sopenharmony_ci#include <linux/ioport.h> 568c2ecf20Sopenharmony_ci#include <linux/mutex.h> 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#include <asm/processor.h> /* for boot_cpu_data */ 598c2ecf20Sopenharmony_ci#include <asm/io.h> 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 628c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 638c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 648c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 658c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#include "dpt/dptsig.h" 688c2ecf20Sopenharmony_ci#include "dpti.h" 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/*============================================================================ 718c2ecf20Sopenharmony_ci * Create a binary signature - this is read by dptsig 728c2ecf20Sopenharmony_ci * Needed for our management apps 738c2ecf20Sopenharmony_ci *============================================================================ 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(adpt_mutex); 768c2ecf20Sopenharmony_cistatic dpt_sig_S DPTI_sig = { 778c2ecf20Sopenharmony_ci {'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, 788c2ecf20Sopenharmony_ci#ifdef __i386__ 798c2ecf20Sopenharmony_ci PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM, 808c2ecf20Sopenharmony_ci#elif defined(__ia64__) 818c2ecf20Sopenharmony_ci PROC_INTEL, PROC_IA64, 828c2ecf20Sopenharmony_ci#elif defined(__sparc__) 838c2ecf20Sopenharmony_ci PROC_ULTRASPARC, PROC_ULTRASPARC, 848c2ecf20Sopenharmony_ci#elif defined(__alpha__) 858c2ecf20Sopenharmony_ci PROC_ALPHA, PROC_ALPHA, 868c2ecf20Sopenharmony_ci#else 878c2ecf20Sopenharmony_ci (-1),(-1), 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL, 908c2ecf20Sopenharmony_ci ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION, 918c2ecf20Sopenharmony_ci DPT_MONTH, DPT_DAY, DPT_YEAR, "Adaptec Linux I2O RAID Driver" 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/*============================================================================ 988c2ecf20Sopenharmony_ci * Globals 998c2ecf20Sopenharmony_ci *============================================================================ 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(adpt_configuration_lock); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic struct i2o_sys_tbl *sys_tbl; 1058c2ecf20Sopenharmony_cistatic dma_addr_t sys_tbl_pa; 1068c2ecf20Sopenharmony_cistatic int sys_tbl_ind; 1078c2ecf20Sopenharmony_cistatic int sys_tbl_len; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic adpt_hba* hba_chain = NULL; 1108c2ecf20Sopenharmony_cistatic int hba_count = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic struct class *adpt_sysfs_class; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic long adpt_unlocked_ioctl(struct file *, unsigned int, unsigned long); 1158c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 1168c2ecf20Sopenharmony_cistatic long compat_adpt_ioctl(struct file *, unsigned int, unsigned long); 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct file_operations adpt_fops = { 1208c2ecf20Sopenharmony_ci .unlocked_ioctl = adpt_unlocked_ioctl, 1218c2ecf20Sopenharmony_ci .open = adpt_open, 1228c2ecf20Sopenharmony_ci .release = adpt_close, 1238c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 1248c2ecf20Sopenharmony_ci .compat_ioctl = compat_adpt_ioctl, 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci .llseek = noop_llseek, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Structures and definitions for synchronous message posting. 1308c2ecf20Sopenharmony_ci * See adpt_i2o_post_wait() for description 1318c2ecf20Sopenharmony_ci * */ 1328c2ecf20Sopenharmony_cistruct adpt_i2o_post_wait_data 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int status; 1358c2ecf20Sopenharmony_ci u32 id; 1368c2ecf20Sopenharmony_ci adpt_wait_queue_head_t *wq; 1378c2ecf20Sopenharmony_ci struct adpt_i2o_post_wait_data *next; 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic struct adpt_i2o_post_wait_data *adpt_post_wait_queue = NULL; 1418c2ecf20Sopenharmony_cistatic u32 adpt_post_wait_id = 0; 1428c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(adpt_post_wait_lock); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/*============================================================================ 1468c2ecf20Sopenharmony_ci * Functions 1478c2ecf20Sopenharmony_ci *============================================================================ 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline int dpt_dma64(adpt_hba *pHba) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return (sizeof(dma_addr_t) > 4 && (pHba)->dma64); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline u32 dma_high(dma_addr_t addr) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return upper_32_bits(addr); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline u32 dma_low(dma_addr_t addr) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return (u32)addr; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic u8 adpt_read_blink_led(adpt_hba* host) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci if (host->FwDebugBLEDflag_P) { 1688c2ecf20Sopenharmony_ci if( readb(host->FwDebugBLEDflag_P) == 0xbc ){ 1698c2ecf20Sopenharmony_ci return readb(host->FwDebugBLEDvalue_P); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/*============================================================================ 1768c2ecf20Sopenharmony_ci * Scsi host template interface functions 1778c2ecf20Sopenharmony_ci *============================================================================ 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#ifdef MODULE 1818c2ecf20Sopenharmony_cistatic struct pci_device_id dptids[] = { 1828c2ecf20Sopenharmony_ci { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, 1838c2ecf20Sopenharmony_ci { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, 1848c2ecf20Sopenharmony_ci { 0, } 1858c2ecf20Sopenharmony_ci}; 1868c2ecf20Sopenharmony_ci#endif 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci,dptids); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int adpt_detect(struct scsi_host_template* sht) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct pci_dev *pDev = NULL; 1938c2ecf20Sopenharmony_ci adpt_hba *pHba; 1948c2ecf20Sopenharmony_ci adpt_hba *next; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci PINFO("Detecting Adaptec I2O RAID controllers...\n"); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* search for all Adatpec I2O RAID cards */ 1998c2ecf20Sopenharmony_ci while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) { 2008c2ecf20Sopenharmony_ci if(pDev->device == PCI_DPT_DEVICE_ID || 2018c2ecf20Sopenharmony_ci pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){ 2028c2ecf20Sopenharmony_ci if(adpt_install_hba(sht, pDev) ){ 2038c2ecf20Sopenharmony_ci PERROR("Could not Init an I2O RAID device\n"); 2048c2ecf20Sopenharmony_ci PERROR("Will not try to detect others.\n"); 2058c2ecf20Sopenharmony_ci return hba_count-1; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci pci_dev_get(pDev); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* In INIT state, Activate IOPs */ 2128c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = next) { 2138c2ecf20Sopenharmony_ci next = pHba->next; 2148c2ecf20Sopenharmony_ci // Activate does get status , init outbound, and get hrt 2158c2ecf20Sopenharmony_ci if (adpt_i2o_activate_hba(pHba) < 0) { 2168c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Active IOPs in HOLD state */ 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cirebuild_sys_tab: 2248c2ecf20Sopenharmony_ci if (hba_chain == NULL) 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * If build_sys_table fails, we kill everything and bail 2298c2ecf20Sopenharmony_ci * as we can't init the IOPs w/o a system table 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci if (adpt_i2o_build_sys_table() < 0) { 2328c2ecf20Sopenharmony_ci adpt_i2o_sys_shutdown(); 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci PDEBUG("HBA's in HOLD state\n"); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* If IOP don't get online, we need to rebuild the System table */ 2398c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 2408c2ecf20Sopenharmony_ci if (adpt_i2o_online_hba(pHba) < 0) { 2418c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 2428c2ecf20Sopenharmony_ci goto rebuild_sys_tab; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Active IOPs now in OPERATIONAL state */ 2478c2ecf20Sopenharmony_ci PDEBUG("HBA's in OPERATIONAL state\n"); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci printk("dpti: If you have a lot of devices this could take a few minutes.\n"); 2508c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = next) { 2518c2ecf20Sopenharmony_ci next = pHba->next; 2528c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name); 2538c2ecf20Sopenharmony_ci if (adpt_i2o_lct_get(pHba) < 0){ 2548c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 2558c2ecf20Sopenharmony_ci continue; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (adpt_i2o_parse_lct(pHba) < 0){ 2598c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 2608c2ecf20Sopenharmony_ci continue; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci adpt_inquiry(pHba); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o"); 2668c2ecf20Sopenharmony_ci if (IS_ERR(adpt_sysfs_class)) { 2678c2ecf20Sopenharmony_ci printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n"); 2688c2ecf20Sopenharmony_ci adpt_sysfs_class = NULL; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = next) { 2728c2ecf20Sopenharmony_ci next = pHba->next; 2738c2ecf20Sopenharmony_ci if (adpt_scsi_host_alloc(pHba, sht) < 0){ 2748c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 2758c2ecf20Sopenharmony_ci continue; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci pHba->initialized = TRUE; 2788c2ecf20Sopenharmony_ci pHba->state &= ~DPTI_STATE_RESET; 2798c2ecf20Sopenharmony_ci if (adpt_sysfs_class) { 2808c2ecf20Sopenharmony_ci struct device *dev = device_create(adpt_sysfs_class, 2818c2ecf20Sopenharmony_ci NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit), NULL, 2828c2ecf20Sopenharmony_ci "dpti%d", pHba->unit); 2838c2ecf20Sopenharmony_ci if (IS_ERR(dev)) { 2848c2ecf20Sopenharmony_ci printk(KERN_WARNING"dpti%d: unable to " 2858c2ecf20Sopenharmony_ci "create device in dpt_i2o class\n", 2868c2ecf20Sopenharmony_ci pHba->unit); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci // Register our control device node 2928c2ecf20Sopenharmony_ci // nodes will need to be created in /dev to access this 2938c2ecf20Sopenharmony_ci // the nodes can not be created from within the driver 2948c2ecf20Sopenharmony_ci if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) { 2958c2ecf20Sopenharmony_ci adpt_i2o_sys_shutdown(); 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci return hba_count; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void adpt_release(adpt_hba *pHba) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct Scsi_Host *shost = pHba->host; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci scsi_remove_host(shost); 3078c2ecf20Sopenharmony_ci// adpt_i2o_quiesce_hba(pHba); 3088c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 3098c2ecf20Sopenharmony_ci scsi_host_put(shost); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void adpt_inquiry(adpt_hba* pHba) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci u32 msg[17]; 3168c2ecf20Sopenharmony_ci u32 *mptr; 3178c2ecf20Sopenharmony_ci u32 *lenptr; 3188c2ecf20Sopenharmony_ci int direction; 3198c2ecf20Sopenharmony_ci int scsidir; 3208c2ecf20Sopenharmony_ci u32 len; 3218c2ecf20Sopenharmony_ci u32 reqlen; 3228c2ecf20Sopenharmony_ci u8* buf; 3238c2ecf20Sopenharmony_ci dma_addr_t addr; 3248c2ecf20Sopenharmony_ci u8 scb[16]; 3258c2ecf20Sopenharmony_ci s32 rcode; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(msg)); 3288c2ecf20Sopenharmony_ci buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL); 3298c2ecf20Sopenharmony_ci if(!buf){ 3308c2ecf20Sopenharmony_ci printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name); 3318c2ecf20Sopenharmony_ci return; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci memset((void*)buf, 0, 36); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci len = 36; 3368c2ecf20Sopenharmony_ci direction = 0x00000000; 3378c2ecf20Sopenharmony_ci scsidir =0x40000000; // DATA IN (iop<--dev) 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (dpt_dma64(pHba)) 3408c2ecf20Sopenharmony_ci reqlen = 17; // SINGLE SGE, 64 bit 3418c2ecf20Sopenharmony_ci else 3428c2ecf20Sopenharmony_ci reqlen = 14; // SINGLE SGE, 32 bit 3438c2ecf20Sopenharmony_ci /* Stick the headers on */ 3448c2ecf20Sopenharmony_ci msg[0] = reqlen<<16 | SGL_OFFSET_12; 3458c2ecf20Sopenharmony_ci msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID); 3468c2ecf20Sopenharmony_ci msg[2] = 0; 3478c2ecf20Sopenharmony_ci msg[3] = 0; 3488c2ecf20Sopenharmony_ci // Adaptec/DPT Private stuff 3498c2ecf20Sopenharmony_ci msg[4] = I2O_CMD_SCSI_EXEC|DPT_ORGANIZATION_ID<<16; 3508c2ecf20Sopenharmony_ci msg[5] = ADAPTER_TID | 1<<16 /* Interpret*/; 3518c2ecf20Sopenharmony_ci /* Direction, disconnect ok | sense data | simple queue , CDBLen */ 3528c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_ENABLE_DISCONNECT | 3538c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | 3548c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; 3558c2ecf20Sopenharmony_ci msg[6] = scsidir|0x20a00000| 6 /* cmd len*/; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci mptr=msg+7; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci memset(scb, 0, sizeof(scb)); 3608c2ecf20Sopenharmony_ci // Write SCSI command into the message - always 16 byte block 3618c2ecf20Sopenharmony_ci scb[0] = INQUIRY; 3628c2ecf20Sopenharmony_ci scb[1] = 0; 3638c2ecf20Sopenharmony_ci scb[2] = 0; 3648c2ecf20Sopenharmony_ci scb[3] = 0; 3658c2ecf20Sopenharmony_ci scb[4] = 36; 3668c2ecf20Sopenharmony_ci scb[5] = 0; 3678c2ecf20Sopenharmony_ci // Don't care about the rest of scb 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci memcpy(mptr, scb, sizeof(scb)); 3708c2ecf20Sopenharmony_ci mptr+=4; 3718c2ecf20Sopenharmony_ci lenptr=mptr++; /* Remember me - fill in when we know */ 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Now fill in the SGList and command */ 3748c2ecf20Sopenharmony_ci *lenptr = len; 3758c2ecf20Sopenharmony_ci if (dpt_dma64(pHba)) { 3768c2ecf20Sopenharmony_ci *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */ 3778c2ecf20Sopenharmony_ci *mptr++ = 1 << PAGE_SHIFT; 3788c2ecf20Sopenharmony_ci *mptr++ = 0xD0000000|direction|len; 3798c2ecf20Sopenharmony_ci *mptr++ = dma_low(addr); 3808c2ecf20Sopenharmony_ci *mptr++ = dma_high(addr); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci *mptr++ = 0xD0000000|direction|len; 3838c2ecf20Sopenharmony_ci *mptr++ = addr; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci // Send it on it's way 3878c2ecf20Sopenharmony_ci rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120); 3888c2ecf20Sopenharmony_ci if (rcode != 0) { 3898c2ecf20Sopenharmony_ci sprintf(pHba->detail, "Adaptec I2O RAID"); 3908c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode); 3918c2ecf20Sopenharmony_ci if (rcode != -ETIME && rcode != -EINTR) 3928c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 80, buf, addr); 3938c2ecf20Sopenharmony_ci } else { 3948c2ecf20Sopenharmony_ci memset(pHba->detail, 0, sizeof(pHba->detail)); 3958c2ecf20Sopenharmony_ci memcpy(&(pHba->detail), "Vendor: Adaptec ", 16); 3968c2ecf20Sopenharmony_ci memcpy(&(pHba->detail[16]), " Model: ", 8); 3978c2ecf20Sopenharmony_ci memcpy(&(pHba->detail[24]), (u8*) &buf[16], 16); 3988c2ecf20Sopenharmony_ci memcpy(&(pHba->detail[40]), " FW: ", 4); 3998c2ecf20Sopenharmony_ci memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4); 4008c2ecf20Sopenharmony_ci pHba->detail[48] = '\0'; /* precautionary */ 4018c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 80, buf, addr); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 4048c2ecf20Sopenharmony_ci return ; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic int adpt_slave_configure(struct scsi_device * device) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct Scsi_Host *host = device->host; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (host->can_queue && device->tagged_supported) { 4138c2ecf20Sopenharmony_ci scsi_change_queue_depth(device, 4148c2ecf20Sopenharmony_ci host->can_queue - 1); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci adpt_hba* pHba = NULL; 4228c2ecf20Sopenharmony_ci struct adpt_device* pDev = NULL; /* dpt per device information */ 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci cmd->scsi_done = done; 4258c2ecf20Sopenharmony_ci /* 4268c2ecf20Sopenharmony_ci * SCSI REQUEST_SENSE commands will be executed automatically by the 4278c2ecf20Sopenharmony_ci * Host Adapter for any errors, so they should not be executed 4288c2ecf20Sopenharmony_ci * explicitly unless the Sense Data is zero indicating that no error 4298c2ecf20Sopenharmony_ci * occurred. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) { 4338c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 4348c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci pHba = (adpt_hba*)cmd->device->host->hostdata[0]; 4398c2ecf20Sopenharmony_ci if (!pHba) { 4408c2ecf20Sopenharmony_ci return FAILED; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci rmb(); 4448c2ecf20Sopenharmony_ci if ((pHba->state) & DPTI_STATE_RESET) 4458c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci // TODO if the cmd->device if offline then I may need to issue a bus rescan 4488c2ecf20Sopenharmony_ci // followed by a get_lct to see if the device is there anymore 4498c2ecf20Sopenharmony_ci if((pDev = (struct adpt_device*) (cmd->device->hostdata)) == NULL) { 4508c2ecf20Sopenharmony_ci /* 4518c2ecf20Sopenharmony_ci * First command request for this device. Set up a pointer 4528c2ecf20Sopenharmony_ci * to the device structure. This should be a TEST_UNIT_READY 4538c2ecf20Sopenharmony_ci * command from scan_scsis_single. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci if ((pDev = adpt_find_device(pHba, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun)) == NULL) { 4568c2ecf20Sopenharmony_ci // TODO: if any luns are at this bus, scsi id then fake a TEST_UNIT_READY and INQUIRY response 4578c2ecf20Sopenharmony_ci // with type 7F (for all luns less than the max for this bus,id) so the lun scan will continue. 4588c2ecf20Sopenharmony_ci cmd->result = (DID_NO_CONNECT << 16); 4598c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci cmd->device->hostdata = pDev; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci pDev->pScsi_dev = cmd->device; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * If we are being called from when the device is being reset, 4688c2ecf20Sopenharmony_ci * delay processing of the command until later. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci if (pDev->state & DPTI_DEV_RESET ) { 4718c2ecf20Sopenharmony_ci return FAILED; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci return adpt_scsi_to_i2o(pHba, cmd, pDev); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(adpt_queue) 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev, 4798c2ecf20Sopenharmony_ci sector_t capacity, int geom[]) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int heads=-1; 4828c2ecf20Sopenharmony_ci int sectors=-1; 4838c2ecf20Sopenharmony_ci int cylinders=-1; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci // *** First lets set the default geometry **** 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci // If the capacity is less than ox2000 4888c2ecf20Sopenharmony_ci if (capacity < 0x2000 ) { // floppy 4898c2ecf20Sopenharmony_ci heads = 18; 4908c2ecf20Sopenharmony_ci sectors = 2; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci // else if between 0x2000 and 0x20000 4938c2ecf20Sopenharmony_ci else if (capacity < 0x20000) { 4948c2ecf20Sopenharmony_ci heads = 64; 4958c2ecf20Sopenharmony_ci sectors = 32; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci // else if between 0x20000 and 0x40000 4988c2ecf20Sopenharmony_ci else if (capacity < 0x40000) { 4998c2ecf20Sopenharmony_ci heads = 65; 5008c2ecf20Sopenharmony_ci sectors = 63; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci // else if between 0x4000 and 0x80000 5038c2ecf20Sopenharmony_ci else if (capacity < 0x80000) { 5048c2ecf20Sopenharmony_ci heads = 128; 5058c2ecf20Sopenharmony_ci sectors = 63; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci // else if greater than 0x80000 5088c2ecf20Sopenharmony_ci else { 5098c2ecf20Sopenharmony_ci heads = 255; 5108c2ecf20Sopenharmony_ci sectors = 63; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci cylinders = sector_div(capacity, heads * sectors); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci // Special case if CDROM 5158c2ecf20Sopenharmony_ci if(sdev->type == 5) { // CDROM 5168c2ecf20Sopenharmony_ci heads = 252; 5178c2ecf20Sopenharmony_ci sectors = 63; 5188c2ecf20Sopenharmony_ci cylinders = 1111; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci geom[0] = heads; 5228c2ecf20Sopenharmony_ci geom[1] = sectors; 5238c2ecf20Sopenharmony_ci geom[2] = cylinders; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci PDEBUG("adpt_bios_param: exit\n"); 5268c2ecf20Sopenharmony_ci return 0; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic const char *adpt_info(struct Scsi_Host *host) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci adpt_hba* pHba; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci pHba = (adpt_hba *) host->hostdata[0]; 5358c2ecf20Sopenharmony_ci return (char *) (pHba->detail); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int adpt_show_info(struct seq_file *m, struct Scsi_Host *host) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct adpt_device* d; 5418c2ecf20Sopenharmony_ci int id; 5428c2ecf20Sopenharmony_ci int chan; 5438c2ecf20Sopenharmony_ci adpt_hba* pHba; 5448c2ecf20Sopenharmony_ci int unit; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci // Find HBA (host bus adapter) we are looking for 5478c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 5488c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 5498c2ecf20Sopenharmony_ci if (pHba->host == host) { 5508c2ecf20Sopenharmony_ci break; /* found adapter */ 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 5548c2ecf20Sopenharmony_ci if (pHba == NULL) { 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci host = pHba->host; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci seq_printf(m, "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION); 5608c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", pHba->detail); 5618c2ecf20Sopenharmony_ci seq_printf(m, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n", 5628c2ecf20Sopenharmony_ci pHba->host->host_no, pHba->name, host->irq); 5638c2ecf20Sopenharmony_ci seq_printf(m, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n", 5648c2ecf20Sopenharmony_ci host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci seq_puts(m, "Devices:\n"); 5678c2ecf20Sopenharmony_ci for(chan = 0; chan < MAX_CHANNEL; chan++) { 5688c2ecf20Sopenharmony_ci for(id = 0; id < MAX_ID; id++) { 5698c2ecf20Sopenharmony_ci d = pHba->channel[chan].device[id]; 5708c2ecf20Sopenharmony_ci while(d) { 5718c2ecf20Sopenharmony_ci seq_printf(m,"\t%-24.24s", d->pScsi_dev->vendor); 5728c2ecf20Sopenharmony_ci seq_printf(m," Rev: %-8.8s\n", d->pScsi_dev->rev); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci unit = d->pI2o_dev->lct_data.tid; 5758c2ecf20Sopenharmony_ci seq_printf(m, "\tTID=%d, (Channel=%d, Target=%d, Lun=%llu) (%s)\n\n", 5768c2ecf20Sopenharmony_ci unit, (int)d->scsi_channel, (int)d->scsi_id, d->scsi_lun, 5778c2ecf20Sopenharmony_ci scsi_device_online(d->pScsi_dev)? "online":"offline"); 5788c2ecf20Sopenharmony_ci d = d->next_lun; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/*=========================================================================== 5868c2ecf20Sopenharmony_ci * Error Handling routines 5878c2ecf20Sopenharmony_ci *=========================================================================== 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int adpt_abort(struct scsi_cmnd * cmd) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci adpt_hba* pHba = NULL; /* host bus adapter structure */ 5938c2ecf20Sopenharmony_ci struct adpt_device* dptdevice; /* dpt per device information */ 5948c2ecf20Sopenharmony_ci u32 msg[5]; 5958c2ecf20Sopenharmony_ci int rcode; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci pHba = (adpt_hba*) cmd->device->host->hostdata[0]; 5988c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); 5998c2ecf20Sopenharmony_ci if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { 6008c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name); 6018c2ecf20Sopenharmony_ci return FAILED; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(msg)); 6058c2ecf20Sopenharmony_ci msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; 6068c2ecf20Sopenharmony_ci msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid; 6078c2ecf20Sopenharmony_ci msg[2] = 0; 6088c2ecf20Sopenharmony_ci msg[3]= 0; 6098c2ecf20Sopenharmony_ci /* Add 1 to avoid firmware treating it as invalid command */ 6108c2ecf20Sopenharmony_ci msg[4] = cmd->request->tag + 1; 6118c2ecf20Sopenharmony_ci if (pHba->host) 6128c2ecf20Sopenharmony_ci spin_lock_irq(pHba->host->host_lock); 6138c2ecf20Sopenharmony_ci rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER); 6148c2ecf20Sopenharmony_ci if (pHba->host) 6158c2ecf20Sopenharmony_ci spin_unlock_irq(pHba->host->host_lock); 6168c2ecf20Sopenharmony_ci if (rcode != 0) { 6178c2ecf20Sopenharmony_ci if(rcode == -EOPNOTSUPP ){ 6188c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); 6198c2ecf20Sopenharmony_ci return FAILED; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Abort failed.\n",pHba->name); 6228c2ecf20Sopenharmony_ci return FAILED; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Abort complete.\n",pHba->name); 6258c2ecf20Sopenharmony_ci return SUCCESS; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci#define I2O_DEVICE_RESET 0x27 6308c2ecf20Sopenharmony_ci// This is the same for BLK and SCSI devices 6318c2ecf20Sopenharmony_ci// NOTE this is wrong in the i2o.h definitions 6328c2ecf20Sopenharmony_ci// This is not currently supported by our adapter but we issue it anyway 6338c2ecf20Sopenharmony_cistatic int adpt_device_reset(struct scsi_cmnd* cmd) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci adpt_hba* pHba; 6368c2ecf20Sopenharmony_ci u32 msg[4]; 6378c2ecf20Sopenharmony_ci u32 rcode; 6388c2ecf20Sopenharmony_ci int old_state; 6398c2ecf20Sopenharmony_ci struct adpt_device* d = cmd->device->hostdata; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci pHba = (void*) cmd->device->host->hostdata[0]; 6428c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Trying to reset device\n",pHba->name); 6438c2ecf20Sopenharmony_ci if (!d) { 6448c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Reset Device: Device Not found\n",pHba->name); 6458c2ecf20Sopenharmony_ci return FAILED; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(msg)); 6488c2ecf20Sopenharmony_ci msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; 6498c2ecf20Sopenharmony_ci msg[1] = (I2O_DEVICE_RESET<<24|HOST_TID<<12|d->tid); 6508c2ecf20Sopenharmony_ci msg[2] = 0; 6518c2ecf20Sopenharmony_ci msg[3] = 0; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (pHba->host) 6548c2ecf20Sopenharmony_ci spin_lock_irq(pHba->host->host_lock); 6558c2ecf20Sopenharmony_ci old_state = d->state; 6568c2ecf20Sopenharmony_ci d->state |= DPTI_DEV_RESET; 6578c2ecf20Sopenharmony_ci rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); 6588c2ecf20Sopenharmony_ci d->state = old_state; 6598c2ecf20Sopenharmony_ci if (pHba->host) 6608c2ecf20Sopenharmony_ci spin_unlock_irq(pHba->host->host_lock); 6618c2ecf20Sopenharmony_ci if (rcode != 0) { 6628c2ecf20Sopenharmony_ci if(rcode == -EOPNOTSUPP ){ 6638c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Device reset not supported\n",pHba->name); 6648c2ecf20Sopenharmony_ci return FAILED; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Device reset failed\n",pHba->name); 6678c2ecf20Sopenharmony_ci return FAILED; 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci printk(KERN_INFO"%s: Device reset successful\n",pHba->name); 6708c2ecf20Sopenharmony_ci return SUCCESS; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci#define I2O_HBA_BUS_RESET 0x87 6768c2ecf20Sopenharmony_ci// This version of bus reset is called by the eh_error handler 6778c2ecf20Sopenharmony_cistatic int adpt_bus_reset(struct scsi_cmnd* cmd) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci adpt_hba* pHba; 6808c2ecf20Sopenharmony_ci u32 msg[4]; 6818c2ecf20Sopenharmony_ci u32 rcode; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci pHba = (adpt_hba*)cmd->device->host->hostdata[0]; 6848c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(msg)); 6858c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Bus reset: SCSI Bus %d: tid: %d\n",pHba->name, cmd->device->channel,pHba->channel[cmd->device->channel].tid ); 6868c2ecf20Sopenharmony_ci msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; 6878c2ecf20Sopenharmony_ci msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid); 6888c2ecf20Sopenharmony_ci msg[2] = 0; 6898c2ecf20Sopenharmony_ci msg[3] = 0; 6908c2ecf20Sopenharmony_ci if (pHba->host) 6918c2ecf20Sopenharmony_ci spin_lock_irq(pHba->host->host_lock); 6928c2ecf20Sopenharmony_ci rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); 6938c2ecf20Sopenharmony_ci if (pHba->host) 6948c2ecf20Sopenharmony_ci spin_unlock_irq(pHba->host->host_lock); 6958c2ecf20Sopenharmony_ci if (rcode != 0) { 6968c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name); 6978c2ecf20Sopenharmony_ci return FAILED; 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Bus reset success.\n",pHba->name); 7008c2ecf20Sopenharmony_ci return SUCCESS; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci// This version of reset is called by the eh_error_handler 7058c2ecf20Sopenharmony_cistatic int __adpt_reset(struct scsi_cmnd* cmd) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci adpt_hba* pHba; 7088c2ecf20Sopenharmony_ci int rcode; 7098c2ecf20Sopenharmony_ci char name[32]; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci pHba = (adpt_hba*)cmd->device->host->hostdata[0]; 7128c2ecf20Sopenharmony_ci strncpy(name, pHba->name, sizeof(name)); 7138c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n", name, cmd->device->channel, pHba->channel[cmd->device->channel].tid); 7148c2ecf20Sopenharmony_ci rcode = adpt_hba_reset(pHba); 7158c2ecf20Sopenharmony_ci if(rcode == 0){ 7168c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: HBA reset complete\n", name); 7178c2ecf20Sopenharmony_ci return SUCCESS; 7188c2ecf20Sopenharmony_ci } else { 7198c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: HBA reset failed (%x)\n", name, rcode); 7208c2ecf20Sopenharmony_ci return FAILED; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int adpt_reset(struct scsi_cmnd* cmd) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci int rc; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci spin_lock_irq(cmd->device->host->host_lock); 7298c2ecf20Sopenharmony_ci rc = __adpt_reset(cmd); 7308c2ecf20Sopenharmony_ci spin_unlock_irq(cmd->device->host->host_lock); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return rc; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci// This version of reset is called by the ioctls and indirectly from eh_error_handler via adpt_reset 7368c2ecf20Sopenharmony_cistatic int adpt_hba_reset(adpt_hba* pHba) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci int rcode; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci pHba->state |= DPTI_STATE_RESET; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci // Activate does get status , init outbound, and get hrt 7438c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_activate_hba(pHba)) < 0) { 7448c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Could not activate\n", pHba->name); 7458c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7468c2ecf20Sopenharmony_ci return rcode; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_build_sys_table()) < 0) { 7508c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7518c2ecf20Sopenharmony_ci return rcode; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci PDEBUG("%s: in HOLD state\n",pHba->name); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_online_hba(pHba)) < 0) { 7568c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7578c2ecf20Sopenharmony_ci return rcode; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci PDEBUG("%s: in OPERATIONAL state\n",pHba->name); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_lct_get(pHba)) < 0){ 7628c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7638c2ecf20Sopenharmony_ci return rcode; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){ 7678c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7688c2ecf20Sopenharmony_ci return rcode; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci pHba->state &= ~DPTI_STATE_RESET; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci scsi_host_complete_all_commands(pHba->host, DID_RESET); 7738c2ecf20Sopenharmony_ci return 0; /* return success */ 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci/*=========================================================================== 7778c2ecf20Sopenharmony_ci * 7788c2ecf20Sopenharmony_ci *=========================================================================== 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic void adpt_i2o_sys_shutdown(void) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci adpt_hba *pHba, *pNext; 7858c2ecf20Sopenharmony_ci struct adpt_i2o_post_wait_data *p1, *old; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci printk(KERN_INFO "Shutting down Adaptec I2O controllers.\n"); 7888c2ecf20Sopenharmony_ci printk(KERN_INFO " This could take a few minutes if there are many devices attached\n"); 7898c2ecf20Sopenharmony_ci /* Delete all IOPs from the controller chain */ 7908c2ecf20Sopenharmony_ci /* They should have already been released by the 7918c2ecf20Sopenharmony_ci * scsi-core 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pNext) { 7948c2ecf20Sopenharmony_ci pNext = pHba->next; 7958c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* Remove any timedout entries from the wait queue. */ 7998c2ecf20Sopenharmony_ci// spin_lock_irqsave(&adpt_post_wait_lock, flags); 8008c2ecf20Sopenharmony_ci /* Nothing should be outstanding at this point so just 8018c2ecf20Sopenharmony_ci * free them 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci for(p1 = adpt_post_wait_queue; p1;) { 8048c2ecf20Sopenharmony_ci old = p1; 8058c2ecf20Sopenharmony_ci p1 = p1->next; 8068c2ecf20Sopenharmony_ci kfree(old); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci// spin_unlock_irqrestore(&adpt_post_wait_lock, flags); 8098c2ecf20Sopenharmony_ci adpt_post_wait_queue = NULL; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci printk(KERN_INFO "Adaptec I2O controllers down.\n"); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci adpt_hba* pHba = NULL; 8188c2ecf20Sopenharmony_ci adpt_hba* p = NULL; 8198c2ecf20Sopenharmony_ci ulong base_addr0_phys = 0; 8208c2ecf20Sopenharmony_ci ulong base_addr1_phys = 0; 8218c2ecf20Sopenharmony_ci u32 hba_map0_area_size = 0; 8228c2ecf20Sopenharmony_ci u32 hba_map1_area_size = 0; 8238c2ecf20Sopenharmony_ci void __iomem *base_addr_virt = NULL; 8248c2ecf20Sopenharmony_ci void __iomem *msg_addr_virt = NULL; 8258c2ecf20Sopenharmony_ci int dma64 = 0; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci int raptorFlag = FALSE; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if(pci_enable_device(pDev)) { 8308c2ecf20Sopenharmony_ci return -EINVAL; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (pci_request_regions(pDev, "dpt_i2o")) { 8348c2ecf20Sopenharmony_ci PERROR("dpti: adpt_config_hba: pci request region failed\n"); 8358c2ecf20Sopenharmony_ci return -EINVAL; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci pci_set_master(pDev); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* 8418c2ecf20Sopenharmony_ci * See if we should enable dma64 mode. 8428c2ecf20Sopenharmony_ci */ 8438c2ecf20Sopenharmony_ci if (sizeof(dma_addr_t) > 4 && 8448c2ecf20Sopenharmony_ci dma_get_required_mask(&pDev->dev) > DMA_BIT_MASK(32) && 8458c2ecf20Sopenharmony_ci dma_set_mask(&pDev->dev, DMA_BIT_MASK(64)) == 0) 8468c2ecf20Sopenharmony_ci dma64 = 1; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (!dma64 && dma_set_mask(&pDev->dev, DMA_BIT_MASK(32)) != 0) 8498c2ecf20Sopenharmony_ci return -EINVAL; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* adapter only supports message blocks below 4GB */ 8528c2ecf20Sopenharmony_ci dma_set_coherent_mask(&pDev->dev, DMA_BIT_MASK(32)); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci base_addr0_phys = pci_resource_start(pDev,0); 8558c2ecf20Sopenharmony_ci hba_map0_area_size = pci_resource_len(pDev,0); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci // Check if standard PCI card or single BAR Raptor 8588c2ecf20Sopenharmony_ci if(pDev->device == PCI_DPT_DEVICE_ID){ 8598c2ecf20Sopenharmony_ci if(pDev->subsystem_device >=0xc032 && pDev->subsystem_device <= 0xc03b){ 8608c2ecf20Sopenharmony_ci // Raptor card with this device id needs 4M 8618c2ecf20Sopenharmony_ci hba_map0_area_size = 0x400000; 8628c2ecf20Sopenharmony_ci } else { // Not Raptor - it is a PCI card 8638c2ecf20Sopenharmony_ci if(hba_map0_area_size > 0x100000 ){ 8648c2ecf20Sopenharmony_ci hba_map0_area_size = 0x100000; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci } else {// Raptor split BAR config 8688c2ecf20Sopenharmony_ci // Use BAR1 in this configuration 8698c2ecf20Sopenharmony_ci base_addr1_phys = pci_resource_start(pDev,1); 8708c2ecf20Sopenharmony_ci hba_map1_area_size = pci_resource_len(pDev,1); 8718c2ecf20Sopenharmony_ci raptorFlag = TRUE; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 64 8758c2ecf20Sopenharmony_ci /* 8768c2ecf20Sopenharmony_ci * The original Adaptec 64 bit driver has this comment here: 8778c2ecf20Sopenharmony_ci * "x86_64 machines need more optimal mappings" 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * I assume some HBAs report ridiculously large mappings 8808c2ecf20Sopenharmony_ci * and we need to limit them on platforms with IOMMUs. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci if (raptorFlag == TRUE) { 8838c2ecf20Sopenharmony_ci if (hba_map0_area_size > 128) 8848c2ecf20Sopenharmony_ci hba_map0_area_size = 128; 8858c2ecf20Sopenharmony_ci if (hba_map1_area_size > 524288) 8868c2ecf20Sopenharmony_ci hba_map1_area_size = 524288; 8878c2ecf20Sopenharmony_ci } else { 8888c2ecf20Sopenharmony_ci if (hba_map0_area_size > 524288) 8898c2ecf20Sopenharmony_ci hba_map0_area_size = 524288; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci#endif 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size); 8948c2ecf20Sopenharmony_ci if (!base_addr_virt) { 8958c2ecf20Sopenharmony_ci pci_release_regions(pDev); 8968c2ecf20Sopenharmony_ci PERROR("dpti: adpt_config_hba: io remap failed\n"); 8978c2ecf20Sopenharmony_ci return -EINVAL; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if(raptorFlag == TRUE) { 9018c2ecf20Sopenharmony_ci msg_addr_virt = ioremap(base_addr1_phys, hba_map1_area_size ); 9028c2ecf20Sopenharmony_ci if (!msg_addr_virt) { 9038c2ecf20Sopenharmony_ci PERROR("dpti: adpt_config_hba: io remap failed on BAR1\n"); 9048c2ecf20Sopenharmony_ci iounmap(base_addr_virt); 9058c2ecf20Sopenharmony_ci pci_release_regions(pDev); 9068c2ecf20Sopenharmony_ci return -EINVAL; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci } else { 9098c2ecf20Sopenharmony_ci msg_addr_virt = base_addr_virt; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci // Allocate and zero the data structure 9138c2ecf20Sopenharmony_ci pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL); 9148c2ecf20Sopenharmony_ci if (!pHba) { 9158c2ecf20Sopenharmony_ci if (msg_addr_virt != base_addr_virt) 9168c2ecf20Sopenharmony_ci iounmap(msg_addr_virt); 9178c2ecf20Sopenharmony_ci iounmap(base_addr_virt); 9188c2ecf20Sopenharmony_ci pci_release_regions(pDev); 9198c2ecf20Sopenharmony_ci return -ENOMEM; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if(hba_chain != NULL){ 9258c2ecf20Sopenharmony_ci for(p = hba_chain; p->next; p = p->next); 9268c2ecf20Sopenharmony_ci p->next = pHba; 9278c2ecf20Sopenharmony_ci } else { 9288c2ecf20Sopenharmony_ci hba_chain = pHba; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci pHba->next = NULL; 9318c2ecf20Sopenharmony_ci pHba->unit = hba_count; 9328c2ecf20Sopenharmony_ci sprintf(pHba->name, "dpti%d", hba_count); 9338c2ecf20Sopenharmony_ci hba_count++; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci pHba->pDev = pDev; 9388c2ecf20Sopenharmony_ci pHba->base_addr_phys = base_addr0_phys; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci // Set up the Virtual Base Address of the I2O Device 9418c2ecf20Sopenharmony_ci pHba->base_addr_virt = base_addr_virt; 9428c2ecf20Sopenharmony_ci pHba->msg_addr_virt = msg_addr_virt; 9438c2ecf20Sopenharmony_ci pHba->irq_mask = base_addr_virt+0x30; 9448c2ecf20Sopenharmony_ci pHba->post_port = base_addr_virt+0x40; 9458c2ecf20Sopenharmony_ci pHba->reply_port = base_addr_virt+0x44; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci pHba->hrt = NULL; 9488c2ecf20Sopenharmony_ci pHba->lct = NULL; 9498c2ecf20Sopenharmony_ci pHba->lct_size = 0; 9508c2ecf20Sopenharmony_ci pHba->status_block = NULL; 9518c2ecf20Sopenharmony_ci pHba->post_count = 0; 9528c2ecf20Sopenharmony_ci pHba->state = DPTI_STATE_RESET; 9538c2ecf20Sopenharmony_ci pHba->pDev = pDev; 9548c2ecf20Sopenharmony_ci pHba->devices = NULL; 9558c2ecf20Sopenharmony_ci pHba->dma64 = dma64; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci // Initializing the spinlocks 9588c2ecf20Sopenharmony_ci spin_lock_init(&pHba->state_lock); 9598c2ecf20Sopenharmony_ci spin_lock_init(&adpt_post_wait_lock); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if(raptorFlag == 0){ 9628c2ecf20Sopenharmony_ci printk(KERN_INFO "Adaptec I2O RAID controller" 9638c2ecf20Sopenharmony_ci " %d at %p size=%x irq=%d%s\n", 9648c2ecf20Sopenharmony_ci hba_count-1, base_addr_virt, 9658c2ecf20Sopenharmony_ci hba_map0_area_size, pDev->irq, 9668c2ecf20Sopenharmony_ci dma64 ? " (64-bit DMA)" : ""); 9678c2ecf20Sopenharmony_ci } else { 9688c2ecf20Sopenharmony_ci printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n", 9698c2ecf20Sopenharmony_ci hba_count-1, pDev->irq, 9708c2ecf20Sopenharmony_ci dma64 ? " (64-bit DMA)" : ""); 9718c2ecf20Sopenharmony_ci printk(KERN_INFO" BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size); 9728c2ecf20Sopenharmony_ci printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size); 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (request_irq (pDev->irq, adpt_isr, IRQF_SHARED, pHba->name, pHba)) { 9768c2ecf20Sopenharmony_ci printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq); 9778c2ecf20Sopenharmony_ci adpt_i2o_delete_hba(pHba); 9788c2ecf20Sopenharmony_ci return -EINVAL; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic void adpt_i2o_delete_hba(adpt_hba* pHba) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci adpt_hba* p1; 9888c2ecf20Sopenharmony_ci adpt_hba* p2; 9898c2ecf20Sopenharmony_ci struct i2o_device* d; 9908c2ecf20Sopenharmony_ci struct i2o_device* next; 9918c2ecf20Sopenharmony_ci int i; 9928c2ecf20Sopenharmony_ci int j; 9938c2ecf20Sopenharmony_ci struct adpt_device* pDev; 9948c2ecf20Sopenharmony_ci struct adpt_device* pNext; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 9988c2ecf20Sopenharmony_ci if(pHba->host){ 9998c2ecf20Sopenharmony_ci free_irq(pHba->host->irq, pHba); 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci p2 = NULL; 10028c2ecf20Sopenharmony_ci for( p1 = hba_chain; p1; p2 = p1,p1=p1->next){ 10038c2ecf20Sopenharmony_ci if(p1 == pHba) { 10048c2ecf20Sopenharmony_ci if(p2) { 10058c2ecf20Sopenharmony_ci p2->next = p1->next; 10068c2ecf20Sopenharmony_ci } else { 10078c2ecf20Sopenharmony_ci hba_chain = p1->next; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci break; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci hba_count--; 10148c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci iounmap(pHba->base_addr_virt); 10178c2ecf20Sopenharmony_ci pci_release_regions(pHba->pDev); 10188c2ecf20Sopenharmony_ci if(pHba->msg_addr_virt != pHba->base_addr_virt){ 10198c2ecf20Sopenharmony_ci iounmap(pHba->msg_addr_virt); 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci if(pHba->FwDebugBuffer_P) 10228c2ecf20Sopenharmony_ci iounmap(pHba->FwDebugBuffer_P); 10238c2ecf20Sopenharmony_ci if(pHba->hrt) { 10248c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 10258c2ecf20Sopenharmony_ci pHba->hrt->num_entries * pHba->hrt->entry_len << 2, 10268c2ecf20Sopenharmony_ci pHba->hrt, pHba->hrt_pa); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci if(pHba->lct) { 10298c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, pHba->lct_size, 10308c2ecf20Sopenharmony_ci pHba->lct, pHba->lct_pa); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci if(pHba->status_block) { 10338c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block), 10348c2ecf20Sopenharmony_ci pHba->status_block, pHba->status_block_pa); 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci if(pHba->reply_pool) { 10378c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 10388c2ecf20Sopenharmony_ci pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, 10398c2ecf20Sopenharmony_ci pHba->reply_pool, pHba->reply_pool_pa); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci for(d = pHba->devices; d ; d = next){ 10438c2ecf20Sopenharmony_ci next = d->next; 10448c2ecf20Sopenharmony_ci kfree(d); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci for(i = 0 ; i < pHba->top_scsi_channel ; i++){ 10478c2ecf20Sopenharmony_ci for(j = 0; j < MAX_ID; j++){ 10488c2ecf20Sopenharmony_ci if(pHba->channel[i].device[j] != NULL){ 10498c2ecf20Sopenharmony_ci for(pDev = pHba->channel[i].device[j]; pDev; pDev = pNext){ 10508c2ecf20Sopenharmony_ci pNext = pDev->next_lun; 10518c2ecf20Sopenharmony_ci kfree(pDev); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci pci_dev_put(pHba->pDev); 10578c2ecf20Sopenharmony_ci if (adpt_sysfs_class) 10588c2ecf20Sopenharmony_ci device_destroy(adpt_sysfs_class, 10598c2ecf20Sopenharmony_ci MKDEV(DPTI_I2O_MAJOR, pHba->unit)); 10608c2ecf20Sopenharmony_ci kfree(pHba); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if(hba_count <= 0){ 10638c2ecf20Sopenharmony_ci unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER); 10648c2ecf20Sopenharmony_ci if (adpt_sysfs_class) { 10658c2ecf20Sopenharmony_ci class_destroy(adpt_sysfs_class); 10668c2ecf20Sopenharmony_ci adpt_sysfs_class = NULL; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u64 lun) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct adpt_device* d; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (chan >= MAX_CHANNEL) 10768c2ecf20Sopenharmony_ci return NULL; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci d = pHba->channel[chan].device[id]; 10798c2ecf20Sopenharmony_ci if(!d || d->tid == 0) { 10808c2ecf20Sopenharmony_ci return NULL; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* If it is the only lun at that address then this should match*/ 10848c2ecf20Sopenharmony_ci if(d->scsi_lun == lun){ 10858c2ecf20Sopenharmony_ci return d; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* else we need to look through all the luns */ 10898c2ecf20Sopenharmony_ci for(d=d->next_lun ; d ; d = d->next_lun){ 10908c2ecf20Sopenharmony_ci if(d->scsi_lun == lun){ 10918c2ecf20Sopenharmony_ci return d; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci return NULL; 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci // I used my own version of the WAIT_QUEUE_HEAD 11018c2ecf20Sopenharmony_ci // to handle some version differences 11028c2ecf20Sopenharmony_ci // When embedded in the kernel this could go back to the vanilla one 11038c2ecf20Sopenharmony_ci ADPT_DECLARE_WAIT_QUEUE_HEAD(adpt_wq_i2o_post); 11048c2ecf20Sopenharmony_ci int status = 0; 11058c2ecf20Sopenharmony_ci ulong flags = 0; 11068c2ecf20Sopenharmony_ci struct adpt_i2o_post_wait_data *p1, *p2; 11078c2ecf20Sopenharmony_ci struct adpt_i2o_post_wait_data *wait_data = 11088c2ecf20Sopenharmony_ci kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC); 11098c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (!wait_data) 11128c2ecf20Sopenharmony_ci return -ENOMEM; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* 11158c2ecf20Sopenharmony_ci * The spin locking is needed to keep anyone from playing 11168c2ecf20Sopenharmony_ci * with the queue pointers and id while we do the same 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci spin_lock_irqsave(&adpt_post_wait_lock, flags); 11198c2ecf20Sopenharmony_ci // TODO we need a MORE unique way of getting ids 11208c2ecf20Sopenharmony_ci // to support async LCT get 11218c2ecf20Sopenharmony_ci wait_data->next = adpt_post_wait_queue; 11228c2ecf20Sopenharmony_ci adpt_post_wait_queue = wait_data; 11238c2ecf20Sopenharmony_ci adpt_post_wait_id++; 11248c2ecf20Sopenharmony_ci adpt_post_wait_id &= 0x7fff; 11258c2ecf20Sopenharmony_ci wait_data->id = adpt_post_wait_id; 11268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adpt_post_wait_lock, flags); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci wait_data->wq = &adpt_wq_i2o_post; 11298c2ecf20Sopenharmony_ci wait_data->status = -ETIMEDOUT; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci add_wait_queue(&adpt_wq_i2o_post, &wait); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci msg[2] |= 0x80000000 | ((u32)wait_data->id); 11348c2ecf20Sopenharmony_ci timeout *= HZ; 11358c2ecf20Sopenharmony_ci if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){ 11368c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 11378c2ecf20Sopenharmony_ci if(pHba->host) 11388c2ecf20Sopenharmony_ci spin_unlock_irq(pHba->host->host_lock); 11398c2ecf20Sopenharmony_ci if (!timeout) 11408c2ecf20Sopenharmony_ci schedule(); 11418c2ecf20Sopenharmony_ci else{ 11428c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 11438c2ecf20Sopenharmony_ci if (timeout == 0) { 11448c2ecf20Sopenharmony_ci // I/O issued, but cannot get result in 11458c2ecf20Sopenharmony_ci // specified time. Freeing resorces is 11468c2ecf20Sopenharmony_ci // dangerous. 11478c2ecf20Sopenharmony_ci status = -ETIME; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci if(pHba->host) 11518c2ecf20Sopenharmony_ci spin_lock_irq(pHba->host->host_lock); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci remove_wait_queue(&adpt_wq_i2o_post, &wait); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if(status == -ETIMEDOUT){ 11568c2ecf20Sopenharmony_ci printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit); 11578c2ecf20Sopenharmony_ci // We will have to free the wait_data memory during shutdown 11588c2ecf20Sopenharmony_ci return status; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci /* Remove the entry from the queue. */ 11628c2ecf20Sopenharmony_ci p2 = NULL; 11638c2ecf20Sopenharmony_ci spin_lock_irqsave(&adpt_post_wait_lock, flags); 11648c2ecf20Sopenharmony_ci for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p1->next) { 11658c2ecf20Sopenharmony_ci if(p1 == wait_data) { 11668c2ecf20Sopenharmony_ci if(p1->status == I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION ) { 11678c2ecf20Sopenharmony_ci status = -EOPNOTSUPP; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci if(p2) { 11708c2ecf20Sopenharmony_ci p2->next = p1->next; 11718c2ecf20Sopenharmony_ci } else { 11728c2ecf20Sopenharmony_ci adpt_post_wait_queue = p1->next; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adpt_post_wait_lock, flags); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci kfree(wait_data); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci return status; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci u32 m = EMPTY_QUEUE; 11898c2ecf20Sopenharmony_ci u32 __iomem *msg; 11908c2ecf20Sopenharmony_ci ulong timeout = jiffies + 30*HZ; 11918c2ecf20Sopenharmony_ci do { 11928c2ecf20Sopenharmony_ci rmb(); 11938c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 11948c2ecf20Sopenharmony_ci if (m != EMPTY_QUEUE) { 11958c2ecf20Sopenharmony_ci break; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 11988c2ecf20Sopenharmony_ci printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit); 11998c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 12028c2ecf20Sopenharmony_ci } while(m == EMPTY_QUEUE); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci msg = pHba->msg_addr_virt + m; 12058c2ecf20Sopenharmony_ci memcpy_toio(msg, data, len); 12068c2ecf20Sopenharmony_ci wmb(); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci //post message 12098c2ecf20Sopenharmony_ci writel(m, pHba->post_port); 12108c2ecf20Sopenharmony_ci wmb(); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci return 0; 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic void adpt_i2o_post_wait_complete(u32 context, int status) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct adpt_i2o_post_wait_data *p1 = NULL; 12198c2ecf20Sopenharmony_ci /* 12208c2ecf20Sopenharmony_ci * We need to search through the adpt_post_wait 12218c2ecf20Sopenharmony_ci * queue to see if the given message is still 12228c2ecf20Sopenharmony_ci * outstanding. If not, it means that the IOP 12238c2ecf20Sopenharmony_ci * took longer to respond to the message than we 12248c2ecf20Sopenharmony_ci * had allowed and timer has already expired. 12258c2ecf20Sopenharmony_ci * Not much we can do about that except log 12268c2ecf20Sopenharmony_ci * it for debug purposes, increase timeout, and recompile 12278c2ecf20Sopenharmony_ci * 12288c2ecf20Sopenharmony_ci * Lock needed to keep anyone from moving queue pointers 12298c2ecf20Sopenharmony_ci * around while we're looking through them. 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci context &= 0x7fff; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci spin_lock(&adpt_post_wait_lock); 12358c2ecf20Sopenharmony_ci for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) { 12368c2ecf20Sopenharmony_ci if(p1->id == context) { 12378c2ecf20Sopenharmony_ci p1->status = status; 12388c2ecf20Sopenharmony_ci spin_unlock(&adpt_post_wait_lock); 12398c2ecf20Sopenharmony_ci wake_up_interruptible(p1->wq); 12408c2ecf20Sopenharmony_ci return; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci spin_unlock(&adpt_post_wait_lock); 12448c2ecf20Sopenharmony_ci // If this happens we lose commands that probably really completed 12458c2ecf20Sopenharmony_ci printk(KERN_DEBUG"dpti: Could Not find task %d in wait queue\n",context); 12468c2ecf20Sopenharmony_ci printk(KERN_DEBUG" Tasks in wait queue:\n"); 12478c2ecf20Sopenharmony_ci for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) { 12488c2ecf20Sopenharmony_ci printk(KERN_DEBUG" %d\n",p1->id); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci return; 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cistatic s32 adpt_i2o_reset_hba(adpt_hba* pHba) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci u32 msg[8]; 12568c2ecf20Sopenharmony_ci u8* status; 12578c2ecf20Sopenharmony_ci dma_addr_t addr; 12588c2ecf20Sopenharmony_ci u32 m = EMPTY_QUEUE ; 12598c2ecf20Sopenharmony_ci ulong timeout = jiffies + (TMOUT_IOPRESET*HZ); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if(pHba->initialized == FALSE) { // First time reset should be quick 12628c2ecf20Sopenharmony_ci timeout = jiffies + (25*HZ); 12638c2ecf20Sopenharmony_ci } else { 12648c2ecf20Sopenharmony_ci adpt_i2o_quiesce_hba(pHba); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci do { 12688c2ecf20Sopenharmony_ci rmb(); 12698c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 12708c2ecf20Sopenharmony_ci if (m != EMPTY_QUEUE) { 12718c2ecf20Sopenharmony_ci break; 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 12748c2ecf20Sopenharmony_ci printk(KERN_WARNING"Timeout waiting for message!\n"); 12758c2ecf20Sopenharmony_ci return -ETIMEDOUT; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 12788c2ecf20Sopenharmony_ci } while (m == EMPTY_QUEUE); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL); 12818c2ecf20Sopenharmony_ci if(status == NULL) { 12828c2ecf20Sopenharmony_ci adpt_send_nop(pHba, m); 12838c2ecf20Sopenharmony_ci printk(KERN_ERR"IOP reset failed - no free memory.\n"); 12848c2ecf20Sopenharmony_ci return -ENOMEM; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; 12888c2ecf20Sopenharmony_ci msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; 12898c2ecf20Sopenharmony_ci msg[2]=0; 12908c2ecf20Sopenharmony_ci msg[3]=0; 12918c2ecf20Sopenharmony_ci msg[4]=0; 12928c2ecf20Sopenharmony_ci msg[5]=0; 12938c2ecf20Sopenharmony_ci msg[6]=dma_low(addr); 12948c2ecf20Sopenharmony_ci msg[7]=dma_high(addr); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg)); 12978c2ecf20Sopenharmony_ci wmb(); 12988c2ecf20Sopenharmony_ci writel(m, pHba->post_port); 12998c2ecf20Sopenharmony_ci wmb(); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci while(*status == 0){ 13028c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 13038c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name); 13048c2ecf20Sopenharmony_ci /* We lose 4 bytes of "status" here, but we cannot 13058c2ecf20Sopenharmony_ci free these because controller may awake and corrupt 13068c2ecf20Sopenharmony_ci those bytes at any time */ 13078c2ecf20Sopenharmony_ci /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */ 13088c2ecf20Sopenharmony_ci return -ETIMEDOUT; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci rmb(); 13118c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) { 13158c2ecf20Sopenharmony_ci PDEBUG("%s: Reset in progress...\n", pHba->name); 13168c2ecf20Sopenharmony_ci // Here we wait for message frame to become available 13178c2ecf20Sopenharmony_ci // indicated that reset has finished 13188c2ecf20Sopenharmony_ci do { 13198c2ecf20Sopenharmony_ci rmb(); 13208c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 13218c2ecf20Sopenharmony_ci if (m != EMPTY_QUEUE) { 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 13258c2ecf20Sopenharmony_ci printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name); 13268c2ecf20Sopenharmony_ci /* We lose 4 bytes of "status" here, but we 13278c2ecf20Sopenharmony_ci cannot free these because controller may 13288c2ecf20Sopenharmony_ci awake and corrupt those bytes at any time */ 13298c2ecf20Sopenharmony_ci /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */ 13308c2ecf20Sopenharmony_ci return -ETIMEDOUT; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 13338c2ecf20Sopenharmony_ci } while (m == EMPTY_QUEUE); 13348c2ecf20Sopenharmony_ci // Flush the offset 13358c2ecf20Sopenharmony_ci adpt_send_nop(pHba, m); 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 13388c2ecf20Sopenharmony_ci if(*status == 0x02 || 13398c2ecf20Sopenharmony_ci pHba->status_block->iop_state != ADAPTER_STATE_RESET) { 13408c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Reset reject, trying to clear\n", 13418c2ecf20Sopenharmony_ci pHba->name); 13428c2ecf20Sopenharmony_ci } else { 13438c2ecf20Sopenharmony_ci PDEBUG("%s: Reset completed.\n", pHba->name); 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 4, status, addr); 13478c2ecf20Sopenharmony_ci#ifdef UARTDELAY 13488c2ecf20Sopenharmony_ci // This delay is to allow someone attached to the card through the debug UART to 13498c2ecf20Sopenharmony_ci // set up the dump levels that they want before the rest of the initialization sequence 13508c2ecf20Sopenharmony_ci adpt_delay(20000); 13518c2ecf20Sopenharmony_ci#endif 13528c2ecf20Sopenharmony_ci return 0; 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cistatic int adpt_i2o_parse_lct(adpt_hba* pHba) 13578c2ecf20Sopenharmony_ci{ 13588c2ecf20Sopenharmony_ci int i; 13598c2ecf20Sopenharmony_ci int max; 13608c2ecf20Sopenharmony_ci int tid; 13618c2ecf20Sopenharmony_ci struct i2o_device *d; 13628c2ecf20Sopenharmony_ci i2o_lct *lct = pHba->lct; 13638c2ecf20Sopenharmony_ci u8 bus_no = 0; 13648c2ecf20Sopenharmony_ci s16 scsi_id; 13658c2ecf20Sopenharmony_ci u64 scsi_lun; 13668c2ecf20Sopenharmony_ci u32 buf[10]; // larger than 7, or 8 ... 13678c2ecf20Sopenharmony_ci struct adpt_device* pDev; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (lct == NULL) { 13708c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: LCT is empty???\n",pHba->name); 13718c2ecf20Sopenharmony_ci return -1; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci max = lct->table_size; 13758c2ecf20Sopenharmony_ci max -= 3; 13768c2ecf20Sopenharmony_ci max /= 9; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci for(i=0;i<max;i++) { 13798c2ecf20Sopenharmony_ci if( lct->lct_entry[i].user_tid != 0xfff){ 13808c2ecf20Sopenharmony_ci /* 13818c2ecf20Sopenharmony_ci * If we have hidden devices, we need to inform the upper layers about 13828c2ecf20Sopenharmony_ci * the possible maximum id reference to handle device access when 13838c2ecf20Sopenharmony_ci * an array is disassembled. This code has no other purpose but to 13848c2ecf20Sopenharmony_ci * allow us future access to devices that are currently hidden 13858c2ecf20Sopenharmony_ci * behind arrays, hotspares or have not been configured (JBOD mode). 13868c2ecf20Sopenharmony_ci */ 13878c2ecf20Sopenharmony_ci if( lct->lct_entry[i].class_id != I2O_CLASS_RANDOM_BLOCK_STORAGE && 13888c2ecf20Sopenharmony_ci lct->lct_entry[i].class_id != I2O_CLASS_SCSI_PERIPHERAL && 13898c2ecf20Sopenharmony_ci lct->lct_entry[i].class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ 13908c2ecf20Sopenharmony_ci continue; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci tid = lct->lct_entry[i].tid; 13938c2ecf20Sopenharmony_ci // I2O_DPT_DEVICE_INFO_GROUP_NO; 13948c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) { 13958c2ecf20Sopenharmony_ci continue; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci bus_no = buf[0]>>16; 13988c2ecf20Sopenharmony_ci scsi_id = buf[1]; 13998c2ecf20Sopenharmony_ci scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]); 14008c2ecf20Sopenharmony_ci if(bus_no >= MAX_CHANNEL) { // Something wrong skip it 14018c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no); 14028c2ecf20Sopenharmony_ci continue; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci if (scsi_id >= MAX_ID){ 14058c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI ID %d out of range \n", pHba->name, bus_no); 14068c2ecf20Sopenharmony_ci continue; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci if(bus_no > pHba->top_scsi_channel){ 14098c2ecf20Sopenharmony_ci pHba->top_scsi_channel = bus_no; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci if(scsi_id > pHba->top_scsi_id){ 14128c2ecf20Sopenharmony_ci pHba->top_scsi_id = scsi_id; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci if(scsi_lun > pHba->top_scsi_lun){ 14158c2ecf20Sopenharmony_ci pHba->top_scsi_lun = scsi_lun; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci continue; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL); 14208c2ecf20Sopenharmony_ci if(d==NULL) 14218c2ecf20Sopenharmony_ci { 14228c2ecf20Sopenharmony_ci printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name); 14238c2ecf20Sopenharmony_ci return -ENOMEM; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci d->controller = pHba; 14278c2ecf20Sopenharmony_ci d->next = NULL; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci d->flags = 0; 14328c2ecf20Sopenharmony_ci tid = d->lct_data.tid; 14338c2ecf20Sopenharmony_ci adpt_i2o_report_hba_unit(pHba, d); 14348c2ecf20Sopenharmony_ci adpt_i2o_install_device(pHba, d); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci bus_no = 0; 14378c2ecf20Sopenharmony_ci for(d = pHba->devices; d ; d = d->next) { 14388c2ecf20Sopenharmony_ci if(d->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT || 14398c2ecf20Sopenharmony_ci d->lct_data.class_id == I2O_CLASS_FIBRE_CHANNEL_PORT){ 14408c2ecf20Sopenharmony_ci tid = d->lct_data.tid; 14418c2ecf20Sopenharmony_ci // TODO get the bus_no from hrt-but for now they are in order 14428c2ecf20Sopenharmony_ci //bus_no = 14438c2ecf20Sopenharmony_ci if(bus_no > pHba->top_scsi_channel){ 14448c2ecf20Sopenharmony_ci pHba->top_scsi_channel = bus_no; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci pHba->channel[bus_no].type = d->lct_data.class_id; 14478c2ecf20Sopenharmony_ci pHba->channel[bus_no].tid = tid; 14488c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, tid, 0x0200, -1, buf, 28)>=0) 14498c2ecf20Sopenharmony_ci { 14508c2ecf20Sopenharmony_ci pHba->channel[bus_no].scsi_id = buf[1]; 14518c2ecf20Sopenharmony_ci PDEBUG("Bus %d - SCSI ID %d.\n", bus_no, buf[1]); 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci // TODO remove - this is just until we get from hrt 14548c2ecf20Sopenharmony_ci bus_no++; 14558c2ecf20Sopenharmony_ci if(bus_no >= MAX_CHANNEL) { // Something wrong skip it 14568c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Channel number %d out of range - LCT\n", pHba->name, bus_no); 14578c2ecf20Sopenharmony_ci break; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci // Setup adpt_device table 14638c2ecf20Sopenharmony_ci for(d = pHba->devices; d ; d = d->next) { 14648c2ecf20Sopenharmony_ci if(d->lct_data.class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE || 14658c2ecf20Sopenharmony_ci d->lct_data.class_id == I2O_CLASS_SCSI_PERIPHERAL || 14668c2ecf20Sopenharmony_ci d->lct_data.class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci tid = d->lct_data.tid; 14698c2ecf20Sopenharmony_ci scsi_id = -1; 14708c2ecf20Sopenharmony_ci // I2O_DPT_DEVICE_INFO_GROUP_NO; 14718c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)>=0) { 14728c2ecf20Sopenharmony_ci bus_no = buf[0]>>16; 14738c2ecf20Sopenharmony_ci scsi_id = buf[1]; 14748c2ecf20Sopenharmony_ci scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]); 14758c2ecf20Sopenharmony_ci if(bus_no >= MAX_CHANNEL) { // Something wrong skip it 14768c2ecf20Sopenharmony_ci continue; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci if (scsi_id >= MAX_ID) { 14798c2ecf20Sopenharmony_ci continue; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci if( pHba->channel[bus_no].device[scsi_id] == NULL){ 14828c2ecf20Sopenharmony_ci pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); 14838c2ecf20Sopenharmony_ci if(pDev == NULL) { 14848c2ecf20Sopenharmony_ci return -ENOMEM; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci pHba->channel[bus_no].device[scsi_id] = pDev; 14878c2ecf20Sopenharmony_ci } else { 14888c2ecf20Sopenharmony_ci for( pDev = pHba->channel[bus_no].device[scsi_id]; 14898c2ecf20Sopenharmony_ci pDev->next_lun; pDev = pDev->next_lun){ 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); 14928c2ecf20Sopenharmony_ci if(pDev->next_lun == NULL) { 14938c2ecf20Sopenharmony_ci return -ENOMEM; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci pDev = pDev->next_lun; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci pDev->tid = tid; 14988c2ecf20Sopenharmony_ci pDev->scsi_channel = bus_no; 14998c2ecf20Sopenharmony_ci pDev->scsi_id = scsi_id; 15008c2ecf20Sopenharmony_ci pDev->scsi_lun = scsi_lun; 15018c2ecf20Sopenharmony_ci pDev->pI2o_dev = d; 15028c2ecf20Sopenharmony_ci d->owner = pDev; 15038c2ecf20Sopenharmony_ci pDev->type = (buf[0])&0xff; 15048c2ecf20Sopenharmony_ci pDev->flags = (buf[0]>>8)&0xff; 15058c2ecf20Sopenharmony_ci if(scsi_id > pHba->top_scsi_id){ 15068c2ecf20Sopenharmony_ci pHba->top_scsi_id = scsi_id; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci if(scsi_lun > pHba->top_scsi_lun){ 15098c2ecf20Sopenharmony_ci pHba->top_scsi_lun = scsi_lun; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci if(scsi_id == -1){ 15138c2ecf20Sopenharmony_ci printk(KERN_WARNING"Could not find SCSI ID for %s\n", 15148c2ecf20Sopenharmony_ci d->lct_data.identity_tag); 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci/* 15238c2ecf20Sopenharmony_ci * Each I2O controller has a chain of devices on it - these match 15248c2ecf20Sopenharmony_ci * the useful parts of the LCT of the board. 15258c2ecf20Sopenharmony_ci */ 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_cistatic int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d) 15288c2ecf20Sopenharmony_ci{ 15298c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 15308c2ecf20Sopenharmony_ci d->controller=pHba; 15318c2ecf20Sopenharmony_ci d->owner=NULL; 15328c2ecf20Sopenharmony_ci d->next=pHba->devices; 15338c2ecf20Sopenharmony_ci d->prev=NULL; 15348c2ecf20Sopenharmony_ci if (pHba->devices != NULL){ 15358c2ecf20Sopenharmony_ci pHba->devices->prev=d; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci pHba->devices=d; 15388c2ecf20Sopenharmony_ci *d->dev_name = 0; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 15418c2ecf20Sopenharmony_ci return 0; 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_cistatic int adpt_open(struct inode *inode, struct file *file) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci int minor; 15478c2ecf20Sopenharmony_ci adpt_hba* pHba; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci mutex_lock(&adpt_mutex); 15508c2ecf20Sopenharmony_ci //TODO check for root access 15518c2ecf20Sopenharmony_ci // 15528c2ecf20Sopenharmony_ci minor = iminor(inode); 15538c2ecf20Sopenharmony_ci if (minor >= hba_count) { 15548c2ecf20Sopenharmony_ci mutex_unlock(&adpt_mutex); 15558c2ecf20Sopenharmony_ci return -ENXIO; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 15588c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 15598c2ecf20Sopenharmony_ci if (pHba->unit == minor) { 15608c2ecf20Sopenharmony_ci break; /* found adapter */ 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci if (pHba == NULL) { 15648c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 15658c2ecf20Sopenharmony_ci mutex_unlock(&adpt_mutex); 15668c2ecf20Sopenharmony_ci return -ENXIO; 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci// if(pHba->in_use){ 15708c2ecf20Sopenharmony_ci // mutex_unlock(&adpt_configuration_lock); 15718c2ecf20Sopenharmony_ci// return -EBUSY; 15728c2ecf20Sopenharmony_ci// } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci pHba->in_use = 1; 15758c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 15768c2ecf20Sopenharmony_ci mutex_unlock(&adpt_mutex); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic int adpt_close(struct inode *inode, struct file *file) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci int minor; 15848c2ecf20Sopenharmony_ci adpt_hba* pHba; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci minor = iminor(inode); 15878c2ecf20Sopenharmony_ci if (minor >= hba_count) { 15888c2ecf20Sopenharmony_ci return -ENXIO; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 15918c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 15928c2ecf20Sopenharmony_ci if (pHba->unit == minor) { 15938c2ecf20Sopenharmony_ci break; /* found adapter */ 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 15978c2ecf20Sopenharmony_ci if (pHba == NULL) { 15988c2ecf20Sopenharmony_ci return -ENXIO; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci pHba->in_use = 0; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci return 0; 16048c2ecf20Sopenharmony_ci} 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci#if defined __ia64__ 16078c2ecf20Sopenharmony_cistatic void adpt_ia64_info(sysInfo_S* si) 16088c2ecf20Sopenharmony_ci{ 16098c2ecf20Sopenharmony_ci // This is all the info we need for now 16108c2ecf20Sopenharmony_ci // We will add more info as our new 16118c2ecf20Sopenharmony_ci // managmenent utility requires it 16128c2ecf20Sopenharmony_ci si->processorType = PROC_IA64; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci#endif 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci#if defined __sparc__ 16178c2ecf20Sopenharmony_cistatic void adpt_sparc_info(sysInfo_S* si) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci // This is all the info we need for now 16208c2ecf20Sopenharmony_ci // We will add more info as our new 16218c2ecf20Sopenharmony_ci // managmenent utility requires it 16228c2ecf20Sopenharmony_ci si->processorType = PROC_ULTRASPARC; 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci#endif 16258c2ecf20Sopenharmony_ci#if defined __alpha__ 16268c2ecf20Sopenharmony_cistatic void adpt_alpha_info(sysInfo_S* si) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci // This is all the info we need for now 16298c2ecf20Sopenharmony_ci // We will add more info as our new 16308c2ecf20Sopenharmony_ci // managmenent utility requires it 16318c2ecf20Sopenharmony_ci si->processorType = PROC_ALPHA; 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci#endif 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci#if defined __i386__ 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci#include <uapi/asm/vm86.h> 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic void adpt_i386_info(sysInfo_S* si) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci // This is all the info we need for now 16428c2ecf20Sopenharmony_ci // We will add more info as our new 16438c2ecf20Sopenharmony_ci // managmenent utility requires it 16448c2ecf20Sopenharmony_ci switch (boot_cpu_data.x86) { 16458c2ecf20Sopenharmony_ci case CPU_386: 16468c2ecf20Sopenharmony_ci si->processorType = PROC_386; 16478c2ecf20Sopenharmony_ci break; 16488c2ecf20Sopenharmony_ci case CPU_486: 16498c2ecf20Sopenharmony_ci si->processorType = PROC_486; 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci case CPU_586: 16528c2ecf20Sopenharmony_ci si->processorType = PROC_PENTIUM; 16538c2ecf20Sopenharmony_ci break; 16548c2ecf20Sopenharmony_ci default: // Just in case 16558c2ecf20Sopenharmony_ci si->processorType = PROC_PENTIUM; 16568c2ecf20Sopenharmony_ci break; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci#endif 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci/* 16628c2ecf20Sopenharmony_ci * This routine returns information about the system. This does not effect 16638c2ecf20Sopenharmony_ci * any logic and if the info is wrong - it doesn't matter. 16648c2ecf20Sopenharmony_ci */ 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* Get all the info we can not get from kernel services */ 16678c2ecf20Sopenharmony_cistatic int adpt_system_info(void __user *buffer) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci sysInfo_S si; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci memset(&si, 0, sizeof(si)); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci si.osType = OS_LINUX; 16748c2ecf20Sopenharmony_ci si.osMajorVersion = 0; 16758c2ecf20Sopenharmony_ci si.osMinorVersion = 0; 16768c2ecf20Sopenharmony_ci si.osRevision = 0; 16778c2ecf20Sopenharmony_ci si.busType = SI_PCI_BUS; 16788c2ecf20Sopenharmony_ci si.processorFamily = DPTI_sig.dsProcessorFamily; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci#if defined __i386__ 16818c2ecf20Sopenharmony_ci adpt_i386_info(&si); 16828c2ecf20Sopenharmony_ci#elif defined (__ia64__) 16838c2ecf20Sopenharmony_ci adpt_ia64_info(&si); 16848c2ecf20Sopenharmony_ci#elif defined(__sparc__) 16858c2ecf20Sopenharmony_ci adpt_sparc_info(&si); 16868c2ecf20Sopenharmony_ci#elif defined (__alpha__) 16878c2ecf20Sopenharmony_ci adpt_alpha_info(&si); 16888c2ecf20Sopenharmony_ci#else 16898c2ecf20Sopenharmony_ci si.processorType = 0xff ; 16908c2ecf20Sopenharmony_ci#endif 16918c2ecf20Sopenharmony_ci if (copy_to_user(buffer, &si, sizeof(si))){ 16928c2ecf20Sopenharmony_ci printk(KERN_WARNING"dpti: Could not copy buffer TO user\n"); 16938c2ecf20Sopenharmony_ci return -EFAULT; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci return 0; 16978c2ecf20Sopenharmony_ci} 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cistatic int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci int minor; 17028c2ecf20Sopenharmony_ci int error = 0; 17038c2ecf20Sopenharmony_ci adpt_hba* pHba; 17048c2ecf20Sopenharmony_ci ulong flags = 0; 17058c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci minor = iminor(inode); 17088c2ecf20Sopenharmony_ci if (minor >= DPTI_MAX_HBA){ 17098c2ecf20Sopenharmony_ci return -ENXIO; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci mutex_lock(&adpt_configuration_lock); 17128c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 17138c2ecf20Sopenharmony_ci if (pHba->unit == minor) { 17148c2ecf20Sopenharmony_ci break; /* found adapter */ 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci mutex_unlock(&adpt_configuration_lock); 17188c2ecf20Sopenharmony_ci if(pHba == NULL){ 17198c2ecf20Sopenharmony_ci return -ENXIO; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci while((volatile u32) pHba->state & DPTI_STATE_RESET ) 17238c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(2); 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci switch (cmd) { 17268c2ecf20Sopenharmony_ci // TODO: handle 3 cases 17278c2ecf20Sopenharmony_ci case DPT_SIGNATURE: 17288c2ecf20Sopenharmony_ci if (copy_to_user(argp, &DPTI_sig, sizeof(DPTI_sig))) { 17298c2ecf20Sopenharmony_ci return -EFAULT; 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci break; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci case DPT_CTRLINFO:{ 17348c2ecf20Sopenharmony_ci drvrHBAinfo_S HbaInfo; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci#define FLG_OSD_PCI_VALID 0x0001 17378c2ecf20Sopenharmony_ci#define FLG_OSD_DMA 0x0002 17388c2ecf20Sopenharmony_ci#define FLG_OSD_I2O 0x0004 17398c2ecf20Sopenharmony_ci memset(&HbaInfo, 0, sizeof(HbaInfo)); 17408c2ecf20Sopenharmony_ci HbaInfo.drvrHBAnum = pHba->unit; 17418c2ecf20Sopenharmony_ci HbaInfo.baseAddr = (ulong) pHba->base_addr_phys; 17428c2ecf20Sopenharmony_ci HbaInfo.blinkState = adpt_read_blink_led(pHba); 17438c2ecf20Sopenharmony_ci HbaInfo.pciBusNum = pHba->pDev->bus->number; 17448c2ecf20Sopenharmony_ci HbaInfo.pciDeviceNum=PCI_SLOT(pHba->pDev->devfn); 17458c2ecf20Sopenharmony_ci HbaInfo.Interrupt = pHba->pDev->irq; 17468c2ecf20Sopenharmony_ci HbaInfo.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O; 17478c2ecf20Sopenharmony_ci if(copy_to_user(argp, &HbaInfo, sizeof(HbaInfo))){ 17488c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Could not copy HbaInfo TO user\n",pHba->name); 17498c2ecf20Sopenharmony_ci return -EFAULT; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci break; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci case DPT_SYSINFO: 17548c2ecf20Sopenharmony_ci return adpt_system_info(argp); 17558c2ecf20Sopenharmony_ci case DPT_BLINKLED:{ 17568c2ecf20Sopenharmony_ci u32 value; 17578c2ecf20Sopenharmony_ci value = (u32)adpt_read_blink_led(pHba); 17588c2ecf20Sopenharmony_ci if (copy_to_user(argp, &value, sizeof(value))) { 17598c2ecf20Sopenharmony_ci return -EFAULT; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci break; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci case I2ORESETCMD: { 17648c2ecf20Sopenharmony_ci struct Scsi_Host *shost = pHba->host; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci if (shost) 17678c2ecf20Sopenharmony_ci spin_lock_irqsave(shost->host_lock, flags); 17688c2ecf20Sopenharmony_ci adpt_hba_reset(pHba); 17698c2ecf20Sopenharmony_ci if (shost) 17708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(shost->host_lock, flags); 17718c2ecf20Sopenharmony_ci break; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci case I2ORESCANCMD: 17748c2ecf20Sopenharmony_ci adpt_rescan(pHba); 17758c2ecf20Sopenharmony_ci break; 17768c2ecf20Sopenharmony_ci default: 17778c2ecf20Sopenharmony_ci return -EINVAL; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return error; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci struct inode *inode; 17868c2ecf20Sopenharmony_ci long ret; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci inode = file_inode(file); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci mutex_lock(&adpt_mutex); 17918c2ecf20Sopenharmony_ci ret = adpt_ioctl(inode, file, cmd, arg); 17928c2ecf20Sopenharmony_ci mutex_unlock(&adpt_mutex); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci return ret; 17958c2ecf20Sopenharmony_ci} 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17988c2ecf20Sopenharmony_cistatic long compat_adpt_ioctl(struct file *file, 17998c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 18008c2ecf20Sopenharmony_ci{ 18018c2ecf20Sopenharmony_ci struct inode *inode; 18028c2ecf20Sopenharmony_ci long ret; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci inode = file_inode(file); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci mutex_lock(&adpt_mutex); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci switch(cmd) { 18098c2ecf20Sopenharmony_ci case DPT_SIGNATURE: 18108c2ecf20Sopenharmony_ci case I2OUSRCMD: 18118c2ecf20Sopenharmony_ci case DPT_CTRLINFO: 18128c2ecf20Sopenharmony_ci case DPT_SYSINFO: 18138c2ecf20Sopenharmony_ci case DPT_BLINKLED: 18148c2ecf20Sopenharmony_ci case I2ORESETCMD: 18158c2ecf20Sopenharmony_ci case I2ORESCANCMD: 18168c2ecf20Sopenharmony_ci case (DPT_TARGET_BUSY & 0xFFFF): 18178c2ecf20Sopenharmony_ci case DPT_TARGET_BUSY: 18188c2ecf20Sopenharmony_ci ret = adpt_ioctl(inode, file, cmd, arg); 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci default: 18218c2ecf20Sopenharmony_ci ret = -ENOIOCTLCMD; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci mutex_unlock(&adpt_mutex); 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci return ret; 18278c2ecf20Sopenharmony_ci} 18288c2ecf20Sopenharmony_ci#endif 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cistatic irqreturn_t adpt_isr(int irq, void *dev_id) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci struct scsi_cmnd* cmd; 18338c2ecf20Sopenharmony_ci adpt_hba* pHba = dev_id; 18348c2ecf20Sopenharmony_ci u32 m; 18358c2ecf20Sopenharmony_ci void __iomem *reply; 18368c2ecf20Sopenharmony_ci u32 status=0; 18378c2ecf20Sopenharmony_ci u32 context; 18388c2ecf20Sopenharmony_ci ulong flags = 0; 18398c2ecf20Sopenharmony_ci int handled = 0; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (pHba == NULL){ 18428c2ecf20Sopenharmony_ci printk(KERN_WARNING"adpt_isr: NULL dev_id\n"); 18438c2ecf20Sopenharmony_ci return IRQ_NONE; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci if(pHba->host) 18468c2ecf20Sopenharmony_ci spin_lock_irqsave(pHba->host->host_lock, flags); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) { 18498c2ecf20Sopenharmony_ci m = readl(pHba->reply_port); 18508c2ecf20Sopenharmony_ci if(m == EMPTY_QUEUE){ 18518c2ecf20Sopenharmony_ci // Try twice then give up 18528c2ecf20Sopenharmony_ci rmb(); 18538c2ecf20Sopenharmony_ci m = readl(pHba->reply_port); 18548c2ecf20Sopenharmony_ci if(m == EMPTY_QUEUE){ 18558c2ecf20Sopenharmony_ci // This really should not happen 18568c2ecf20Sopenharmony_ci printk(KERN_ERR"dpti: Could not get reply frame\n"); 18578c2ecf20Sopenharmony_ci goto out; 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci if (pHba->reply_pool_pa <= m && 18618c2ecf20Sopenharmony_ci m < pHba->reply_pool_pa + 18628c2ecf20Sopenharmony_ci (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) { 18638c2ecf20Sopenharmony_ci reply = (u8 *)pHba->reply_pool + 18648c2ecf20Sopenharmony_ci (m - pHba->reply_pool_pa); 18658c2ecf20Sopenharmony_ci } else { 18668c2ecf20Sopenharmony_ci /* Ick, we should *never* be here */ 18678c2ecf20Sopenharmony_ci printk(KERN_ERR "dpti: reply frame not from pool\n"); 18688c2ecf20Sopenharmony_ci continue; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (readl(reply) & MSG_FAIL) { 18728c2ecf20Sopenharmony_ci u32 old_m = readl(reply+28); 18738c2ecf20Sopenharmony_ci void __iomem *msg; 18748c2ecf20Sopenharmony_ci u32 old_context; 18758c2ecf20Sopenharmony_ci PDEBUG("%s: Failed message\n",pHba->name); 18768c2ecf20Sopenharmony_ci if(old_m >= 0x100000){ 18778c2ecf20Sopenharmony_ci printk(KERN_ERR"%s: Bad preserved MFA (%x)- dropping frame\n",pHba->name,old_m); 18788c2ecf20Sopenharmony_ci writel(m,pHba->reply_port); 18798c2ecf20Sopenharmony_ci continue; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci // Transaction context is 0 in failed reply frame 18828c2ecf20Sopenharmony_ci msg = pHba->msg_addr_virt + old_m; 18838c2ecf20Sopenharmony_ci old_context = readl(msg+12); 18848c2ecf20Sopenharmony_ci writel(old_context, reply+12); 18858c2ecf20Sopenharmony_ci adpt_send_nop(pHba, old_m); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci context = readl(reply+8); 18888c2ecf20Sopenharmony_ci if(context & 0x80000000){ // Post wait message 18898c2ecf20Sopenharmony_ci status = readl(reply+16); 18908c2ecf20Sopenharmony_ci if(status >> 24){ 18918c2ecf20Sopenharmony_ci status &= 0xffff; /* Get detail status */ 18928c2ecf20Sopenharmony_ci } else { 18938c2ecf20Sopenharmony_ci status = I2O_POST_WAIT_OK; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci /* 18968c2ecf20Sopenharmony_ci * The request tag is one less than the command tag 18978c2ecf20Sopenharmony_ci * as the firmware might treat a 0 tag as invalid 18988c2ecf20Sopenharmony_ci */ 18998c2ecf20Sopenharmony_ci cmd = scsi_host_find_tag(pHba->host, 19008c2ecf20Sopenharmony_ci readl(reply + 12) - 1); 19018c2ecf20Sopenharmony_ci if(cmd != NULL) { 19028c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci adpt_i2o_post_wait_complete(context, status); 19058c2ecf20Sopenharmony_ci } else { // SCSI message 19068c2ecf20Sopenharmony_ci /* 19078c2ecf20Sopenharmony_ci * The request tag is one less than the command tag 19088c2ecf20Sopenharmony_ci * as the firmware might treat a 0 tag as invalid 19098c2ecf20Sopenharmony_ci */ 19108c2ecf20Sopenharmony_ci cmd = scsi_host_find_tag(pHba->host, 19118c2ecf20Sopenharmony_ci readl(reply + 12) - 1); 19128c2ecf20Sopenharmony_ci if(cmd != NULL){ 19138c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 19148c2ecf20Sopenharmony_ci adpt_i2o_scsi_complete(reply, cmd); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci writel(m, pHba->reply_port); 19188c2ecf20Sopenharmony_ci wmb(); 19198c2ecf20Sopenharmony_ci rmb(); 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci handled = 1; 19228c2ecf20Sopenharmony_ciout: if(pHba->host) 19238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(pHba->host->host_lock, flags); 19248c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_cistatic s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* d) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci int i; 19308c2ecf20Sopenharmony_ci u32 msg[MAX_MESSAGE_SIZE]; 19318c2ecf20Sopenharmony_ci u32* mptr; 19328c2ecf20Sopenharmony_ci u32* lptr; 19338c2ecf20Sopenharmony_ci u32 *lenptr; 19348c2ecf20Sopenharmony_ci int direction; 19358c2ecf20Sopenharmony_ci int scsidir; 19368c2ecf20Sopenharmony_ci int nseg; 19378c2ecf20Sopenharmony_ci u32 len; 19388c2ecf20Sopenharmony_ci u32 reqlen; 19398c2ecf20Sopenharmony_ci s32 rcode; 19408c2ecf20Sopenharmony_ci dma_addr_t addr; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci memset(msg, 0 , sizeof(msg)); 19438c2ecf20Sopenharmony_ci len = scsi_bufflen(cmd); 19448c2ecf20Sopenharmony_ci direction = 0x00000000; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci scsidir = 0x00000000; // DATA NO XFER 19478c2ecf20Sopenharmony_ci if(len) { 19488c2ecf20Sopenharmony_ci /* 19498c2ecf20Sopenharmony_ci * Set SCBFlags to indicate if data is being transferred 19508c2ecf20Sopenharmony_ci * in or out, or no data transfer 19518c2ecf20Sopenharmony_ci * Note: Do not have to verify index is less than 0 since 19528c2ecf20Sopenharmony_ci * cmd->cmnd[0] is an unsigned char 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci switch(cmd->sc_data_direction){ 19558c2ecf20Sopenharmony_ci case DMA_FROM_DEVICE: 19568c2ecf20Sopenharmony_ci scsidir =0x40000000; // DATA IN (iop<--dev) 19578c2ecf20Sopenharmony_ci break; 19588c2ecf20Sopenharmony_ci case DMA_TO_DEVICE: 19598c2ecf20Sopenharmony_ci direction=0x04000000; // SGL OUT 19608c2ecf20Sopenharmony_ci scsidir =0x80000000; // DATA OUT (iop-->dev) 19618c2ecf20Sopenharmony_ci break; 19628c2ecf20Sopenharmony_ci case DMA_NONE: 19638c2ecf20Sopenharmony_ci break; 19648c2ecf20Sopenharmony_ci case DMA_BIDIRECTIONAL: 19658c2ecf20Sopenharmony_ci scsidir =0x40000000; // DATA IN (iop<--dev) 19668c2ecf20Sopenharmony_ci // Assume In - and continue; 19678c2ecf20Sopenharmony_ci break; 19688c2ecf20Sopenharmony_ci default: 19698c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: scsi opcode 0x%x not supported.\n", 19708c2ecf20Sopenharmony_ci pHba->name, cmd->cmnd[0]); 19718c2ecf20Sopenharmony_ci cmd->result = (DID_OK <<16) | (INITIATOR_ERROR << 8); 19728c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 19738c2ecf20Sopenharmony_ci return 0; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci // msg[0] is set later 19778c2ecf20Sopenharmony_ci // I2O_CMD_SCSI_EXEC 19788c2ecf20Sopenharmony_ci msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid); 19798c2ecf20Sopenharmony_ci msg[2] = 0; 19808c2ecf20Sopenharmony_ci /* Add 1 to avoid firmware treating it as invalid command */ 19818c2ecf20Sopenharmony_ci msg[3] = cmd->request->tag + 1; 19828c2ecf20Sopenharmony_ci // Our cards use the transaction context as the tag for queueing 19838c2ecf20Sopenharmony_ci // Adaptec/DPT Private stuff 19848c2ecf20Sopenharmony_ci msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16); 19858c2ecf20Sopenharmony_ci msg[5] = d->tid; 19868c2ecf20Sopenharmony_ci /* Direction, disconnect ok | sense data | simple queue , CDBLen */ 19878c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_ENABLE_DISCONNECT | 19888c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | 19898c2ecf20Sopenharmony_ci // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; 19908c2ecf20Sopenharmony_ci msg[6] = scsidir|0x20a00000|cmd->cmd_len; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci mptr=msg+7; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci // Write SCSI command into the message - always 16 byte block 19958c2ecf20Sopenharmony_ci memset(mptr, 0, 16); 19968c2ecf20Sopenharmony_ci memcpy(mptr, cmd->cmnd, cmd->cmd_len); 19978c2ecf20Sopenharmony_ci mptr+=4; 19988c2ecf20Sopenharmony_ci lenptr=mptr++; /* Remember me - fill in when we know */ 19998c2ecf20Sopenharmony_ci if (dpt_dma64(pHba)) { 20008c2ecf20Sopenharmony_ci reqlen = 16; // SINGLE SGE 20018c2ecf20Sopenharmony_ci *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */ 20028c2ecf20Sopenharmony_ci *mptr++ = 1 << PAGE_SHIFT; 20038c2ecf20Sopenharmony_ci } else { 20048c2ecf20Sopenharmony_ci reqlen = 14; // SINGLE SGE 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci /* Now fill in the SGList and command */ 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci nseg = scsi_dma_map(cmd); 20098c2ecf20Sopenharmony_ci BUG_ON(nseg < 0); 20108c2ecf20Sopenharmony_ci if (nseg) { 20118c2ecf20Sopenharmony_ci struct scatterlist *sg; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci len = 0; 20148c2ecf20Sopenharmony_ci scsi_for_each_sg(cmd, sg, nseg, i) { 20158c2ecf20Sopenharmony_ci lptr = mptr; 20168c2ecf20Sopenharmony_ci *mptr++ = direction|0x10000000|sg_dma_len(sg); 20178c2ecf20Sopenharmony_ci len+=sg_dma_len(sg); 20188c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 20198c2ecf20Sopenharmony_ci *mptr++ = dma_low(addr); 20208c2ecf20Sopenharmony_ci if (dpt_dma64(pHba)) 20218c2ecf20Sopenharmony_ci *mptr++ = dma_high(addr); 20228c2ecf20Sopenharmony_ci /* Make this an end of list */ 20238c2ecf20Sopenharmony_ci if (i == nseg - 1) 20248c2ecf20Sopenharmony_ci *lptr = direction|0xD0000000|sg_dma_len(sg); 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci reqlen = mptr - msg; 20278c2ecf20Sopenharmony_ci *lenptr = len; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci if(cmd->underflow && len != cmd->underflow){ 20308c2ecf20Sopenharmony_ci printk(KERN_WARNING"Cmd len %08X Cmd underflow %08X\n", 20318c2ecf20Sopenharmony_ci len, cmd->underflow); 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci } else { 20348c2ecf20Sopenharmony_ci *lenptr = len = 0; 20358c2ecf20Sopenharmony_ci reqlen = 12; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* Stick the headers on */ 20398c2ecf20Sopenharmony_ci msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci // Send it on it's way 20428c2ecf20Sopenharmony_ci rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2); 20438c2ecf20Sopenharmony_ci if (rcode == 0) { 20448c2ecf20Sopenharmony_ci return 0; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci return rcode; 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_cistatic s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht) 20518c2ecf20Sopenharmony_ci{ 20528c2ecf20Sopenharmony_ci struct Scsi_Host *host; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci host = scsi_host_alloc(sht, sizeof(adpt_hba*)); 20558c2ecf20Sopenharmony_ci if (host == NULL) { 20568c2ecf20Sopenharmony_ci printk("%s: scsi_host_alloc returned NULL\n", pHba->name); 20578c2ecf20Sopenharmony_ci return -1; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci host->hostdata[0] = (unsigned long)pHba; 20608c2ecf20Sopenharmony_ci pHba->host = host; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci host->irq = pHba->pDev->irq; 20638c2ecf20Sopenharmony_ci /* no IO ports, so don't have to set host->io_port and 20648c2ecf20Sopenharmony_ci * host->n_io_port 20658c2ecf20Sopenharmony_ci */ 20668c2ecf20Sopenharmony_ci host->io_port = 0; 20678c2ecf20Sopenharmony_ci host->n_io_port = 0; 20688c2ecf20Sopenharmony_ci /* see comments in scsi_host.h */ 20698c2ecf20Sopenharmony_ci host->max_id = 16; 20708c2ecf20Sopenharmony_ci host->max_lun = 256; 20718c2ecf20Sopenharmony_ci host->max_channel = pHba->top_scsi_channel + 1; 20728c2ecf20Sopenharmony_ci host->cmd_per_lun = 1; 20738c2ecf20Sopenharmony_ci host->unique_id = (u32)sys_tbl_pa + pHba->unit; 20748c2ecf20Sopenharmony_ci host->sg_tablesize = pHba->sg_tablesize; 20758c2ecf20Sopenharmony_ci host->can_queue = pHba->post_fifo_size; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci return 0; 20788c2ecf20Sopenharmony_ci} 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_cistatic void adpt_i2o_scsi_complete(void __iomem *reply, struct scsi_cmnd *cmd) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci adpt_hba* pHba; 20848c2ecf20Sopenharmony_ci u32 hba_status; 20858c2ecf20Sopenharmony_ci u32 dev_status; 20868c2ecf20Sopenharmony_ci u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits 20878c2ecf20Sopenharmony_ci // I know this would look cleaner if I just read bytes 20888c2ecf20Sopenharmony_ci // but the model I have been using for all the rest of the 20898c2ecf20Sopenharmony_ci // io is in 4 byte words - so I keep that model 20908c2ecf20Sopenharmony_ci u16 detailed_status = readl(reply+16) &0xffff; 20918c2ecf20Sopenharmony_ci dev_status = (detailed_status & 0xff); 20928c2ecf20Sopenharmony_ci hba_status = detailed_status >> 8; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci // calculate resid for sg 20958c2ecf20Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+20)); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci pHba = (adpt_hba*) cmd->device->host->hostdata[0]; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci cmd->sense_buffer[0] = '\0'; // initialize sense valid flag to false 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if(!(reply_flags & MSG_FAIL)) { 21028c2ecf20Sopenharmony_ci switch(detailed_status & I2O_SCSI_DSC_MASK) { 21038c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_SUCCESS: 21048c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 21058c2ecf20Sopenharmony_ci // handle underflow 21068c2ecf20Sopenharmony_ci if (readl(reply+20) < cmd->underflow) { 21078c2ecf20Sopenharmony_ci cmd->result = (DID_ERROR <<16); 21088c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name); 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci break; 21118c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_REQUEST_ABORTED: 21128c2ecf20Sopenharmony_ci cmd->result = (DID_ABORT << 16); 21138c2ecf20Sopenharmony_ci break; 21148c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_PATH_INVALID: 21158c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_DEVICE_NOT_PRESENT: 21168c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_SELECTION_TIMEOUT: 21178c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_COMMAND_TIMEOUT: 21188c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_NO_ADAPTER: 21198c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_RESOURCE_UNAVAILABLE: 21208c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI Timeout-Device (%d,%d,%llu) hba status=0x%x, dev status=0x%x, cmd=0x%x\n", 21218c2ecf20Sopenharmony_ci pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun, hba_status, dev_status, cmd->cmnd[0]); 21228c2ecf20Sopenharmony_ci cmd->result = (DID_TIME_OUT << 16); 21238c2ecf20Sopenharmony_ci break; 21248c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_ADAPTER_BUSY: 21258c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_BUS_BUSY: 21268c2ecf20Sopenharmony_ci cmd->result = (DID_BUS_BUSY << 16); 21278c2ecf20Sopenharmony_ci break; 21288c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_SCSI_BUS_RESET: 21298c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_BDR_MESSAGE_SENT: 21308c2ecf20Sopenharmony_ci cmd->result = (DID_RESET << 16); 21318c2ecf20Sopenharmony_ci break; 21328c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_PARITY_ERROR_FAILURE: 21338c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI CMD parity error\n",pHba->name); 21348c2ecf20Sopenharmony_ci cmd->result = (DID_PARITY << 16); 21358c2ecf20Sopenharmony_ci break; 21368c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_UNABLE_TO_ABORT: 21378c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_COMPLETE_WITH_ERROR: 21388c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_UNABLE_TO_TERMINATE: 21398c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_MR_MESSAGE_RECEIVED: 21408c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_AUTOSENSE_FAILED: 21418c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_DATA_OVERRUN: 21428c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_UNEXPECTED_BUS_FREE: 21438c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_SEQUENCE_FAILURE: 21448c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_REQUEST_LENGTH_ERROR: 21458c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_PROVIDE_FAILURE: 21468c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_REQUEST_TERMINATED: 21478c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_IDE_MESSAGE_SENT: 21488c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT: 21498c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_MESSAGE_RECEIVED: 21508c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_INVALID_CDB: 21518c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_LUN_INVALID: 21528c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_SCSI_TID_INVALID: 21538c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_FUNCTION_UNAVAILABLE: 21548c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_NO_NEXUS: 21558c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_CDB_RECEIVED: 21568c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_LUN_ALREADY_ENABLED: 21578c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_QUEUE_FROZEN: 21588c2ecf20Sopenharmony_ci case I2O_SCSI_DSC_REQUEST_INVALID: 21598c2ecf20Sopenharmony_ci default: 21608c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI error %0x-Device(%d,%d,%llu) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", 21618c2ecf20Sopenharmony_ci pHba->name, detailed_status & I2O_SCSI_DSC_MASK, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun, 21628c2ecf20Sopenharmony_ci hba_status, dev_status, cmd->cmnd[0]); 21638c2ecf20Sopenharmony_ci cmd->result = (DID_ERROR << 16); 21648c2ecf20Sopenharmony_ci break; 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci // copy over the request sense data if it was a check 21688c2ecf20Sopenharmony_ci // condition status 21698c2ecf20Sopenharmony_ci if (dev_status == SAM_STAT_CHECK_CONDITION) { 21708c2ecf20Sopenharmony_ci u32 len = min(SCSI_SENSE_BUFFERSIZE, 40); 21718c2ecf20Sopenharmony_ci // Copy over the sense data 21728c2ecf20Sopenharmony_ci memcpy_fromio(cmd->sense_buffer, (reply+28) , len); 21738c2ecf20Sopenharmony_ci if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 21748c2ecf20Sopenharmony_ci cmd->sense_buffer[2] == DATA_PROTECT ){ 21758c2ecf20Sopenharmony_ci /* This is to handle an array failed */ 21768c2ecf20Sopenharmony_ci cmd->result = (DID_TIME_OUT << 16); 21778c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: SCSI Data Protect-Device (%d,%d,%llu) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", 21788c2ecf20Sopenharmony_ci pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun, 21798c2ecf20Sopenharmony_ci hba_status, dev_status, cmd->cmnd[0]); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci } else { 21848c2ecf20Sopenharmony_ci /* In this condtion we could not talk to the tid 21858c2ecf20Sopenharmony_ci * the card rejected it. We should signal a retry 21868c2ecf20Sopenharmony_ci * for a limitted number of retries. 21878c2ecf20Sopenharmony_ci */ 21888c2ecf20Sopenharmony_ci cmd->result = (DID_TIME_OUT << 16); 21898c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: I2O MSG_FAIL - Device (%d,%d,%llu) tid=%d, cmd=0x%x\n", 21908c2ecf20Sopenharmony_ci pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, cmd->device->lun, 21918c2ecf20Sopenharmony_ci ((struct adpt_device*)(cmd->device->hostdata))->tid, cmd->cmnd[0]); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci cmd->result |= (dev_status); 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if(cmd->scsi_done != NULL){ 21978c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic s32 adpt_rescan(adpt_hba* pHba) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci s32 rcode; 22058c2ecf20Sopenharmony_ci ulong flags = 0; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if(pHba->host) 22088c2ecf20Sopenharmony_ci spin_lock_irqsave(pHba->host->host_lock, flags); 22098c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_lct_get(pHba)) < 0) 22108c2ecf20Sopenharmony_ci goto out; 22118c2ecf20Sopenharmony_ci if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0) 22128c2ecf20Sopenharmony_ci goto out; 22138c2ecf20Sopenharmony_ci rcode = 0; 22148c2ecf20Sopenharmony_ciout: if(pHba->host) 22158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(pHba->host->host_lock, flags); 22168c2ecf20Sopenharmony_ci return rcode; 22178c2ecf20Sopenharmony_ci} 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_cistatic s32 adpt_i2o_reparse_lct(adpt_hba* pHba) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci int i; 22238c2ecf20Sopenharmony_ci int max; 22248c2ecf20Sopenharmony_ci int tid; 22258c2ecf20Sopenharmony_ci struct i2o_device *d; 22268c2ecf20Sopenharmony_ci i2o_lct *lct = pHba->lct; 22278c2ecf20Sopenharmony_ci u8 bus_no = 0; 22288c2ecf20Sopenharmony_ci s16 scsi_id; 22298c2ecf20Sopenharmony_ci u64 scsi_lun; 22308c2ecf20Sopenharmony_ci u32 buf[10]; // at least 8 u32's 22318c2ecf20Sopenharmony_ci struct adpt_device* pDev = NULL; 22328c2ecf20Sopenharmony_ci struct i2o_device* pI2o_dev = NULL; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci if (lct == NULL) { 22358c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: LCT is empty???\n",pHba->name); 22368c2ecf20Sopenharmony_ci return -1; 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci max = lct->table_size; 22408c2ecf20Sopenharmony_ci max -= 3; 22418c2ecf20Sopenharmony_ci max /= 9; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci // Mark each drive as unscanned 22448c2ecf20Sopenharmony_ci for (d = pHba->devices; d; d = d->next) { 22458c2ecf20Sopenharmony_ci pDev =(struct adpt_device*) d->owner; 22468c2ecf20Sopenharmony_ci if(!pDev){ 22478c2ecf20Sopenharmony_ci continue; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci pDev->state |= DPTI_DEV_UNSCANNED; 22508c2ecf20Sopenharmony_ci } 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: LCT has %d entries.\n", pHba->name,max); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci for(i=0;i<max;i++) { 22558c2ecf20Sopenharmony_ci if( lct->lct_entry[i].user_tid != 0xfff){ 22568c2ecf20Sopenharmony_ci continue; 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci if( lct->lct_entry[i].class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE || 22608c2ecf20Sopenharmony_ci lct->lct_entry[i].class_id == I2O_CLASS_SCSI_PERIPHERAL || 22618c2ecf20Sopenharmony_ci lct->lct_entry[i].class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ 22628c2ecf20Sopenharmony_ci tid = lct->lct_entry[i].tid; 22638c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) { 22648c2ecf20Sopenharmony_ci printk(KERN_ERR"%s: Could not query device\n",pHba->name); 22658c2ecf20Sopenharmony_ci continue; 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci bus_no = buf[0]>>16; 22688c2ecf20Sopenharmony_ci if (bus_no >= MAX_CHANNEL) { /* Something wrong skip it */ 22698c2ecf20Sopenharmony_ci printk(KERN_WARNING 22708c2ecf20Sopenharmony_ci "%s: Channel number %d out of range\n", 22718c2ecf20Sopenharmony_ci pHba->name, bus_no); 22728c2ecf20Sopenharmony_ci continue; 22738c2ecf20Sopenharmony_ci } 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci scsi_id = buf[1]; 22768c2ecf20Sopenharmony_ci scsi_lun = scsilun_to_int((struct scsi_lun *)&buf[2]); 22778c2ecf20Sopenharmony_ci pDev = pHba->channel[bus_no].device[scsi_id]; 22788c2ecf20Sopenharmony_ci /* da lun */ 22798c2ecf20Sopenharmony_ci while(pDev) { 22808c2ecf20Sopenharmony_ci if(pDev->scsi_lun == scsi_lun) { 22818c2ecf20Sopenharmony_ci break; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci pDev = pDev->next_lun; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci if(!pDev ) { // Something new add it 22868c2ecf20Sopenharmony_ci d = kmalloc(sizeof(struct i2o_device), 22878c2ecf20Sopenharmony_ci GFP_ATOMIC); 22888c2ecf20Sopenharmony_ci if(d==NULL) 22898c2ecf20Sopenharmony_ci { 22908c2ecf20Sopenharmony_ci printk(KERN_CRIT "Out of memory for I2O device data.\n"); 22918c2ecf20Sopenharmony_ci return -ENOMEM; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci d->controller = pHba; 22958c2ecf20Sopenharmony_ci d->next = NULL; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci d->flags = 0; 23008c2ecf20Sopenharmony_ci adpt_i2o_report_hba_unit(pHba, d); 23018c2ecf20Sopenharmony_ci adpt_i2o_install_device(pHba, d); 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci pDev = pHba->channel[bus_no].device[scsi_id]; 23048c2ecf20Sopenharmony_ci if( pDev == NULL){ 23058c2ecf20Sopenharmony_ci pDev = 23068c2ecf20Sopenharmony_ci kzalloc(sizeof(struct adpt_device), 23078c2ecf20Sopenharmony_ci GFP_ATOMIC); 23088c2ecf20Sopenharmony_ci if(pDev == NULL) { 23098c2ecf20Sopenharmony_ci return -ENOMEM; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci pHba->channel[bus_no].device[scsi_id] = pDev; 23128c2ecf20Sopenharmony_ci } else { 23138c2ecf20Sopenharmony_ci while (pDev->next_lun) { 23148c2ecf20Sopenharmony_ci pDev = pDev->next_lun; 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci pDev = pDev->next_lun = 23178c2ecf20Sopenharmony_ci kzalloc(sizeof(struct adpt_device), 23188c2ecf20Sopenharmony_ci GFP_ATOMIC); 23198c2ecf20Sopenharmony_ci if(pDev == NULL) { 23208c2ecf20Sopenharmony_ci return -ENOMEM; 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci pDev->tid = d->lct_data.tid; 23248c2ecf20Sopenharmony_ci pDev->scsi_channel = bus_no; 23258c2ecf20Sopenharmony_ci pDev->scsi_id = scsi_id; 23268c2ecf20Sopenharmony_ci pDev->scsi_lun = scsi_lun; 23278c2ecf20Sopenharmony_ci pDev->pI2o_dev = d; 23288c2ecf20Sopenharmony_ci d->owner = pDev; 23298c2ecf20Sopenharmony_ci pDev->type = (buf[0])&0xff; 23308c2ecf20Sopenharmony_ci pDev->flags = (buf[0]>>8)&0xff; 23318c2ecf20Sopenharmony_ci // Too late, SCSI system has made up it's mind, but what the hey ... 23328c2ecf20Sopenharmony_ci if(scsi_id > pHba->top_scsi_id){ 23338c2ecf20Sopenharmony_ci pHba->top_scsi_id = scsi_id; 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci if(scsi_lun > pHba->top_scsi_lun){ 23368c2ecf20Sopenharmony_ci pHba->top_scsi_lun = scsi_lun; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci continue; 23398c2ecf20Sopenharmony_ci } // end of new i2o device 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci // We found an old device - check it 23428c2ecf20Sopenharmony_ci while(pDev) { 23438c2ecf20Sopenharmony_ci if(pDev->scsi_lun == scsi_lun) { 23448c2ecf20Sopenharmony_ci if(!scsi_device_online(pDev->pScsi_dev)) { 23458c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Setting device (%d,%d,%llu) back online\n", 23468c2ecf20Sopenharmony_ci pHba->name,bus_no,scsi_id,scsi_lun); 23478c2ecf20Sopenharmony_ci if (pDev->pScsi_dev) { 23488c2ecf20Sopenharmony_ci scsi_device_set_state(pDev->pScsi_dev, SDEV_RUNNING); 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci d = pDev->pI2o_dev; 23528c2ecf20Sopenharmony_ci if(d->lct_data.tid != tid) { // something changed 23538c2ecf20Sopenharmony_ci pDev->tid = tid; 23548c2ecf20Sopenharmony_ci memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); 23558c2ecf20Sopenharmony_ci if (pDev->pScsi_dev) { 23568c2ecf20Sopenharmony_ci pDev->pScsi_dev->changed = TRUE; 23578c2ecf20Sopenharmony_ci pDev->pScsi_dev->removable = TRUE; 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci // Found it - mark it scanned 23618c2ecf20Sopenharmony_ci pDev->state = DPTI_DEV_ONLINE; 23628c2ecf20Sopenharmony_ci break; 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci pDev = pDev->next_lun; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci for (pI2o_dev = pHba->devices; pI2o_dev; pI2o_dev = pI2o_dev->next) { 23698c2ecf20Sopenharmony_ci pDev =(struct adpt_device*) pI2o_dev->owner; 23708c2ecf20Sopenharmony_ci if(!pDev){ 23718c2ecf20Sopenharmony_ci continue; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci // Drive offline drives that previously existed but could not be found 23748c2ecf20Sopenharmony_ci // in the LCT table 23758c2ecf20Sopenharmony_ci if (pDev->state & DPTI_DEV_UNSCANNED){ 23768c2ecf20Sopenharmony_ci pDev->state = DPTI_DEV_OFFLINE; 23778c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Device (%d,%d,%llu) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun); 23788c2ecf20Sopenharmony_ci if (pDev->pScsi_dev) { 23798c2ecf20Sopenharmony_ci scsi_device_set_state(pDev->pScsi_dev, SDEV_OFFLINE); 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci } 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci return 0; 23848c2ecf20Sopenharmony_ci} 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci/*============================================================================ 23878c2ecf20Sopenharmony_ci * Routines from i2o subsystem 23888c2ecf20Sopenharmony_ci *============================================================================ 23898c2ecf20Sopenharmony_ci */ 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci/* 23948c2ecf20Sopenharmony_ci * Bring an I2O controller into HOLD state. See the spec. 23958c2ecf20Sopenharmony_ci */ 23968c2ecf20Sopenharmony_cistatic int adpt_i2o_activate_hba(adpt_hba* pHba) 23978c2ecf20Sopenharmony_ci{ 23988c2ecf20Sopenharmony_ci int rcode; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if(pHba->initialized ) { 24018c2ecf20Sopenharmony_ci if (adpt_i2o_status_get(pHba) < 0) { 24028c2ecf20Sopenharmony_ci if((rcode = adpt_i2o_reset_hba(pHba)) != 0){ 24038c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name); 24048c2ecf20Sopenharmony_ci return rcode; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci if (adpt_i2o_status_get(pHba) < 0) { 24078c2ecf20Sopenharmony_ci printk(KERN_INFO "HBA not responding.\n"); 24088c2ecf20Sopenharmony_ci return -1; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if(pHba->status_block->iop_state == ADAPTER_STATE_FAULTED) { 24138c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: hardware fault\n", pHba->name); 24148c2ecf20Sopenharmony_ci return -1; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci if (pHba->status_block->iop_state == ADAPTER_STATE_READY || 24188c2ecf20Sopenharmony_ci pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || 24198c2ecf20Sopenharmony_ci pHba->status_block->iop_state == ADAPTER_STATE_HOLD || 24208c2ecf20Sopenharmony_ci pHba->status_block->iop_state == ADAPTER_STATE_FAILED) { 24218c2ecf20Sopenharmony_ci adpt_i2o_reset_hba(pHba); 24228c2ecf20Sopenharmony_ci if (adpt_i2o_status_get(pHba) < 0 || pHba->status_block->iop_state != ADAPTER_STATE_RESET) { 24238c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Failed to initialize.\n", pHba->name); 24248c2ecf20Sopenharmony_ci return -1; 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci } 24278c2ecf20Sopenharmony_ci } else { 24288c2ecf20Sopenharmony_ci if((rcode = adpt_i2o_reset_hba(pHba)) != 0){ 24298c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name); 24308c2ecf20Sopenharmony_ci return rcode; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci if (adpt_i2o_init_outbound_q(pHba) < 0) { 24368c2ecf20Sopenharmony_ci return -1; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci /* In HOLD state */ 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (adpt_i2o_hrt_get(pHba) < 0) { 24428c2ecf20Sopenharmony_ci return -1; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci return 0; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci/* 24498c2ecf20Sopenharmony_ci * Bring a controller online into OPERATIONAL state. 24508c2ecf20Sopenharmony_ci */ 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_cistatic int adpt_i2o_online_hba(adpt_hba* pHba) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci if (adpt_i2o_systab_send(pHba) < 0) 24558c2ecf20Sopenharmony_ci return -1; 24568c2ecf20Sopenharmony_ci /* In READY state */ 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci if (adpt_i2o_enable_hba(pHba) < 0) 24598c2ecf20Sopenharmony_ci return -1; 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci /* In OPERATIONAL state */ 24628c2ecf20Sopenharmony_ci return 0; 24638c2ecf20Sopenharmony_ci} 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_cistatic s32 adpt_send_nop(adpt_hba*pHba,u32 m) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci u32 __iomem *msg; 24688c2ecf20Sopenharmony_ci ulong timeout = jiffies + 5*HZ; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci while(m == EMPTY_QUEUE){ 24718c2ecf20Sopenharmony_ci rmb(); 24728c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 24738c2ecf20Sopenharmony_ci if(m != EMPTY_QUEUE){ 24748c2ecf20Sopenharmony_ci break; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 24778c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name); 24788c2ecf20Sopenharmony_ci return 2; 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci msg = (u32 __iomem *)(pHba->msg_addr_virt + m); 24838c2ecf20Sopenharmony_ci writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]); 24848c2ecf20Sopenharmony_ci writel( I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0,&msg[1]); 24858c2ecf20Sopenharmony_ci writel( 0,&msg[2]); 24868c2ecf20Sopenharmony_ci wmb(); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci writel(m, pHba->post_port); 24898c2ecf20Sopenharmony_ci wmb(); 24908c2ecf20Sopenharmony_ci return 0; 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cistatic s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci u8 *status; 24968c2ecf20Sopenharmony_ci dma_addr_t addr; 24978c2ecf20Sopenharmony_ci u32 __iomem *msg = NULL; 24988c2ecf20Sopenharmony_ci int i; 24998c2ecf20Sopenharmony_ci ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ; 25008c2ecf20Sopenharmony_ci u32 m; 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci do { 25038c2ecf20Sopenharmony_ci rmb(); 25048c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 25058c2ecf20Sopenharmony_ci if (m != EMPTY_QUEUE) { 25068c2ecf20Sopenharmony_ci break; 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 25108c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name); 25118c2ecf20Sopenharmony_ci return -ETIMEDOUT; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 25148c2ecf20Sopenharmony_ci } while(m == EMPTY_QUEUE); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci msg=(u32 __iomem *)(pHba->msg_addr_virt+m); 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL); 25198c2ecf20Sopenharmony_ci if (!status) { 25208c2ecf20Sopenharmony_ci adpt_send_nop(pHba, m); 25218c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n", 25228c2ecf20Sopenharmony_ci pHba->name); 25238c2ecf20Sopenharmony_ci return -ENOMEM; 25248c2ecf20Sopenharmony_ci } 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]); 25278c2ecf20Sopenharmony_ci writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); 25288c2ecf20Sopenharmony_ci writel(0, &msg[2]); 25298c2ecf20Sopenharmony_ci writel(0x0106, &msg[3]); /* Transaction context */ 25308c2ecf20Sopenharmony_ci writel(4096, &msg[4]); /* Host page frame size */ 25318c2ecf20Sopenharmony_ci writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */ 25328c2ecf20Sopenharmony_ci writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */ 25338c2ecf20Sopenharmony_ci writel((u32)addr, &msg[7]); 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci writel(m, pHba->post_port); 25368c2ecf20Sopenharmony_ci wmb(); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci // Wait for the reply status to come back 25398c2ecf20Sopenharmony_ci do { 25408c2ecf20Sopenharmony_ci if (*status) { 25418c2ecf20Sopenharmony_ci if (*status != 0x01 /*I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS*/) { 25428c2ecf20Sopenharmony_ci break; 25438c2ecf20Sopenharmony_ci } 25448c2ecf20Sopenharmony_ci } 25458c2ecf20Sopenharmony_ci rmb(); 25468c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 25478c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name); 25488c2ecf20Sopenharmony_ci /* We lose 4 bytes of "status" here, but we 25498c2ecf20Sopenharmony_ci cannot free these because controller may 25508c2ecf20Sopenharmony_ci awake and corrupt those bytes at any time */ 25518c2ecf20Sopenharmony_ci /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */ 25528c2ecf20Sopenharmony_ci return -ETIMEDOUT; 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 25558c2ecf20Sopenharmony_ci } while (1); 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci // If the command was successful, fill the fifo with our reply 25588c2ecf20Sopenharmony_ci // message packets 25598c2ecf20Sopenharmony_ci if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) { 25608c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 4, status, addr); 25618c2ecf20Sopenharmony_ci return -2; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 4, status, addr); 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci if(pHba->reply_pool != NULL) { 25668c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, 25678c2ecf20Sopenharmony_ci pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, 25688c2ecf20Sopenharmony_ci pHba->reply_pool, pHba->reply_pool_pa); 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev, 25728c2ecf20Sopenharmony_ci pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, 25738c2ecf20Sopenharmony_ci &pHba->reply_pool_pa, GFP_KERNEL); 25748c2ecf20Sopenharmony_ci if (!pHba->reply_pool) { 25758c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name); 25768c2ecf20Sopenharmony_ci return -ENOMEM; 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci for(i = 0; i < pHba->reply_fifo_size; i++) { 25808c2ecf20Sopenharmony_ci writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4), 25818c2ecf20Sopenharmony_ci pHba->reply_port); 25828c2ecf20Sopenharmony_ci wmb(); 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 25858c2ecf20Sopenharmony_ci return 0; 25868c2ecf20Sopenharmony_ci} 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci/* 25908c2ecf20Sopenharmony_ci * I2O System Table. Contains information about 25918c2ecf20Sopenharmony_ci * all the IOPs in the system. Used to inform IOPs 25928c2ecf20Sopenharmony_ci * about each other's existence. 25938c2ecf20Sopenharmony_ci * 25948c2ecf20Sopenharmony_ci * sys_tbl_ver is the CurrentChangeIndicator that is 25958c2ecf20Sopenharmony_ci * used by IOPs to track changes. 25968c2ecf20Sopenharmony_ci */ 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_cistatic s32 adpt_i2o_status_get(adpt_hba* pHba) 26018c2ecf20Sopenharmony_ci{ 26028c2ecf20Sopenharmony_ci ulong timeout; 26038c2ecf20Sopenharmony_ci u32 m; 26048c2ecf20Sopenharmony_ci u32 __iomem *msg; 26058c2ecf20Sopenharmony_ci u8 *status_block=NULL; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci if(pHba->status_block == NULL) { 26088c2ecf20Sopenharmony_ci pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev, 26098c2ecf20Sopenharmony_ci sizeof(i2o_status_block), 26108c2ecf20Sopenharmony_ci &pHba->status_block_pa, GFP_KERNEL); 26118c2ecf20Sopenharmony_ci if(pHba->status_block == NULL) { 26128c2ecf20Sopenharmony_ci printk(KERN_ERR 26138c2ecf20Sopenharmony_ci "dpti%d: Get Status Block failed; Out of memory. \n", 26148c2ecf20Sopenharmony_ci pHba->unit); 26158c2ecf20Sopenharmony_ci return -ENOMEM; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci memset(pHba->status_block, 0, sizeof(i2o_status_block)); 26198c2ecf20Sopenharmony_ci status_block = (u8*)(pHba->status_block); 26208c2ecf20Sopenharmony_ci timeout = jiffies+TMOUT_GETSTATUS*HZ; 26218c2ecf20Sopenharmony_ci do { 26228c2ecf20Sopenharmony_ci rmb(); 26238c2ecf20Sopenharmony_ci m = readl(pHba->post_port); 26248c2ecf20Sopenharmony_ci if (m != EMPTY_QUEUE) { 26258c2ecf20Sopenharmony_ci break; 26268c2ecf20Sopenharmony_ci } 26278c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 26288c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Timeout waiting for message !\n", 26298c2ecf20Sopenharmony_ci pHba->name); 26308c2ecf20Sopenharmony_ci return -ETIMEDOUT; 26318c2ecf20Sopenharmony_ci } 26328c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 26338c2ecf20Sopenharmony_ci } while(m==EMPTY_QUEUE); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci msg=(u32 __iomem *)(pHba->msg_addr_virt+m); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); 26398c2ecf20Sopenharmony_ci writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]); 26408c2ecf20Sopenharmony_ci writel(1, &msg[2]); 26418c2ecf20Sopenharmony_ci writel(0, &msg[3]); 26428c2ecf20Sopenharmony_ci writel(0, &msg[4]); 26438c2ecf20Sopenharmony_ci writel(0, &msg[5]); 26448c2ecf20Sopenharmony_ci writel( dma_low(pHba->status_block_pa), &msg[6]); 26458c2ecf20Sopenharmony_ci writel( dma_high(pHba->status_block_pa), &msg[7]); 26468c2ecf20Sopenharmony_ci writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci //post message 26498c2ecf20Sopenharmony_ci writel(m, pHba->post_port); 26508c2ecf20Sopenharmony_ci wmb(); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci while(status_block[87]!=0xff){ 26538c2ecf20Sopenharmony_ci if(time_after(jiffies,timeout)){ 26548c2ecf20Sopenharmony_ci printk(KERN_ERR"dpti%d: Get status timeout.\n", 26558c2ecf20Sopenharmony_ci pHba->unit); 26568c2ecf20Sopenharmony_ci return -ETIMEDOUT; 26578c2ecf20Sopenharmony_ci } 26588c2ecf20Sopenharmony_ci rmb(); 26598c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci // Set up our number of outbound and inbound messages 26638c2ecf20Sopenharmony_ci pHba->post_fifo_size = pHba->status_block->max_inbound_frames; 26648c2ecf20Sopenharmony_ci if (pHba->post_fifo_size > MAX_TO_IOP_MESSAGES) { 26658c2ecf20Sopenharmony_ci pHba->post_fifo_size = MAX_TO_IOP_MESSAGES; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci pHba->reply_fifo_size = pHba->status_block->max_outbound_frames; 26698c2ecf20Sopenharmony_ci if (pHba->reply_fifo_size > MAX_FROM_IOP_MESSAGES) { 26708c2ecf20Sopenharmony_ci pHba->reply_fifo_size = MAX_FROM_IOP_MESSAGES; 26718c2ecf20Sopenharmony_ci } 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci // Calculate the Scatter Gather list size 26748c2ecf20Sopenharmony_ci if (dpt_dma64(pHba)) { 26758c2ecf20Sopenharmony_ci pHba->sg_tablesize 26768c2ecf20Sopenharmony_ci = ((pHba->status_block->inbound_frame_size * 4 26778c2ecf20Sopenharmony_ci - 14 * sizeof(u32)) 26788c2ecf20Sopenharmony_ci / (sizeof(struct sg_simple_element) + sizeof(u32))); 26798c2ecf20Sopenharmony_ci } else { 26808c2ecf20Sopenharmony_ci pHba->sg_tablesize 26818c2ecf20Sopenharmony_ci = ((pHba->status_block->inbound_frame_size * 4 26828c2ecf20Sopenharmony_ci - 12 * sizeof(u32)) 26838c2ecf20Sopenharmony_ci / sizeof(struct sg_simple_element)); 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci if (pHba->sg_tablesize > SG_LIST_ELEMENTS) { 26868c2ecf20Sopenharmony_ci pHba->sg_tablesize = SG_LIST_ELEMENTS; 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci#ifdef DEBUG 26918c2ecf20Sopenharmony_ci printk("dpti%d: State = ",pHba->unit); 26928c2ecf20Sopenharmony_ci switch(pHba->status_block->iop_state) { 26938c2ecf20Sopenharmony_ci case 0x01: 26948c2ecf20Sopenharmony_ci printk("INIT\n"); 26958c2ecf20Sopenharmony_ci break; 26968c2ecf20Sopenharmony_ci case 0x02: 26978c2ecf20Sopenharmony_ci printk("RESET\n"); 26988c2ecf20Sopenharmony_ci break; 26998c2ecf20Sopenharmony_ci case 0x04: 27008c2ecf20Sopenharmony_ci printk("HOLD\n"); 27018c2ecf20Sopenharmony_ci break; 27028c2ecf20Sopenharmony_ci case 0x05: 27038c2ecf20Sopenharmony_ci printk("READY\n"); 27048c2ecf20Sopenharmony_ci break; 27058c2ecf20Sopenharmony_ci case 0x08: 27068c2ecf20Sopenharmony_ci printk("OPERATIONAL\n"); 27078c2ecf20Sopenharmony_ci break; 27088c2ecf20Sopenharmony_ci case 0x10: 27098c2ecf20Sopenharmony_ci printk("FAILED\n"); 27108c2ecf20Sopenharmony_ci break; 27118c2ecf20Sopenharmony_ci case 0x11: 27128c2ecf20Sopenharmony_ci printk("FAULTED\n"); 27138c2ecf20Sopenharmony_ci break; 27148c2ecf20Sopenharmony_ci default: 27158c2ecf20Sopenharmony_ci printk("%x (unknown!!)\n",pHba->status_block->iop_state); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci#endif 27188c2ecf20Sopenharmony_ci return 0; 27198c2ecf20Sopenharmony_ci} 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci/* 27228c2ecf20Sopenharmony_ci * Get the IOP's Logical Configuration Table 27238c2ecf20Sopenharmony_ci */ 27248c2ecf20Sopenharmony_cistatic int adpt_i2o_lct_get(adpt_hba* pHba) 27258c2ecf20Sopenharmony_ci{ 27268c2ecf20Sopenharmony_ci u32 msg[8]; 27278c2ecf20Sopenharmony_ci int ret; 27288c2ecf20Sopenharmony_ci u32 buf[16]; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if ((pHba->lct_size == 0) || (pHba->lct == NULL)){ 27318c2ecf20Sopenharmony_ci pHba->lct_size = pHba->status_block->expected_lct_size; 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci do { 27348c2ecf20Sopenharmony_ci if (pHba->lct == NULL) { 27358c2ecf20Sopenharmony_ci pHba->lct = dma_alloc_coherent(&pHba->pDev->dev, 27368c2ecf20Sopenharmony_ci pHba->lct_size, &pHba->lct_pa, 27378c2ecf20Sopenharmony_ci GFP_ATOMIC); 27388c2ecf20Sopenharmony_ci if(pHba->lct == NULL) { 27398c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", 27408c2ecf20Sopenharmony_ci pHba->name); 27418c2ecf20Sopenharmony_ci return -ENOMEM; 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci } 27448c2ecf20Sopenharmony_ci memset(pHba->lct, 0, pHba->lct_size); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; 27478c2ecf20Sopenharmony_ci msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; 27488c2ecf20Sopenharmony_ci msg[2] = 0; 27498c2ecf20Sopenharmony_ci msg[3] = 0; 27508c2ecf20Sopenharmony_ci msg[4] = 0xFFFFFFFF; /* All devices */ 27518c2ecf20Sopenharmony_ci msg[5] = 0x00000000; /* Report now */ 27528c2ecf20Sopenharmony_ci msg[6] = 0xD0000000|pHba->lct_size; 27538c2ecf20Sopenharmony_ci msg[7] = (u32)pHba->lct_pa; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) { 27568c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 27578c2ecf20Sopenharmony_ci pHba->name, ret); 27588c2ecf20Sopenharmony_ci printk(KERN_ERR"Adaptec: Error Reading Hardware.\n"); 27598c2ecf20Sopenharmony_ci return ret; 27608c2ecf20Sopenharmony_ci } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci if ((pHba->lct->table_size << 2) > pHba->lct_size) { 27638c2ecf20Sopenharmony_ci pHba->lct_size = pHba->lct->table_size << 2; 27648c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, pHba->lct_size, 27658c2ecf20Sopenharmony_ci pHba->lct, pHba->lct_pa); 27668c2ecf20Sopenharmony_ci pHba->lct = NULL; 27678c2ecf20Sopenharmony_ci } 27688c2ecf20Sopenharmony_ci } while (pHba->lct == NULL); 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci PDEBUG("%s: Hardware resource table read.\n", pHba->name); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci // I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO; 27748c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) { 27758c2ecf20Sopenharmony_ci pHba->FwDebugBufferSize = buf[1]; 27768c2ecf20Sopenharmony_ci pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0], 27778c2ecf20Sopenharmony_ci pHba->FwDebugBufferSize); 27788c2ecf20Sopenharmony_ci if (pHba->FwDebugBuffer_P) { 27798c2ecf20Sopenharmony_ci pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P + 27808c2ecf20Sopenharmony_ci FW_DEBUG_FLAGS_OFFSET; 27818c2ecf20Sopenharmony_ci pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + 27828c2ecf20Sopenharmony_ci FW_DEBUG_BLED_OFFSET; 27838c2ecf20Sopenharmony_ci pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1; 27848c2ecf20Sopenharmony_ci pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + 27858c2ecf20Sopenharmony_ci FW_DEBUG_STR_LENGTH_OFFSET; 27868c2ecf20Sopenharmony_ci pHba->FwDebugBuffer_P += buf[2]; 27878c2ecf20Sopenharmony_ci pHba->FwDebugFlags = 0; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci return 0; 27928c2ecf20Sopenharmony_ci} 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_cistatic int adpt_i2o_build_sys_table(void) 27958c2ecf20Sopenharmony_ci{ 27968c2ecf20Sopenharmony_ci adpt_hba* pHba = hba_chain; 27978c2ecf20Sopenharmony_ci int count = 0; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci if (sys_tbl) 28008c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sys_tbl_len, 28018c2ecf20Sopenharmony_ci sys_tbl, sys_tbl_pa); 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs 28048c2ecf20Sopenharmony_ci (hba_count) * sizeof(struct i2o_sys_tbl_entry); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci sys_tbl = dma_alloc_coherent(&pHba->pDev->dev, 28078c2ecf20Sopenharmony_ci sys_tbl_len, &sys_tbl_pa, GFP_KERNEL); 28088c2ecf20Sopenharmony_ci if (!sys_tbl) { 28098c2ecf20Sopenharmony_ci printk(KERN_WARNING "SysTab Set failed. Out of memory.\n"); 28108c2ecf20Sopenharmony_ci return -ENOMEM; 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci sys_tbl->num_entries = hba_count; 28148c2ecf20Sopenharmony_ci sys_tbl->version = I2OVERSION; 28158c2ecf20Sopenharmony_ci sys_tbl->change_ind = sys_tbl_ind++; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci for(pHba = hba_chain; pHba; pHba = pHba->next) { 28188c2ecf20Sopenharmony_ci u64 addr; 28198c2ecf20Sopenharmony_ci // Get updated Status Block so we have the latest information 28208c2ecf20Sopenharmony_ci if (adpt_i2o_status_get(pHba)) { 28218c2ecf20Sopenharmony_ci sys_tbl->num_entries--; 28228c2ecf20Sopenharmony_ci continue; // try next one 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci sys_tbl->iops[count].org_id = pHba->status_block->org_id; 28268c2ecf20Sopenharmony_ci sys_tbl->iops[count].iop_id = pHba->unit + 2; 28278c2ecf20Sopenharmony_ci sys_tbl->iops[count].seg_num = 0; 28288c2ecf20Sopenharmony_ci sys_tbl->iops[count].i2o_version = pHba->status_block->i2o_version; 28298c2ecf20Sopenharmony_ci sys_tbl->iops[count].iop_state = pHba->status_block->iop_state; 28308c2ecf20Sopenharmony_ci sys_tbl->iops[count].msg_type = pHba->status_block->msg_type; 28318c2ecf20Sopenharmony_ci sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size; 28328c2ecf20Sopenharmony_ci sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? 28338c2ecf20Sopenharmony_ci sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities; 28348c2ecf20Sopenharmony_ci addr = pHba->base_addr_phys + 0x40; 28358c2ecf20Sopenharmony_ci sys_tbl->iops[count].inbound_low = dma_low(addr); 28368c2ecf20Sopenharmony_ci sys_tbl->iops[count].inbound_high = dma_high(addr); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci count++; 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci#ifdef DEBUG 28428c2ecf20Sopenharmony_ci{ 28438c2ecf20Sopenharmony_ci u32 *table = (u32*)sys_tbl; 28448c2ecf20Sopenharmony_ci printk(KERN_DEBUG"sys_tbl_len=%d in 32bit words\n",(sys_tbl_len >>2)); 28458c2ecf20Sopenharmony_ci for(count = 0; count < (sys_tbl_len >>2); count++) { 28468c2ecf20Sopenharmony_ci printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", 28478c2ecf20Sopenharmony_ci count, table[count]); 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci} 28508c2ecf20Sopenharmony_ci#endif 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci return 0; 28538c2ecf20Sopenharmony_ci} 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci/* 28578c2ecf20Sopenharmony_ci * Dump the information block associated with a given unit (TID) 28588c2ecf20Sopenharmony_ci */ 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_cistatic void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d) 28618c2ecf20Sopenharmony_ci{ 28628c2ecf20Sopenharmony_ci char buf[64]; 28638c2ecf20Sopenharmony_ci int unit = d->lct_data.tid; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci printk(KERN_INFO "TID %3.3d ", unit); 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 3, buf, 16)>=0) 28688c2ecf20Sopenharmony_ci { 28698c2ecf20Sopenharmony_ci buf[16]=0; 28708c2ecf20Sopenharmony_ci printk(" Vendor: %-12.12s", buf); 28718c2ecf20Sopenharmony_ci } 28728c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 4, buf, 16)>=0) 28738c2ecf20Sopenharmony_ci { 28748c2ecf20Sopenharmony_ci buf[16]=0; 28758c2ecf20Sopenharmony_ci printk(" Device: %-12.12s", buf); 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 6, buf, 8)>=0) 28788c2ecf20Sopenharmony_ci { 28798c2ecf20Sopenharmony_ci buf[8]=0; 28808c2ecf20Sopenharmony_ci printk(" Rev: %-12.12s\n", buf); 28818c2ecf20Sopenharmony_ci } 28828c2ecf20Sopenharmony_ci#ifdef DEBUG 28838c2ecf20Sopenharmony_ci printk(KERN_INFO "\tClass: %.21s\n", adpt_i2o_get_class_name(d->lct_data.class_id)); 28848c2ecf20Sopenharmony_ci printk(KERN_INFO "\tSubclass: 0x%04X\n", d->lct_data.sub_class); 28858c2ecf20Sopenharmony_ci printk(KERN_INFO "\tFlags: "); 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if(d->lct_data.device_flags&(1<<0)) 28888c2ecf20Sopenharmony_ci printk("C"); // ConfigDialog requested 28898c2ecf20Sopenharmony_ci if(d->lct_data.device_flags&(1<<1)) 28908c2ecf20Sopenharmony_ci printk("U"); // Multi-user capable 28918c2ecf20Sopenharmony_ci if(!(d->lct_data.device_flags&(1<<4))) 28928c2ecf20Sopenharmony_ci printk("P"); // Peer service enabled! 28938c2ecf20Sopenharmony_ci if(!(d->lct_data.device_flags&(1<<5))) 28948c2ecf20Sopenharmony_ci printk("M"); // Mgmt service enabled! 28958c2ecf20Sopenharmony_ci printk("\n"); 28968c2ecf20Sopenharmony_ci#endif 28978c2ecf20Sopenharmony_ci} 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci#ifdef DEBUG 29008c2ecf20Sopenharmony_ci/* 29018c2ecf20Sopenharmony_ci * Do i2o class name lookup 29028c2ecf20Sopenharmony_ci */ 29038c2ecf20Sopenharmony_cistatic const char *adpt_i2o_get_class_name(int class) 29048c2ecf20Sopenharmony_ci{ 29058c2ecf20Sopenharmony_ci int idx = 16; 29068c2ecf20Sopenharmony_ci static char *i2o_class_name[] = { 29078c2ecf20Sopenharmony_ci "Executive", 29088c2ecf20Sopenharmony_ci "Device Driver Module", 29098c2ecf20Sopenharmony_ci "Block Device", 29108c2ecf20Sopenharmony_ci "Tape Device", 29118c2ecf20Sopenharmony_ci "LAN Interface", 29128c2ecf20Sopenharmony_ci "WAN Interface", 29138c2ecf20Sopenharmony_ci "Fibre Channel Port", 29148c2ecf20Sopenharmony_ci "Fibre Channel Device", 29158c2ecf20Sopenharmony_ci "SCSI Device", 29168c2ecf20Sopenharmony_ci "ATE Port", 29178c2ecf20Sopenharmony_ci "ATE Device", 29188c2ecf20Sopenharmony_ci "Floppy Controller", 29198c2ecf20Sopenharmony_ci "Floppy Device", 29208c2ecf20Sopenharmony_ci "Secondary Bus Port", 29218c2ecf20Sopenharmony_ci "Peer Transport Agent", 29228c2ecf20Sopenharmony_ci "Peer Transport", 29238c2ecf20Sopenharmony_ci "Unknown" 29248c2ecf20Sopenharmony_ci }; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci switch(class&0xFFF) { 29278c2ecf20Sopenharmony_ci case I2O_CLASS_EXECUTIVE: 29288c2ecf20Sopenharmony_ci idx = 0; break; 29298c2ecf20Sopenharmony_ci case I2O_CLASS_DDM: 29308c2ecf20Sopenharmony_ci idx = 1; break; 29318c2ecf20Sopenharmony_ci case I2O_CLASS_RANDOM_BLOCK_STORAGE: 29328c2ecf20Sopenharmony_ci idx = 2; break; 29338c2ecf20Sopenharmony_ci case I2O_CLASS_SEQUENTIAL_STORAGE: 29348c2ecf20Sopenharmony_ci idx = 3; break; 29358c2ecf20Sopenharmony_ci case I2O_CLASS_LAN: 29368c2ecf20Sopenharmony_ci idx = 4; break; 29378c2ecf20Sopenharmony_ci case I2O_CLASS_WAN: 29388c2ecf20Sopenharmony_ci idx = 5; break; 29398c2ecf20Sopenharmony_ci case I2O_CLASS_FIBRE_CHANNEL_PORT: 29408c2ecf20Sopenharmony_ci idx = 6; break; 29418c2ecf20Sopenharmony_ci case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: 29428c2ecf20Sopenharmony_ci idx = 7; break; 29438c2ecf20Sopenharmony_ci case I2O_CLASS_SCSI_PERIPHERAL: 29448c2ecf20Sopenharmony_ci idx = 8; break; 29458c2ecf20Sopenharmony_ci case I2O_CLASS_ATE_PORT: 29468c2ecf20Sopenharmony_ci idx = 9; break; 29478c2ecf20Sopenharmony_ci case I2O_CLASS_ATE_PERIPHERAL: 29488c2ecf20Sopenharmony_ci idx = 10; break; 29498c2ecf20Sopenharmony_ci case I2O_CLASS_FLOPPY_CONTROLLER: 29508c2ecf20Sopenharmony_ci idx = 11; break; 29518c2ecf20Sopenharmony_ci case I2O_CLASS_FLOPPY_DEVICE: 29528c2ecf20Sopenharmony_ci idx = 12; break; 29538c2ecf20Sopenharmony_ci case I2O_CLASS_BUS_ADAPTER_PORT: 29548c2ecf20Sopenharmony_ci idx = 13; break; 29558c2ecf20Sopenharmony_ci case I2O_CLASS_PEER_TRANSPORT_AGENT: 29568c2ecf20Sopenharmony_ci idx = 14; break; 29578c2ecf20Sopenharmony_ci case I2O_CLASS_PEER_TRANSPORT: 29588c2ecf20Sopenharmony_ci idx = 15; break; 29598c2ecf20Sopenharmony_ci } 29608c2ecf20Sopenharmony_ci return i2o_class_name[idx]; 29618c2ecf20Sopenharmony_ci} 29628c2ecf20Sopenharmony_ci#endif 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_cistatic s32 adpt_i2o_hrt_get(adpt_hba* pHba) 29668c2ecf20Sopenharmony_ci{ 29678c2ecf20Sopenharmony_ci u32 msg[6]; 29688c2ecf20Sopenharmony_ci int ret, size = sizeof(i2o_hrt); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci do { 29718c2ecf20Sopenharmony_ci if (pHba->hrt == NULL) { 29728c2ecf20Sopenharmony_ci pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev, 29738c2ecf20Sopenharmony_ci size, &pHba->hrt_pa, GFP_KERNEL); 29748c2ecf20Sopenharmony_ci if (pHba->hrt == NULL) { 29758c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name); 29768c2ecf20Sopenharmony_ci return -ENOMEM; 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci } 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; 29818c2ecf20Sopenharmony_ci msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; 29828c2ecf20Sopenharmony_ci msg[2]= 0; 29838c2ecf20Sopenharmony_ci msg[3]= 0; 29848c2ecf20Sopenharmony_ci msg[4]= (0xD0000000 | size); /* Simple transaction */ 29858c2ecf20Sopenharmony_ci msg[5]= (u32)pHba->hrt_pa; /* Dump it here */ 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) { 29888c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret); 29898c2ecf20Sopenharmony_ci return ret; 29908c2ecf20Sopenharmony_ci } 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) { 29938c2ecf20Sopenharmony_ci int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2; 29948c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, size, 29958c2ecf20Sopenharmony_ci pHba->hrt, pHba->hrt_pa); 29968c2ecf20Sopenharmony_ci size = newsize; 29978c2ecf20Sopenharmony_ci pHba->hrt = NULL; 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci } while(pHba->hrt == NULL); 30008c2ecf20Sopenharmony_ci return 0; 30018c2ecf20Sopenharmony_ci} 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci/* 30048c2ecf20Sopenharmony_ci * Query one scalar group value or a whole scalar group. 30058c2ecf20Sopenharmony_ci */ 30068c2ecf20Sopenharmony_cistatic int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, 30078c2ecf20Sopenharmony_ci int group, int field, void *buf, int buflen) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; 30108c2ecf20Sopenharmony_ci u8 *opblk_va; 30118c2ecf20Sopenharmony_ci dma_addr_t opblk_pa; 30128c2ecf20Sopenharmony_ci u8 *resblk_va; 30138c2ecf20Sopenharmony_ci dma_addr_t resblk_pa; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci int size; 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci /* 8 bytes for header */ 30188c2ecf20Sopenharmony_ci resblk_va = dma_alloc_coherent(&pHba->pDev->dev, 30198c2ecf20Sopenharmony_ci sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL); 30208c2ecf20Sopenharmony_ci if (resblk_va == NULL) { 30218c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name); 30228c2ecf20Sopenharmony_ci return -ENOMEM; 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci opblk_va = dma_alloc_coherent(&pHba->pDev->dev, 30268c2ecf20Sopenharmony_ci sizeof(opblk), &opblk_pa, GFP_KERNEL); 30278c2ecf20Sopenharmony_ci if (opblk_va == NULL) { 30288c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), 30298c2ecf20Sopenharmony_ci resblk_va, resblk_pa); 30308c2ecf20Sopenharmony_ci printk(KERN_CRIT "%s: query operation failed; Out of memory.\n", 30318c2ecf20Sopenharmony_ci pHba->name); 30328c2ecf20Sopenharmony_ci return -ENOMEM; 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci if (field == -1) /* whole group */ 30358c2ecf20Sopenharmony_ci opblk[4] = -1; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci memcpy(opblk_va, opblk, sizeof(opblk)); 30388c2ecf20Sopenharmony_ci size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid, 30398c2ecf20Sopenharmony_ci opblk_va, opblk_pa, sizeof(opblk), 30408c2ecf20Sopenharmony_ci resblk_va, resblk_pa, sizeof(u8)*(8+buflen)); 30418c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa); 30428c2ecf20Sopenharmony_ci if (size == -ETIME) { 30438c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), 30448c2ecf20Sopenharmony_ci resblk_va, resblk_pa); 30458c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name); 30468c2ecf20Sopenharmony_ci return -ETIME; 30478c2ecf20Sopenharmony_ci } else if (size == -EINTR) { 30488c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), 30498c2ecf20Sopenharmony_ci resblk_va, resblk_pa); 30508c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name); 30518c2ecf20Sopenharmony_ci return -EINTR; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci memcpy(buf, resblk_va+8, buflen); /* cut off header */ 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), 30578c2ecf20Sopenharmony_ci resblk_va, resblk_pa); 30588c2ecf20Sopenharmony_ci if (size < 0) 30598c2ecf20Sopenharmony_ci return size; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci return buflen; 30628c2ecf20Sopenharmony_ci} 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET 30668c2ecf20Sopenharmony_ci * 30678c2ecf20Sopenharmony_ci * This function can be used for all UtilParamsGet/Set operations. 30688c2ecf20Sopenharmony_ci * The OperationBlock is given in opblk-buffer, 30698c2ecf20Sopenharmony_ci * and results are returned in resblk-buffer. 30708c2ecf20Sopenharmony_ci * Note that the minimum sized resblk is 8 bytes and contains 30718c2ecf20Sopenharmony_ci * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. 30728c2ecf20Sopenharmony_ci */ 30738c2ecf20Sopenharmony_cistatic int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, 30748c2ecf20Sopenharmony_ci void *opblk_va, dma_addr_t opblk_pa, int oplen, 30758c2ecf20Sopenharmony_ci void *resblk_va, dma_addr_t resblk_pa, int reslen) 30768c2ecf20Sopenharmony_ci{ 30778c2ecf20Sopenharmony_ci u32 msg[9]; 30788c2ecf20Sopenharmony_ci u32 *res = (u32 *)resblk_va; 30798c2ecf20Sopenharmony_ci int wait_status; 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; 30828c2ecf20Sopenharmony_ci msg[1] = cmd << 24 | HOST_TID << 12 | tid; 30838c2ecf20Sopenharmony_ci msg[2] = 0; 30848c2ecf20Sopenharmony_ci msg[3] = 0; 30858c2ecf20Sopenharmony_ci msg[4] = 0; 30868c2ecf20Sopenharmony_ci msg[5] = 0x54000000 | oplen; /* OperationBlock */ 30878c2ecf20Sopenharmony_ci msg[6] = (u32)opblk_pa; 30888c2ecf20Sopenharmony_ci msg[7] = 0xD0000000 | reslen; /* ResultBlock */ 30898c2ecf20Sopenharmony_ci msg[8] = (u32)resblk_pa; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) { 30928c2ecf20Sopenharmony_ci printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va); 30938c2ecf20Sopenharmony_ci return wait_status; /* -DetailedStatus */ 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci if (res[1]&0x00FF0000) { /* BlockStatus != SUCCESS */ 30978c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s - Error:\n ErrorInfoSize = 0x%02x, " 30988c2ecf20Sopenharmony_ci "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", 30998c2ecf20Sopenharmony_ci pHba->name, 31008c2ecf20Sopenharmony_ci (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" 31018c2ecf20Sopenharmony_ci : "PARAMS_GET", 31028c2ecf20Sopenharmony_ci res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); 31038c2ecf20Sopenharmony_ci return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ 31048c2ecf20Sopenharmony_ci } 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_cistatic s32 adpt_i2o_quiesce_hba(adpt_hba* pHba) 31118c2ecf20Sopenharmony_ci{ 31128c2ecf20Sopenharmony_ci u32 msg[4]; 31138c2ecf20Sopenharmony_ci int ret; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci if((pHba->status_block->iop_state != ADAPTER_STATE_READY) && 31208c2ecf20Sopenharmony_ci (pHba->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)){ 31218c2ecf20Sopenharmony_ci return 0; 31228c2ecf20Sopenharmony_ci } 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; 31258c2ecf20Sopenharmony_ci msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; 31268c2ecf20Sopenharmony_ci msg[2] = 0; 31278c2ecf20Sopenharmony_ci msg[3] = 0; 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_ci if((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) { 31308c2ecf20Sopenharmony_ci printk(KERN_INFO"dpti%d: Unable to quiesce (status=%#x).\n", 31318c2ecf20Sopenharmony_ci pHba->unit, -ret); 31328c2ecf20Sopenharmony_ci } else { 31338c2ecf20Sopenharmony_ci printk(KERN_INFO"dpti%d: Quiesced.\n",pHba->unit); 31348c2ecf20Sopenharmony_ci } 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 31378c2ecf20Sopenharmony_ci return ret; 31388c2ecf20Sopenharmony_ci} 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci/* 31428c2ecf20Sopenharmony_ci * Enable IOP. Allows the IOP to resume external operations. 31438c2ecf20Sopenharmony_ci */ 31448c2ecf20Sopenharmony_cistatic int adpt_i2o_enable_hba(adpt_hba* pHba) 31458c2ecf20Sopenharmony_ci{ 31468c2ecf20Sopenharmony_ci u32 msg[4]; 31478c2ecf20Sopenharmony_ci int ret; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 31508c2ecf20Sopenharmony_ci if(!pHba->status_block){ 31518c2ecf20Sopenharmony_ci return -ENOMEM; 31528c2ecf20Sopenharmony_ci } 31538c2ecf20Sopenharmony_ci /* Enable only allowed on READY state */ 31548c2ecf20Sopenharmony_ci if(pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) 31558c2ecf20Sopenharmony_ci return 0; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci if(pHba->status_block->iop_state != ADAPTER_STATE_READY) 31588c2ecf20Sopenharmony_ci return -EINVAL; 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; 31618c2ecf20Sopenharmony_ci msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; 31628c2ecf20Sopenharmony_ci msg[2]= 0; 31638c2ecf20Sopenharmony_ci msg[3]= 0; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) { 31668c2ecf20Sopenharmony_ci printk(KERN_WARNING"%s: Could not enable (status=%#10x).\n", 31678c2ecf20Sopenharmony_ci pHba->name, ret); 31688c2ecf20Sopenharmony_ci } else { 31698c2ecf20Sopenharmony_ci PDEBUG("%s: Enabled.\n", pHba->name); 31708c2ecf20Sopenharmony_ci } 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci adpt_i2o_status_get(pHba); 31738c2ecf20Sopenharmony_ci return ret; 31748c2ecf20Sopenharmony_ci} 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_cistatic int adpt_i2o_systab_send(adpt_hba* pHba) 31788c2ecf20Sopenharmony_ci{ 31798c2ecf20Sopenharmony_ci u32 msg[12]; 31808c2ecf20Sopenharmony_ci int ret; 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; 31838c2ecf20Sopenharmony_ci msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; 31848c2ecf20Sopenharmony_ci msg[2] = 0; 31858c2ecf20Sopenharmony_ci msg[3] = 0; 31868c2ecf20Sopenharmony_ci msg[4] = (0<<16) | ((pHba->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ 31878c2ecf20Sopenharmony_ci msg[5] = 0; /* Segment 0 */ 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci /* 31908c2ecf20Sopenharmony_ci * Provide three SGL-elements: 31918c2ecf20Sopenharmony_ci * System table (SysTab), Private memory space declaration and 31928c2ecf20Sopenharmony_ci * Private i/o space declaration 31938c2ecf20Sopenharmony_ci */ 31948c2ecf20Sopenharmony_ci msg[6] = 0x54000000 | sys_tbl_len; 31958c2ecf20Sopenharmony_ci msg[7] = (u32)sys_tbl_pa; 31968c2ecf20Sopenharmony_ci msg[8] = 0x54000000 | 0; 31978c2ecf20Sopenharmony_ci msg[9] = 0; 31988c2ecf20Sopenharmony_ci msg[10] = 0xD4000000 | 0; 31998c2ecf20Sopenharmony_ci msg[11] = 0; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 120))) { 32028c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 32038c2ecf20Sopenharmony_ci pHba->name, ret); 32048c2ecf20Sopenharmony_ci } 32058c2ecf20Sopenharmony_ci#ifdef DEBUG 32068c2ecf20Sopenharmony_ci else { 32078c2ecf20Sopenharmony_ci PINFO("%s: SysTab set.\n", pHba->name); 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci#endif 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci return ret; 32128c2ecf20Sopenharmony_ci} 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci/*============================================================================ 32168c2ecf20Sopenharmony_ci * 32178c2ecf20Sopenharmony_ci *============================================================================ 32188c2ecf20Sopenharmony_ci */ 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci#ifdef UARTDELAY 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_cistatic static void adpt_delay(int millisec) 32248c2ecf20Sopenharmony_ci{ 32258c2ecf20Sopenharmony_ci int i; 32268c2ecf20Sopenharmony_ci for (i = 0; i < millisec; i++) { 32278c2ecf20Sopenharmony_ci udelay(1000); /* delay for one millisecond */ 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci} 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci#endif 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = { 32348c2ecf20Sopenharmony_ci .module = THIS_MODULE, 32358c2ecf20Sopenharmony_ci .name = "dpt_i2o", 32368c2ecf20Sopenharmony_ci .proc_name = "dpt_i2o", 32378c2ecf20Sopenharmony_ci .show_info = adpt_show_info, 32388c2ecf20Sopenharmony_ci .info = adpt_info, 32398c2ecf20Sopenharmony_ci .queuecommand = adpt_queue, 32408c2ecf20Sopenharmony_ci .eh_abort_handler = adpt_abort, 32418c2ecf20Sopenharmony_ci .eh_device_reset_handler = adpt_device_reset, 32428c2ecf20Sopenharmony_ci .eh_bus_reset_handler = adpt_bus_reset, 32438c2ecf20Sopenharmony_ci .eh_host_reset_handler = adpt_reset, 32448c2ecf20Sopenharmony_ci .bios_param = adpt_bios_param, 32458c2ecf20Sopenharmony_ci .slave_configure = adpt_slave_configure, 32468c2ecf20Sopenharmony_ci .can_queue = MAX_TO_IOP_MESSAGES, 32478c2ecf20Sopenharmony_ci .this_id = 7, 32488c2ecf20Sopenharmony_ci}; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_cistatic int __init adpt_init(void) 32518c2ecf20Sopenharmony_ci{ 32528c2ecf20Sopenharmony_ci int error; 32538c2ecf20Sopenharmony_ci adpt_hba *pHba, *next; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n"); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci error = adpt_detect(&driver_template); 32588c2ecf20Sopenharmony_ci if (error < 0) 32598c2ecf20Sopenharmony_ci return error; 32608c2ecf20Sopenharmony_ci if (hba_chain == NULL) 32618c2ecf20Sopenharmony_ci return -ENODEV; 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = pHba->next) { 32648c2ecf20Sopenharmony_ci error = scsi_add_host(pHba->host, &pHba->pDev->dev); 32658c2ecf20Sopenharmony_ci if (error) 32668c2ecf20Sopenharmony_ci goto fail; 32678c2ecf20Sopenharmony_ci scsi_scan_host(pHba->host); 32688c2ecf20Sopenharmony_ci } 32698c2ecf20Sopenharmony_ci return 0; 32708c2ecf20Sopenharmony_cifail: 32718c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = next) { 32728c2ecf20Sopenharmony_ci next = pHba->next; 32738c2ecf20Sopenharmony_ci scsi_remove_host(pHba->host); 32748c2ecf20Sopenharmony_ci } 32758c2ecf20Sopenharmony_ci return error; 32768c2ecf20Sopenharmony_ci} 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_cistatic void __exit adpt_exit(void) 32798c2ecf20Sopenharmony_ci{ 32808c2ecf20Sopenharmony_ci adpt_hba *pHba, *next; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci for (pHba = hba_chain; pHba; pHba = next) { 32838c2ecf20Sopenharmony_ci next = pHba->next; 32848c2ecf20Sopenharmony_ci adpt_release(pHba); 32858c2ecf20Sopenharmony_ci } 32868c2ecf20Sopenharmony_ci} 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_cimodule_init(adpt_init); 32898c2ecf20Sopenharmony_cimodule_exit(adpt_exit); 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3292