11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ipr.c -- driver for IBM Power Linux RAID adapters 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Written By: Brian King <brking@us.ibm.com>, IBM Corporation 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 2003, 2004 IBM Corporation 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds * 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds /* 251da177e4SLinus Torvalds * Notes: 261da177e4SLinus Torvalds * 271da177e4SLinus Torvalds * This driver is used to control the following SCSI adapters: 281da177e4SLinus Torvalds * 291da177e4SLinus Torvalds * IBM iSeries: 5702, 5703, 2780, 5709, 570A, 570B 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * IBM pSeries: PCI-X Dual Channel Ultra 320 SCSI RAID Adapter 321da177e4SLinus Torvalds * PCI-X Dual Channel Ultra 320 SCSI Adapter 331da177e4SLinus Torvalds * PCI-X Dual Channel Ultra 320 SCSI RAID Enablement Card 341da177e4SLinus Torvalds * Embedded SCSI adapter on p615 and p655 systems 351da177e4SLinus Torvalds * 361da177e4SLinus Torvalds * Supported Hardware Features: 371da177e4SLinus Torvalds * - Ultra 320 SCSI controller 381da177e4SLinus Torvalds * - PCI-X host interface 391da177e4SLinus Torvalds * - Embedded PowerPC RISC Processor and Hardware XOR DMA Engine 401da177e4SLinus Torvalds * - Non-Volatile Write Cache 411da177e4SLinus Torvalds * - Supports attachment of non-RAID disks, tape, and optical devices 421da177e4SLinus Torvalds * - RAID Levels 0, 5, 10 431da177e4SLinus Torvalds * - Hot spare 441da177e4SLinus Torvalds * - Background Parity Checking 451da177e4SLinus Torvalds * - Background Data Scrubbing 461da177e4SLinus Torvalds * - Ability to increase the capacity of an existing RAID 5 disk array 471da177e4SLinus Torvalds * by adding disks 481da177e4SLinus Torvalds * 491da177e4SLinus Torvalds * Driver Features: 501da177e4SLinus Torvalds * - Tagged command queuing 511da177e4SLinus Torvalds * - Adapter microcode download 521da177e4SLinus Torvalds * - PCI hot plug 531da177e4SLinus Torvalds * - SCSI device hot plug 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds */ 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds #include <linux/fs.h> 581da177e4SLinus Torvalds #include <linux/init.h> 591da177e4SLinus Torvalds #include <linux/types.h> 601da177e4SLinus Torvalds #include <linux/errno.h> 611da177e4SLinus Torvalds #include <linux/kernel.h> 621da177e4SLinus Torvalds #include <linux/ioport.h> 631da177e4SLinus Torvalds #include <linux/delay.h> 641da177e4SLinus Torvalds #include <linux/pci.h> 651da177e4SLinus Torvalds #include <linux/wait.h> 661da177e4SLinus Torvalds #include <linux/spinlock.h> 671da177e4SLinus Torvalds #include <linux/sched.h> 681da177e4SLinus Torvalds #include <linux/interrupt.h> 691da177e4SLinus Torvalds #include <linux/blkdev.h> 701da177e4SLinus Torvalds #include <linux/firmware.h> 711da177e4SLinus Torvalds #include <linux/module.h> 721da177e4SLinus Torvalds #include <linux/moduleparam.h> 7335a39691SBrian King #include <linux/libata.h> 741da177e4SLinus Torvalds #include <asm/io.h> 751da177e4SLinus Torvalds #include <asm/irq.h> 761da177e4SLinus Torvalds #include <asm/processor.h> 771da177e4SLinus Torvalds #include <scsi/scsi.h> 781da177e4SLinus Torvalds #include <scsi/scsi_host.h> 791da177e4SLinus Torvalds #include <scsi/scsi_tcq.h> 801da177e4SLinus Torvalds #include <scsi/scsi_eh.h> 811da177e4SLinus Torvalds #include <scsi/scsi_cmnd.h> 821da177e4SLinus Torvalds #include "ipr.h" 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* 851da177e4SLinus Torvalds * Global Data 861da177e4SLinus Torvalds */ 871da177e4SLinus Torvalds static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head); 881da177e4SLinus Torvalds static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; 891da177e4SLinus Torvalds static unsigned int ipr_max_speed = 1; 901da177e4SLinus Torvalds static int ipr_testmode = 0; 911da177e4SLinus Torvalds static unsigned int ipr_fastfail = 0; 921da177e4SLinus Torvalds static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT; 9362275040Sbrking@us.ibm.com static unsigned int ipr_enable_cache = 1; 94d3c74871Sbrking@us.ibm.com static unsigned int ipr_debug = 0; 9532d29776Sbrking@us.ibm.com static int ipr_auto_create = 1; 961da177e4SLinus Torvalds static DEFINE_SPINLOCK(ipr_driver_lock); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /* This table describes the differences between DMA controller chips */ 991da177e4SLinus Torvalds static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { 10060e7486bSBrian King { /* Gemstone, Citrine, Obsidian, and Obsidian-E */ 1011da177e4SLinus Torvalds .mailbox = 0x0042C, 1021da177e4SLinus Torvalds .cache_line_size = 0x20, 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds .set_interrupt_mask_reg = 0x0022C, 1051da177e4SLinus Torvalds .clr_interrupt_mask_reg = 0x00230, 1061da177e4SLinus Torvalds .sense_interrupt_mask_reg = 0x0022C, 1071da177e4SLinus Torvalds .clr_interrupt_reg = 0x00228, 1081da177e4SLinus Torvalds .sense_interrupt_reg = 0x00224, 1091da177e4SLinus Torvalds .ioarrin_reg = 0x00404, 1101da177e4SLinus Torvalds .sense_uproc_interrupt_reg = 0x00214, 1111da177e4SLinus Torvalds .set_uproc_interrupt_reg = 0x00214, 1121da177e4SLinus Torvalds .clr_uproc_interrupt_reg = 0x00218 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds }, 1151da177e4SLinus Torvalds { /* Snipe and Scamp */ 1161da177e4SLinus Torvalds .mailbox = 0x0052C, 1171da177e4SLinus Torvalds .cache_line_size = 0x20, 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds .set_interrupt_mask_reg = 0x00288, 1201da177e4SLinus Torvalds .clr_interrupt_mask_reg = 0x0028C, 1211da177e4SLinus Torvalds .sense_interrupt_mask_reg = 0x00288, 1221da177e4SLinus Torvalds .clr_interrupt_reg = 0x00284, 1231da177e4SLinus Torvalds .sense_interrupt_reg = 0x00280, 1241da177e4SLinus Torvalds .ioarrin_reg = 0x00504, 1251da177e4SLinus Torvalds .sense_uproc_interrupt_reg = 0x00290, 1261da177e4SLinus Torvalds .set_uproc_interrupt_reg = 0x00290, 1271da177e4SLinus Torvalds .clr_uproc_interrupt_reg = 0x00294 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds }, 1301da177e4SLinus Torvalds }; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds static const struct ipr_chip_t ipr_chip[] = { 1331da177e4SLinus Torvalds { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] }, 1341da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] }, 13586f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] }, 13686f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] }, 13760e7486bSBrian King { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, &ipr_chip_cfg[0] }, 1381da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] }, 1391da177e4SLinus Torvalds { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] } 1401da177e4SLinus Torvalds }; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds static int ipr_max_bus_speeds [] = { 1431da177e4SLinus Torvalds IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE 1441da177e4SLinus Torvalds }; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds MODULE_AUTHOR("Brian King <brking@us.ibm.com>"); 1471da177e4SLinus Torvalds MODULE_DESCRIPTION("IBM Power RAID SCSI Adapter Driver"); 1481da177e4SLinus Torvalds module_param_named(max_speed, ipr_max_speed, uint, 0); 1491da177e4SLinus Torvalds MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320"); 1501da177e4SLinus Torvalds module_param_named(log_level, ipr_log_level, uint, 0); 1511da177e4SLinus Torvalds MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); 1521da177e4SLinus Torvalds module_param_named(testmode, ipr_testmode, int, 0); 1531da177e4SLinus Torvalds MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); 1541da177e4SLinus Torvalds module_param_named(fastfail, ipr_fastfail, int, 0); 1551da177e4SLinus Torvalds MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); 1561da177e4SLinus Torvalds module_param_named(transop_timeout, ipr_transop_timeout, int, 0); 1571da177e4SLinus Torvalds MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)"); 15862275040Sbrking@us.ibm.com module_param_named(enable_cache, ipr_enable_cache, int, 0); 15962275040Sbrking@us.ibm.com MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)"); 160d3c74871Sbrking@us.ibm.com module_param_named(debug, ipr_debug, int, 0); 161d3c74871Sbrking@us.ibm.com MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); 16232d29776Sbrking@us.ibm.com module_param_named(auto_create, ipr_auto_create, int, 0); 16332d29776Sbrking@us.ibm.com MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)"); 1641da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1651da177e4SLinus Torvalds MODULE_VERSION(IPR_DRIVER_VERSION); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* A constant array of IOASCs/URCs/Error Messages */ 1681da177e4SLinus Torvalds static const 1691da177e4SLinus Torvalds struct ipr_error_table_t ipr_error_table[] = { 1701da177e4SLinus Torvalds {0x00000000, 1, 1, 1711da177e4SLinus Torvalds "8155: An unknown error was received"}, 1721da177e4SLinus Torvalds {0x00330000, 0, 0, 1731da177e4SLinus Torvalds "Soft underlength error"}, 1741da177e4SLinus Torvalds {0x005A0000, 0, 0, 1751da177e4SLinus Torvalds "Command to be cancelled not found"}, 1761da177e4SLinus Torvalds {0x00808000, 0, 0, 1771da177e4SLinus Torvalds "Qualified success"}, 1781da177e4SLinus Torvalds {0x01080000, 1, 1, 1791da177e4SLinus Torvalds "FFFE: Soft device bus error recovered by the IOA"}, 180896bbd21SBrian King {0x01088100, 0, 1, 181896bbd21SBrian King "4101: Soft device bus fabric error"}, 1821da177e4SLinus Torvalds {0x01170600, 0, 1, 1831da177e4SLinus Torvalds "FFF9: Device sector reassign successful"}, 1841da177e4SLinus Torvalds {0x01170900, 0, 1, 1851da177e4SLinus Torvalds "FFF7: Media error recovered by device rewrite procedures"}, 1861da177e4SLinus Torvalds {0x01180200, 0, 1, 1871da177e4SLinus Torvalds "7001: IOA sector reassignment successful"}, 1881da177e4SLinus Torvalds {0x01180500, 0, 1, 1891da177e4SLinus Torvalds "FFF9: Soft media error. Sector reassignment recommended"}, 1901da177e4SLinus Torvalds {0x01180600, 0, 1, 1911da177e4SLinus Torvalds "FFF7: Media error recovered by IOA rewrite procedures"}, 1921da177e4SLinus Torvalds {0x01418000, 0, 1, 1931da177e4SLinus Torvalds "FF3D: Soft PCI bus error recovered by the IOA"}, 1941da177e4SLinus Torvalds {0x01440000, 1, 1, 1951da177e4SLinus Torvalds "FFF6: Device hardware error recovered by the IOA"}, 1961da177e4SLinus Torvalds {0x01448100, 0, 1, 1971da177e4SLinus Torvalds "FFF6: Device hardware error recovered by the device"}, 1981da177e4SLinus Torvalds {0x01448200, 1, 1, 1991da177e4SLinus Torvalds "FF3D: Soft IOA error recovered by the IOA"}, 2001da177e4SLinus Torvalds {0x01448300, 0, 1, 2011da177e4SLinus Torvalds "FFFA: Undefined device response recovered by the IOA"}, 2021da177e4SLinus Torvalds {0x014A0000, 1, 1, 2031da177e4SLinus Torvalds "FFF6: Device bus error, message or command phase"}, 20435a39691SBrian King {0x014A8000, 0, 1, 20535a39691SBrian King "FFFE: Task Management Function failed"}, 2061da177e4SLinus Torvalds {0x015D0000, 0, 1, 2071da177e4SLinus Torvalds "FFF6: Failure prediction threshold exceeded"}, 2081da177e4SLinus Torvalds {0x015D9200, 0, 1, 2091da177e4SLinus Torvalds "8009: Impending cache battery pack failure"}, 2101da177e4SLinus Torvalds {0x02040400, 0, 0, 2111da177e4SLinus Torvalds "34FF: Disk device format in progress"}, 2121da177e4SLinus Torvalds {0x023F0000, 0, 0, 2131da177e4SLinus Torvalds "Synchronization required"}, 2141da177e4SLinus Torvalds {0x024E0000, 0, 0, 2151da177e4SLinus Torvalds "No ready, IOA shutdown"}, 2161da177e4SLinus Torvalds {0x025A0000, 0, 0, 2171da177e4SLinus Torvalds "Not ready, IOA has been shutdown"}, 2181da177e4SLinus Torvalds {0x02670100, 0, 1, 2191da177e4SLinus Torvalds "3020: Storage subsystem configuration error"}, 2201da177e4SLinus Torvalds {0x03110B00, 0, 0, 2211da177e4SLinus Torvalds "FFF5: Medium error, data unreadable, recommend reassign"}, 2221da177e4SLinus Torvalds {0x03110C00, 0, 0, 2231da177e4SLinus Torvalds "7000: Medium error, data unreadable, do not reassign"}, 2241da177e4SLinus Torvalds {0x03310000, 0, 1, 2251da177e4SLinus Torvalds "FFF3: Disk media format bad"}, 2261da177e4SLinus Torvalds {0x04050000, 0, 1, 2271da177e4SLinus Torvalds "3002: Addressed device failed to respond to selection"}, 2281da177e4SLinus Torvalds {0x04080000, 1, 1, 2291da177e4SLinus Torvalds "3100: Device bus error"}, 2301da177e4SLinus Torvalds {0x04080100, 0, 1, 2311da177e4SLinus Torvalds "3109: IOA timed out a device command"}, 2321da177e4SLinus Torvalds {0x04088000, 0, 0, 2331da177e4SLinus Torvalds "3120: SCSI bus is not operational"}, 234896bbd21SBrian King {0x04088100, 0, 1, 235896bbd21SBrian King "4100: Hard device bus fabric error"}, 2361da177e4SLinus Torvalds {0x04118000, 0, 1, 2371da177e4SLinus Torvalds "9000: IOA reserved area data check"}, 2381da177e4SLinus Torvalds {0x04118100, 0, 1, 2391da177e4SLinus Torvalds "9001: IOA reserved area invalid data pattern"}, 2401da177e4SLinus Torvalds {0x04118200, 0, 1, 2411da177e4SLinus Torvalds "9002: IOA reserved area LRC error"}, 2421da177e4SLinus Torvalds {0x04320000, 0, 1, 2431da177e4SLinus Torvalds "102E: Out of alternate sectors for disk storage"}, 2441da177e4SLinus Torvalds {0x04330000, 1, 1, 2451da177e4SLinus Torvalds "FFF4: Data transfer underlength error"}, 2461da177e4SLinus Torvalds {0x04338000, 1, 1, 2471da177e4SLinus Torvalds "FFF4: Data transfer overlength error"}, 2481da177e4SLinus Torvalds {0x043E0100, 0, 1, 2491da177e4SLinus Torvalds "3400: Logical unit failure"}, 2501da177e4SLinus Torvalds {0x04408500, 0, 1, 2511da177e4SLinus Torvalds "FFF4: Device microcode is corrupt"}, 2521da177e4SLinus Torvalds {0x04418000, 1, 1, 2531da177e4SLinus Torvalds "8150: PCI bus error"}, 2541da177e4SLinus Torvalds {0x04430000, 1, 0, 2551da177e4SLinus Torvalds "Unsupported device bus message received"}, 2561da177e4SLinus Torvalds {0x04440000, 1, 1, 2571da177e4SLinus Torvalds "FFF4: Disk device problem"}, 2581da177e4SLinus Torvalds {0x04448200, 1, 1, 2591da177e4SLinus Torvalds "8150: Permanent IOA failure"}, 2601da177e4SLinus Torvalds {0x04448300, 0, 1, 2611da177e4SLinus Torvalds "3010: Disk device returned wrong response to IOA"}, 2621da177e4SLinus Torvalds {0x04448400, 0, 1, 2631da177e4SLinus Torvalds "8151: IOA microcode error"}, 2641da177e4SLinus Torvalds {0x04448500, 0, 0, 2651da177e4SLinus Torvalds "Device bus status error"}, 2661da177e4SLinus Torvalds {0x04448600, 0, 1, 2671da177e4SLinus Torvalds "8157: IOA error requiring IOA reset to recover"}, 26835a39691SBrian King {0x04448700, 0, 0, 26935a39691SBrian King "ATA device status error"}, 2701da177e4SLinus Torvalds {0x04490000, 0, 0, 2711da177e4SLinus Torvalds "Message reject received from the device"}, 2721da177e4SLinus Torvalds {0x04449200, 0, 1, 2731da177e4SLinus Torvalds "8008: A permanent cache battery pack failure occurred"}, 2741da177e4SLinus Torvalds {0x0444A000, 0, 1, 2751da177e4SLinus Torvalds "9090: Disk unit has been modified after the last known status"}, 2761da177e4SLinus Torvalds {0x0444A200, 0, 1, 2771da177e4SLinus Torvalds "9081: IOA detected device error"}, 2781da177e4SLinus Torvalds {0x0444A300, 0, 1, 2791da177e4SLinus Torvalds "9082: IOA detected device error"}, 2801da177e4SLinus Torvalds {0x044A0000, 1, 1, 2811da177e4SLinus Torvalds "3110: Device bus error, message or command phase"}, 28235a39691SBrian King {0x044A8000, 1, 1, 28335a39691SBrian King "3110: SAS Command / Task Management Function failed"}, 2841da177e4SLinus Torvalds {0x04670400, 0, 1, 2851da177e4SLinus Torvalds "9091: Incorrect hardware configuration change has been detected"}, 286b0df54bbSbrking@us.ibm.com {0x04678000, 0, 1, 287b0df54bbSbrking@us.ibm.com "9073: Invalid multi-adapter configuration"}, 288896bbd21SBrian King {0x04678100, 0, 1, 289896bbd21SBrian King "4010: Incorrect connection between cascaded expanders"}, 290896bbd21SBrian King {0x04678200, 0, 1, 291896bbd21SBrian King "4020: Connections exceed IOA design limits"}, 292896bbd21SBrian King {0x04678300, 0, 1, 293896bbd21SBrian King "4030: Incorrect multipath connection"}, 294896bbd21SBrian King {0x04679000, 0, 1, 295896bbd21SBrian King "4110: Unsupported enclosure function"}, 2961da177e4SLinus Torvalds {0x046E0000, 0, 1, 2971da177e4SLinus Torvalds "FFF4: Command to logical unit failed"}, 2981da177e4SLinus Torvalds {0x05240000, 1, 0, 2991da177e4SLinus Torvalds "Illegal request, invalid request type or request packet"}, 3001da177e4SLinus Torvalds {0x05250000, 0, 0, 3011da177e4SLinus Torvalds "Illegal request, invalid resource handle"}, 302b0df54bbSbrking@us.ibm.com {0x05258000, 0, 0, 303b0df54bbSbrking@us.ibm.com "Illegal request, commands not allowed to this device"}, 304b0df54bbSbrking@us.ibm.com {0x05258100, 0, 0, 305b0df54bbSbrking@us.ibm.com "Illegal request, command not allowed to a secondary adapter"}, 3061da177e4SLinus Torvalds {0x05260000, 0, 0, 3071da177e4SLinus Torvalds "Illegal request, invalid field in parameter list"}, 3081da177e4SLinus Torvalds {0x05260100, 0, 0, 3091da177e4SLinus Torvalds "Illegal request, parameter not supported"}, 3101da177e4SLinus Torvalds {0x05260200, 0, 0, 3111da177e4SLinus Torvalds "Illegal request, parameter value invalid"}, 3121da177e4SLinus Torvalds {0x052C0000, 0, 0, 3131da177e4SLinus Torvalds "Illegal request, command sequence error"}, 314b0df54bbSbrking@us.ibm.com {0x052C8000, 1, 0, 315b0df54bbSbrking@us.ibm.com "Illegal request, dual adapter support not enabled"}, 3161da177e4SLinus Torvalds {0x06040500, 0, 1, 3171da177e4SLinus Torvalds "9031: Array protection temporarily suspended, protection resuming"}, 3181da177e4SLinus Torvalds {0x06040600, 0, 1, 3191da177e4SLinus Torvalds "9040: Array protection temporarily suspended, protection resuming"}, 320896bbd21SBrian King {0x06288000, 0, 1, 321896bbd21SBrian King "3140: Device bus not ready to ready transition"}, 3221da177e4SLinus Torvalds {0x06290000, 0, 1, 3231da177e4SLinus Torvalds "FFFB: SCSI bus was reset"}, 3241da177e4SLinus Torvalds {0x06290500, 0, 0, 3251da177e4SLinus Torvalds "FFFE: SCSI bus transition to single ended"}, 3261da177e4SLinus Torvalds {0x06290600, 0, 0, 3271da177e4SLinus Torvalds "FFFE: SCSI bus transition to LVD"}, 3281da177e4SLinus Torvalds {0x06298000, 0, 1, 3291da177e4SLinus Torvalds "FFFB: SCSI bus was reset by another initiator"}, 3301da177e4SLinus Torvalds {0x063F0300, 0, 1, 3311da177e4SLinus Torvalds "3029: A device replacement has occurred"}, 3321da177e4SLinus Torvalds {0x064C8000, 0, 1, 3331da177e4SLinus Torvalds "9051: IOA cache data exists for a missing or failed device"}, 334b0df54bbSbrking@us.ibm.com {0x064C8100, 0, 1, 335b0df54bbSbrking@us.ibm.com "9055: Auxiliary cache IOA contains cache data needed by the primary IOA"}, 3361da177e4SLinus Torvalds {0x06670100, 0, 1, 3371da177e4SLinus Torvalds "9025: Disk unit is not supported at its physical location"}, 3381da177e4SLinus Torvalds {0x06670600, 0, 1, 3391da177e4SLinus Torvalds "3020: IOA detected a SCSI bus configuration error"}, 3401da177e4SLinus Torvalds {0x06678000, 0, 1, 3411da177e4SLinus Torvalds "3150: SCSI bus configuration error"}, 342b0df54bbSbrking@us.ibm.com {0x06678100, 0, 1, 343b0df54bbSbrking@us.ibm.com "9074: Asymmetric advanced function disk configuration"}, 344896bbd21SBrian King {0x06678300, 0, 1, 345896bbd21SBrian King "4040: Incomplete multipath connection between IOA and enclosure"}, 346896bbd21SBrian King {0x06678400, 0, 1, 347896bbd21SBrian King "4041: Incomplete multipath connection between enclosure and device"}, 348896bbd21SBrian King {0x06678500, 0, 1, 349896bbd21SBrian King "9075: Incomplete multipath connection between IOA and remote IOA"}, 350896bbd21SBrian King {0x06678600, 0, 1, 351896bbd21SBrian King "9076: Configuration error, missing remote IOA"}, 352896bbd21SBrian King {0x06679100, 0, 1, 353896bbd21SBrian King "4050: Enclosure does not support a required multipath function"}, 3541da177e4SLinus Torvalds {0x06690200, 0, 1, 3551da177e4SLinus Torvalds "9041: Array protection temporarily suspended"}, 3561da177e4SLinus Torvalds {0x06698200, 0, 1, 3571da177e4SLinus Torvalds "9042: Corrupt array parity detected on specified device"}, 3581da177e4SLinus Torvalds {0x066B0200, 0, 1, 3591da177e4SLinus Torvalds "9030: Array no longer protected due to missing or failed disk unit"}, 360b0df54bbSbrking@us.ibm.com {0x066B8000, 0, 1, 361b0df54bbSbrking@us.ibm.com "9071: Link operational transition"}, 362b0df54bbSbrking@us.ibm.com {0x066B8100, 0, 1, 363b0df54bbSbrking@us.ibm.com "9072: Link not operational transition"}, 3641da177e4SLinus Torvalds {0x066B8200, 0, 1, 3651da177e4SLinus Torvalds "9032: Array exposed but still protected"}, 366896bbd21SBrian King {0x066B9100, 0, 1, 367896bbd21SBrian King "4061: Multipath redundancy level got better"}, 368896bbd21SBrian King {0x066B9200, 0, 1, 369896bbd21SBrian King "4060: Multipath redundancy level got worse"}, 3701da177e4SLinus Torvalds {0x07270000, 0, 0, 3711da177e4SLinus Torvalds "Failure due to other device"}, 3721da177e4SLinus Torvalds {0x07278000, 0, 1, 3731da177e4SLinus Torvalds "9008: IOA does not support functions expected by devices"}, 3741da177e4SLinus Torvalds {0x07278100, 0, 1, 3751da177e4SLinus Torvalds "9010: Cache data associated with attached devices cannot be found"}, 3761da177e4SLinus Torvalds {0x07278200, 0, 1, 3771da177e4SLinus Torvalds "9011: Cache data belongs to devices other than those attached"}, 3781da177e4SLinus Torvalds {0x07278400, 0, 1, 3791da177e4SLinus Torvalds "9020: Array missing 2 or more devices with only 1 device present"}, 3801da177e4SLinus Torvalds {0x07278500, 0, 1, 3811da177e4SLinus Torvalds "9021: Array missing 2 or more devices with 2 or more devices present"}, 3821da177e4SLinus Torvalds {0x07278600, 0, 1, 3831da177e4SLinus Torvalds "9022: Exposed array is missing a required device"}, 3841da177e4SLinus Torvalds {0x07278700, 0, 1, 3851da177e4SLinus Torvalds "9023: Array member(s) not at required physical locations"}, 3861da177e4SLinus Torvalds {0x07278800, 0, 1, 3871da177e4SLinus Torvalds "9024: Array not functional due to present hardware configuration"}, 3881da177e4SLinus Torvalds {0x07278900, 0, 1, 3891da177e4SLinus Torvalds "9026: Array not functional due to present hardware configuration"}, 3901da177e4SLinus Torvalds {0x07278A00, 0, 1, 3911da177e4SLinus Torvalds "9027: Array is missing a device and parity is out of sync"}, 3921da177e4SLinus Torvalds {0x07278B00, 0, 1, 3931da177e4SLinus Torvalds "9028: Maximum number of arrays already exist"}, 3941da177e4SLinus Torvalds {0x07278C00, 0, 1, 3951da177e4SLinus Torvalds "9050: Required cache data cannot be located for a disk unit"}, 3961da177e4SLinus Torvalds {0x07278D00, 0, 1, 3971da177e4SLinus Torvalds "9052: Cache data exists for a device that has been modified"}, 3981da177e4SLinus Torvalds {0x07278F00, 0, 1, 3991da177e4SLinus Torvalds "9054: IOA resources not available due to previous problems"}, 4001da177e4SLinus Torvalds {0x07279100, 0, 1, 4011da177e4SLinus Torvalds "9092: Disk unit requires initialization before use"}, 4021da177e4SLinus Torvalds {0x07279200, 0, 1, 4031da177e4SLinus Torvalds "9029: Incorrect hardware configuration change has been detected"}, 4041da177e4SLinus Torvalds {0x07279600, 0, 1, 4051da177e4SLinus Torvalds "9060: One or more disk pairs are missing from an array"}, 4061da177e4SLinus Torvalds {0x07279700, 0, 1, 4071da177e4SLinus Torvalds "9061: One or more disks are missing from an array"}, 4081da177e4SLinus Torvalds {0x07279800, 0, 1, 4091da177e4SLinus Torvalds "9062: One or more disks are missing from an array"}, 4101da177e4SLinus Torvalds {0x07279900, 0, 1, 4111da177e4SLinus Torvalds "9063: Maximum number of functional arrays has been exceeded"}, 4121da177e4SLinus Torvalds {0x0B260000, 0, 0, 4131da177e4SLinus Torvalds "Aborted command, invalid descriptor"}, 4141da177e4SLinus Torvalds {0x0B5A0000, 0, 0, 4151da177e4SLinus Torvalds "Command terminated by host"} 4161da177e4SLinus Torvalds }; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds static const struct ipr_ses_table_entry ipr_ses_table[] = { 4191da177e4SLinus Torvalds { "2104-DL1 ", "XXXXXXXXXXXXXXXX", 80 }, 4201da177e4SLinus Torvalds { "2104-TL1 ", "XXXXXXXXXXXXXXXX", 80 }, 4211da177e4SLinus Torvalds { "HSBP07M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 7 slot */ 4221da177e4SLinus Torvalds { "HSBP05M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 5 slot */ 4231da177e4SLinus Torvalds { "HSBP05M S U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Bowtie */ 4241da177e4SLinus Torvalds { "HSBP06E ASU2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* MartinFenning */ 4251da177e4SLinus Torvalds { "2104-DU3 ", "XXXXXXXXXXXXXXXX", 160 }, 4261da177e4SLinus Torvalds { "2104-TU3 ", "XXXXXXXXXXXXXXXX", 160 }, 4271da177e4SLinus Torvalds { "HSBP04C RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, 4281da177e4SLinus Torvalds { "HSBP06E RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, 4291da177e4SLinus Torvalds { "St V1S2 ", "XXXXXXXXXXXXXXXX", 160 }, 4301da177e4SLinus Torvalds { "HSBPD4M PU3SCSI", "XXXXXXX*XXXXXXXX", 160 }, 4311da177e4SLinus Torvalds { "VSBPD1H U3SCSI", "XXXXXXX*XXXXXXXX", 160 } 4321da177e4SLinus Torvalds }; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* 4351da177e4SLinus Torvalds * Function Prototypes 4361da177e4SLinus Torvalds */ 4371da177e4SLinus Torvalds static int ipr_reset_alert(struct ipr_cmnd *); 4381da177e4SLinus Torvalds static void ipr_process_ccn(struct ipr_cmnd *); 4391da177e4SLinus Torvalds static void ipr_process_error(struct ipr_cmnd *); 4401da177e4SLinus Torvalds static void ipr_reset_ioa_job(struct ipr_cmnd *); 4411da177e4SLinus Torvalds static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *, 4421da177e4SLinus Torvalds enum ipr_shutdown_type); 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds #ifdef CONFIG_SCSI_IPR_TRACE 4451da177e4SLinus Torvalds /** 4461da177e4SLinus Torvalds * ipr_trc_hook - Add a trace entry to the driver trace 4471da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 4481da177e4SLinus Torvalds * @type: trace type 4491da177e4SLinus Torvalds * @add_data: additional data 4501da177e4SLinus Torvalds * 4511da177e4SLinus Torvalds * Return value: 4521da177e4SLinus Torvalds * none 4531da177e4SLinus Torvalds **/ 4541da177e4SLinus Torvalds static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, 4551da177e4SLinus Torvalds u8 type, u32 add_data) 4561da177e4SLinus Torvalds { 4571da177e4SLinus Torvalds struct ipr_trace_entry *trace_entry; 4581da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++]; 4611da177e4SLinus Torvalds trace_entry->time = jiffies; 4621da177e4SLinus Torvalds trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; 4631da177e4SLinus Torvalds trace_entry->type = type; 46435a39691SBrian King trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command; 46535a39691SBrian King trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; 4661da177e4SLinus Torvalds trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; 4671da177e4SLinus Torvalds trace_entry->u.add_data = add_data; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds #else 4701da177e4SLinus Torvalds #define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0) 4711da177e4SLinus Torvalds #endif 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds /** 4741da177e4SLinus Torvalds * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse 4751da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 4761da177e4SLinus Torvalds * 4771da177e4SLinus Torvalds * Return value: 4781da177e4SLinus Torvalds * none 4791da177e4SLinus Torvalds **/ 4801da177e4SLinus Torvalds static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) 4811da177e4SLinus Torvalds { 4821da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 4831da177e4SLinus Torvalds struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); 4861da177e4SLinus Torvalds ioarcb->write_data_transfer_length = 0; 4871da177e4SLinus Torvalds ioarcb->read_data_transfer_length = 0; 4881da177e4SLinus Torvalds ioarcb->write_ioadl_len = 0; 4891da177e4SLinus Torvalds ioarcb->read_ioadl_len = 0; 4901da177e4SLinus Torvalds ioasa->ioasc = 0; 4911da177e4SLinus Torvalds ioasa->residual_data_len = 0; 49235a39691SBrian King ioasa->u.gata.status = 0; 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds ipr_cmd->scsi_cmd = NULL; 49535a39691SBrian King ipr_cmd->qc = NULL; 4961da177e4SLinus Torvalds ipr_cmd->sense_buffer[0] = 0; 4971da177e4SLinus Torvalds ipr_cmd->dma_use_sg = 0; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds /** 5011da177e4SLinus Torvalds * ipr_init_ipr_cmnd - Initialize an IPR Cmnd block 5021da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 5031da177e4SLinus Torvalds * 5041da177e4SLinus Torvalds * Return value: 5051da177e4SLinus Torvalds * none 5061da177e4SLinus Torvalds **/ 5071da177e4SLinus Torvalds static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd) 5081da177e4SLinus Torvalds { 5091da177e4SLinus Torvalds ipr_reinit_ipr_cmnd(ipr_cmd); 5101da177e4SLinus Torvalds ipr_cmd->u.scratch = 0; 5111da177e4SLinus Torvalds ipr_cmd->sibling = NULL; 5121da177e4SLinus Torvalds init_timer(&ipr_cmd->timer); 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds /** 5161da177e4SLinus Torvalds * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block 5171da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 5181da177e4SLinus Torvalds * 5191da177e4SLinus Torvalds * Return value: 5201da177e4SLinus Torvalds * pointer to ipr command struct 5211da177e4SLinus Torvalds **/ 5221da177e4SLinus Torvalds static 5231da177e4SLinus Torvalds struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg) 5241da177e4SLinus Torvalds { 5251da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue); 5281da177e4SLinus Torvalds list_del(&ipr_cmd->queue); 5291da177e4SLinus Torvalds ipr_init_ipr_cmnd(ipr_cmd); 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds return ipr_cmd; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /** 5351da177e4SLinus Torvalds * ipr_unmap_sglist - Unmap scatterlist if mapped 5361da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 5371da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 5381da177e4SLinus Torvalds * 5391da177e4SLinus Torvalds * Return value: 5401da177e4SLinus Torvalds * nothing 5411da177e4SLinus Torvalds **/ 5421da177e4SLinus Torvalds static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg, 5431da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds if (ipr_cmd->dma_use_sg) { 5481da177e4SLinus Torvalds if (scsi_cmd->use_sg > 0) { 5491da177e4SLinus Torvalds pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer, 5501da177e4SLinus Torvalds scsi_cmd->use_sg, 5511da177e4SLinus Torvalds scsi_cmd->sc_data_direction); 5521da177e4SLinus Torvalds } else { 5531da177e4SLinus Torvalds pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle, 5541da177e4SLinus Torvalds scsi_cmd->request_bufflen, 5551da177e4SLinus Torvalds scsi_cmd->sc_data_direction); 5561da177e4SLinus Torvalds } 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds 5601da177e4SLinus Torvalds /** 5611da177e4SLinus Torvalds * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts 5621da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 5631da177e4SLinus Torvalds * @clr_ints: interrupts to clear 5641da177e4SLinus Torvalds * 5651da177e4SLinus Torvalds * This function masks all interrupts on the adapter, then clears the 5661da177e4SLinus Torvalds * interrupts specified in the mask 5671da177e4SLinus Torvalds * 5681da177e4SLinus Torvalds * Return value: 5691da177e4SLinus Torvalds * none 5701da177e4SLinus Torvalds **/ 5711da177e4SLinus Torvalds static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg, 5721da177e4SLinus Torvalds u32 clr_ints) 5731da177e4SLinus Torvalds { 5741da177e4SLinus Torvalds volatile u32 int_reg; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* Stop new interrupts */ 5771da177e4SLinus Torvalds ioa_cfg->allow_interrupts = 0; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /* Set interrupt mask to stop all new interrupts */ 5801da177e4SLinus Torvalds writel(~0, ioa_cfg->regs.set_interrupt_mask_reg); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds /* Clear any pending interrupts */ 5831da177e4SLinus Torvalds writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg); 5841da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /** 5881da177e4SLinus Torvalds * ipr_save_pcix_cmd_reg - Save PCI-X command register 5891da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 5901da177e4SLinus Torvalds * 5911da177e4SLinus Torvalds * Return value: 5921da177e4SLinus Torvalds * 0 on success / -EIO on failure 5931da177e4SLinus Torvalds **/ 5941da177e4SLinus Torvalds static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) 5951da177e4SLinus Torvalds { 5961da177e4SLinus Torvalds int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds if (pcix_cmd_reg == 0) { 5991da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); 6001da177e4SLinus Torvalds return -EIO; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, 6041da177e4SLinus Torvalds &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { 6051da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); 6061da177e4SLinus Torvalds return -EIO; 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO; 6101da177e4SLinus Torvalds return 0; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds /** 6141da177e4SLinus Torvalds * ipr_set_pcix_cmd_reg - Setup PCI-X command register 6151da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 6161da177e4SLinus Torvalds * 6171da177e4SLinus Torvalds * Return value: 6181da177e4SLinus Torvalds * 0 on success / -EIO on failure 6191da177e4SLinus Torvalds **/ 6201da177e4SLinus Torvalds static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) 6211da177e4SLinus Torvalds { 6221da177e4SLinus Torvalds int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds if (pcix_cmd_reg) { 6251da177e4SLinus Torvalds if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, 6261da177e4SLinus Torvalds ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { 6271da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); 6281da177e4SLinus Torvalds return -EIO; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds } else { 6311da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 6321da177e4SLinus Torvalds "Failed to setup PCI-X command register\n"); 6331da177e4SLinus Torvalds return -EIO; 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds return 0; 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds /** 64035a39691SBrian King * ipr_sata_eh_done - done function for aborted SATA commands 64135a39691SBrian King * @ipr_cmd: ipr command struct 64235a39691SBrian King * 64335a39691SBrian King * This function is invoked for ops generated to SATA 64435a39691SBrian King * devices which are being aborted. 64535a39691SBrian King * 64635a39691SBrian King * Return value: 64735a39691SBrian King * none 64835a39691SBrian King **/ 64935a39691SBrian King static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) 65035a39691SBrian King { 65135a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 65235a39691SBrian King struct ata_queued_cmd *qc = ipr_cmd->qc; 65335a39691SBrian King struct ipr_sata_port *sata_port = qc->ap->private_data; 65435a39691SBrian King 65535a39691SBrian King qc->err_mask |= AC_ERR_OTHER; 65635a39691SBrian King sata_port->ioasa.status |= ATA_BUSY; 65735a39691SBrian King list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 65835a39691SBrian King ata_qc_complete(qc); 65935a39691SBrian King } 66035a39691SBrian King 66135a39691SBrian King /** 6621da177e4SLinus Torvalds * ipr_scsi_eh_done - mid-layer done function for aborted ops 6631da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 6641da177e4SLinus Torvalds * 6651da177e4SLinus Torvalds * This function is invoked by the interrupt handler for 6661da177e4SLinus Torvalds * ops generated by the SCSI mid-layer which are being aborted. 6671da177e4SLinus Torvalds * 6681da177e4SLinus Torvalds * Return value: 6691da177e4SLinus Torvalds * none 6701da177e4SLinus Torvalds **/ 6711da177e4SLinus Torvalds static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) 6721da177e4SLinus Torvalds { 6731da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 6741da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds scsi_cmd->result |= (DID_ERROR << 16); 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds ipr_unmap_sglist(ioa_cfg, ipr_cmd); 6791da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 6801da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds /** 6841da177e4SLinus Torvalds * ipr_fail_all_ops - Fails all outstanding ops. 6851da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 6861da177e4SLinus Torvalds * 6871da177e4SLinus Torvalds * This function fails all outstanding ops. 6881da177e4SLinus Torvalds * 6891da177e4SLinus Torvalds * Return value: 6901da177e4SLinus Torvalds * none 6911da177e4SLinus Torvalds **/ 6921da177e4SLinus Torvalds static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) 6931da177e4SLinus Torvalds { 6941da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd, *temp; 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds ENTER; 6971da177e4SLinus Torvalds list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) { 6981da177e4SLinus Torvalds list_del(&ipr_cmd->queue); 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET); 7011da177e4SLinus Torvalds ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID); 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds if (ipr_cmd->scsi_cmd) 7041da177e4SLinus Torvalds ipr_cmd->done = ipr_scsi_eh_done; 70535a39691SBrian King else if (ipr_cmd->qc) 70635a39691SBrian King ipr_cmd->done = ipr_sata_eh_done; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); 7091da177e4SLinus Torvalds del_timer(&ipr_cmd->timer); 7101da177e4SLinus Torvalds ipr_cmd->done(ipr_cmd); 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds LEAVE; 7141da177e4SLinus Torvalds } 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds /** 7171da177e4SLinus Torvalds * ipr_do_req - Send driver initiated requests. 7181da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 7191da177e4SLinus Torvalds * @done: done function 7201da177e4SLinus Torvalds * @timeout_func: timeout function 7211da177e4SLinus Torvalds * @timeout: timeout value 7221da177e4SLinus Torvalds * 7231da177e4SLinus Torvalds * This function sends the specified command to the adapter with the 7241da177e4SLinus Torvalds * timeout given. The done function is invoked on command completion. 7251da177e4SLinus Torvalds * 7261da177e4SLinus Torvalds * Return value: 7271da177e4SLinus Torvalds * none 7281da177e4SLinus Torvalds **/ 7291da177e4SLinus Torvalds static void ipr_do_req(struct ipr_cmnd *ipr_cmd, 7301da177e4SLinus Torvalds void (*done) (struct ipr_cmnd *), 7311da177e4SLinus Torvalds void (*timeout_func) (struct ipr_cmnd *), u32 timeout) 7321da177e4SLinus Torvalds { 7331da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 7341da177e4SLinus Torvalds 7351da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds ipr_cmd->done = done; 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds ipr_cmd->timer.data = (unsigned long) ipr_cmd; 7401da177e4SLinus Torvalds ipr_cmd->timer.expires = jiffies + timeout; 7411da177e4SLinus Torvalds ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func; 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds add_timer(&ipr_cmd->timer); 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0); 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds mb(); 7481da177e4SLinus Torvalds writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), 7491da177e4SLinus Torvalds ioa_cfg->regs.ioarrin_reg); 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds /** 7531da177e4SLinus Torvalds * ipr_internal_cmd_done - Op done function for an internally generated op. 7541da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 7551da177e4SLinus Torvalds * 7561da177e4SLinus Torvalds * This function is the op done function for an internally generated, 7571da177e4SLinus Torvalds * blocking op. It simply wakes the sleeping thread. 7581da177e4SLinus Torvalds * 7591da177e4SLinus Torvalds * Return value: 7601da177e4SLinus Torvalds * none 7611da177e4SLinus Torvalds **/ 7621da177e4SLinus Torvalds static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd) 7631da177e4SLinus Torvalds { 7641da177e4SLinus Torvalds if (ipr_cmd->sibling) 7651da177e4SLinus Torvalds ipr_cmd->sibling = NULL; 7661da177e4SLinus Torvalds else 7671da177e4SLinus Torvalds complete(&ipr_cmd->completion); 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds /** 7711da177e4SLinus Torvalds * ipr_send_blocking_cmd - Send command and sleep on its completion. 7721da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 7731da177e4SLinus Torvalds * @timeout_func: function to invoke if command times out 7741da177e4SLinus Torvalds * @timeout: timeout 7751da177e4SLinus Torvalds * 7761da177e4SLinus Torvalds * Return value: 7771da177e4SLinus Torvalds * none 7781da177e4SLinus Torvalds **/ 7791da177e4SLinus Torvalds static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, 7801da177e4SLinus Torvalds void (*timeout_func) (struct ipr_cmnd *ipr_cmd), 7811da177e4SLinus Torvalds u32 timeout) 7821da177e4SLinus Torvalds { 7831da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds init_completion(&ipr_cmd->completion); 7861da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout); 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds spin_unlock_irq(ioa_cfg->host->host_lock); 7891da177e4SLinus Torvalds wait_for_completion(&ipr_cmd->completion); 7901da177e4SLinus Torvalds spin_lock_irq(ioa_cfg->host->host_lock); 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds /** 7941da177e4SLinus Torvalds * ipr_send_hcam - Send an HCAM to the adapter. 7951da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 7961da177e4SLinus Torvalds * @type: HCAM type 7971da177e4SLinus Torvalds * @hostrcb: hostrcb struct 7981da177e4SLinus Torvalds * 7991da177e4SLinus Torvalds * This function will send a Host Controlled Async command to the adapter. 8001da177e4SLinus Torvalds * If HCAMs are currently not allowed to be issued to the adapter, it will 8011da177e4SLinus Torvalds * place the hostrcb on the free queue. 8021da177e4SLinus Torvalds * 8031da177e4SLinus Torvalds * Return value: 8041da177e4SLinus Torvalds * none 8051da177e4SLinus Torvalds **/ 8061da177e4SLinus Torvalds static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, 8071da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 8081da177e4SLinus Torvalds { 8091da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 8101da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds if (ioa_cfg->allow_cmds) { 8131da177e4SLinus Torvalds ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 8141da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); 8151da177e4SLinus Torvalds list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q); 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds ipr_cmd->u.hostrcb = hostrcb; 8181da177e4SLinus Torvalds ioarcb = &ipr_cmd->ioarcb; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 8211da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM; 8221da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC; 8231da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[1] = type; 8241da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff; 8251da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff; 8261da177e4SLinus Torvalds 8271da177e4SLinus Torvalds ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam)); 8281da177e4SLinus Torvalds ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 8291da177e4SLinus Torvalds ipr_cmd->ioadl[0].flags_and_data_len = 8301da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam)); 8311da177e4SLinus Torvalds ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma); 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE) 8341da177e4SLinus Torvalds ipr_cmd->done = ipr_process_ccn; 8351da177e4SLinus Torvalds else 8361da177e4SLinus Torvalds ipr_cmd->done = ipr_process_error; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR); 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds mb(); 8411da177e4SLinus Torvalds writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), 8421da177e4SLinus Torvalds ioa_cfg->regs.ioarrin_reg); 8431da177e4SLinus Torvalds } else { 8441da177e4SLinus Torvalds list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); 8451da177e4SLinus Torvalds } 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds /** 8491da177e4SLinus Torvalds * ipr_init_res_entry - Initialize a resource entry struct. 8501da177e4SLinus Torvalds * @res: resource entry struct 8511da177e4SLinus Torvalds * 8521da177e4SLinus Torvalds * Return value: 8531da177e4SLinus Torvalds * none 8541da177e4SLinus Torvalds **/ 8551da177e4SLinus Torvalds static void ipr_init_res_entry(struct ipr_resource_entry *res) 8561da177e4SLinus Torvalds { 857ee0a90faSbrking@us.ibm.com res->needs_sync_complete = 0; 8581da177e4SLinus Torvalds res->in_erp = 0; 8591da177e4SLinus Torvalds res->add_to_ml = 0; 8601da177e4SLinus Torvalds res->del_from_ml = 0; 8611da177e4SLinus Torvalds res->resetting_device = 0; 8621da177e4SLinus Torvalds res->sdev = NULL; 86335a39691SBrian King res->sata_port = NULL; 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds /** 8671da177e4SLinus Torvalds * ipr_handle_config_change - Handle a config change from the adapter 8681da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 8691da177e4SLinus Torvalds * @hostrcb: hostrcb 8701da177e4SLinus Torvalds * 8711da177e4SLinus Torvalds * Return value: 8721da177e4SLinus Torvalds * none 8731da177e4SLinus Torvalds **/ 8741da177e4SLinus Torvalds static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, 8751da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 8761da177e4SLinus Torvalds { 8771da177e4SLinus Torvalds struct ipr_resource_entry *res = NULL; 8781da177e4SLinus Torvalds struct ipr_config_table_entry *cfgte; 8791da177e4SLinus Torvalds u32 is_ndn = 1; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds cfgte = &hostrcb->hcam.u.ccn.cfgte; 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 8841da177e4SLinus Torvalds if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr, 8851da177e4SLinus Torvalds sizeof(cfgte->res_addr))) { 8861da177e4SLinus Torvalds is_ndn = 0; 8871da177e4SLinus Torvalds break; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds if (is_ndn) { 8921da177e4SLinus Torvalds if (list_empty(&ioa_cfg->free_res_q)) { 8931da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, 8941da177e4SLinus Torvalds IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, 8951da177e4SLinus Torvalds hostrcb); 8961da177e4SLinus Torvalds return; 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds res = list_entry(ioa_cfg->free_res_q.next, 9001da177e4SLinus Torvalds struct ipr_resource_entry, queue); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds list_del(&res->queue); 9031da177e4SLinus Torvalds ipr_init_res_entry(res); 9041da177e4SLinus Torvalds list_add_tail(&res->queue, &ioa_cfg->used_res_q); 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry)); 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { 9101da177e4SLinus Torvalds if (res->sdev) { 9111da177e4SLinus Torvalds res->del_from_ml = 1; 9121121b794SBrian King res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; 9131da177e4SLinus Torvalds if (ioa_cfg->allow_ml_add_del) 9141da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 9151da177e4SLinus Torvalds } else 9161da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->free_res_q); 9171da177e4SLinus Torvalds } else if (!res->sdev) { 9181da177e4SLinus Torvalds res->add_to_ml = 1; 9191da177e4SLinus Torvalds if (ioa_cfg->allow_ml_add_del) 9201da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /** 9271da177e4SLinus Torvalds * ipr_process_ccn - Op done function for a CCN. 9281da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 9291da177e4SLinus Torvalds * 9301da177e4SLinus Torvalds * This function is the op done function for a configuration 9311da177e4SLinus Torvalds * change notification host controlled async from the adapter. 9321da177e4SLinus Torvalds * 9331da177e4SLinus Torvalds * Return value: 9341da177e4SLinus Torvalds * none 9351da177e4SLinus Torvalds **/ 9361da177e4SLinus Torvalds static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) 9371da177e4SLinus Torvalds { 9381da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 9391da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; 9401da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds list_del(&hostrcb->queue); 9431da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds if (ioasc) { 9461da177e4SLinus Torvalds if (ioasc != IPR_IOASC_IOA_WAS_RESET) 9471da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 9481da177e4SLinus Torvalds "Host RCB failed with IOASC: 0x%08X\n", ioasc); 9491da177e4SLinus Torvalds 9501da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); 9511da177e4SLinus Torvalds } else { 9521da177e4SLinus Torvalds ipr_handle_config_change(ioa_cfg, hostrcb); 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds /** 9571da177e4SLinus Torvalds * ipr_log_vpd - Log the passed VPD to the error log. 958cfc32139Sbrking@us.ibm.com * @vpd: vendor/product id/sn struct 9591da177e4SLinus Torvalds * 9601da177e4SLinus Torvalds * Return value: 9611da177e4SLinus Torvalds * none 9621da177e4SLinus Torvalds **/ 963cfc32139Sbrking@us.ibm.com static void ipr_log_vpd(struct ipr_vpd *vpd) 9641da177e4SLinus Torvalds { 9651da177e4SLinus Torvalds char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN 9661da177e4SLinus Torvalds + IPR_SERIAL_NUM_LEN]; 9671da177e4SLinus Torvalds 968cfc32139Sbrking@us.ibm.com memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); 969cfc32139Sbrking@us.ibm.com memcpy(buffer + IPR_VENDOR_ID_LEN, vpd->vpids.product_id, 9701da177e4SLinus Torvalds IPR_PROD_ID_LEN); 9711da177e4SLinus Torvalds buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0'; 9721da177e4SLinus Torvalds ipr_err("Vendor/Product ID: %s\n", buffer); 9731da177e4SLinus Torvalds 974cfc32139Sbrking@us.ibm.com memcpy(buffer, vpd->sn, IPR_SERIAL_NUM_LEN); 9751da177e4SLinus Torvalds buffer[IPR_SERIAL_NUM_LEN] = '\0'; 9761da177e4SLinus Torvalds ipr_err(" Serial Number: %s\n", buffer); 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds /** 980ee0f05b8Sbrking@us.ibm.com * ipr_log_ext_vpd - Log the passed extended VPD to the error log. 981ee0f05b8Sbrking@us.ibm.com * @vpd: vendor/product id/sn/wwn struct 982ee0f05b8Sbrking@us.ibm.com * 983ee0f05b8Sbrking@us.ibm.com * Return value: 984ee0f05b8Sbrking@us.ibm.com * none 985ee0f05b8Sbrking@us.ibm.com **/ 986ee0f05b8Sbrking@us.ibm.com static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd) 987ee0f05b8Sbrking@us.ibm.com { 988ee0f05b8Sbrking@us.ibm.com ipr_log_vpd(&vpd->vpd); 989ee0f05b8Sbrking@us.ibm.com ipr_err(" WWN: %08X%08X\n", be32_to_cpu(vpd->wwid[0]), 990ee0f05b8Sbrking@us.ibm.com be32_to_cpu(vpd->wwid[1])); 991ee0f05b8Sbrking@us.ibm.com } 992ee0f05b8Sbrking@us.ibm.com 993ee0f05b8Sbrking@us.ibm.com /** 994ee0f05b8Sbrking@us.ibm.com * ipr_log_enhanced_cache_error - Log a cache error. 995ee0f05b8Sbrking@us.ibm.com * @ioa_cfg: ioa config struct 996ee0f05b8Sbrking@us.ibm.com * @hostrcb: hostrcb struct 997ee0f05b8Sbrking@us.ibm.com * 998ee0f05b8Sbrking@us.ibm.com * Return value: 999ee0f05b8Sbrking@us.ibm.com * none 1000ee0f05b8Sbrking@us.ibm.com **/ 1001ee0f05b8Sbrking@us.ibm.com static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg, 1002ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb *hostrcb) 1003ee0f05b8Sbrking@us.ibm.com { 1004ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_type_12_error *error = 1005ee0f05b8Sbrking@us.ibm.com &hostrcb->hcam.u.error.u.type_12_error; 1006ee0f05b8Sbrking@us.ibm.com 1007ee0f05b8Sbrking@us.ibm.com ipr_err("-----Current Configuration-----\n"); 1008ee0f05b8Sbrking@us.ibm.com ipr_err("Cache Directory Card Information:\n"); 1009ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&error->ioa_vpd); 1010ee0f05b8Sbrking@us.ibm.com ipr_err("Adapter Card Information:\n"); 1011ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&error->cfc_vpd); 1012ee0f05b8Sbrking@us.ibm.com 1013ee0f05b8Sbrking@us.ibm.com ipr_err("-----Expected Configuration-----\n"); 1014ee0f05b8Sbrking@us.ibm.com ipr_err("Cache Directory Card Information:\n"); 1015ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&error->ioa_last_attached_to_cfc_vpd); 1016ee0f05b8Sbrking@us.ibm.com ipr_err("Adapter Card Information:\n"); 1017ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&error->cfc_last_attached_to_ioa_vpd); 1018ee0f05b8Sbrking@us.ibm.com 1019ee0f05b8Sbrking@us.ibm.com ipr_err("Additional IOA Data: %08X %08X %08X\n", 1020ee0f05b8Sbrking@us.ibm.com be32_to_cpu(error->ioa_data[0]), 1021ee0f05b8Sbrking@us.ibm.com be32_to_cpu(error->ioa_data[1]), 1022ee0f05b8Sbrking@us.ibm.com be32_to_cpu(error->ioa_data[2])); 1023ee0f05b8Sbrking@us.ibm.com } 1024ee0f05b8Sbrking@us.ibm.com 1025ee0f05b8Sbrking@us.ibm.com /** 10261da177e4SLinus Torvalds * ipr_log_cache_error - Log a cache error. 10271da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 10281da177e4SLinus Torvalds * @hostrcb: hostrcb struct 10291da177e4SLinus Torvalds * 10301da177e4SLinus Torvalds * Return value: 10311da177e4SLinus Torvalds * none 10321da177e4SLinus Torvalds **/ 10331da177e4SLinus Torvalds static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg, 10341da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 10351da177e4SLinus Torvalds { 10361da177e4SLinus Torvalds struct ipr_hostrcb_type_02_error *error = 10371da177e4SLinus Torvalds &hostrcb->hcam.u.error.u.type_02_error; 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds ipr_err("-----Current Configuration-----\n"); 10401da177e4SLinus Torvalds ipr_err("Cache Directory Card Information:\n"); 1041cfc32139Sbrking@us.ibm.com ipr_log_vpd(&error->ioa_vpd); 10421da177e4SLinus Torvalds ipr_err("Adapter Card Information:\n"); 1043cfc32139Sbrking@us.ibm.com ipr_log_vpd(&error->cfc_vpd); 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds ipr_err("-----Expected Configuration-----\n"); 10461da177e4SLinus Torvalds ipr_err("Cache Directory Card Information:\n"); 1047cfc32139Sbrking@us.ibm.com ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpd); 10481da177e4SLinus Torvalds ipr_err("Adapter Card Information:\n"); 1049cfc32139Sbrking@us.ibm.com ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpd); 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds ipr_err("Additional IOA Data: %08X %08X %08X\n", 10521da177e4SLinus Torvalds be32_to_cpu(error->ioa_data[0]), 10531da177e4SLinus Torvalds be32_to_cpu(error->ioa_data[1]), 10541da177e4SLinus Torvalds be32_to_cpu(error->ioa_data[2])); 10551da177e4SLinus Torvalds } 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds /** 1058ee0f05b8Sbrking@us.ibm.com * ipr_log_enhanced_config_error - Log a configuration error. 1059ee0f05b8Sbrking@us.ibm.com * @ioa_cfg: ioa config struct 1060ee0f05b8Sbrking@us.ibm.com * @hostrcb: hostrcb struct 1061ee0f05b8Sbrking@us.ibm.com * 1062ee0f05b8Sbrking@us.ibm.com * Return value: 1063ee0f05b8Sbrking@us.ibm.com * none 1064ee0f05b8Sbrking@us.ibm.com **/ 1065ee0f05b8Sbrking@us.ibm.com static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg, 1066ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb *hostrcb) 1067ee0f05b8Sbrking@us.ibm.com { 1068ee0f05b8Sbrking@us.ibm.com int errors_logged, i; 1069ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_device_data_entry_enhanced *dev_entry; 1070ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_type_13_error *error; 1071ee0f05b8Sbrking@us.ibm.com 1072ee0f05b8Sbrking@us.ibm.com error = &hostrcb->hcam.u.error.u.type_13_error; 1073ee0f05b8Sbrking@us.ibm.com errors_logged = be32_to_cpu(error->errors_logged); 1074ee0f05b8Sbrking@us.ibm.com 1075ee0f05b8Sbrking@us.ibm.com ipr_err("Device Errors Detected/Logged: %d/%d\n", 1076ee0f05b8Sbrking@us.ibm.com be32_to_cpu(error->errors_detected), errors_logged); 1077ee0f05b8Sbrking@us.ibm.com 1078ee0f05b8Sbrking@us.ibm.com dev_entry = error->dev; 1079ee0f05b8Sbrking@us.ibm.com 1080ee0f05b8Sbrking@us.ibm.com for (i = 0; i < errors_logged; i++, dev_entry++) { 1081ee0f05b8Sbrking@us.ibm.com ipr_err_separator; 1082ee0f05b8Sbrking@us.ibm.com 1083ee0f05b8Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); 1084ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&dev_entry->vpd); 1085ee0f05b8Sbrking@us.ibm.com 1086ee0f05b8Sbrking@us.ibm.com ipr_err("-----New Device Information-----\n"); 1087ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&dev_entry->new_vpd); 1088ee0f05b8Sbrking@us.ibm.com 1089ee0f05b8Sbrking@us.ibm.com ipr_err("Cache Directory Card Information:\n"); 1090ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd); 1091ee0f05b8Sbrking@us.ibm.com 1092ee0f05b8Sbrking@us.ibm.com ipr_err("Adapter Card Information:\n"); 1093ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd); 1094ee0f05b8Sbrking@us.ibm.com } 1095ee0f05b8Sbrking@us.ibm.com } 1096ee0f05b8Sbrking@us.ibm.com 1097ee0f05b8Sbrking@us.ibm.com /** 10981da177e4SLinus Torvalds * ipr_log_config_error - Log a configuration error. 10991da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 11001da177e4SLinus Torvalds * @hostrcb: hostrcb struct 11011da177e4SLinus Torvalds * 11021da177e4SLinus Torvalds * Return value: 11031da177e4SLinus Torvalds * none 11041da177e4SLinus Torvalds **/ 11051da177e4SLinus Torvalds static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg, 11061da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 11071da177e4SLinus Torvalds { 11081da177e4SLinus Torvalds int errors_logged, i; 11091da177e4SLinus Torvalds struct ipr_hostrcb_device_data_entry *dev_entry; 11101da177e4SLinus Torvalds struct ipr_hostrcb_type_03_error *error; 11111da177e4SLinus Torvalds 11121da177e4SLinus Torvalds error = &hostrcb->hcam.u.error.u.type_03_error; 11131da177e4SLinus Torvalds errors_logged = be32_to_cpu(error->errors_logged); 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds ipr_err("Device Errors Detected/Logged: %d/%d\n", 11161da177e4SLinus Torvalds be32_to_cpu(error->errors_detected), errors_logged); 11171da177e4SLinus Torvalds 1118cfc32139Sbrking@us.ibm.com dev_entry = error->dev; 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds for (i = 0; i < errors_logged; i++, dev_entry++) { 11211da177e4SLinus Torvalds ipr_err_separator; 11221da177e4SLinus Torvalds 1123fa15b1f6Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); 1124cfc32139Sbrking@us.ibm.com ipr_log_vpd(&dev_entry->vpd); 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds ipr_err("-----New Device Information-----\n"); 1127cfc32139Sbrking@us.ibm.com ipr_log_vpd(&dev_entry->new_vpd); 11281da177e4SLinus Torvalds 11291da177e4SLinus Torvalds ipr_err("Cache Directory Card Information:\n"); 1130cfc32139Sbrking@us.ibm.com ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpd); 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds ipr_err("Adapter Card Information:\n"); 1133cfc32139Sbrking@us.ibm.com ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpd); 11341da177e4SLinus Torvalds 11351da177e4SLinus Torvalds ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n", 11361da177e4SLinus Torvalds be32_to_cpu(dev_entry->ioa_data[0]), 11371da177e4SLinus Torvalds be32_to_cpu(dev_entry->ioa_data[1]), 11381da177e4SLinus Torvalds be32_to_cpu(dev_entry->ioa_data[2]), 11391da177e4SLinus Torvalds be32_to_cpu(dev_entry->ioa_data[3]), 11401da177e4SLinus Torvalds be32_to_cpu(dev_entry->ioa_data[4])); 11411da177e4SLinus Torvalds } 11421da177e4SLinus Torvalds } 11431da177e4SLinus Torvalds 11441da177e4SLinus Torvalds /** 1145ee0f05b8Sbrking@us.ibm.com * ipr_log_enhanced_array_error - Log an array configuration error. 1146ee0f05b8Sbrking@us.ibm.com * @ioa_cfg: ioa config struct 1147ee0f05b8Sbrking@us.ibm.com * @hostrcb: hostrcb struct 1148ee0f05b8Sbrking@us.ibm.com * 1149ee0f05b8Sbrking@us.ibm.com * Return value: 1150ee0f05b8Sbrking@us.ibm.com * none 1151ee0f05b8Sbrking@us.ibm.com **/ 1152ee0f05b8Sbrking@us.ibm.com static void ipr_log_enhanced_array_error(struct ipr_ioa_cfg *ioa_cfg, 1153ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb *hostrcb) 1154ee0f05b8Sbrking@us.ibm.com { 1155ee0f05b8Sbrking@us.ibm.com int i, num_entries; 1156ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_type_14_error *error; 1157ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_array_data_entry_enhanced *array_entry; 1158ee0f05b8Sbrking@us.ibm.com const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; 1159ee0f05b8Sbrking@us.ibm.com 1160ee0f05b8Sbrking@us.ibm.com error = &hostrcb->hcam.u.error.u.type_14_error; 1161ee0f05b8Sbrking@us.ibm.com 1162ee0f05b8Sbrking@us.ibm.com ipr_err_separator; 1163ee0f05b8Sbrking@us.ibm.com 1164ee0f05b8Sbrking@us.ibm.com ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", 1165ee0f05b8Sbrking@us.ibm.com error->protection_level, 1166ee0f05b8Sbrking@us.ibm.com ioa_cfg->host->host_no, 1167ee0f05b8Sbrking@us.ibm.com error->last_func_vset_res_addr.bus, 1168ee0f05b8Sbrking@us.ibm.com error->last_func_vset_res_addr.target, 1169ee0f05b8Sbrking@us.ibm.com error->last_func_vset_res_addr.lun); 1170ee0f05b8Sbrking@us.ibm.com 1171ee0f05b8Sbrking@us.ibm.com ipr_err_separator; 1172ee0f05b8Sbrking@us.ibm.com 1173ee0f05b8Sbrking@us.ibm.com array_entry = error->array_member; 1174ee0f05b8Sbrking@us.ibm.com num_entries = min_t(u32, be32_to_cpu(error->num_entries), 1175ee0f05b8Sbrking@us.ibm.com sizeof(error->array_member)); 1176ee0f05b8Sbrking@us.ibm.com 1177ee0f05b8Sbrking@us.ibm.com for (i = 0; i < num_entries; i++, array_entry++) { 1178ee0f05b8Sbrking@us.ibm.com if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) 1179ee0f05b8Sbrking@us.ibm.com continue; 1180ee0f05b8Sbrking@us.ibm.com 1181ee0f05b8Sbrking@us.ibm.com if (be32_to_cpu(error->exposed_mode_adn) == i) 1182ee0f05b8Sbrking@us.ibm.com ipr_err("Exposed Array Member %d:\n", i); 1183ee0f05b8Sbrking@us.ibm.com else 1184ee0f05b8Sbrking@us.ibm.com ipr_err("Array Member %d:\n", i); 1185ee0f05b8Sbrking@us.ibm.com 1186ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&array_entry->vpd); 1187ee0f05b8Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); 1188ee0f05b8Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, 1189ee0f05b8Sbrking@us.ibm.com "Expected Location"); 1190ee0f05b8Sbrking@us.ibm.com 1191ee0f05b8Sbrking@us.ibm.com ipr_err_separator; 1192ee0f05b8Sbrking@us.ibm.com } 1193ee0f05b8Sbrking@us.ibm.com } 1194ee0f05b8Sbrking@us.ibm.com 1195ee0f05b8Sbrking@us.ibm.com /** 11961da177e4SLinus Torvalds * ipr_log_array_error - Log an array configuration error. 11971da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 11981da177e4SLinus Torvalds * @hostrcb: hostrcb struct 11991da177e4SLinus Torvalds * 12001da177e4SLinus Torvalds * Return value: 12011da177e4SLinus Torvalds * none 12021da177e4SLinus Torvalds **/ 12031da177e4SLinus Torvalds static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, 12041da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 12051da177e4SLinus Torvalds { 12061da177e4SLinus Torvalds int i; 12071da177e4SLinus Torvalds struct ipr_hostrcb_type_04_error *error; 12081da177e4SLinus Torvalds struct ipr_hostrcb_array_data_entry *array_entry; 12091da177e4SLinus Torvalds const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds error = &hostrcb->hcam.u.error.u.type_04_error; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds ipr_err_separator; 12141da177e4SLinus Torvalds 12151da177e4SLinus Torvalds ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", 12161da177e4SLinus Torvalds error->protection_level, 12171da177e4SLinus Torvalds ioa_cfg->host->host_no, 12181da177e4SLinus Torvalds error->last_func_vset_res_addr.bus, 12191da177e4SLinus Torvalds error->last_func_vset_res_addr.target, 12201da177e4SLinus Torvalds error->last_func_vset_res_addr.lun); 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds ipr_err_separator; 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds array_entry = error->array_member; 12251da177e4SLinus Torvalds 12261da177e4SLinus Torvalds for (i = 0; i < 18; i++) { 1227cfc32139Sbrking@us.ibm.com if (!memcmp(array_entry->vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) 12281da177e4SLinus Torvalds continue; 12291da177e4SLinus Torvalds 1230fa15b1f6Sbrking@us.ibm.com if (be32_to_cpu(error->exposed_mode_adn) == i) 12311da177e4SLinus Torvalds ipr_err("Exposed Array Member %d:\n", i); 1232fa15b1f6Sbrking@us.ibm.com else 12331da177e4SLinus Torvalds ipr_err("Array Member %d:\n", i); 12341da177e4SLinus Torvalds 1235cfc32139Sbrking@us.ibm.com ipr_log_vpd(&array_entry->vpd); 12361da177e4SLinus Torvalds 1237fa15b1f6Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); 1238fa15b1f6Sbrking@us.ibm.com ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, 1239fa15b1f6Sbrking@us.ibm.com "Expected Location"); 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds ipr_err_separator; 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds if (i == 9) 12441da177e4SLinus Torvalds array_entry = error->array_member2; 12451da177e4SLinus Torvalds else 12461da177e4SLinus Torvalds array_entry++; 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds } 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds /** 1251b0df54bbSbrking@us.ibm.com * ipr_log_hex_data - Log additional hex IOA error data. 1252ac719abaSBrian King * @ioa_cfg: ioa config struct 1253b0df54bbSbrking@us.ibm.com * @data: IOA error data 1254b0df54bbSbrking@us.ibm.com * @len: data length 1255b0df54bbSbrking@us.ibm.com * 1256b0df54bbSbrking@us.ibm.com * Return value: 1257b0df54bbSbrking@us.ibm.com * none 1258b0df54bbSbrking@us.ibm.com **/ 1259ac719abaSBrian King static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len) 1260b0df54bbSbrking@us.ibm.com { 1261b0df54bbSbrking@us.ibm.com int i; 1262b0df54bbSbrking@us.ibm.com 1263b0df54bbSbrking@us.ibm.com if (len == 0) 1264b0df54bbSbrking@us.ibm.com return; 1265b0df54bbSbrking@us.ibm.com 1266ac719abaSBrian King if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL) 1267ac719abaSBrian King len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP); 1268ac719abaSBrian King 1269b0df54bbSbrking@us.ibm.com for (i = 0; i < len / 4; i += 4) { 1270b0df54bbSbrking@us.ibm.com ipr_err("%08X: %08X %08X %08X %08X\n", i*4, 1271b0df54bbSbrking@us.ibm.com be32_to_cpu(data[i]), 1272b0df54bbSbrking@us.ibm.com be32_to_cpu(data[i+1]), 1273b0df54bbSbrking@us.ibm.com be32_to_cpu(data[i+2]), 1274b0df54bbSbrking@us.ibm.com be32_to_cpu(data[i+3])); 1275b0df54bbSbrking@us.ibm.com } 1276b0df54bbSbrking@us.ibm.com } 1277b0df54bbSbrking@us.ibm.com 1278b0df54bbSbrking@us.ibm.com /** 1279ee0f05b8Sbrking@us.ibm.com * ipr_log_enhanced_dual_ioa_error - Log an enhanced dual adapter error. 1280ee0f05b8Sbrking@us.ibm.com * @ioa_cfg: ioa config struct 1281ee0f05b8Sbrking@us.ibm.com * @hostrcb: hostrcb struct 1282ee0f05b8Sbrking@us.ibm.com * 1283ee0f05b8Sbrking@us.ibm.com * Return value: 1284ee0f05b8Sbrking@us.ibm.com * none 1285ee0f05b8Sbrking@us.ibm.com **/ 1286ee0f05b8Sbrking@us.ibm.com static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, 1287ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb *hostrcb) 1288ee0f05b8Sbrking@us.ibm.com { 1289ee0f05b8Sbrking@us.ibm.com struct ipr_hostrcb_type_17_error *error; 1290ee0f05b8Sbrking@us.ibm.com 1291ee0f05b8Sbrking@us.ibm.com error = &hostrcb->hcam.u.error.u.type_17_error; 1292ee0f05b8Sbrking@us.ibm.com error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; 1293ee0f05b8Sbrking@us.ibm.com 1294ee0f05b8Sbrking@us.ibm.com ipr_err("%s\n", error->failure_reason); 1295ee0f05b8Sbrking@us.ibm.com ipr_err("Remote Adapter VPD:\n"); 1296ee0f05b8Sbrking@us.ibm.com ipr_log_ext_vpd(&error->vpd); 1297ac719abaSBrian King ipr_log_hex_data(ioa_cfg, error->data, 1298ee0f05b8Sbrking@us.ibm.com be32_to_cpu(hostrcb->hcam.length) - 1299ee0f05b8Sbrking@us.ibm.com (offsetof(struct ipr_hostrcb_error, u) + 1300ee0f05b8Sbrking@us.ibm.com offsetof(struct ipr_hostrcb_type_17_error, data))); 1301ee0f05b8Sbrking@us.ibm.com } 1302ee0f05b8Sbrking@us.ibm.com 1303ee0f05b8Sbrking@us.ibm.com /** 1304b0df54bbSbrking@us.ibm.com * ipr_log_dual_ioa_error - Log a dual adapter error. 1305b0df54bbSbrking@us.ibm.com * @ioa_cfg: ioa config struct 1306b0df54bbSbrking@us.ibm.com * @hostrcb: hostrcb struct 1307b0df54bbSbrking@us.ibm.com * 1308b0df54bbSbrking@us.ibm.com * Return value: 1309b0df54bbSbrking@us.ibm.com * none 1310b0df54bbSbrking@us.ibm.com **/ 1311b0df54bbSbrking@us.ibm.com static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, 1312b0df54bbSbrking@us.ibm.com struct ipr_hostrcb *hostrcb) 1313b0df54bbSbrking@us.ibm.com { 1314b0df54bbSbrking@us.ibm.com struct ipr_hostrcb_type_07_error *error; 1315b0df54bbSbrking@us.ibm.com 1316b0df54bbSbrking@us.ibm.com error = &hostrcb->hcam.u.error.u.type_07_error; 1317b0df54bbSbrking@us.ibm.com error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; 1318b0df54bbSbrking@us.ibm.com 1319b0df54bbSbrking@us.ibm.com ipr_err("%s\n", error->failure_reason); 1320b0df54bbSbrking@us.ibm.com ipr_err("Remote Adapter VPD:\n"); 1321b0df54bbSbrking@us.ibm.com ipr_log_vpd(&error->vpd); 1322ac719abaSBrian King ipr_log_hex_data(ioa_cfg, error->data, 1323b0df54bbSbrking@us.ibm.com be32_to_cpu(hostrcb->hcam.length) - 1324b0df54bbSbrking@us.ibm.com (offsetof(struct ipr_hostrcb_error, u) + 1325b0df54bbSbrking@us.ibm.com offsetof(struct ipr_hostrcb_type_07_error, data))); 1326b0df54bbSbrking@us.ibm.com } 1327b0df54bbSbrking@us.ibm.com 132849dc6a18SBrian King static const struct { 132949dc6a18SBrian King u8 active; 133049dc6a18SBrian King char *desc; 133149dc6a18SBrian King } path_active_desc[] = { 133249dc6a18SBrian King { IPR_PATH_NO_INFO, "Path" }, 133349dc6a18SBrian King { IPR_PATH_ACTIVE, "Active path" }, 133449dc6a18SBrian King { IPR_PATH_NOT_ACTIVE, "Inactive path" } 133549dc6a18SBrian King }; 133649dc6a18SBrian King 133749dc6a18SBrian King static const struct { 133849dc6a18SBrian King u8 state; 133949dc6a18SBrian King char *desc; 134049dc6a18SBrian King } path_state_desc[] = { 134149dc6a18SBrian King { IPR_PATH_STATE_NO_INFO, "has no path state information available" }, 134249dc6a18SBrian King { IPR_PATH_HEALTHY, "is healthy" }, 134349dc6a18SBrian King { IPR_PATH_DEGRADED, "is degraded" }, 134449dc6a18SBrian King { IPR_PATH_FAILED, "is failed" } 134549dc6a18SBrian King }; 134649dc6a18SBrian King 134749dc6a18SBrian King /** 134849dc6a18SBrian King * ipr_log_fabric_path - Log a fabric path error 134949dc6a18SBrian King * @hostrcb: hostrcb struct 135049dc6a18SBrian King * @fabric: fabric descriptor 135149dc6a18SBrian King * 135249dc6a18SBrian King * Return value: 135349dc6a18SBrian King * none 135449dc6a18SBrian King **/ 135549dc6a18SBrian King static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb, 135649dc6a18SBrian King struct ipr_hostrcb_fabric_desc *fabric) 135749dc6a18SBrian King { 135849dc6a18SBrian King int i, j; 135949dc6a18SBrian King u8 path_state = fabric->path_state; 136049dc6a18SBrian King u8 active = path_state & IPR_PATH_ACTIVE_MASK; 136149dc6a18SBrian King u8 state = path_state & IPR_PATH_STATE_MASK; 136249dc6a18SBrian King 136349dc6a18SBrian King for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { 136449dc6a18SBrian King if (path_active_desc[i].active != active) 136549dc6a18SBrian King continue; 136649dc6a18SBrian King 136749dc6a18SBrian King for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { 136849dc6a18SBrian King if (path_state_desc[j].state != state) 136949dc6a18SBrian King continue; 137049dc6a18SBrian King 137149dc6a18SBrian King if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) { 137249dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n", 137349dc6a18SBrian King path_active_desc[i].desc, path_state_desc[j].desc, 137449dc6a18SBrian King fabric->ioa_port); 137549dc6a18SBrian King } else if (fabric->cascaded_expander == 0xff) { 137649dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n", 137749dc6a18SBrian King path_active_desc[i].desc, path_state_desc[j].desc, 137849dc6a18SBrian King fabric->ioa_port, fabric->phy); 137949dc6a18SBrian King } else if (fabric->phy == 0xff) { 138049dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n", 138149dc6a18SBrian King path_active_desc[i].desc, path_state_desc[j].desc, 138249dc6a18SBrian King fabric->ioa_port, fabric->cascaded_expander); 138349dc6a18SBrian King } else { 138449dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n", 138549dc6a18SBrian King path_active_desc[i].desc, path_state_desc[j].desc, 138649dc6a18SBrian King fabric->ioa_port, fabric->cascaded_expander, fabric->phy); 138749dc6a18SBrian King } 138849dc6a18SBrian King return; 138949dc6a18SBrian King } 139049dc6a18SBrian King } 139149dc6a18SBrian King 139249dc6a18SBrian King ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state, 139349dc6a18SBrian King fabric->ioa_port, fabric->cascaded_expander, fabric->phy); 139449dc6a18SBrian King } 139549dc6a18SBrian King 139649dc6a18SBrian King static const struct { 139749dc6a18SBrian King u8 type; 139849dc6a18SBrian King char *desc; 139949dc6a18SBrian King } path_type_desc[] = { 140049dc6a18SBrian King { IPR_PATH_CFG_IOA_PORT, "IOA port" }, 140149dc6a18SBrian King { IPR_PATH_CFG_EXP_PORT, "Expander port" }, 140249dc6a18SBrian King { IPR_PATH_CFG_DEVICE_PORT, "Device port" }, 140349dc6a18SBrian King { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" } 140449dc6a18SBrian King }; 140549dc6a18SBrian King 140649dc6a18SBrian King static const struct { 140749dc6a18SBrian King u8 status; 140849dc6a18SBrian King char *desc; 140949dc6a18SBrian King } path_status_desc[] = { 141049dc6a18SBrian King { IPR_PATH_CFG_NO_PROB, "Functional" }, 141149dc6a18SBrian King { IPR_PATH_CFG_DEGRADED, "Degraded" }, 141249dc6a18SBrian King { IPR_PATH_CFG_FAILED, "Failed" }, 141349dc6a18SBrian King { IPR_PATH_CFG_SUSPECT, "Suspect" }, 141449dc6a18SBrian King { IPR_PATH_NOT_DETECTED, "Missing" }, 141549dc6a18SBrian King { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" } 141649dc6a18SBrian King }; 141749dc6a18SBrian King 141849dc6a18SBrian King static const char *link_rate[] = { 141949dc6a18SBrian King "unknown", 142049dc6a18SBrian King "disabled", 142149dc6a18SBrian King "phy reset problem", 142249dc6a18SBrian King "spinup hold", 142349dc6a18SBrian King "port selector", 142449dc6a18SBrian King "unknown", 142549dc6a18SBrian King "unknown", 142649dc6a18SBrian King "unknown", 142749dc6a18SBrian King "1.5Gbps", 142849dc6a18SBrian King "3.0Gbps", 142949dc6a18SBrian King "unknown", 143049dc6a18SBrian King "unknown", 143149dc6a18SBrian King "unknown", 143249dc6a18SBrian King "unknown", 143349dc6a18SBrian King "unknown", 143449dc6a18SBrian King "unknown" 143549dc6a18SBrian King }; 143649dc6a18SBrian King 143749dc6a18SBrian King /** 143849dc6a18SBrian King * ipr_log_path_elem - Log a fabric path element. 143949dc6a18SBrian King * @hostrcb: hostrcb struct 144049dc6a18SBrian King * @cfg: fabric path element struct 144149dc6a18SBrian King * 144249dc6a18SBrian King * Return value: 144349dc6a18SBrian King * none 144449dc6a18SBrian King **/ 144549dc6a18SBrian King static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb, 144649dc6a18SBrian King struct ipr_hostrcb_config_element *cfg) 144749dc6a18SBrian King { 144849dc6a18SBrian King int i, j; 144949dc6a18SBrian King u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; 145049dc6a18SBrian King u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; 145149dc6a18SBrian King 145249dc6a18SBrian King if (type == IPR_PATH_CFG_NOT_EXIST) 145349dc6a18SBrian King return; 145449dc6a18SBrian King 145549dc6a18SBrian King for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { 145649dc6a18SBrian King if (path_type_desc[i].type != type) 145749dc6a18SBrian King continue; 145849dc6a18SBrian King 145949dc6a18SBrian King for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { 146049dc6a18SBrian King if (path_status_desc[j].status != status) 146149dc6a18SBrian King continue; 146249dc6a18SBrian King 146349dc6a18SBrian King if (type == IPR_PATH_CFG_IOA_PORT) { 146449dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n", 146549dc6a18SBrian King path_status_desc[j].desc, path_type_desc[i].desc, 146649dc6a18SBrian King cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 146749dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 146849dc6a18SBrian King } else { 146949dc6a18SBrian King if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) { 147049dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n", 147149dc6a18SBrian King path_status_desc[j].desc, path_type_desc[i].desc, 147249dc6a18SBrian King link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 147349dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 147449dc6a18SBrian King } else if (cfg->cascaded_expander == 0xff) { 147549dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, " 147649dc6a18SBrian King "WWN=%08X%08X\n", path_status_desc[j].desc, 147749dc6a18SBrian King path_type_desc[i].desc, cfg->phy, 147849dc6a18SBrian King link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 147949dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 148049dc6a18SBrian King } else if (cfg->phy == 0xff) { 148149dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, " 148249dc6a18SBrian King "WWN=%08X%08X\n", path_status_desc[j].desc, 148349dc6a18SBrian King path_type_desc[i].desc, cfg->cascaded_expander, 148449dc6a18SBrian King link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 148549dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 148649dc6a18SBrian King } else { 148749dc6a18SBrian King ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s " 148849dc6a18SBrian King "WWN=%08X%08X\n", path_status_desc[j].desc, 148949dc6a18SBrian King path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy, 149049dc6a18SBrian King link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 149149dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 149249dc6a18SBrian King } 149349dc6a18SBrian King } 149449dc6a18SBrian King return; 149549dc6a18SBrian King } 149649dc6a18SBrian King } 149749dc6a18SBrian King 149849dc6a18SBrian King ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s " 149949dc6a18SBrian King "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy, 150049dc6a18SBrian King link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], 150149dc6a18SBrian King be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); 150249dc6a18SBrian King } 150349dc6a18SBrian King 150449dc6a18SBrian King /** 150549dc6a18SBrian King * ipr_log_fabric_error - Log a fabric error. 150649dc6a18SBrian King * @ioa_cfg: ioa config struct 150749dc6a18SBrian King * @hostrcb: hostrcb struct 150849dc6a18SBrian King * 150949dc6a18SBrian King * Return value: 151049dc6a18SBrian King * none 151149dc6a18SBrian King **/ 151249dc6a18SBrian King static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, 151349dc6a18SBrian King struct ipr_hostrcb *hostrcb) 151449dc6a18SBrian King { 151549dc6a18SBrian King struct ipr_hostrcb_type_20_error *error; 151649dc6a18SBrian King struct ipr_hostrcb_fabric_desc *fabric; 151749dc6a18SBrian King struct ipr_hostrcb_config_element *cfg; 151849dc6a18SBrian King int i, add_len; 151949dc6a18SBrian King 152049dc6a18SBrian King error = &hostrcb->hcam.u.error.u.type_20_error; 152149dc6a18SBrian King error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; 152249dc6a18SBrian King ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); 152349dc6a18SBrian King 152449dc6a18SBrian King add_len = be32_to_cpu(hostrcb->hcam.length) - 152549dc6a18SBrian King (offsetof(struct ipr_hostrcb_error, u) + 152649dc6a18SBrian King offsetof(struct ipr_hostrcb_type_20_error, desc)); 152749dc6a18SBrian King 152849dc6a18SBrian King for (i = 0, fabric = error->desc; i < error->num_entries; i++) { 152949dc6a18SBrian King ipr_log_fabric_path(hostrcb, fabric); 153049dc6a18SBrian King for_each_fabric_cfg(fabric, cfg) 153149dc6a18SBrian King ipr_log_path_elem(hostrcb, cfg); 153249dc6a18SBrian King 153349dc6a18SBrian King add_len -= be16_to_cpu(fabric->length); 153449dc6a18SBrian King fabric = (struct ipr_hostrcb_fabric_desc *) 153549dc6a18SBrian King ((unsigned long)fabric + be16_to_cpu(fabric->length)); 153649dc6a18SBrian King } 153749dc6a18SBrian King 1538ac719abaSBrian King ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); 153949dc6a18SBrian King } 154049dc6a18SBrian King 1541b0df54bbSbrking@us.ibm.com /** 15421da177e4SLinus Torvalds * ipr_log_generic_error - Log an adapter error. 15431da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 15441da177e4SLinus Torvalds * @hostrcb: hostrcb struct 15451da177e4SLinus Torvalds * 15461da177e4SLinus Torvalds * Return value: 15471da177e4SLinus Torvalds * none 15481da177e4SLinus Torvalds **/ 15491da177e4SLinus Torvalds static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, 15501da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 15511da177e4SLinus Torvalds { 1552ac719abaSBrian King ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data, 1553b0df54bbSbrking@us.ibm.com be32_to_cpu(hostrcb->hcam.length)); 15541da177e4SLinus Torvalds } 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds /** 15571da177e4SLinus Torvalds * ipr_get_error - Find the specfied IOASC in the ipr_error_table. 15581da177e4SLinus Torvalds * @ioasc: IOASC 15591da177e4SLinus Torvalds * 15601da177e4SLinus Torvalds * This function will return the index of into the ipr_error_table 15611da177e4SLinus Torvalds * for the specified IOASC. If the IOASC is not in the table, 15621da177e4SLinus Torvalds * 0 will be returned, which points to the entry used for unknown errors. 15631da177e4SLinus Torvalds * 15641da177e4SLinus Torvalds * Return value: 15651da177e4SLinus Torvalds * index into the ipr_error_table 15661da177e4SLinus Torvalds **/ 15671da177e4SLinus Torvalds static u32 ipr_get_error(u32 ioasc) 15681da177e4SLinus Torvalds { 15691da177e4SLinus Torvalds int i; 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++) 157235a39691SBrian King if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK)) 15731da177e4SLinus Torvalds return i; 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds return 0; 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds /** 15791da177e4SLinus Torvalds * ipr_handle_log_data - Log an adapter error. 15801da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 15811da177e4SLinus Torvalds * @hostrcb: hostrcb struct 15821da177e4SLinus Torvalds * 15831da177e4SLinus Torvalds * This function logs an adapter error to the system. 15841da177e4SLinus Torvalds * 15851da177e4SLinus Torvalds * Return value: 15861da177e4SLinus Torvalds * none 15871da177e4SLinus Torvalds **/ 15881da177e4SLinus Torvalds static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, 15891da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb) 15901da177e4SLinus Torvalds { 15911da177e4SLinus Torvalds u32 ioasc; 15921da177e4SLinus Torvalds int error_index; 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY) 15951da177e4SLinus Torvalds return; 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST) 15981da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n"); 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); 16011da177e4SLinus Torvalds 16021da177e4SLinus Torvalds if (ioasc == IPR_IOASC_BUS_WAS_RESET || 16031da177e4SLinus Torvalds ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) { 16041da177e4SLinus Torvalds /* Tell the midlayer we had a bus reset so it will handle the UA properly */ 16051da177e4SLinus Torvalds scsi_report_bus_reset(ioa_cfg->host, 16061da177e4SLinus Torvalds hostrcb->hcam.u.error.failing_dev_res_addr.bus); 16071da177e4SLinus Torvalds } 16081da177e4SLinus Torvalds 16091da177e4SLinus Torvalds error_index = ipr_get_error(ioasc); 16101da177e4SLinus Torvalds 16111da177e4SLinus Torvalds if (!ipr_error_table[error_index].log_hcam) 16121da177e4SLinus Torvalds return; 16131da177e4SLinus Torvalds 161449dc6a18SBrian King ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error); 16151da177e4SLinus Torvalds 16161da177e4SLinus Torvalds /* Set indication we have logged an error */ 16171da177e4SLinus Torvalds ioa_cfg->errors_logged++; 16181da177e4SLinus Torvalds 16191da177e4SLinus Torvalds if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) 16201da177e4SLinus Torvalds return; 1621cf852037Sbrking@us.ibm.com if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw)) 1622cf852037Sbrking@us.ibm.com hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw)); 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds switch (hostrcb->hcam.overlay_id) { 16251da177e4SLinus Torvalds case IPR_HOST_RCB_OVERLAY_ID_2: 16261da177e4SLinus Torvalds ipr_log_cache_error(ioa_cfg, hostrcb); 16271da177e4SLinus Torvalds break; 16281da177e4SLinus Torvalds case IPR_HOST_RCB_OVERLAY_ID_3: 16291da177e4SLinus Torvalds ipr_log_config_error(ioa_cfg, hostrcb); 16301da177e4SLinus Torvalds break; 16311da177e4SLinus Torvalds case IPR_HOST_RCB_OVERLAY_ID_4: 16321da177e4SLinus Torvalds case IPR_HOST_RCB_OVERLAY_ID_6: 16331da177e4SLinus Torvalds ipr_log_array_error(ioa_cfg, hostrcb); 16341da177e4SLinus Torvalds break; 1635b0df54bbSbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_7: 1636b0df54bbSbrking@us.ibm.com ipr_log_dual_ioa_error(ioa_cfg, hostrcb); 1637b0df54bbSbrking@us.ibm.com break; 1638ee0f05b8Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_12: 1639ee0f05b8Sbrking@us.ibm.com ipr_log_enhanced_cache_error(ioa_cfg, hostrcb); 1640ee0f05b8Sbrking@us.ibm.com break; 1641ee0f05b8Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_13: 1642ee0f05b8Sbrking@us.ibm.com ipr_log_enhanced_config_error(ioa_cfg, hostrcb); 1643ee0f05b8Sbrking@us.ibm.com break; 1644ee0f05b8Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_14: 1645ee0f05b8Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_16: 1646ee0f05b8Sbrking@us.ibm.com ipr_log_enhanced_array_error(ioa_cfg, hostrcb); 1647ee0f05b8Sbrking@us.ibm.com break; 1648ee0f05b8Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_17: 1649ee0f05b8Sbrking@us.ibm.com ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); 1650ee0f05b8Sbrking@us.ibm.com break; 165149dc6a18SBrian King case IPR_HOST_RCB_OVERLAY_ID_20: 165249dc6a18SBrian King ipr_log_fabric_error(ioa_cfg, hostrcb); 165349dc6a18SBrian King break; 1654cf852037Sbrking@us.ibm.com case IPR_HOST_RCB_OVERLAY_ID_1: 16551da177e4SLinus Torvalds case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: 16561da177e4SLinus Torvalds default: 1657a9cfca96Sbrking@us.ibm.com ipr_log_generic_error(ioa_cfg, hostrcb); 16581da177e4SLinus Torvalds break; 16591da177e4SLinus Torvalds } 16601da177e4SLinus Torvalds } 16611da177e4SLinus Torvalds 16621da177e4SLinus Torvalds /** 16631da177e4SLinus Torvalds * ipr_process_error - Op done function for an adapter error log. 16641da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 16651da177e4SLinus Torvalds * 16661da177e4SLinus Torvalds * This function is the op done function for an error log host 16671da177e4SLinus Torvalds * controlled async from the adapter. It will log the error and 16681da177e4SLinus Torvalds * send the HCAM back to the adapter. 16691da177e4SLinus Torvalds * 16701da177e4SLinus Torvalds * Return value: 16711da177e4SLinus Torvalds * none 16721da177e4SLinus Torvalds **/ 16731da177e4SLinus Torvalds static void ipr_process_error(struct ipr_cmnd *ipr_cmd) 16741da177e4SLinus Torvalds { 16751da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 16761da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; 16771da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 16781da177e4SLinus Torvalds 16791da177e4SLinus Torvalds list_del(&hostrcb->queue); 16801da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 16811da177e4SLinus Torvalds 16821da177e4SLinus Torvalds if (!ioasc) { 16831da177e4SLinus Torvalds ipr_handle_log_data(ioa_cfg, hostrcb); 16841da177e4SLinus Torvalds } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) { 16851da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 16861da177e4SLinus Torvalds "Host RCB failed with IOASC: 0x%08X\n", ioasc); 16871da177e4SLinus Torvalds } 16881da177e4SLinus Torvalds 16891da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds 16921da177e4SLinus Torvalds /** 16931da177e4SLinus Torvalds * ipr_timeout - An internally generated op has timed out. 16941da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 16951da177e4SLinus Torvalds * 16961da177e4SLinus Torvalds * This function blocks host requests and initiates an 16971da177e4SLinus Torvalds * adapter reset. 16981da177e4SLinus Torvalds * 16991da177e4SLinus Torvalds * Return value: 17001da177e4SLinus Torvalds * none 17011da177e4SLinus Torvalds **/ 17021da177e4SLinus Torvalds static void ipr_timeout(struct ipr_cmnd *ipr_cmd) 17031da177e4SLinus Torvalds { 17041da177e4SLinus Torvalds unsigned long lock_flags = 0; 17051da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 17061da177e4SLinus Torvalds 17071da177e4SLinus Torvalds ENTER; 17081da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds ioa_cfg->errors_logged++; 17111da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 17121da177e4SLinus Torvalds "Adapter being reset due to command timeout.\n"); 17131da177e4SLinus Torvalds 17141da177e4SLinus Torvalds if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) 17151da177e4SLinus Torvalds ioa_cfg->sdt_state = GET_DUMP; 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) 17181da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 17191da177e4SLinus Torvalds 17201da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 17211da177e4SLinus Torvalds LEAVE; 17221da177e4SLinus Torvalds } 17231da177e4SLinus Torvalds 17241da177e4SLinus Torvalds /** 17251da177e4SLinus Torvalds * ipr_oper_timeout - Adapter timed out transitioning to operational 17261da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 17271da177e4SLinus Torvalds * 17281da177e4SLinus Torvalds * This function blocks host requests and initiates an 17291da177e4SLinus Torvalds * adapter reset. 17301da177e4SLinus Torvalds * 17311da177e4SLinus Torvalds * Return value: 17321da177e4SLinus Torvalds * none 17331da177e4SLinus Torvalds **/ 17341da177e4SLinus Torvalds static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd) 17351da177e4SLinus Torvalds { 17361da177e4SLinus Torvalds unsigned long lock_flags = 0; 17371da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 17381da177e4SLinus Torvalds 17391da177e4SLinus Torvalds ENTER; 17401da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds ioa_cfg->errors_logged++; 17431da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 17441da177e4SLinus Torvalds "Adapter timed out transitioning to operational.\n"); 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) 17471da177e4SLinus Torvalds ioa_cfg->sdt_state = GET_DUMP; 17481da177e4SLinus Torvalds 17491da177e4SLinus Torvalds if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) { 17501da177e4SLinus Torvalds if (ipr_fastfail) 17511da177e4SLinus Torvalds ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES; 17521da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 17531da177e4SLinus Torvalds } 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 17561da177e4SLinus Torvalds LEAVE; 17571da177e4SLinus Torvalds } 17581da177e4SLinus Torvalds 17591da177e4SLinus Torvalds /** 17601da177e4SLinus Torvalds * ipr_reset_reload - Reset/Reload the IOA 17611da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 17621da177e4SLinus Torvalds * @shutdown_type: shutdown type 17631da177e4SLinus Torvalds * 17641da177e4SLinus Torvalds * This function resets the adapter and re-initializes it. 17651da177e4SLinus Torvalds * This function assumes that all new host commands have been stopped. 17661da177e4SLinus Torvalds * Return value: 17671da177e4SLinus Torvalds * SUCCESS / FAILED 17681da177e4SLinus Torvalds **/ 17691da177e4SLinus Torvalds static int ipr_reset_reload(struct ipr_ioa_cfg *ioa_cfg, 17701da177e4SLinus Torvalds enum ipr_shutdown_type shutdown_type) 17711da177e4SLinus Torvalds { 17721da177e4SLinus Torvalds if (!ioa_cfg->in_reset_reload) 17731da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); 17741da177e4SLinus Torvalds 17751da177e4SLinus Torvalds spin_unlock_irq(ioa_cfg->host->host_lock); 17761da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 17771da177e4SLinus Torvalds spin_lock_irq(ioa_cfg->host->host_lock); 17781da177e4SLinus Torvalds 17791da177e4SLinus Torvalds /* If we got hit with a host reset while we were already resetting 17801da177e4SLinus Torvalds the adapter for some reason, and the reset failed. */ 17811da177e4SLinus Torvalds if (ioa_cfg->ioa_is_dead) { 17821da177e4SLinus Torvalds ipr_trace; 17831da177e4SLinus Torvalds return FAILED; 17841da177e4SLinus Torvalds } 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds return SUCCESS; 17871da177e4SLinus Torvalds } 17881da177e4SLinus Torvalds 17891da177e4SLinus Torvalds /** 17901da177e4SLinus Torvalds * ipr_find_ses_entry - Find matching SES in SES table 17911da177e4SLinus Torvalds * @res: resource entry struct of SES 17921da177e4SLinus Torvalds * 17931da177e4SLinus Torvalds * Return value: 17941da177e4SLinus Torvalds * pointer to SES table entry / NULL on failure 17951da177e4SLinus Torvalds **/ 17961da177e4SLinus Torvalds static const struct ipr_ses_table_entry * 17971da177e4SLinus Torvalds ipr_find_ses_entry(struct ipr_resource_entry *res) 17981da177e4SLinus Torvalds { 17991da177e4SLinus Torvalds int i, j, matches; 18001da177e4SLinus Torvalds const struct ipr_ses_table_entry *ste = ipr_ses_table; 18011da177e4SLinus Torvalds 18021da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) { 18031da177e4SLinus Torvalds for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) { 18041da177e4SLinus Torvalds if (ste->compare_product_id_byte[j] == 'X') { 18051da177e4SLinus Torvalds if (res->cfgte.std_inq_data.vpids.product_id[j] == ste->product_id[j]) 18061da177e4SLinus Torvalds matches++; 18071da177e4SLinus Torvalds else 18081da177e4SLinus Torvalds break; 18091da177e4SLinus Torvalds } else 18101da177e4SLinus Torvalds matches++; 18111da177e4SLinus Torvalds } 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds if (matches == IPR_PROD_ID_LEN) 18141da177e4SLinus Torvalds return ste; 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds 18171da177e4SLinus Torvalds return NULL; 18181da177e4SLinus Torvalds } 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds /** 18211da177e4SLinus Torvalds * ipr_get_max_scsi_speed - Determine max SCSI speed for a given bus 18221da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 18231da177e4SLinus Torvalds * @bus: SCSI bus 18241da177e4SLinus Torvalds * @bus_width: bus width 18251da177e4SLinus Torvalds * 18261da177e4SLinus Torvalds * Return value: 18271da177e4SLinus Torvalds * SCSI bus speed in units of 100KHz, 1600 is 160 MHz 18281da177e4SLinus Torvalds * For a 2-byte wide SCSI bus, the maximum transfer speed is 18291da177e4SLinus Torvalds * twice the maximum transfer rate (e.g. for a wide enabled bus, 18301da177e4SLinus Torvalds * max 160MHz = max 320MB/sec). 18311da177e4SLinus Torvalds **/ 18321da177e4SLinus Torvalds static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_width) 18331da177e4SLinus Torvalds { 18341da177e4SLinus Torvalds struct ipr_resource_entry *res; 18351da177e4SLinus Torvalds const struct ipr_ses_table_entry *ste; 18361da177e4SLinus Torvalds u32 max_xfer_rate = IPR_MAX_SCSI_RATE(bus_width); 18371da177e4SLinus Torvalds 18381da177e4SLinus Torvalds /* Loop through each config table entry in the config table buffer */ 18391da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 18401da177e4SLinus Torvalds if (!(IPR_IS_SES_DEVICE(res->cfgte.std_inq_data))) 18411da177e4SLinus Torvalds continue; 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds if (bus != res->cfgte.res_addr.bus) 18441da177e4SLinus Torvalds continue; 18451da177e4SLinus Torvalds 18461da177e4SLinus Torvalds if (!(ste = ipr_find_ses_entry(res))) 18471da177e4SLinus Torvalds continue; 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds max_xfer_rate = (ste->max_bus_speed_limit * 10) / (bus_width / 8); 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds 18521da177e4SLinus Torvalds return max_xfer_rate; 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds /** 18561da177e4SLinus Torvalds * ipr_wait_iodbg_ack - Wait for an IODEBUG ACK from the IOA 18571da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 18581da177e4SLinus Torvalds * @max_delay: max delay in micro-seconds to wait 18591da177e4SLinus Torvalds * 18601da177e4SLinus Torvalds * Waits for an IODEBUG ACK from the IOA, doing busy looping. 18611da177e4SLinus Torvalds * 18621da177e4SLinus Torvalds * Return value: 18631da177e4SLinus Torvalds * 0 on success / other on failure 18641da177e4SLinus Torvalds **/ 18651da177e4SLinus Torvalds static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay) 18661da177e4SLinus Torvalds { 18671da177e4SLinus Torvalds volatile u32 pcii_reg; 18681da177e4SLinus Torvalds int delay = 1; 18691da177e4SLinus Torvalds 18701da177e4SLinus Torvalds /* Read interrupt reg until IOA signals IO Debug Acknowledge */ 18711da177e4SLinus Torvalds while (delay < max_delay) { 18721da177e4SLinus Torvalds pcii_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 18731da177e4SLinus Torvalds 18741da177e4SLinus Torvalds if (pcii_reg & IPR_PCII_IO_DEBUG_ACKNOWLEDGE) 18751da177e4SLinus Torvalds return 0; 18761da177e4SLinus Torvalds 18771da177e4SLinus Torvalds /* udelay cannot be used if delay is more than a few milliseconds */ 18781da177e4SLinus Torvalds if ((delay / 1000) > MAX_UDELAY_MS) 18791da177e4SLinus Torvalds mdelay(delay / 1000); 18801da177e4SLinus Torvalds else 18811da177e4SLinus Torvalds udelay(delay); 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds delay += delay; 18841da177e4SLinus Torvalds } 18851da177e4SLinus Torvalds return -EIO; 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds /** 18891da177e4SLinus Torvalds * ipr_get_ldump_data_section - Dump IOA memory 18901da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 18911da177e4SLinus Torvalds * @start_addr: adapter address to dump 18921da177e4SLinus Torvalds * @dest: destination kernel buffer 18931da177e4SLinus Torvalds * @length_in_words: length to dump in 4 byte words 18941da177e4SLinus Torvalds * 18951da177e4SLinus Torvalds * Return value: 18961da177e4SLinus Torvalds * 0 on success / -EIO on failure 18971da177e4SLinus Torvalds **/ 18981da177e4SLinus Torvalds static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, 18991da177e4SLinus Torvalds u32 start_addr, 19001da177e4SLinus Torvalds __be32 *dest, u32 length_in_words) 19011da177e4SLinus Torvalds { 19021da177e4SLinus Torvalds volatile u32 temp_pcii_reg; 19031da177e4SLinus Torvalds int i, delay = 0; 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds /* Write IOA interrupt reg starting LDUMP state */ 19061da177e4SLinus Torvalds writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), 19071da177e4SLinus Torvalds ioa_cfg->regs.set_uproc_interrupt_reg); 19081da177e4SLinus Torvalds 19091da177e4SLinus Torvalds /* Wait for IO debug acknowledge */ 19101da177e4SLinus Torvalds if (ipr_wait_iodbg_ack(ioa_cfg, 19111da177e4SLinus Torvalds IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC)) { 19121da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 19131da177e4SLinus Torvalds "IOA dump long data transfer timeout\n"); 19141da177e4SLinus Torvalds return -EIO; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds 19171da177e4SLinus Torvalds /* Signal LDUMP interlocked - clear IO debug ack */ 19181da177e4SLinus Torvalds writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, 19191da177e4SLinus Torvalds ioa_cfg->regs.clr_interrupt_reg); 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds /* Write Mailbox with starting address */ 19221da177e4SLinus Torvalds writel(start_addr, ioa_cfg->ioa_mailbox); 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds /* Signal address valid - clear IOA Reset alert */ 19251da177e4SLinus Torvalds writel(IPR_UPROCI_RESET_ALERT, 19261da177e4SLinus Torvalds ioa_cfg->regs.clr_uproc_interrupt_reg); 19271da177e4SLinus Torvalds 19281da177e4SLinus Torvalds for (i = 0; i < length_in_words; i++) { 19291da177e4SLinus Torvalds /* Wait for IO debug acknowledge */ 19301da177e4SLinus Torvalds if (ipr_wait_iodbg_ack(ioa_cfg, 19311da177e4SLinus Torvalds IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC)) { 19321da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 19331da177e4SLinus Torvalds "IOA dump short data transfer timeout\n"); 19341da177e4SLinus Torvalds return -EIO; 19351da177e4SLinus Torvalds } 19361da177e4SLinus Torvalds 19371da177e4SLinus Torvalds /* Read data from mailbox and increment destination pointer */ 19381da177e4SLinus Torvalds *dest = cpu_to_be32(readl(ioa_cfg->ioa_mailbox)); 19391da177e4SLinus Torvalds dest++; 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds /* For all but the last word of data, signal data received */ 19421da177e4SLinus Torvalds if (i < (length_in_words - 1)) { 19431da177e4SLinus Torvalds /* Signal dump data received - Clear IO debug Ack */ 19441da177e4SLinus Torvalds writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, 19451da177e4SLinus Torvalds ioa_cfg->regs.clr_interrupt_reg); 19461da177e4SLinus Torvalds } 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds /* Signal end of block transfer. Set reset alert then clear IO debug ack */ 19501da177e4SLinus Torvalds writel(IPR_UPROCI_RESET_ALERT, 19511da177e4SLinus Torvalds ioa_cfg->regs.set_uproc_interrupt_reg); 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds writel(IPR_UPROCI_IO_DEBUG_ALERT, 19541da177e4SLinus Torvalds ioa_cfg->regs.clr_uproc_interrupt_reg); 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds /* Signal dump data received - Clear IO debug Ack */ 19571da177e4SLinus Torvalds writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, 19581da177e4SLinus Torvalds ioa_cfg->regs.clr_interrupt_reg); 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds /* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */ 19611da177e4SLinus Torvalds while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) { 19621da177e4SLinus Torvalds temp_pcii_reg = 19631da177e4SLinus Torvalds readl(ioa_cfg->regs.sense_uproc_interrupt_reg); 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT)) 19661da177e4SLinus Torvalds return 0; 19671da177e4SLinus Torvalds 19681da177e4SLinus Torvalds udelay(10); 19691da177e4SLinus Torvalds delay += 10; 19701da177e4SLinus Torvalds } 19711da177e4SLinus Torvalds 19721da177e4SLinus Torvalds return 0; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds #ifdef CONFIG_SCSI_IPR_DUMP 19761da177e4SLinus Torvalds /** 19771da177e4SLinus Torvalds * ipr_sdt_copy - Copy Smart Dump Table to kernel buffer 19781da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 19791da177e4SLinus Torvalds * @pci_address: adapter address 19801da177e4SLinus Torvalds * @length: length of data to copy 19811da177e4SLinus Torvalds * 19821da177e4SLinus Torvalds * Copy data from PCI adapter to kernel buffer. 19831da177e4SLinus Torvalds * Note: length MUST be a 4 byte multiple 19841da177e4SLinus Torvalds * Return value: 19851da177e4SLinus Torvalds * 0 on success / other on failure 19861da177e4SLinus Torvalds **/ 19871da177e4SLinus Torvalds static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg, 19881da177e4SLinus Torvalds unsigned long pci_address, u32 length) 19891da177e4SLinus Torvalds { 19901da177e4SLinus Torvalds int bytes_copied = 0; 19911da177e4SLinus Torvalds int cur_len, rc, rem_len, rem_page_len; 19921da177e4SLinus Torvalds __be32 *page; 19931da177e4SLinus Torvalds unsigned long lock_flags = 0; 19941da177e4SLinus Torvalds struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump; 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds while (bytes_copied < length && 19971da177e4SLinus Torvalds (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) { 19981da177e4SLinus Torvalds if (ioa_dump->page_offset >= PAGE_SIZE || 19991da177e4SLinus Torvalds ioa_dump->page_offset == 0) { 20001da177e4SLinus Torvalds page = (__be32 *)__get_free_page(GFP_ATOMIC); 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds if (!page) { 20031da177e4SLinus Torvalds ipr_trace; 20041da177e4SLinus Torvalds return bytes_copied; 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds ioa_dump->page_offset = 0; 20081da177e4SLinus Torvalds ioa_dump->ioa_data[ioa_dump->next_page_index] = page; 20091da177e4SLinus Torvalds ioa_dump->next_page_index++; 20101da177e4SLinus Torvalds } else 20111da177e4SLinus Torvalds page = ioa_dump->ioa_data[ioa_dump->next_page_index - 1]; 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds rem_len = length - bytes_copied; 20141da177e4SLinus Torvalds rem_page_len = PAGE_SIZE - ioa_dump->page_offset; 20151da177e4SLinus Torvalds cur_len = min(rem_len, rem_page_len); 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 20181da177e4SLinus Torvalds if (ioa_cfg->sdt_state == ABORT_DUMP) { 20191da177e4SLinus Torvalds rc = -EIO; 20201da177e4SLinus Torvalds } else { 20211da177e4SLinus Torvalds rc = ipr_get_ldump_data_section(ioa_cfg, 20221da177e4SLinus Torvalds pci_address + bytes_copied, 20231da177e4SLinus Torvalds &page[ioa_dump->page_offset / 4], 20241da177e4SLinus Torvalds (cur_len / sizeof(u32))); 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 20271da177e4SLinus Torvalds 20281da177e4SLinus Torvalds if (!rc) { 20291da177e4SLinus Torvalds ioa_dump->page_offset += cur_len; 20301da177e4SLinus Torvalds bytes_copied += cur_len; 20311da177e4SLinus Torvalds } else { 20321da177e4SLinus Torvalds ipr_trace; 20331da177e4SLinus Torvalds break; 20341da177e4SLinus Torvalds } 20351da177e4SLinus Torvalds schedule(); 20361da177e4SLinus Torvalds } 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds return bytes_copied; 20391da177e4SLinus Torvalds } 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds /** 20421da177e4SLinus Torvalds * ipr_init_dump_entry_hdr - Initialize a dump entry header. 20431da177e4SLinus Torvalds * @hdr: dump entry header struct 20441da177e4SLinus Torvalds * 20451da177e4SLinus Torvalds * Return value: 20461da177e4SLinus Torvalds * nothing 20471da177e4SLinus Torvalds **/ 20481da177e4SLinus Torvalds static void ipr_init_dump_entry_hdr(struct ipr_dump_entry_header *hdr) 20491da177e4SLinus Torvalds { 20501da177e4SLinus Torvalds hdr->eye_catcher = IPR_DUMP_EYE_CATCHER; 20511da177e4SLinus Torvalds hdr->num_elems = 1; 20521da177e4SLinus Torvalds hdr->offset = sizeof(*hdr); 20531da177e4SLinus Torvalds hdr->status = IPR_DUMP_STATUS_SUCCESS; 20541da177e4SLinus Torvalds } 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds /** 20571da177e4SLinus Torvalds * ipr_dump_ioa_type_data - Fill in the adapter type in the dump. 20581da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 20591da177e4SLinus Torvalds * @driver_dump: driver dump struct 20601da177e4SLinus Torvalds * 20611da177e4SLinus Torvalds * Return value: 20621da177e4SLinus Torvalds * nothing 20631da177e4SLinus Torvalds **/ 20641da177e4SLinus Torvalds static void ipr_dump_ioa_type_data(struct ipr_ioa_cfg *ioa_cfg, 20651da177e4SLinus Torvalds struct ipr_driver_dump *driver_dump) 20661da177e4SLinus Torvalds { 20671da177e4SLinus Torvalds struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds ipr_init_dump_entry_hdr(&driver_dump->ioa_type_entry.hdr); 20701da177e4SLinus Torvalds driver_dump->ioa_type_entry.hdr.len = 20711da177e4SLinus Torvalds sizeof(struct ipr_dump_ioa_type_entry) - 20721da177e4SLinus Torvalds sizeof(struct ipr_dump_entry_header); 20731da177e4SLinus Torvalds driver_dump->ioa_type_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; 20741da177e4SLinus Torvalds driver_dump->ioa_type_entry.hdr.id = IPR_DUMP_DRIVER_TYPE_ID; 20751da177e4SLinus Torvalds driver_dump->ioa_type_entry.type = ioa_cfg->type; 20761da177e4SLinus Torvalds driver_dump->ioa_type_entry.fw_version = (ucode_vpd->major_release << 24) | 20771da177e4SLinus Torvalds (ucode_vpd->card_type << 16) | (ucode_vpd->minor_release[0] << 8) | 20781da177e4SLinus Torvalds ucode_vpd->minor_release[1]; 20791da177e4SLinus Torvalds driver_dump->hdr.num_entries++; 20801da177e4SLinus Torvalds } 20811da177e4SLinus Torvalds 20821da177e4SLinus Torvalds /** 20831da177e4SLinus Torvalds * ipr_dump_version_data - Fill in the driver version in the dump. 20841da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 20851da177e4SLinus Torvalds * @driver_dump: driver dump struct 20861da177e4SLinus Torvalds * 20871da177e4SLinus Torvalds * Return value: 20881da177e4SLinus Torvalds * nothing 20891da177e4SLinus Torvalds **/ 20901da177e4SLinus Torvalds static void ipr_dump_version_data(struct ipr_ioa_cfg *ioa_cfg, 20911da177e4SLinus Torvalds struct ipr_driver_dump *driver_dump) 20921da177e4SLinus Torvalds { 20931da177e4SLinus Torvalds ipr_init_dump_entry_hdr(&driver_dump->version_entry.hdr); 20941da177e4SLinus Torvalds driver_dump->version_entry.hdr.len = 20951da177e4SLinus Torvalds sizeof(struct ipr_dump_version_entry) - 20961da177e4SLinus Torvalds sizeof(struct ipr_dump_entry_header); 20971da177e4SLinus Torvalds driver_dump->version_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; 20981da177e4SLinus Torvalds driver_dump->version_entry.hdr.id = IPR_DUMP_DRIVER_VERSION_ID; 20991da177e4SLinus Torvalds strcpy(driver_dump->version_entry.version, IPR_DRIVER_VERSION); 21001da177e4SLinus Torvalds driver_dump->hdr.num_entries++; 21011da177e4SLinus Torvalds } 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds /** 21041da177e4SLinus Torvalds * ipr_dump_trace_data - Fill in the IOA trace in the dump. 21051da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 21061da177e4SLinus Torvalds * @driver_dump: driver dump struct 21071da177e4SLinus Torvalds * 21081da177e4SLinus Torvalds * Return value: 21091da177e4SLinus Torvalds * nothing 21101da177e4SLinus Torvalds **/ 21111da177e4SLinus Torvalds static void ipr_dump_trace_data(struct ipr_ioa_cfg *ioa_cfg, 21121da177e4SLinus Torvalds struct ipr_driver_dump *driver_dump) 21131da177e4SLinus Torvalds { 21141da177e4SLinus Torvalds ipr_init_dump_entry_hdr(&driver_dump->trace_entry.hdr); 21151da177e4SLinus Torvalds driver_dump->trace_entry.hdr.len = 21161da177e4SLinus Torvalds sizeof(struct ipr_dump_trace_entry) - 21171da177e4SLinus Torvalds sizeof(struct ipr_dump_entry_header); 21181da177e4SLinus Torvalds driver_dump->trace_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; 21191da177e4SLinus Torvalds driver_dump->trace_entry.hdr.id = IPR_DUMP_TRACE_ID; 21201da177e4SLinus Torvalds memcpy(driver_dump->trace_entry.trace, ioa_cfg->trace, IPR_TRACE_SIZE); 21211da177e4SLinus Torvalds driver_dump->hdr.num_entries++; 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds /** 21251da177e4SLinus Torvalds * ipr_dump_location_data - Fill in the IOA location in the dump. 21261da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 21271da177e4SLinus Torvalds * @driver_dump: driver dump struct 21281da177e4SLinus Torvalds * 21291da177e4SLinus Torvalds * Return value: 21301da177e4SLinus Torvalds * nothing 21311da177e4SLinus Torvalds **/ 21321da177e4SLinus Torvalds static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg, 21331da177e4SLinus Torvalds struct ipr_driver_dump *driver_dump) 21341da177e4SLinus Torvalds { 21351da177e4SLinus Torvalds ipr_init_dump_entry_hdr(&driver_dump->location_entry.hdr); 21361da177e4SLinus Torvalds driver_dump->location_entry.hdr.len = 21371da177e4SLinus Torvalds sizeof(struct ipr_dump_location_entry) - 21381da177e4SLinus Torvalds sizeof(struct ipr_dump_entry_header); 21391da177e4SLinus Torvalds driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; 21401da177e4SLinus Torvalds driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID; 21411da177e4SLinus Torvalds strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id); 21421da177e4SLinus Torvalds driver_dump->hdr.num_entries++; 21431da177e4SLinus Torvalds } 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds /** 21461da177e4SLinus Torvalds * ipr_get_ioa_dump - Perform a dump of the driver and adapter. 21471da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 21481da177e4SLinus Torvalds * @dump: dump struct 21491da177e4SLinus Torvalds * 21501da177e4SLinus Torvalds * Return value: 21511da177e4SLinus Torvalds * nothing 21521da177e4SLinus Torvalds **/ 21531da177e4SLinus Torvalds static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) 21541da177e4SLinus Torvalds { 21551da177e4SLinus Torvalds unsigned long start_addr, sdt_word; 21561da177e4SLinus Torvalds unsigned long lock_flags = 0; 21571da177e4SLinus Torvalds struct ipr_driver_dump *driver_dump = &dump->driver_dump; 21581da177e4SLinus Torvalds struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump; 21591da177e4SLinus Torvalds u32 num_entries, start_off, end_off; 21601da177e4SLinus Torvalds u32 bytes_to_copy, bytes_copied, rc; 21611da177e4SLinus Torvalds struct ipr_sdt *sdt; 21621da177e4SLinus Torvalds int i; 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds ENTER; 21651da177e4SLinus Torvalds 21661da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds if (ioa_cfg->sdt_state != GET_DUMP) { 21691da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 21701da177e4SLinus Torvalds return; 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds 21731da177e4SLinus Torvalds start_addr = readl(ioa_cfg->ioa_mailbox); 21741da177e4SLinus Torvalds 21751da177e4SLinus Torvalds if (!ipr_sdt_is_fmt2(start_addr)) { 21761da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 21771da177e4SLinus Torvalds "Invalid dump table format: %lx\n", start_addr); 21781da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 21791da177e4SLinus Torvalds return; 21801da177e4SLinus Torvalds } 21811da177e4SLinus Torvalds 21821da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Dump of IOA initiated\n"); 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds driver_dump->hdr.eye_catcher = IPR_DUMP_EYE_CATCHER; 21851da177e4SLinus Torvalds 21861da177e4SLinus Torvalds /* Initialize the overall dump header */ 21871da177e4SLinus Torvalds driver_dump->hdr.len = sizeof(struct ipr_driver_dump); 21881da177e4SLinus Torvalds driver_dump->hdr.num_entries = 1; 21891da177e4SLinus Torvalds driver_dump->hdr.first_entry_offset = sizeof(struct ipr_dump_header); 21901da177e4SLinus Torvalds driver_dump->hdr.status = IPR_DUMP_STATUS_SUCCESS; 21911da177e4SLinus Torvalds driver_dump->hdr.os = IPR_DUMP_OS_LINUX; 21921da177e4SLinus Torvalds driver_dump->hdr.driver_name = IPR_DUMP_DRIVER_NAME; 21931da177e4SLinus Torvalds 21941da177e4SLinus Torvalds ipr_dump_version_data(ioa_cfg, driver_dump); 21951da177e4SLinus Torvalds ipr_dump_location_data(ioa_cfg, driver_dump); 21961da177e4SLinus Torvalds ipr_dump_ioa_type_data(ioa_cfg, driver_dump); 21971da177e4SLinus Torvalds ipr_dump_trace_data(ioa_cfg, driver_dump); 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds /* Update dump_header */ 22001da177e4SLinus Torvalds driver_dump->hdr.len += sizeof(struct ipr_dump_entry_header); 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds /* IOA Dump entry */ 22031da177e4SLinus Torvalds ipr_init_dump_entry_hdr(&ioa_dump->hdr); 22041da177e4SLinus Torvalds ioa_dump->format = IPR_SDT_FMT2; 22051da177e4SLinus Torvalds ioa_dump->hdr.len = 0; 22061da177e4SLinus Torvalds ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; 22071da177e4SLinus Torvalds ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID; 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds /* First entries in sdt are actually a list of dump addresses and 22101da177e4SLinus Torvalds lengths to gather the real dump data. sdt represents the pointer 22111da177e4SLinus Torvalds to the ioa generated dump table. Dump data will be extracted based 22121da177e4SLinus Torvalds on entries in this table */ 22131da177e4SLinus Torvalds sdt = &ioa_dump->sdt; 22141da177e4SLinus Torvalds 22151da177e4SLinus Torvalds rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt, 22161da177e4SLinus Torvalds sizeof(struct ipr_sdt) / sizeof(__be32)); 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds /* Smart Dump table is ready to use and the first entry is valid */ 22191da177e4SLinus Torvalds if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) { 22201da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 22211da177e4SLinus Torvalds "Dump of IOA failed. Dump table not valid: %d, %X.\n", 22221da177e4SLinus Torvalds rc, be32_to_cpu(sdt->hdr.state)); 22231da177e4SLinus Torvalds driver_dump->hdr.status = IPR_DUMP_STATUS_FAILED; 22241da177e4SLinus Torvalds ioa_cfg->sdt_state = DUMP_OBTAINED; 22251da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 22261da177e4SLinus Torvalds return; 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds 22291da177e4SLinus Torvalds num_entries = be32_to_cpu(sdt->hdr.num_entries_used); 22301da177e4SLinus Torvalds 22311da177e4SLinus Torvalds if (num_entries > IPR_NUM_SDT_ENTRIES) 22321da177e4SLinus Torvalds num_entries = IPR_NUM_SDT_ENTRIES; 22331da177e4SLinus Torvalds 22341da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 22351da177e4SLinus Torvalds 22361da177e4SLinus Torvalds for (i = 0; i < num_entries; i++) { 22371da177e4SLinus Torvalds if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) { 22381da177e4SLinus Torvalds driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; 22391da177e4SLinus Torvalds break; 22401da177e4SLinus Torvalds } 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { 22431da177e4SLinus Torvalds sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset); 22441da177e4SLinus Torvalds start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; 22451da177e4SLinus Torvalds end_off = be32_to_cpu(sdt->entry[i].end_offset); 22461da177e4SLinus Torvalds 22471da177e4SLinus Torvalds if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) { 22481da177e4SLinus Torvalds bytes_to_copy = end_off - start_off; 22491da177e4SLinus Torvalds if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) { 22501da177e4SLinus Torvalds sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; 22511da177e4SLinus Torvalds continue; 22521da177e4SLinus Torvalds } 22531da177e4SLinus Torvalds 22541da177e4SLinus Torvalds /* Copy data from adapter to driver buffers */ 22551da177e4SLinus Torvalds bytes_copied = ipr_sdt_copy(ioa_cfg, sdt_word, 22561da177e4SLinus Torvalds bytes_to_copy); 22571da177e4SLinus Torvalds 22581da177e4SLinus Torvalds ioa_dump->hdr.len += bytes_copied; 22591da177e4SLinus Torvalds 22601da177e4SLinus Torvalds if (bytes_copied != bytes_to_copy) { 22611da177e4SLinus Torvalds driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; 22621da177e4SLinus Torvalds break; 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds } 22651da177e4SLinus Torvalds } 22661da177e4SLinus Torvalds } 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Dump of IOA completed.\n"); 22691da177e4SLinus Torvalds 22701da177e4SLinus Torvalds /* Update dump_header */ 22711da177e4SLinus Torvalds driver_dump->hdr.len += ioa_dump->hdr.len; 22721da177e4SLinus Torvalds wmb(); 22731da177e4SLinus Torvalds ioa_cfg->sdt_state = DUMP_OBTAINED; 22741da177e4SLinus Torvalds LEAVE; 22751da177e4SLinus Torvalds } 22761da177e4SLinus Torvalds 22771da177e4SLinus Torvalds #else 22781da177e4SLinus Torvalds #define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0) 22791da177e4SLinus Torvalds #endif 22801da177e4SLinus Torvalds 22811da177e4SLinus Torvalds /** 22821da177e4SLinus Torvalds * ipr_release_dump - Free adapter dump memory 22831da177e4SLinus Torvalds * @kref: kref struct 22841da177e4SLinus Torvalds * 22851da177e4SLinus Torvalds * Return value: 22861da177e4SLinus Torvalds * nothing 22871da177e4SLinus Torvalds **/ 22881da177e4SLinus Torvalds static void ipr_release_dump(struct kref *kref) 22891da177e4SLinus Torvalds { 22901da177e4SLinus Torvalds struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref); 22911da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; 22921da177e4SLinus Torvalds unsigned long lock_flags = 0; 22931da177e4SLinus Torvalds int i; 22941da177e4SLinus Torvalds 22951da177e4SLinus Torvalds ENTER; 22961da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 22971da177e4SLinus Torvalds ioa_cfg->dump = NULL; 22981da177e4SLinus Torvalds ioa_cfg->sdt_state = INACTIVE; 22991da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23001da177e4SLinus Torvalds 23011da177e4SLinus Torvalds for (i = 0; i < dump->ioa_dump.next_page_index; i++) 23021da177e4SLinus Torvalds free_page((unsigned long) dump->ioa_dump.ioa_data[i]); 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds kfree(dump); 23051da177e4SLinus Torvalds LEAVE; 23061da177e4SLinus Torvalds } 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds /** 23091da177e4SLinus Torvalds * ipr_worker_thread - Worker thread 2310c4028958SDavid Howells * @work: ioa config struct 23111da177e4SLinus Torvalds * 23121da177e4SLinus Torvalds * Called at task level from a work thread. This function takes care 23131da177e4SLinus Torvalds * of adding and removing device from the mid-layer as configuration 23141da177e4SLinus Torvalds * changes are detected by the adapter. 23151da177e4SLinus Torvalds * 23161da177e4SLinus Torvalds * Return value: 23171da177e4SLinus Torvalds * nothing 23181da177e4SLinus Torvalds **/ 2319c4028958SDavid Howells static void ipr_worker_thread(struct work_struct *work) 23201da177e4SLinus Torvalds { 23211da177e4SLinus Torvalds unsigned long lock_flags; 23221da177e4SLinus Torvalds struct ipr_resource_entry *res; 23231da177e4SLinus Torvalds struct scsi_device *sdev; 23241da177e4SLinus Torvalds struct ipr_dump *dump; 2325c4028958SDavid Howells struct ipr_ioa_cfg *ioa_cfg = 2326c4028958SDavid Howells container_of(work, struct ipr_ioa_cfg, work_q); 23271da177e4SLinus Torvalds u8 bus, target, lun; 23281da177e4SLinus Torvalds int did_work; 23291da177e4SLinus Torvalds 23301da177e4SLinus Torvalds ENTER; 23311da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 23321da177e4SLinus Torvalds 23331da177e4SLinus Torvalds if (ioa_cfg->sdt_state == GET_DUMP) { 23341da177e4SLinus Torvalds dump = ioa_cfg->dump; 23351da177e4SLinus Torvalds if (!dump) { 23361da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23371da177e4SLinus Torvalds return; 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds kref_get(&dump->kref); 23401da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23411da177e4SLinus Torvalds ipr_get_ioa_dump(ioa_cfg, dump); 23421da177e4SLinus Torvalds kref_put(&dump->kref, ipr_release_dump); 23431da177e4SLinus Torvalds 23441da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 23451da177e4SLinus Torvalds if (ioa_cfg->sdt_state == DUMP_OBTAINED) 23461da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 23471da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23481da177e4SLinus Torvalds return; 23491da177e4SLinus Torvalds } 23501da177e4SLinus Torvalds 23511da177e4SLinus Torvalds restart: 23521da177e4SLinus Torvalds do { 23531da177e4SLinus Torvalds did_work = 0; 23541da177e4SLinus Torvalds if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) { 23551da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23561da177e4SLinus Torvalds return; 23571da177e4SLinus Torvalds } 23581da177e4SLinus Torvalds 23591da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 23601da177e4SLinus Torvalds if (res->del_from_ml && res->sdev) { 23611da177e4SLinus Torvalds did_work = 1; 23621da177e4SLinus Torvalds sdev = res->sdev; 23631da177e4SLinus Torvalds if (!scsi_device_get(sdev)) { 23641da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->free_res_q); 23651da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23661da177e4SLinus Torvalds scsi_remove_device(sdev); 23671da177e4SLinus Torvalds scsi_device_put(sdev); 23681da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 23691da177e4SLinus Torvalds } 23701da177e4SLinus Torvalds break; 23711da177e4SLinus Torvalds } 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds } while(did_work); 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 23761da177e4SLinus Torvalds if (res->add_to_ml) { 23771da177e4SLinus Torvalds bus = res->cfgte.res_addr.bus; 23781da177e4SLinus Torvalds target = res->cfgte.res_addr.target; 23791da177e4SLinus Torvalds lun = res->cfgte.res_addr.lun; 23801121b794SBrian King res->add_to_ml = 0; 23811da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 23821da177e4SLinus Torvalds scsi_add_device(ioa_cfg->host, bus, target, lun); 23831da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 23841da177e4SLinus Torvalds goto restart; 23851da177e4SLinus Torvalds } 23861da177e4SLinus Torvalds } 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 2389312c004dSKay Sievers kobject_uevent(&ioa_cfg->host->shost_classdev.kobj, KOBJ_CHANGE); 23901da177e4SLinus Torvalds LEAVE; 23911da177e4SLinus Torvalds } 23921da177e4SLinus Torvalds 23931da177e4SLinus Torvalds #ifdef CONFIG_SCSI_IPR_TRACE 23941da177e4SLinus Torvalds /** 23951da177e4SLinus Torvalds * ipr_read_trace - Dump the adapter trace 23961da177e4SLinus Torvalds * @kobj: kobject struct 23971da177e4SLinus Torvalds * @buf: buffer 23981da177e4SLinus Torvalds * @off: offset 23991da177e4SLinus Torvalds * @count: buffer size 24001da177e4SLinus Torvalds * 24011da177e4SLinus Torvalds * Return value: 24021da177e4SLinus Torvalds * number of bytes printed to buffer 24031da177e4SLinus Torvalds **/ 24041da177e4SLinus Torvalds static ssize_t ipr_read_trace(struct kobject *kobj, char *buf, 24051da177e4SLinus Torvalds loff_t off, size_t count) 24061da177e4SLinus Torvalds { 24071da177e4SLinus Torvalds struct class_device *cdev = container_of(kobj,struct class_device,kobj); 24081da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(cdev); 24091da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 24101da177e4SLinus Torvalds unsigned long lock_flags = 0; 24111da177e4SLinus Torvalds int size = IPR_TRACE_SIZE; 24121da177e4SLinus Torvalds char *src = (char *)ioa_cfg->trace; 24131da177e4SLinus Torvalds 24141da177e4SLinus Torvalds if (off > size) 24151da177e4SLinus Torvalds return 0; 24161da177e4SLinus Torvalds if (off + count > size) { 24171da177e4SLinus Torvalds size -= off; 24181da177e4SLinus Torvalds count = size; 24191da177e4SLinus Torvalds } 24201da177e4SLinus Torvalds 24211da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 24221da177e4SLinus Torvalds memcpy(buf, &src[off], count); 24231da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 24241da177e4SLinus Torvalds return count; 24251da177e4SLinus Torvalds } 24261da177e4SLinus Torvalds 24271da177e4SLinus Torvalds static struct bin_attribute ipr_trace_attr = { 24281da177e4SLinus Torvalds .attr = { 24291da177e4SLinus Torvalds .name = "trace", 24301da177e4SLinus Torvalds .mode = S_IRUGO, 24311da177e4SLinus Torvalds }, 24321da177e4SLinus Torvalds .size = 0, 24331da177e4SLinus Torvalds .read = ipr_read_trace, 24341da177e4SLinus Torvalds }; 24351da177e4SLinus Torvalds #endif 24361da177e4SLinus Torvalds 243762275040Sbrking@us.ibm.com static const struct { 243862275040Sbrking@us.ibm.com enum ipr_cache_state state; 243962275040Sbrking@us.ibm.com char *name; 244062275040Sbrking@us.ibm.com } cache_state [] = { 244162275040Sbrking@us.ibm.com { CACHE_NONE, "none" }, 244262275040Sbrking@us.ibm.com { CACHE_DISABLED, "disabled" }, 244362275040Sbrking@us.ibm.com { CACHE_ENABLED, "enabled" } 244462275040Sbrking@us.ibm.com }; 244562275040Sbrking@us.ibm.com 244662275040Sbrking@us.ibm.com /** 244762275040Sbrking@us.ibm.com * ipr_show_write_caching - Show the write caching attribute 244862275040Sbrking@us.ibm.com * @class_dev: class device struct 244962275040Sbrking@us.ibm.com * @buf: buffer 245062275040Sbrking@us.ibm.com * 245162275040Sbrking@us.ibm.com * Return value: 245262275040Sbrking@us.ibm.com * number of bytes printed to buffer 245362275040Sbrking@us.ibm.com **/ 245462275040Sbrking@us.ibm.com static ssize_t ipr_show_write_caching(struct class_device *class_dev, char *buf) 245562275040Sbrking@us.ibm.com { 245662275040Sbrking@us.ibm.com struct Scsi_Host *shost = class_to_shost(class_dev); 245762275040Sbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 245862275040Sbrking@us.ibm.com unsigned long lock_flags = 0; 245962275040Sbrking@us.ibm.com int i, len = 0; 246062275040Sbrking@us.ibm.com 246162275040Sbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 246262275040Sbrking@us.ibm.com for (i = 0; i < ARRAY_SIZE(cache_state); i++) { 246362275040Sbrking@us.ibm.com if (cache_state[i].state == ioa_cfg->cache_state) { 246462275040Sbrking@us.ibm.com len = snprintf(buf, PAGE_SIZE, "%s\n", cache_state[i].name); 246562275040Sbrking@us.ibm.com break; 246662275040Sbrking@us.ibm.com } 246762275040Sbrking@us.ibm.com } 246862275040Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 246962275040Sbrking@us.ibm.com return len; 247062275040Sbrking@us.ibm.com } 247162275040Sbrking@us.ibm.com 247262275040Sbrking@us.ibm.com 247362275040Sbrking@us.ibm.com /** 247462275040Sbrking@us.ibm.com * ipr_store_write_caching - Enable/disable adapter write cache 247562275040Sbrking@us.ibm.com * @class_dev: class_device struct 247662275040Sbrking@us.ibm.com * @buf: buffer 247762275040Sbrking@us.ibm.com * @count: buffer size 247862275040Sbrking@us.ibm.com * 247962275040Sbrking@us.ibm.com * This function will enable/disable adapter write cache. 248062275040Sbrking@us.ibm.com * 248162275040Sbrking@us.ibm.com * Return value: 248262275040Sbrking@us.ibm.com * count on success / other on failure 248362275040Sbrking@us.ibm.com **/ 248462275040Sbrking@us.ibm.com static ssize_t ipr_store_write_caching(struct class_device *class_dev, 248562275040Sbrking@us.ibm.com const char *buf, size_t count) 248662275040Sbrking@us.ibm.com { 248762275040Sbrking@us.ibm.com struct Scsi_Host *shost = class_to_shost(class_dev); 248862275040Sbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 248962275040Sbrking@us.ibm.com unsigned long lock_flags = 0; 249062275040Sbrking@us.ibm.com enum ipr_cache_state new_state = CACHE_INVALID; 249162275040Sbrking@us.ibm.com int i; 249262275040Sbrking@us.ibm.com 249362275040Sbrking@us.ibm.com if (!capable(CAP_SYS_ADMIN)) 249462275040Sbrking@us.ibm.com return -EACCES; 249562275040Sbrking@us.ibm.com if (ioa_cfg->cache_state == CACHE_NONE) 249662275040Sbrking@us.ibm.com return -EINVAL; 249762275040Sbrking@us.ibm.com 249862275040Sbrking@us.ibm.com for (i = 0; i < ARRAY_SIZE(cache_state); i++) { 249962275040Sbrking@us.ibm.com if (!strncmp(cache_state[i].name, buf, strlen(cache_state[i].name))) { 250062275040Sbrking@us.ibm.com new_state = cache_state[i].state; 250162275040Sbrking@us.ibm.com break; 250262275040Sbrking@us.ibm.com } 250362275040Sbrking@us.ibm.com } 250462275040Sbrking@us.ibm.com 250562275040Sbrking@us.ibm.com if (new_state != CACHE_DISABLED && new_state != CACHE_ENABLED) 250662275040Sbrking@us.ibm.com return -EINVAL; 250762275040Sbrking@us.ibm.com 250862275040Sbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 250962275040Sbrking@us.ibm.com if (ioa_cfg->cache_state == new_state) { 251062275040Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 251162275040Sbrking@us.ibm.com return count; 251262275040Sbrking@us.ibm.com } 251362275040Sbrking@us.ibm.com 251462275040Sbrking@us.ibm.com ioa_cfg->cache_state = new_state; 251562275040Sbrking@us.ibm.com dev_info(&ioa_cfg->pdev->dev, "%s adapter write cache.\n", 251662275040Sbrking@us.ibm.com new_state == CACHE_ENABLED ? "Enabling" : "Disabling"); 251762275040Sbrking@us.ibm.com if (!ioa_cfg->in_reset_reload) 251862275040Sbrking@us.ibm.com ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); 251962275040Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 252062275040Sbrking@us.ibm.com wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 252162275040Sbrking@us.ibm.com 252262275040Sbrking@us.ibm.com return count; 252362275040Sbrking@us.ibm.com } 252462275040Sbrking@us.ibm.com 252562275040Sbrking@us.ibm.com static struct class_device_attribute ipr_ioa_cache_attr = { 252662275040Sbrking@us.ibm.com .attr = { 252762275040Sbrking@us.ibm.com .name = "write_cache", 252862275040Sbrking@us.ibm.com .mode = S_IRUGO | S_IWUSR, 252962275040Sbrking@us.ibm.com }, 253062275040Sbrking@us.ibm.com .show = ipr_show_write_caching, 253162275040Sbrking@us.ibm.com .store = ipr_store_write_caching 253262275040Sbrking@us.ibm.com }; 253362275040Sbrking@us.ibm.com 25341da177e4SLinus Torvalds /** 25351da177e4SLinus Torvalds * ipr_show_fw_version - Show the firmware version 25361da177e4SLinus Torvalds * @class_dev: class device struct 25371da177e4SLinus Torvalds * @buf: buffer 25381da177e4SLinus Torvalds * 25391da177e4SLinus Torvalds * Return value: 25401da177e4SLinus Torvalds * number of bytes printed to buffer 25411da177e4SLinus Torvalds **/ 25421da177e4SLinus Torvalds static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf) 25431da177e4SLinus Torvalds { 25441da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 25451da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 25461da177e4SLinus Torvalds struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; 25471da177e4SLinus Torvalds unsigned long lock_flags = 0; 25481da177e4SLinus Torvalds int len; 25491da177e4SLinus Torvalds 25501da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 25511da177e4SLinus Torvalds len = snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X\n", 25521da177e4SLinus Torvalds ucode_vpd->major_release, ucode_vpd->card_type, 25531da177e4SLinus Torvalds ucode_vpd->minor_release[0], 25541da177e4SLinus Torvalds ucode_vpd->minor_release[1]); 25551da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 25561da177e4SLinus Torvalds return len; 25571da177e4SLinus Torvalds } 25581da177e4SLinus Torvalds 25591da177e4SLinus Torvalds static struct class_device_attribute ipr_fw_version_attr = { 25601da177e4SLinus Torvalds .attr = { 25611da177e4SLinus Torvalds .name = "fw_version", 25621da177e4SLinus Torvalds .mode = S_IRUGO, 25631da177e4SLinus Torvalds }, 25641da177e4SLinus Torvalds .show = ipr_show_fw_version, 25651da177e4SLinus Torvalds }; 25661da177e4SLinus Torvalds 25671da177e4SLinus Torvalds /** 25681da177e4SLinus Torvalds * ipr_show_log_level - Show the adapter's error logging level 25691da177e4SLinus Torvalds * @class_dev: class device struct 25701da177e4SLinus Torvalds * @buf: buffer 25711da177e4SLinus Torvalds * 25721da177e4SLinus Torvalds * Return value: 25731da177e4SLinus Torvalds * number of bytes printed to buffer 25741da177e4SLinus Torvalds **/ 25751da177e4SLinus Torvalds static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf) 25761da177e4SLinus Torvalds { 25771da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 25781da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 25791da177e4SLinus Torvalds unsigned long lock_flags = 0; 25801da177e4SLinus Torvalds int len; 25811da177e4SLinus Torvalds 25821da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 25831da177e4SLinus Torvalds len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->log_level); 25841da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 25851da177e4SLinus Torvalds return len; 25861da177e4SLinus Torvalds } 25871da177e4SLinus Torvalds 25881da177e4SLinus Torvalds /** 25891da177e4SLinus Torvalds * ipr_store_log_level - Change the adapter's error logging level 25901da177e4SLinus Torvalds * @class_dev: class device struct 25911da177e4SLinus Torvalds * @buf: buffer 25921da177e4SLinus Torvalds * 25931da177e4SLinus Torvalds * Return value: 25941da177e4SLinus Torvalds * number of bytes printed to buffer 25951da177e4SLinus Torvalds **/ 25961da177e4SLinus Torvalds static ssize_t ipr_store_log_level(struct class_device *class_dev, 25971da177e4SLinus Torvalds const char *buf, size_t count) 25981da177e4SLinus Torvalds { 25991da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 26001da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 26011da177e4SLinus Torvalds unsigned long lock_flags = 0; 26021da177e4SLinus Torvalds 26031da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 26041da177e4SLinus Torvalds ioa_cfg->log_level = simple_strtoul(buf, NULL, 10); 26051da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 26061da177e4SLinus Torvalds return strlen(buf); 26071da177e4SLinus Torvalds } 26081da177e4SLinus Torvalds 26091da177e4SLinus Torvalds static struct class_device_attribute ipr_log_level_attr = { 26101da177e4SLinus Torvalds .attr = { 26111da177e4SLinus Torvalds .name = "log_level", 26121da177e4SLinus Torvalds .mode = S_IRUGO | S_IWUSR, 26131da177e4SLinus Torvalds }, 26141da177e4SLinus Torvalds .show = ipr_show_log_level, 26151da177e4SLinus Torvalds .store = ipr_store_log_level 26161da177e4SLinus Torvalds }; 26171da177e4SLinus Torvalds 26181da177e4SLinus Torvalds /** 26191da177e4SLinus Torvalds * ipr_store_diagnostics - IOA Diagnostics interface 26201da177e4SLinus Torvalds * @class_dev: class_device struct 26211da177e4SLinus Torvalds * @buf: buffer 26221da177e4SLinus Torvalds * @count: buffer size 26231da177e4SLinus Torvalds * 26241da177e4SLinus Torvalds * This function will reset the adapter and wait a reasonable 26251da177e4SLinus Torvalds * amount of time for any errors that the adapter might log. 26261da177e4SLinus Torvalds * 26271da177e4SLinus Torvalds * Return value: 26281da177e4SLinus Torvalds * count on success / other on failure 26291da177e4SLinus Torvalds **/ 26301da177e4SLinus Torvalds static ssize_t ipr_store_diagnostics(struct class_device *class_dev, 26311da177e4SLinus Torvalds const char *buf, size_t count) 26321da177e4SLinus Torvalds { 26331da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 26341da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 26351da177e4SLinus Torvalds unsigned long lock_flags = 0; 26361da177e4SLinus Torvalds int rc = count; 26371da177e4SLinus Torvalds 26381da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 26391da177e4SLinus Torvalds return -EACCES; 26401da177e4SLinus Torvalds 26411da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 26421da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 26431da177e4SLinus Torvalds ioa_cfg->errors_logged = 0; 26441da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); 26451da177e4SLinus Torvalds 26461da177e4SLinus Torvalds if (ioa_cfg->in_reset_reload) { 26471da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 26481da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds /* Wait for a second for any errors to be logged */ 26511da177e4SLinus Torvalds msleep(1000); 26521da177e4SLinus Torvalds } else { 26531da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 26541da177e4SLinus Torvalds return -EIO; 26551da177e4SLinus Torvalds } 26561da177e4SLinus Torvalds 26571da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 26581da177e4SLinus Torvalds if (ioa_cfg->in_reset_reload || ioa_cfg->errors_logged) 26591da177e4SLinus Torvalds rc = -EIO; 26601da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 26611da177e4SLinus Torvalds 26621da177e4SLinus Torvalds return rc; 26631da177e4SLinus Torvalds } 26641da177e4SLinus Torvalds 26651da177e4SLinus Torvalds static struct class_device_attribute ipr_diagnostics_attr = { 26661da177e4SLinus Torvalds .attr = { 26671da177e4SLinus Torvalds .name = "run_diagnostics", 26681da177e4SLinus Torvalds .mode = S_IWUSR, 26691da177e4SLinus Torvalds }, 26701da177e4SLinus Torvalds .store = ipr_store_diagnostics 26711da177e4SLinus Torvalds }; 26721da177e4SLinus Torvalds 26731da177e4SLinus Torvalds /** 2674f37eb54bSbrking@us.ibm.com * ipr_show_adapter_state - Show the adapter's state 2675f37eb54bSbrking@us.ibm.com * @class_dev: class device struct 2676f37eb54bSbrking@us.ibm.com * @buf: buffer 2677f37eb54bSbrking@us.ibm.com * 2678f37eb54bSbrking@us.ibm.com * Return value: 2679f37eb54bSbrking@us.ibm.com * number of bytes printed to buffer 2680f37eb54bSbrking@us.ibm.com **/ 2681f37eb54bSbrking@us.ibm.com static ssize_t ipr_show_adapter_state(struct class_device *class_dev, char *buf) 2682f37eb54bSbrking@us.ibm.com { 2683f37eb54bSbrking@us.ibm.com struct Scsi_Host *shost = class_to_shost(class_dev); 2684f37eb54bSbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 2685f37eb54bSbrking@us.ibm.com unsigned long lock_flags = 0; 2686f37eb54bSbrking@us.ibm.com int len; 2687f37eb54bSbrking@us.ibm.com 2688f37eb54bSbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 2689f37eb54bSbrking@us.ibm.com if (ioa_cfg->ioa_is_dead) 2690f37eb54bSbrking@us.ibm.com len = snprintf(buf, PAGE_SIZE, "offline\n"); 2691f37eb54bSbrking@us.ibm.com else 2692f37eb54bSbrking@us.ibm.com len = snprintf(buf, PAGE_SIZE, "online\n"); 2693f37eb54bSbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 2694f37eb54bSbrking@us.ibm.com return len; 2695f37eb54bSbrking@us.ibm.com } 2696f37eb54bSbrking@us.ibm.com 2697f37eb54bSbrking@us.ibm.com /** 2698f37eb54bSbrking@us.ibm.com * ipr_store_adapter_state - Change adapter state 2699f37eb54bSbrking@us.ibm.com * @class_dev: class_device struct 2700f37eb54bSbrking@us.ibm.com * @buf: buffer 2701f37eb54bSbrking@us.ibm.com * @count: buffer size 2702f37eb54bSbrking@us.ibm.com * 2703f37eb54bSbrking@us.ibm.com * This function will change the adapter's state. 2704f37eb54bSbrking@us.ibm.com * 2705f37eb54bSbrking@us.ibm.com * Return value: 2706f37eb54bSbrking@us.ibm.com * count on success / other on failure 2707f37eb54bSbrking@us.ibm.com **/ 2708f37eb54bSbrking@us.ibm.com static ssize_t ipr_store_adapter_state(struct class_device *class_dev, 2709f37eb54bSbrking@us.ibm.com const char *buf, size_t count) 2710f37eb54bSbrking@us.ibm.com { 2711f37eb54bSbrking@us.ibm.com struct Scsi_Host *shost = class_to_shost(class_dev); 2712f37eb54bSbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 2713f37eb54bSbrking@us.ibm.com unsigned long lock_flags; 2714f37eb54bSbrking@us.ibm.com int result = count; 2715f37eb54bSbrking@us.ibm.com 2716f37eb54bSbrking@us.ibm.com if (!capable(CAP_SYS_ADMIN)) 2717f37eb54bSbrking@us.ibm.com return -EACCES; 2718f37eb54bSbrking@us.ibm.com 2719f37eb54bSbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 2720f37eb54bSbrking@us.ibm.com if (ioa_cfg->ioa_is_dead && !strncmp(buf, "online", 6)) { 2721f37eb54bSbrking@us.ibm.com ioa_cfg->ioa_is_dead = 0; 2722f37eb54bSbrking@us.ibm.com ioa_cfg->reset_retries = 0; 2723f37eb54bSbrking@us.ibm.com ioa_cfg->in_ioa_bringdown = 0; 2724f37eb54bSbrking@us.ibm.com ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 2725f37eb54bSbrking@us.ibm.com } 2726f37eb54bSbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 2727f37eb54bSbrking@us.ibm.com wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 2728f37eb54bSbrking@us.ibm.com 2729f37eb54bSbrking@us.ibm.com return result; 2730f37eb54bSbrking@us.ibm.com } 2731f37eb54bSbrking@us.ibm.com 2732f37eb54bSbrking@us.ibm.com static struct class_device_attribute ipr_ioa_state_attr = { 2733f37eb54bSbrking@us.ibm.com .attr = { 2734f37eb54bSbrking@us.ibm.com .name = "state", 2735f37eb54bSbrking@us.ibm.com .mode = S_IRUGO | S_IWUSR, 2736f37eb54bSbrking@us.ibm.com }, 2737f37eb54bSbrking@us.ibm.com .show = ipr_show_adapter_state, 2738f37eb54bSbrking@us.ibm.com .store = ipr_store_adapter_state 2739f37eb54bSbrking@us.ibm.com }; 2740f37eb54bSbrking@us.ibm.com 2741f37eb54bSbrking@us.ibm.com /** 27421da177e4SLinus Torvalds * ipr_store_reset_adapter - Reset the adapter 27431da177e4SLinus Torvalds * @class_dev: class_device struct 27441da177e4SLinus Torvalds * @buf: buffer 27451da177e4SLinus Torvalds * @count: buffer size 27461da177e4SLinus Torvalds * 27471da177e4SLinus Torvalds * This function will reset the adapter. 27481da177e4SLinus Torvalds * 27491da177e4SLinus Torvalds * Return value: 27501da177e4SLinus Torvalds * count on success / other on failure 27511da177e4SLinus Torvalds **/ 27521da177e4SLinus Torvalds static ssize_t ipr_store_reset_adapter(struct class_device *class_dev, 27531da177e4SLinus Torvalds const char *buf, size_t count) 27541da177e4SLinus Torvalds { 27551da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 27561da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 27571da177e4SLinus Torvalds unsigned long lock_flags; 27581da177e4SLinus Torvalds int result = count; 27591da177e4SLinus Torvalds 27601da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 27611da177e4SLinus Torvalds return -EACCES; 27621da177e4SLinus Torvalds 27631da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 27641da177e4SLinus Torvalds if (!ioa_cfg->in_reset_reload) 27651da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); 27661da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 27671da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 27681da177e4SLinus Torvalds 27691da177e4SLinus Torvalds return result; 27701da177e4SLinus Torvalds } 27711da177e4SLinus Torvalds 27721da177e4SLinus Torvalds static struct class_device_attribute ipr_ioa_reset_attr = { 27731da177e4SLinus Torvalds .attr = { 27741da177e4SLinus Torvalds .name = "reset_host", 27751da177e4SLinus Torvalds .mode = S_IWUSR, 27761da177e4SLinus Torvalds }, 27771da177e4SLinus Torvalds .store = ipr_store_reset_adapter 27781da177e4SLinus Torvalds }; 27791da177e4SLinus Torvalds 27801da177e4SLinus Torvalds /** 27811da177e4SLinus Torvalds * ipr_alloc_ucode_buffer - Allocates a microcode download buffer 27821da177e4SLinus Torvalds * @buf_len: buffer length 27831da177e4SLinus Torvalds * 27841da177e4SLinus Torvalds * Allocates a DMA'able buffer in chunks and assembles a scatter/gather 27851da177e4SLinus Torvalds * list to use for microcode download 27861da177e4SLinus Torvalds * 27871da177e4SLinus Torvalds * Return value: 27881da177e4SLinus Torvalds * pointer to sglist / NULL on failure 27891da177e4SLinus Torvalds **/ 27901da177e4SLinus Torvalds static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) 27911da177e4SLinus Torvalds { 27921da177e4SLinus Torvalds int sg_size, order, bsize_elem, num_elem, i, j; 27931da177e4SLinus Torvalds struct ipr_sglist *sglist; 27941da177e4SLinus Torvalds struct scatterlist *scatterlist; 27951da177e4SLinus Torvalds struct page *page; 27961da177e4SLinus Torvalds 27971da177e4SLinus Torvalds /* Get the minimum size per scatter/gather element */ 27981da177e4SLinus Torvalds sg_size = buf_len / (IPR_MAX_SGLIST - 1); 27991da177e4SLinus Torvalds 28001da177e4SLinus Torvalds /* Get the actual size per element */ 28011da177e4SLinus Torvalds order = get_order(sg_size); 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds /* Determine the actual number of bytes per element */ 28041da177e4SLinus Torvalds bsize_elem = PAGE_SIZE * (1 << order); 28051da177e4SLinus Torvalds 28061da177e4SLinus Torvalds /* Determine the actual number of sg entries needed */ 28071da177e4SLinus Torvalds if (buf_len % bsize_elem) 28081da177e4SLinus Torvalds num_elem = (buf_len / bsize_elem) + 1; 28091da177e4SLinus Torvalds else 28101da177e4SLinus Torvalds num_elem = buf_len / bsize_elem; 28111da177e4SLinus Torvalds 28121da177e4SLinus Torvalds /* Allocate a scatter/gather list for the DMA */ 28130bc42e35Sbrking@us.ibm.com sglist = kzalloc(sizeof(struct ipr_sglist) + 28141da177e4SLinus Torvalds (sizeof(struct scatterlist) * (num_elem - 1)), 28151da177e4SLinus Torvalds GFP_KERNEL); 28161da177e4SLinus Torvalds 28171da177e4SLinus Torvalds if (sglist == NULL) { 28181da177e4SLinus Torvalds ipr_trace; 28191da177e4SLinus Torvalds return NULL; 28201da177e4SLinus Torvalds } 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds scatterlist = sglist->scatterlist; 28231da177e4SLinus Torvalds 28241da177e4SLinus Torvalds sglist->order = order; 28251da177e4SLinus Torvalds sglist->num_sg = num_elem; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds /* Allocate a bunch of sg elements */ 28281da177e4SLinus Torvalds for (i = 0; i < num_elem; i++) { 28291da177e4SLinus Torvalds page = alloc_pages(GFP_KERNEL, order); 28301da177e4SLinus Torvalds if (!page) { 28311da177e4SLinus Torvalds ipr_trace; 28321da177e4SLinus Torvalds 28331da177e4SLinus Torvalds /* Free up what we already allocated */ 28341da177e4SLinus Torvalds for (j = i - 1; j >= 0; j--) 28351da177e4SLinus Torvalds __free_pages(scatterlist[j].page, order); 28361da177e4SLinus Torvalds kfree(sglist); 28371da177e4SLinus Torvalds return NULL; 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds 28401da177e4SLinus Torvalds scatterlist[i].page = page; 28411da177e4SLinus Torvalds } 28421da177e4SLinus Torvalds 28431da177e4SLinus Torvalds return sglist; 28441da177e4SLinus Torvalds } 28451da177e4SLinus Torvalds 28461da177e4SLinus Torvalds /** 28471da177e4SLinus Torvalds * ipr_free_ucode_buffer - Frees a microcode download buffer 28481da177e4SLinus Torvalds * @p_dnld: scatter/gather list pointer 28491da177e4SLinus Torvalds * 28501da177e4SLinus Torvalds * Free a DMA'able ucode download buffer previously allocated with 28511da177e4SLinus Torvalds * ipr_alloc_ucode_buffer 28521da177e4SLinus Torvalds * 28531da177e4SLinus Torvalds * Return value: 28541da177e4SLinus Torvalds * nothing 28551da177e4SLinus Torvalds **/ 28561da177e4SLinus Torvalds static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) 28571da177e4SLinus Torvalds { 28581da177e4SLinus Torvalds int i; 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds for (i = 0; i < sglist->num_sg; i++) 28611da177e4SLinus Torvalds __free_pages(sglist->scatterlist[i].page, sglist->order); 28621da177e4SLinus Torvalds 28631da177e4SLinus Torvalds kfree(sglist); 28641da177e4SLinus Torvalds } 28651da177e4SLinus Torvalds 28661da177e4SLinus Torvalds /** 28671da177e4SLinus Torvalds * ipr_copy_ucode_buffer - Copy user buffer to kernel buffer 28681da177e4SLinus Torvalds * @sglist: scatter/gather list pointer 28691da177e4SLinus Torvalds * @buffer: buffer pointer 28701da177e4SLinus Torvalds * @len: buffer length 28711da177e4SLinus Torvalds * 28721da177e4SLinus Torvalds * Copy a microcode image from a user buffer into a buffer allocated by 28731da177e4SLinus Torvalds * ipr_alloc_ucode_buffer 28741da177e4SLinus Torvalds * 28751da177e4SLinus Torvalds * Return value: 28761da177e4SLinus Torvalds * 0 on success / other on failure 28771da177e4SLinus Torvalds **/ 28781da177e4SLinus Torvalds static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, 28791da177e4SLinus Torvalds u8 *buffer, u32 len) 28801da177e4SLinus Torvalds { 28811da177e4SLinus Torvalds int bsize_elem, i, result = 0; 28821da177e4SLinus Torvalds struct scatterlist *scatterlist; 28831da177e4SLinus Torvalds void *kaddr; 28841da177e4SLinus Torvalds 28851da177e4SLinus Torvalds /* Determine the actual number of bytes per element */ 28861da177e4SLinus Torvalds bsize_elem = PAGE_SIZE * (1 << sglist->order); 28871da177e4SLinus Torvalds 28881da177e4SLinus Torvalds scatterlist = sglist->scatterlist; 28891da177e4SLinus Torvalds 28901da177e4SLinus Torvalds for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { 28911da177e4SLinus Torvalds kaddr = kmap(scatterlist[i].page); 28921da177e4SLinus Torvalds memcpy(kaddr, buffer, bsize_elem); 28931da177e4SLinus Torvalds kunmap(scatterlist[i].page); 28941da177e4SLinus Torvalds 28951da177e4SLinus Torvalds scatterlist[i].length = bsize_elem; 28961da177e4SLinus Torvalds 28971da177e4SLinus Torvalds if (result != 0) { 28981da177e4SLinus Torvalds ipr_trace; 28991da177e4SLinus Torvalds return result; 29001da177e4SLinus Torvalds } 29011da177e4SLinus Torvalds } 29021da177e4SLinus Torvalds 29031da177e4SLinus Torvalds if (len % bsize_elem) { 29041da177e4SLinus Torvalds kaddr = kmap(scatterlist[i].page); 29051da177e4SLinus Torvalds memcpy(kaddr, buffer, len % bsize_elem); 29061da177e4SLinus Torvalds kunmap(scatterlist[i].page); 29071da177e4SLinus Torvalds 29081da177e4SLinus Torvalds scatterlist[i].length = len % bsize_elem; 29091da177e4SLinus Torvalds } 29101da177e4SLinus Torvalds 29111da177e4SLinus Torvalds sglist->buffer_len = len; 29121da177e4SLinus Torvalds return result; 29131da177e4SLinus Torvalds } 29141da177e4SLinus Torvalds 29151da177e4SLinus Torvalds /** 291612baa420Sbrking@us.ibm.com * ipr_build_ucode_ioadl - Build a microcode download IOADL 29171da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 29181da177e4SLinus Torvalds * @sglist: scatter/gather list 29191da177e4SLinus Torvalds * 292012baa420Sbrking@us.ibm.com * Builds a microcode download IOA data list (IOADL). 29211da177e4SLinus Torvalds * 29221da177e4SLinus Torvalds **/ 292312baa420Sbrking@us.ibm.com static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, 292412baa420Sbrking@us.ibm.com struct ipr_sglist *sglist) 29251da177e4SLinus Torvalds { 29261da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 29271da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 29281da177e4SLinus Torvalds struct scatterlist *scatterlist = sglist->scatterlist; 29291da177e4SLinus Torvalds int i; 29301da177e4SLinus Torvalds 293112baa420Sbrking@us.ibm.com ipr_cmd->dma_use_sg = sglist->num_dma_sg; 29321da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 293312baa420Sbrking@us.ibm.com ioarcb->write_data_transfer_length = cpu_to_be32(sglist->buffer_len); 29341da177e4SLinus Torvalds ioarcb->write_ioadl_len = 29351da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 29361da177e4SLinus Torvalds 29371da177e4SLinus Torvalds for (i = 0; i < ipr_cmd->dma_use_sg; i++) { 29381da177e4SLinus Torvalds ioadl[i].flags_and_data_len = 29391da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i])); 29401da177e4SLinus Torvalds ioadl[i].address = 29411da177e4SLinus Torvalds cpu_to_be32(sg_dma_address(&scatterlist[i])); 29421da177e4SLinus Torvalds } 29431da177e4SLinus Torvalds 29441da177e4SLinus Torvalds ioadl[i-1].flags_and_data_len |= 29451da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_LAST); 29461da177e4SLinus Torvalds } 294712baa420Sbrking@us.ibm.com 294812baa420Sbrking@us.ibm.com /** 294912baa420Sbrking@us.ibm.com * ipr_update_ioa_ucode - Update IOA's microcode 295012baa420Sbrking@us.ibm.com * @ioa_cfg: ioa config struct 295112baa420Sbrking@us.ibm.com * @sglist: scatter/gather list 295212baa420Sbrking@us.ibm.com * 295312baa420Sbrking@us.ibm.com * Initiate an adapter reset to update the IOA's microcode 295412baa420Sbrking@us.ibm.com * 295512baa420Sbrking@us.ibm.com * Return value: 295612baa420Sbrking@us.ibm.com * 0 on success / -EIO on failure 295712baa420Sbrking@us.ibm.com **/ 295812baa420Sbrking@us.ibm.com static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, 295912baa420Sbrking@us.ibm.com struct ipr_sglist *sglist) 296012baa420Sbrking@us.ibm.com { 296112baa420Sbrking@us.ibm.com unsigned long lock_flags; 296212baa420Sbrking@us.ibm.com 296312baa420Sbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 296412baa420Sbrking@us.ibm.com 296512baa420Sbrking@us.ibm.com if (ioa_cfg->ucode_sglist) { 296612baa420Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 296712baa420Sbrking@us.ibm.com dev_err(&ioa_cfg->pdev->dev, 296812baa420Sbrking@us.ibm.com "Microcode download already in progress\n"); 29691da177e4SLinus Torvalds return -EIO; 29701da177e4SLinus Torvalds } 29711da177e4SLinus Torvalds 297212baa420Sbrking@us.ibm.com sglist->num_dma_sg = pci_map_sg(ioa_cfg->pdev, sglist->scatterlist, 297312baa420Sbrking@us.ibm.com sglist->num_sg, DMA_TO_DEVICE); 297412baa420Sbrking@us.ibm.com 297512baa420Sbrking@us.ibm.com if (!sglist->num_dma_sg) { 297612baa420Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 297712baa420Sbrking@us.ibm.com dev_err(&ioa_cfg->pdev->dev, 297812baa420Sbrking@us.ibm.com "Failed to map microcode download buffer!\n"); 297912baa420Sbrking@us.ibm.com return -EIO; 298012baa420Sbrking@us.ibm.com } 298112baa420Sbrking@us.ibm.com 298212baa420Sbrking@us.ibm.com ioa_cfg->ucode_sglist = sglist; 298312baa420Sbrking@us.ibm.com ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); 298412baa420Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 298512baa420Sbrking@us.ibm.com wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 298612baa420Sbrking@us.ibm.com 298712baa420Sbrking@us.ibm.com spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 298812baa420Sbrking@us.ibm.com ioa_cfg->ucode_sglist = NULL; 298912baa420Sbrking@us.ibm.com spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 29901da177e4SLinus Torvalds return 0; 29911da177e4SLinus Torvalds } 29921da177e4SLinus Torvalds 29931da177e4SLinus Torvalds /** 29941da177e4SLinus Torvalds * ipr_store_update_fw - Update the firmware on the adapter 29951da177e4SLinus Torvalds * @class_dev: class_device struct 29961da177e4SLinus Torvalds * @buf: buffer 29971da177e4SLinus Torvalds * @count: buffer size 29981da177e4SLinus Torvalds * 29991da177e4SLinus Torvalds * This function will update the firmware on the adapter. 30001da177e4SLinus Torvalds * 30011da177e4SLinus Torvalds * Return value: 30021da177e4SLinus Torvalds * count on success / other on failure 30031da177e4SLinus Torvalds **/ 30041da177e4SLinus Torvalds static ssize_t ipr_store_update_fw(struct class_device *class_dev, 30051da177e4SLinus Torvalds const char *buf, size_t count) 30061da177e4SLinus Torvalds { 30071da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(class_dev); 30081da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 30091da177e4SLinus Torvalds struct ipr_ucode_image_header *image_hdr; 30101da177e4SLinus Torvalds const struct firmware *fw_entry; 30111da177e4SLinus Torvalds struct ipr_sglist *sglist; 30121da177e4SLinus Torvalds char fname[100]; 30131da177e4SLinus Torvalds char *src; 30141da177e4SLinus Torvalds int len, result, dnld_size; 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 30171da177e4SLinus Torvalds return -EACCES; 30181da177e4SLinus Torvalds 30191da177e4SLinus Torvalds len = snprintf(fname, 99, "%s", buf); 30201da177e4SLinus Torvalds fname[len-1] = '\0'; 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { 30231da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); 30241da177e4SLinus Torvalds return -EIO; 30251da177e4SLinus Torvalds } 30261da177e4SLinus Torvalds 30271da177e4SLinus Torvalds image_hdr = (struct ipr_ucode_image_header *)fw_entry->data; 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds if (be32_to_cpu(image_hdr->header_length) > fw_entry->size || 30301da177e4SLinus Torvalds (ioa_cfg->vpd_cbs->page3_data.card_type && 30311da177e4SLinus Torvalds ioa_cfg->vpd_cbs->page3_data.card_type != image_hdr->card_type)) { 30321da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Invalid microcode buffer\n"); 30331da177e4SLinus Torvalds release_firmware(fw_entry); 30341da177e4SLinus Torvalds return -EINVAL; 30351da177e4SLinus Torvalds } 30361da177e4SLinus Torvalds 30371da177e4SLinus Torvalds src = (u8 *)image_hdr + be32_to_cpu(image_hdr->header_length); 30381da177e4SLinus Torvalds dnld_size = fw_entry->size - be32_to_cpu(image_hdr->header_length); 30391da177e4SLinus Torvalds sglist = ipr_alloc_ucode_buffer(dnld_size); 30401da177e4SLinus Torvalds 30411da177e4SLinus Torvalds if (!sglist) { 30421da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Microcode buffer allocation failed\n"); 30431da177e4SLinus Torvalds release_firmware(fw_entry); 30441da177e4SLinus Torvalds return -ENOMEM; 30451da177e4SLinus Torvalds } 30461da177e4SLinus Torvalds 30471da177e4SLinus Torvalds result = ipr_copy_ucode_buffer(sglist, src, dnld_size); 30481da177e4SLinus Torvalds 30491da177e4SLinus Torvalds if (result) { 30501da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 30511da177e4SLinus Torvalds "Microcode buffer copy to DMA buffer failed\n"); 305212baa420Sbrking@us.ibm.com goto out; 305312baa420Sbrking@us.ibm.com } 305412baa420Sbrking@us.ibm.com 305512baa420Sbrking@us.ibm.com result = ipr_update_ioa_ucode(ioa_cfg, sglist); 305612baa420Sbrking@us.ibm.com 305712baa420Sbrking@us.ibm.com if (!result) 305812baa420Sbrking@us.ibm.com result = count; 305912baa420Sbrking@us.ibm.com out: 30601da177e4SLinus Torvalds ipr_free_ucode_buffer(sglist); 30611da177e4SLinus Torvalds release_firmware(fw_entry); 30621da177e4SLinus Torvalds return result; 30631da177e4SLinus Torvalds } 30641da177e4SLinus Torvalds 30651da177e4SLinus Torvalds static struct class_device_attribute ipr_update_fw_attr = { 30661da177e4SLinus Torvalds .attr = { 30671da177e4SLinus Torvalds .name = "update_fw", 30681da177e4SLinus Torvalds .mode = S_IWUSR, 30691da177e4SLinus Torvalds }, 30701da177e4SLinus Torvalds .store = ipr_store_update_fw 30711da177e4SLinus Torvalds }; 30721da177e4SLinus Torvalds 30731da177e4SLinus Torvalds static struct class_device_attribute *ipr_ioa_attrs[] = { 30741da177e4SLinus Torvalds &ipr_fw_version_attr, 30751da177e4SLinus Torvalds &ipr_log_level_attr, 30761da177e4SLinus Torvalds &ipr_diagnostics_attr, 3077f37eb54bSbrking@us.ibm.com &ipr_ioa_state_attr, 30781da177e4SLinus Torvalds &ipr_ioa_reset_attr, 30791da177e4SLinus Torvalds &ipr_update_fw_attr, 308062275040Sbrking@us.ibm.com &ipr_ioa_cache_attr, 30811da177e4SLinus Torvalds NULL, 30821da177e4SLinus Torvalds }; 30831da177e4SLinus Torvalds 30841da177e4SLinus Torvalds #ifdef CONFIG_SCSI_IPR_DUMP 30851da177e4SLinus Torvalds /** 30861da177e4SLinus Torvalds * ipr_read_dump - Dump the adapter 30871da177e4SLinus Torvalds * @kobj: kobject struct 30881da177e4SLinus Torvalds * @buf: buffer 30891da177e4SLinus Torvalds * @off: offset 30901da177e4SLinus Torvalds * @count: buffer size 30911da177e4SLinus Torvalds * 30921da177e4SLinus Torvalds * Return value: 30931da177e4SLinus Torvalds * number of bytes printed to buffer 30941da177e4SLinus Torvalds **/ 30951da177e4SLinus Torvalds static ssize_t ipr_read_dump(struct kobject *kobj, char *buf, 30961da177e4SLinus Torvalds loff_t off, size_t count) 30971da177e4SLinus Torvalds { 30981da177e4SLinus Torvalds struct class_device *cdev = container_of(kobj,struct class_device,kobj); 30991da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(cdev); 31001da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 31011da177e4SLinus Torvalds struct ipr_dump *dump; 31021da177e4SLinus Torvalds unsigned long lock_flags = 0; 31031da177e4SLinus Torvalds char *src; 31041da177e4SLinus Torvalds int len; 31051da177e4SLinus Torvalds size_t rc = count; 31061da177e4SLinus Torvalds 31071da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 31081da177e4SLinus Torvalds return -EACCES; 31091da177e4SLinus Torvalds 31101da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 31111da177e4SLinus Torvalds dump = ioa_cfg->dump; 31121da177e4SLinus Torvalds 31131da177e4SLinus Torvalds if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump) { 31141da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 31151da177e4SLinus Torvalds return 0; 31161da177e4SLinus Torvalds } 31171da177e4SLinus Torvalds kref_get(&dump->kref); 31181da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 31191da177e4SLinus Torvalds 31201da177e4SLinus Torvalds if (off > dump->driver_dump.hdr.len) { 31211da177e4SLinus Torvalds kref_put(&dump->kref, ipr_release_dump); 31221da177e4SLinus Torvalds return 0; 31231da177e4SLinus Torvalds } 31241da177e4SLinus Torvalds 31251da177e4SLinus Torvalds if (off + count > dump->driver_dump.hdr.len) { 31261da177e4SLinus Torvalds count = dump->driver_dump.hdr.len - off; 31271da177e4SLinus Torvalds rc = count; 31281da177e4SLinus Torvalds } 31291da177e4SLinus Torvalds 31301da177e4SLinus Torvalds if (count && off < sizeof(dump->driver_dump)) { 31311da177e4SLinus Torvalds if (off + count > sizeof(dump->driver_dump)) 31321da177e4SLinus Torvalds len = sizeof(dump->driver_dump) - off; 31331da177e4SLinus Torvalds else 31341da177e4SLinus Torvalds len = count; 31351da177e4SLinus Torvalds src = (u8 *)&dump->driver_dump + off; 31361da177e4SLinus Torvalds memcpy(buf, src, len); 31371da177e4SLinus Torvalds buf += len; 31381da177e4SLinus Torvalds off += len; 31391da177e4SLinus Torvalds count -= len; 31401da177e4SLinus Torvalds } 31411da177e4SLinus Torvalds 31421da177e4SLinus Torvalds off -= sizeof(dump->driver_dump); 31431da177e4SLinus Torvalds 31441da177e4SLinus Torvalds if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) { 31451da177e4SLinus Torvalds if (off + count > offsetof(struct ipr_ioa_dump, ioa_data)) 31461da177e4SLinus Torvalds len = offsetof(struct ipr_ioa_dump, ioa_data) - off; 31471da177e4SLinus Torvalds else 31481da177e4SLinus Torvalds len = count; 31491da177e4SLinus Torvalds src = (u8 *)&dump->ioa_dump + off; 31501da177e4SLinus Torvalds memcpy(buf, src, len); 31511da177e4SLinus Torvalds buf += len; 31521da177e4SLinus Torvalds off += len; 31531da177e4SLinus Torvalds count -= len; 31541da177e4SLinus Torvalds } 31551da177e4SLinus Torvalds 31561da177e4SLinus Torvalds off -= offsetof(struct ipr_ioa_dump, ioa_data); 31571da177e4SLinus Torvalds 31581da177e4SLinus Torvalds while (count) { 31591da177e4SLinus Torvalds if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK)) 31601da177e4SLinus Torvalds len = PAGE_ALIGN(off) - off; 31611da177e4SLinus Torvalds else 31621da177e4SLinus Torvalds len = count; 31631da177e4SLinus Torvalds src = (u8 *)dump->ioa_dump.ioa_data[(off & PAGE_MASK) >> PAGE_SHIFT]; 31641da177e4SLinus Torvalds src += off & ~PAGE_MASK; 31651da177e4SLinus Torvalds memcpy(buf, src, len); 31661da177e4SLinus Torvalds buf += len; 31671da177e4SLinus Torvalds off += len; 31681da177e4SLinus Torvalds count -= len; 31691da177e4SLinus Torvalds } 31701da177e4SLinus Torvalds 31711da177e4SLinus Torvalds kref_put(&dump->kref, ipr_release_dump); 31721da177e4SLinus Torvalds return rc; 31731da177e4SLinus Torvalds } 31741da177e4SLinus Torvalds 31751da177e4SLinus Torvalds /** 31761da177e4SLinus Torvalds * ipr_alloc_dump - Prepare for adapter dump 31771da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 31781da177e4SLinus Torvalds * 31791da177e4SLinus Torvalds * Return value: 31801da177e4SLinus Torvalds * 0 on success / other on failure 31811da177e4SLinus Torvalds **/ 31821da177e4SLinus Torvalds static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) 31831da177e4SLinus Torvalds { 31841da177e4SLinus Torvalds struct ipr_dump *dump; 31851da177e4SLinus Torvalds unsigned long lock_flags = 0; 31861da177e4SLinus Torvalds 31870bc42e35Sbrking@us.ibm.com dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); 31881da177e4SLinus Torvalds 31891da177e4SLinus Torvalds if (!dump) { 31901da177e4SLinus Torvalds ipr_err("Dump memory allocation failed\n"); 31911da177e4SLinus Torvalds return -ENOMEM; 31921da177e4SLinus Torvalds } 31931da177e4SLinus Torvalds 31941da177e4SLinus Torvalds kref_init(&dump->kref); 31951da177e4SLinus Torvalds dump->ioa_cfg = ioa_cfg; 31961da177e4SLinus Torvalds 31971da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 31981da177e4SLinus Torvalds 31991da177e4SLinus Torvalds if (INACTIVE != ioa_cfg->sdt_state) { 32001da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 32011da177e4SLinus Torvalds kfree(dump); 32021da177e4SLinus Torvalds return 0; 32031da177e4SLinus Torvalds } 32041da177e4SLinus Torvalds 32051da177e4SLinus Torvalds ioa_cfg->dump = dump; 32061da177e4SLinus Torvalds ioa_cfg->sdt_state = WAIT_FOR_DUMP; 32071da177e4SLinus Torvalds if (ioa_cfg->ioa_is_dead && !ioa_cfg->dump_taken) { 32081da177e4SLinus Torvalds ioa_cfg->dump_taken = 1; 32091da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 32101da177e4SLinus Torvalds } 32111da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 32121da177e4SLinus Torvalds 32131da177e4SLinus Torvalds return 0; 32141da177e4SLinus Torvalds } 32151da177e4SLinus Torvalds 32161da177e4SLinus Torvalds /** 32171da177e4SLinus Torvalds * ipr_free_dump - Free adapter dump memory 32181da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 32191da177e4SLinus Torvalds * 32201da177e4SLinus Torvalds * Return value: 32211da177e4SLinus Torvalds * 0 on success / other on failure 32221da177e4SLinus Torvalds **/ 32231da177e4SLinus Torvalds static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) 32241da177e4SLinus Torvalds { 32251da177e4SLinus Torvalds struct ipr_dump *dump; 32261da177e4SLinus Torvalds unsigned long lock_flags = 0; 32271da177e4SLinus Torvalds 32281da177e4SLinus Torvalds ENTER; 32291da177e4SLinus Torvalds 32301da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 32311da177e4SLinus Torvalds dump = ioa_cfg->dump; 32321da177e4SLinus Torvalds if (!dump) { 32331da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 32341da177e4SLinus Torvalds return 0; 32351da177e4SLinus Torvalds } 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds ioa_cfg->dump = NULL; 32381da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 32391da177e4SLinus Torvalds 32401da177e4SLinus Torvalds kref_put(&dump->kref, ipr_release_dump); 32411da177e4SLinus Torvalds 32421da177e4SLinus Torvalds LEAVE; 32431da177e4SLinus Torvalds return 0; 32441da177e4SLinus Torvalds } 32451da177e4SLinus Torvalds 32461da177e4SLinus Torvalds /** 32471da177e4SLinus Torvalds * ipr_write_dump - Setup dump state of adapter 32481da177e4SLinus Torvalds * @kobj: kobject struct 32491da177e4SLinus Torvalds * @buf: buffer 32501da177e4SLinus Torvalds * @off: offset 32511da177e4SLinus Torvalds * @count: buffer size 32521da177e4SLinus Torvalds * 32531da177e4SLinus Torvalds * Return value: 32541da177e4SLinus Torvalds * number of bytes printed to buffer 32551da177e4SLinus Torvalds **/ 32561da177e4SLinus Torvalds static ssize_t ipr_write_dump(struct kobject *kobj, char *buf, 32571da177e4SLinus Torvalds loff_t off, size_t count) 32581da177e4SLinus Torvalds { 32591da177e4SLinus Torvalds struct class_device *cdev = container_of(kobj,struct class_device,kobj); 32601da177e4SLinus Torvalds struct Scsi_Host *shost = class_to_shost(cdev); 32611da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; 32621da177e4SLinus Torvalds int rc; 32631da177e4SLinus Torvalds 32641da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 32651da177e4SLinus Torvalds return -EACCES; 32661da177e4SLinus Torvalds 32671da177e4SLinus Torvalds if (buf[0] == '1') 32681da177e4SLinus Torvalds rc = ipr_alloc_dump(ioa_cfg); 32691da177e4SLinus Torvalds else if (buf[0] == '0') 32701da177e4SLinus Torvalds rc = ipr_free_dump(ioa_cfg); 32711da177e4SLinus Torvalds else 32721da177e4SLinus Torvalds return -EINVAL; 32731da177e4SLinus Torvalds 32741da177e4SLinus Torvalds if (rc) 32751da177e4SLinus Torvalds return rc; 32761da177e4SLinus Torvalds else 32771da177e4SLinus Torvalds return count; 32781da177e4SLinus Torvalds } 32791da177e4SLinus Torvalds 32801da177e4SLinus Torvalds static struct bin_attribute ipr_dump_attr = { 32811da177e4SLinus Torvalds .attr = { 32821da177e4SLinus Torvalds .name = "dump", 32831da177e4SLinus Torvalds .mode = S_IRUSR | S_IWUSR, 32841da177e4SLinus Torvalds }, 32851da177e4SLinus Torvalds .size = 0, 32861da177e4SLinus Torvalds .read = ipr_read_dump, 32871da177e4SLinus Torvalds .write = ipr_write_dump 32881da177e4SLinus Torvalds }; 32891da177e4SLinus Torvalds #else 32901da177e4SLinus Torvalds static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; 32911da177e4SLinus Torvalds #endif 32921da177e4SLinus Torvalds 32931da177e4SLinus Torvalds /** 32941da177e4SLinus Torvalds * ipr_change_queue_depth - Change the device's queue depth 32951da177e4SLinus Torvalds * @sdev: scsi device struct 32961da177e4SLinus Torvalds * @qdepth: depth to set 32971da177e4SLinus Torvalds * 32981da177e4SLinus Torvalds * Return value: 32991da177e4SLinus Torvalds * actual depth set 33001da177e4SLinus Torvalds **/ 33011da177e4SLinus Torvalds static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth) 33021da177e4SLinus Torvalds { 330335a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; 330435a39691SBrian King struct ipr_resource_entry *res; 330535a39691SBrian King unsigned long lock_flags = 0; 330635a39691SBrian King 330735a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 330835a39691SBrian King res = (struct ipr_resource_entry *)sdev->hostdata; 330935a39691SBrian King 331035a39691SBrian King if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN) 331135a39691SBrian King qdepth = IPR_MAX_CMD_PER_ATA_LUN; 331235a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 331335a39691SBrian King 33141da177e4SLinus Torvalds scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); 33151da177e4SLinus Torvalds return sdev->queue_depth; 33161da177e4SLinus Torvalds } 33171da177e4SLinus Torvalds 33181da177e4SLinus Torvalds /** 33191da177e4SLinus Torvalds * ipr_change_queue_type - Change the device's queue type 33201da177e4SLinus Torvalds * @dsev: scsi device struct 33211da177e4SLinus Torvalds * @tag_type: type of tags to use 33221da177e4SLinus Torvalds * 33231da177e4SLinus Torvalds * Return value: 33241da177e4SLinus Torvalds * actual queue type set 33251da177e4SLinus Torvalds **/ 33261da177e4SLinus Torvalds static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type) 33271da177e4SLinus Torvalds { 33281da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; 33291da177e4SLinus Torvalds struct ipr_resource_entry *res; 33301da177e4SLinus Torvalds unsigned long lock_flags = 0; 33311da177e4SLinus Torvalds 33321da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 33331da177e4SLinus Torvalds res = (struct ipr_resource_entry *)sdev->hostdata; 33341da177e4SLinus Torvalds 33351da177e4SLinus Torvalds if (res) { 33361da177e4SLinus Torvalds if (ipr_is_gscsi(res) && sdev->tagged_supported) { 33371da177e4SLinus Torvalds /* 33381da177e4SLinus Torvalds * We don't bother quiescing the device here since the 33391da177e4SLinus Torvalds * adapter firmware does it for us. 33401da177e4SLinus Torvalds */ 33411da177e4SLinus Torvalds scsi_set_tag_type(sdev, tag_type); 33421da177e4SLinus Torvalds 33431da177e4SLinus Torvalds if (tag_type) 33441da177e4SLinus Torvalds scsi_activate_tcq(sdev, sdev->queue_depth); 33451da177e4SLinus Torvalds else 33461da177e4SLinus Torvalds scsi_deactivate_tcq(sdev, sdev->queue_depth); 33471da177e4SLinus Torvalds } else 33481da177e4SLinus Torvalds tag_type = 0; 33491da177e4SLinus Torvalds } else 33501da177e4SLinus Torvalds tag_type = 0; 33511da177e4SLinus Torvalds 33521da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 33531da177e4SLinus Torvalds return tag_type; 33541da177e4SLinus Torvalds } 33551da177e4SLinus Torvalds 33561da177e4SLinus Torvalds /** 33571da177e4SLinus Torvalds * ipr_show_adapter_handle - Show the adapter's resource handle for this device 33581da177e4SLinus Torvalds * @dev: device struct 33591da177e4SLinus Torvalds * @buf: buffer 33601da177e4SLinus Torvalds * 33611da177e4SLinus Torvalds * Return value: 33621da177e4SLinus Torvalds * number of bytes printed to buffer 33631da177e4SLinus Torvalds **/ 336410523b3bSYani Ioannou static ssize_t ipr_show_adapter_handle(struct device *dev, struct device_attribute *attr, char *buf) 33651da177e4SLinus Torvalds { 33661da177e4SLinus Torvalds struct scsi_device *sdev = to_scsi_device(dev); 33671da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; 33681da177e4SLinus Torvalds struct ipr_resource_entry *res; 33691da177e4SLinus Torvalds unsigned long lock_flags = 0; 33701da177e4SLinus Torvalds ssize_t len = -ENXIO; 33711da177e4SLinus Torvalds 33721da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 33731da177e4SLinus Torvalds res = (struct ipr_resource_entry *)sdev->hostdata; 33741da177e4SLinus Torvalds if (res) 33751da177e4SLinus Torvalds len = snprintf(buf, PAGE_SIZE, "%08X\n", res->cfgte.res_handle); 33761da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 33771da177e4SLinus Torvalds return len; 33781da177e4SLinus Torvalds } 33791da177e4SLinus Torvalds 33801da177e4SLinus Torvalds static struct device_attribute ipr_adapter_handle_attr = { 33811da177e4SLinus Torvalds .attr = { 33821da177e4SLinus Torvalds .name = "adapter_handle", 33831da177e4SLinus Torvalds .mode = S_IRUSR, 33841da177e4SLinus Torvalds }, 33851da177e4SLinus Torvalds .show = ipr_show_adapter_handle 33861da177e4SLinus Torvalds }; 33871da177e4SLinus Torvalds 33881da177e4SLinus Torvalds static struct device_attribute *ipr_dev_attrs[] = { 33891da177e4SLinus Torvalds &ipr_adapter_handle_attr, 33901da177e4SLinus Torvalds NULL, 33911da177e4SLinus Torvalds }; 33921da177e4SLinus Torvalds 33931da177e4SLinus Torvalds /** 33941da177e4SLinus Torvalds * ipr_biosparam - Return the HSC mapping 33951da177e4SLinus Torvalds * @sdev: scsi device struct 33961da177e4SLinus Torvalds * @block_device: block device pointer 33971da177e4SLinus Torvalds * @capacity: capacity of the device 33981da177e4SLinus Torvalds * @parm: Array containing returned HSC values. 33991da177e4SLinus Torvalds * 34001da177e4SLinus Torvalds * This function generates the HSC parms that fdisk uses. 34011da177e4SLinus Torvalds * We want to make sure we return something that places partitions 34021da177e4SLinus Torvalds * on 4k boundaries for best performance with the IOA. 34031da177e4SLinus Torvalds * 34041da177e4SLinus Torvalds * Return value: 34051da177e4SLinus Torvalds * 0 on success 34061da177e4SLinus Torvalds **/ 34071da177e4SLinus Torvalds static int ipr_biosparam(struct scsi_device *sdev, 34081da177e4SLinus Torvalds struct block_device *block_device, 34091da177e4SLinus Torvalds sector_t capacity, int *parm) 34101da177e4SLinus Torvalds { 34111da177e4SLinus Torvalds int heads, sectors; 34121da177e4SLinus Torvalds sector_t cylinders; 34131da177e4SLinus Torvalds 34141da177e4SLinus Torvalds heads = 128; 34151da177e4SLinus Torvalds sectors = 32; 34161da177e4SLinus Torvalds 34171da177e4SLinus Torvalds cylinders = capacity; 34181da177e4SLinus Torvalds sector_div(cylinders, (128 * 32)); 34191da177e4SLinus Torvalds 34201da177e4SLinus Torvalds /* return result */ 34211da177e4SLinus Torvalds parm[0] = heads; 34221da177e4SLinus Torvalds parm[1] = sectors; 34231da177e4SLinus Torvalds parm[2] = cylinders; 34241da177e4SLinus Torvalds 34251da177e4SLinus Torvalds return 0; 34261da177e4SLinus Torvalds } 34271da177e4SLinus Torvalds 34281da177e4SLinus Torvalds /** 342935a39691SBrian King * ipr_find_starget - Find target based on bus/target. 343035a39691SBrian King * @starget: scsi target struct 343135a39691SBrian King * 343235a39691SBrian King * Return value: 343335a39691SBrian King * resource entry pointer if found / NULL if not found 343435a39691SBrian King **/ 343535a39691SBrian King static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget) 343635a39691SBrian King { 343735a39691SBrian King struct Scsi_Host *shost = dev_to_shost(&starget->dev); 343835a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; 343935a39691SBrian King struct ipr_resource_entry *res; 344035a39691SBrian King 344135a39691SBrian King list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 344235a39691SBrian King if ((res->cfgte.res_addr.bus == starget->channel) && 344335a39691SBrian King (res->cfgte.res_addr.target == starget->id) && 344435a39691SBrian King (res->cfgte.res_addr.lun == 0)) { 344535a39691SBrian King return res; 344635a39691SBrian King } 344735a39691SBrian King } 344835a39691SBrian King 344935a39691SBrian King return NULL; 345035a39691SBrian King } 345135a39691SBrian King 345235a39691SBrian King static struct ata_port_info sata_port_info; 345335a39691SBrian King 345435a39691SBrian King /** 345535a39691SBrian King * ipr_target_alloc - Prepare for commands to a SCSI target 345635a39691SBrian King * @starget: scsi target struct 345735a39691SBrian King * 345835a39691SBrian King * If the device is a SATA device, this function allocates an 345935a39691SBrian King * ATA port with libata, else it does nothing. 346035a39691SBrian King * 346135a39691SBrian King * Return value: 346235a39691SBrian King * 0 on success / non-0 on failure 346335a39691SBrian King **/ 346435a39691SBrian King static int ipr_target_alloc(struct scsi_target *starget) 346535a39691SBrian King { 346635a39691SBrian King struct Scsi_Host *shost = dev_to_shost(&starget->dev); 346735a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; 346835a39691SBrian King struct ipr_sata_port *sata_port; 346935a39691SBrian King struct ata_port *ap; 347035a39691SBrian King struct ipr_resource_entry *res; 347135a39691SBrian King unsigned long lock_flags; 347235a39691SBrian King 347335a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 347435a39691SBrian King res = ipr_find_starget(starget); 347535a39691SBrian King starget->hostdata = NULL; 347635a39691SBrian King 347735a39691SBrian King if (res && ipr_is_gata(res)) { 347835a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 347935a39691SBrian King sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); 348035a39691SBrian King if (!sata_port) 348135a39691SBrian King return -ENOMEM; 348235a39691SBrian King 348335a39691SBrian King ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost); 348435a39691SBrian King if (ap) { 348535a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 348635a39691SBrian King sata_port->ioa_cfg = ioa_cfg; 348735a39691SBrian King sata_port->ap = ap; 348835a39691SBrian King sata_port->res = res; 348935a39691SBrian King 349035a39691SBrian King res->sata_port = sata_port; 349135a39691SBrian King ap->private_data = sata_port; 349235a39691SBrian King starget->hostdata = sata_port; 349335a39691SBrian King } else { 349435a39691SBrian King kfree(sata_port); 349535a39691SBrian King return -ENOMEM; 349635a39691SBrian King } 349735a39691SBrian King } 349835a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 349935a39691SBrian King 350035a39691SBrian King return 0; 350135a39691SBrian King } 350235a39691SBrian King 350335a39691SBrian King /** 350435a39691SBrian King * ipr_target_destroy - Destroy a SCSI target 350535a39691SBrian King * @starget: scsi target struct 350635a39691SBrian King * 350735a39691SBrian King * If the device was a SATA device, this function frees the libata 350835a39691SBrian King * ATA port, else it does nothing. 350935a39691SBrian King * 351035a39691SBrian King **/ 351135a39691SBrian King static void ipr_target_destroy(struct scsi_target *starget) 351235a39691SBrian King { 351335a39691SBrian King struct ipr_sata_port *sata_port = starget->hostdata; 351435a39691SBrian King 351535a39691SBrian King if (sata_port) { 351635a39691SBrian King starget->hostdata = NULL; 351735a39691SBrian King ata_sas_port_destroy(sata_port->ap); 351835a39691SBrian King kfree(sata_port); 351935a39691SBrian King } 352035a39691SBrian King } 352135a39691SBrian King 352235a39691SBrian King /** 352335a39691SBrian King * ipr_find_sdev - Find device based on bus/target/lun. 352435a39691SBrian King * @sdev: scsi device struct 352535a39691SBrian King * 352635a39691SBrian King * Return value: 352735a39691SBrian King * resource entry pointer if found / NULL if not found 352835a39691SBrian King **/ 352935a39691SBrian King static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev) 353035a39691SBrian King { 353135a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; 353235a39691SBrian King struct ipr_resource_entry *res; 353335a39691SBrian King 353435a39691SBrian King list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 353535a39691SBrian King if ((res->cfgte.res_addr.bus == sdev->channel) && 353635a39691SBrian King (res->cfgte.res_addr.target == sdev->id) && 353735a39691SBrian King (res->cfgte.res_addr.lun == sdev->lun)) 353835a39691SBrian King return res; 353935a39691SBrian King } 354035a39691SBrian King 354135a39691SBrian King return NULL; 354235a39691SBrian King } 354335a39691SBrian King 354435a39691SBrian King /** 35451da177e4SLinus Torvalds * ipr_slave_destroy - Unconfigure a SCSI device 35461da177e4SLinus Torvalds * @sdev: scsi device struct 35471da177e4SLinus Torvalds * 35481da177e4SLinus Torvalds * Return value: 35491da177e4SLinus Torvalds * nothing 35501da177e4SLinus Torvalds **/ 35511da177e4SLinus Torvalds static void ipr_slave_destroy(struct scsi_device *sdev) 35521da177e4SLinus Torvalds { 35531da177e4SLinus Torvalds struct ipr_resource_entry *res; 35541da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 35551da177e4SLinus Torvalds unsigned long lock_flags = 0; 35561da177e4SLinus Torvalds 35571da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; 35581da177e4SLinus Torvalds 35591da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 35601da177e4SLinus Torvalds res = (struct ipr_resource_entry *) sdev->hostdata; 35611da177e4SLinus Torvalds if (res) { 356235a39691SBrian King if (res->sata_port) 356335a39691SBrian King ata_port_disable(res->sata_port->ap); 35641da177e4SLinus Torvalds sdev->hostdata = NULL; 35651da177e4SLinus Torvalds res->sdev = NULL; 356635a39691SBrian King res->sata_port = NULL; 35671da177e4SLinus Torvalds } 35681da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 35691da177e4SLinus Torvalds } 35701da177e4SLinus Torvalds 35711da177e4SLinus Torvalds /** 35721da177e4SLinus Torvalds * ipr_slave_configure - Configure a SCSI device 35731da177e4SLinus Torvalds * @sdev: scsi device struct 35741da177e4SLinus Torvalds * 35751da177e4SLinus Torvalds * This function configures the specified scsi device. 35761da177e4SLinus Torvalds * 35771da177e4SLinus Torvalds * Return value: 35781da177e4SLinus Torvalds * 0 on success 35791da177e4SLinus Torvalds **/ 35801da177e4SLinus Torvalds static int ipr_slave_configure(struct scsi_device *sdev) 35811da177e4SLinus Torvalds { 35821da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; 35831da177e4SLinus Torvalds struct ipr_resource_entry *res; 35841da177e4SLinus Torvalds unsigned long lock_flags = 0; 35851da177e4SLinus Torvalds 35861da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 35871da177e4SLinus Torvalds res = sdev->hostdata; 35881da177e4SLinus Torvalds if (res) { 35891da177e4SLinus Torvalds if (ipr_is_af_dasd_device(res)) 35901da177e4SLinus Torvalds sdev->type = TYPE_RAID; 35910726ce26Sbrking@us.ibm.com if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) { 35921da177e4SLinus Torvalds sdev->scsi_level = 4; 35930726ce26Sbrking@us.ibm.com sdev->no_uld_attach = 1; 35940726ce26Sbrking@us.ibm.com } 35951da177e4SLinus Torvalds if (ipr_is_vset_device(res)) { 35961da177e4SLinus Torvalds sdev->timeout = IPR_VSET_RW_TIMEOUT; 35971da177e4SLinus Torvalds blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); 35981da177e4SLinus Torvalds } 3599e4fbf44eSBrian King if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) 36001da177e4SLinus Torvalds sdev->allow_restart = 1; 360135a39691SBrian King if (ipr_is_gata(res) && res->sata_port) { 360235a39691SBrian King scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); 360335a39691SBrian King ata_sas_slave_configure(sdev, res->sata_port->ap); 360435a39691SBrian King } else { 36051da177e4SLinus Torvalds scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); 36061da177e4SLinus Torvalds } 360735a39691SBrian King } 36081da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 36091da177e4SLinus Torvalds return 0; 36101da177e4SLinus Torvalds } 36111da177e4SLinus Torvalds 36121da177e4SLinus Torvalds /** 361335a39691SBrian King * ipr_ata_slave_alloc - Prepare for commands to a SATA device 361435a39691SBrian King * @sdev: scsi device struct 361535a39691SBrian King * 361635a39691SBrian King * This function initializes an ATA port so that future commands 361735a39691SBrian King * sent through queuecommand will work. 361835a39691SBrian King * 361935a39691SBrian King * Return value: 362035a39691SBrian King * 0 on success 362135a39691SBrian King **/ 362235a39691SBrian King static int ipr_ata_slave_alloc(struct scsi_device *sdev) 362335a39691SBrian King { 362435a39691SBrian King struct ipr_sata_port *sata_port = NULL; 362535a39691SBrian King int rc = -ENXIO; 362635a39691SBrian King 362735a39691SBrian King ENTER; 362835a39691SBrian King if (sdev->sdev_target) 362935a39691SBrian King sata_port = sdev->sdev_target->hostdata; 363035a39691SBrian King if (sata_port) 363135a39691SBrian King rc = ata_sas_port_init(sata_port->ap); 363235a39691SBrian King if (rc) 363335a39691SBrian King ipr_slave_destroy(sdev); 363435a39691SBrian King 363535a39691SBrian King LEAVE; 363635a39691SBrian King return rc; 363735a39691SBrian King } 363835a39691SBrian King 363935a39691SBrian King /** 36401da177e4SLinus Torvalds * ipr_slave_alloc - Prepare for commands to a device. 36411da177e4SLinus Torvalds * @sdev: scsi device struct 36421da177e4SLinus Torvalds * 36431da177e4SLinus Torvalds * This function saves a pointer to the resource entry 36441da177e4SLinus Torvalds * in the scsi device struct if the device exists. We 36451da177e4SLinus Torvalds * can then use this pointer in ipr_queuecommand when 36461da177e4SLinus Torvalds * handling new commands. 36471da177e4SLinus Torvalds * 36481da177e4SLinus Torvalds * Return value: 3649692aebfcSbrking@us.ibm.com * 0 on success / -ENXIO if device does not exist 36501da177e4SLinus Torvalds **/ 36511da177e4SLinus Torvalds static int ipr_slave_alloc(struct scsi_device *sdev) 36521da177e4SLinus Torvalds { 36531da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; 36541da177e4SLinus Torvalds struct ipr_resource_entry *res; 36551da177e4SLinus Torvalds unsigned long lock_flags; 3656692aebfcSbrking@us.ibm.com int rc = -ENXIO; 36571da177e4SLinus Torvalds 36581da177e4SLinus Torvalds sdev->hostdata = NULL; 36591da177e4SLinus Torvalds 36601da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 36611da177e4SLinus Torvalds 366235a39691SBrian King res = ipr_find_sdev(sdev); 366335a39691SBrian King if (res) { 36641da177e4SLinus Torvalds res->sdev = sdev; 36651da177e4SLinus Torvalds res->add_to_ml = 0; 36661da177e4SLinus Torvalds res->in_erp = 0; 36671da177e4SLinus Torvalds sdev->hostdata = res; 3668ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 36691da177e4SLinus Torvalds res->needs_sync_complete = 1; 3670692aebfcSbrking@us.ibm.com rc = 0; 367135a39691SBrian King if (ipr_is_gata(res)) { 367235a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 367335a39691SBrian King return ipr_ata_slave_alloc(sdev); 36741da177e4SLinus Torvalds } 36751da177e4SLinus Torvalds } 36761da177e4SLinus Torvalds 36771da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 36781da177e4SLinus Torvalds 3679692aebfcSbrking@us.ibm.com return rc; 36801da177e4SLinus Torvalds } 36811da177e4SLinus Torvalds 36821da177e4SLinus Torvalds /** 36831da177e4SLinus Torvalds * ipr_eh_host_reset - Reset the host adapter 36841da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 36851da177e4SLinus Torvalds * 36861da177e4SLinus Torvalds * Return value: 36871da177e4SLinus Torvalds * SUCCESS / FAILED 36881da177e4SLinus Torvalds **/ 3689df0ae249SJeff Garzik static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) 36901da177e4SLinus Torvalds { 36911da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 36921da177e4SLinus Torvalds int rc; 36931da177e4SLinus Torvalds 36941da177e4SLinus Torvalds ENTER; 36951da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; 36961da177e4SLinus Torvalds 36971da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 36981da177e4SLinus Torvalds "Adapter being reset as a result of error recovery.\n"); 36991da177e4SLinus Torvalds 37001da177e4SLinus Torvalds if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) 37011da177e4SLinus Torvalds ioa_cfg->sdt_state = GET_DUMP; 37021da177e4SLinus Torvalds 37031da177e4SLinus Torvalds rc = ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV); 37041da177e4SLinus Torvalds 37051da177e4SLinus Torvalds LEAVE; 37061da177e4SLinus Torvalds return rc; 37071da177e4SLinus Torvalds } 37081da177e4SLinus Torvalds 3709df0ae249SJeff Garzik static int ipr_eh_host_reset(struct scsi_cmnd * cmd) 3710df0ae249SJeff Garzik { 3711df0ae249SJeff Garzik int rc; 3712df0ae249SJeff Garzik 3713df0ae249SJeff Garzik spin_lock_irq(cmd->device->host->host_lock); 3714df0ae249SJeff Garzik rc = __ipr_eh_host_reset(cmd); 3715df0ae249SJeff Garzik spin_unlock_irq(cmd->device->host->host_lock); 3716df0ae249SJeff Garzik 3717df0ae249SJeff Garzik return rc; 3718df0ae249SJeff Garzik } 3719df0ae249SJeff Garzik 37201da177e4SLinus Torvalds /** 3721c6513096SBrian King * ipr_device_reset - Reset the device 3722c6513096SBrian King * @ioa_cfg: ioa config struct 3723c6513096SBrian King * @res: resource entry struct 3724c6513096SBrian King * 3725c6513096SBrian King * This function issues a device reset to the affected device. 3726c6513096SBrian King * If the device is a SCSI device, a LUN reset will be sent 3727c6513096SBrian King * to the device first. If that does not work, a target reset 372835a39691SBrian King * will be sent. If the device is a SATA device, a PHY reset will 372935a39691SBrian King * be sent. 3730c6513096SBrian King * 3731c6513096SBrian King * Return value: 3732c6513096SBrian King * 0 on success / non-zero on failure 3733c6513096SBrian King **/ 3734c6513096SBrian King static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, 3735c6513096SBrian King struct ipr_resource_entry *res) 3736c6513096SBrian King { 3737c6513096SBrian King struct ipr_cmnd *ipr_cmd; 3738c6513096SBrian King struct ipr_ioarcb *ioarcb; 3739c6513096SBrian King struct ipr_cmd_pkt *cmd_pkt; 374035a39691SBrian King struct ipr_ioarcb_ata_regs *regs; 3741c6513096SBrian King u32 ioasc; 3742c6513096SBrian King 3743c6513096SBrian King ENTER; 3744c6513096SBrian King ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 3745c6513096SBrian King ioarcb = &ipr_cmd->ioarcb; 3746c6513096SBrian King cmd_pkt = &ioarcb->cmd_pkt; 374735a39691SBrian King regs = &ioarcb->add_data.u.regs; 3748c6513096SBrian King 3749c6513096SBrian King ioarcb->res_handle = res->cfgte.res_handle; 3750c6513096SBrian King cmd_pkt->request_type = IPR_RQTYPE_IOACMD; 3751c6513096SBrian King cmd_pkt->cdb[0] = IPR_RESET_DEVICE; 375235a39691SBrian King if (ipr_is_gata(res)) { 375335a39691SBrian King cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET; 375435a39691SBrian King ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags)); 375535a39691SBrian King regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; 375635a39691SBrian King } 3757c6513096SBrian King 3758c6513096SBrian King ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); 3759c6513096SBrian King ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 3760c6513096SBrian King list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 376135a39691SBrian King if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) 376235a39691SBrian King memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata, 376335a39691SBrian King sizeof(struct ipr_ioasa_gata)); 3764c6513096SBrian King 3765c6513096SBrian King LEAVE; 3766c6513096SBrian King return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); 3767c6513096SBrian King } 3768c6513096SBrian King 3769c6513096SBrian King /** 377035a39691SBrian King * ipr_sata_reset - Reset the SATA port 377135a39691SBrian King * @ap: SATA port to reset 377235a39691SBrian King * @classes: class of the attached device 377335a39691SBrian King * 377435a39691SBrian King * This function issues a SATA phy reset to the affected ATA port. 377535a39691SBrian King * 377635a39691SBrian King * Return value: 377735a39691SBrian King * 0 on success / non-zero on failure 377835a39691SBrian King **/ 377935a39691SBrian King static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes) 378035a39691SBrian King { 378135a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 378235a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; 378335a39691SBrian King struct ipr_resource_entry *res; 378435a39691SBrian King unsigned long lock_flags = 0; 378535a39691SBrian King int rc = -ENXIO; 378635a39691SBrian King 378735a39691SBrian King ENTER; 378835a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 378973d98ff0SBrian King while(ioa_cfg->in_reset_reload) { 379073d98ff0SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 379173d98ff0SBrian King wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 379273d98ff0SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 379373d98ff0SBrian King } 379473d98ff0SBrian King 379535a39691SBrian King res = sata_port->res; 379635a39691SBrian King if (res) { 379735a39691SBrian King rc = ipr_device_reset(ioa_cfg, res); 379835a39691SBrian King switch(res->cfgte.proto) { 379935a39691SBrian King case IPR_PROTO_SATA: 380035a39691SBrian King case IPR_PROTO_SAS_STP: 380135a39691SBrian King *classes = ATA_DEV_ATA; 380235a39691SBrian King break; 380335a39691SBrian King case IPR_PROTO_SATA_ATAPI: 380435a39691SBrian King case IPR_PROTO_SAS_STP_ATAPI: 380535a39691SBrian King *classes = ATA_DEV_ATAPI; 380635a39691SBrian King break; 380735a39691SBrian King default: 380835a39691SBrian King *classes = ATA_DEV_UNKNOWN; 380935a39691SBrian King break; 381035a39691SBrian King }; 381135a39691SBrian King } 381235a39691SBrian King 381335a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 381435a39691SBrian King LEAVE; 381535a39691SBrian King return rc; 381635a39691SBrian King } 381735a39691SBrian King 381835a39691SBrian King /** 38191da177e4SLinus Torvalds * ipr_eh_dev_reset - Reset the device 38201da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 38211da177e4SLinus Torvalds * 38221da177e4SLinus Torvalds * This function issues a device reset to the affected device. 38231da177e4SLinus Torvalds * A LUN reset will be sent to the device first. If that does 38241da177e4SLinus Torvalds * not work, a target reset will be sent. 38251da177e4SLinus Torvalds * 38261da177e4SLinus Torvalds * Return value: 38271da177e4SLinus Torvalds * SUCCESS / FAILED 38281da177e4SLinus Torvalds **/ 382994d0e7b8SJeff Garzik static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) 38301da177e4SLinus Torvalds { 38311da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 38321da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 38331da177e4SLinus Torvalds struct ipr_resource_entry *res; 383435a39691SBrian King struct ata_port *ap; 383535a39691SBrian King int rc = 0; 38361da177e4SLinus Torvalds 38371da177e4SLinus Torvalds ENTER; 38381da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; 38391da177e4SLinus Torvalds res = scsi_cmd->device->hostdata; 38401da177e4SLinus Torvalds 3841eeb88307Sbrking@us.ibm.com if (!res) 38421da177e4SLinus Torvalds return FAILED; 38431da177e4SLinus Torvalds 38441da177e4SLinus Torvalds /* 38451da177e4SLinus Torvalds * If we are currently going through reset/reload, return failed. This will force the 38461da177e4SLinus Torvalds * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the 38471da177e4SLinus Torvalds * reset to complete 38481da177e4SLinus Torvalds */ 38491da177e4SLinus Torvalds if (ioa_cfg->in_reset_reload) 38501da177e4SLinus Torvalds return FAILED; 38511da177e4SLinus Torvalds if (ioa_cfg->ioa_is_dead) 38521da177e4SLinus Torvalds return FAILED; 38531da177e4SLinus Torvalds 38541da177e4SLinus Torvalds list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { 38551da177e4SLinus Torvalds if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { 38561da177e4SLinus Torvalds if (ipr_cmd->scsi_cmd) 38571da177e4SLinus Torvalds ipr_cmd->done = ipr_scsi_eh_done; 38587402ecefSBrian King if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { 38597402ecefSBrian King ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; 38607402ecefSBrian King ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; 38617402ecefSBrian King } 38621da177e4SLinus Torvalds } 38631da177e4SLinus Torvalds } 38641da177e4SLinus Torvalds 38651da177e4SLinus Torvalds res->resetting_device = 1; 3866fb3ed3cbSBrian King scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); 386735a39691SBrian King 386835a39691SBrian King if (ipr_is_gata(res) && res->sata_port) { 386935a39691SBrian King ap = res->sata_port->ap; 387035a39691SBrian King spin_unlock_irq(scsi_cmd->device->host->host_lock); 387135a39691SBrian King ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL); 387235a39691SBrian King spin_lock_irq(scsi_cmd->device->host->host_lock); 387335a39691SBrian King } else 3874c6513096SBrian King rc = ipr_device_reset(ioa_cfg, res); 38751da177e4SLinus Torvalds res->resetting_device = 0; 38761da177e4SLinus Torvalds 38771da177e4SLinus Torvalds LEAVE; 3878c6513096SBrian King return (rc ? FAILED : SUCCESS); 38791da177e4SLinus Torvalds } 38801da177e4SLinus Torvalds 388194d0e7b8SJeff Garzik static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) 388294d0e7b8SJeff Garzik { 388394d0e7b8SJeff Garzik int rc; 388494d0e7b8SJeff Garzik 388594d0e7b8SJeff Garzik spin_lock_irq(cmd->device->host->host_lock); 388694d0e7b8SJeff Garzik rc = __ipr_eh_dev_reset(cmd); 388794d0e7b8SJeff Garzik spin_unlock_irq(cmd->device->host->host_lock); 388894d0e7b8SJeff Garzik 388994d0e7b8SJeff Garzik return rc; 389094d0e7b8SJeff Garzik } 389194d0e7b8SJeff Garzik 38921da177e4SLinus Torvalds /** 38931da177e4SLinus Torvalds * ipr_bus_reset_done - Op done function for bus reset. 38941da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 38951da177e4SLinus Torvalds * 38961da177e4SLinus Torvalds * This function is the op done function for a bus reset 38971da177e4SLinus Torvalds * 38981da177e4SLinus Torvalds * Return value: 38991da177e4SLinus Torvalds * none 39001da177e4SLinus Torvalds **/ 39011da177e4SLinus Torvalds static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd) 39021da177e4SLinus Torvalds { 39031da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 39041da177e4SLinus Torvalds struct ipr_resource_entry *res; 39051da177e4SLinus Torvalds 39061da177e4SLinus Torvalds ENTER; 39071da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 39081da177e4SLinus Torvalds if (!memcmp(&res->cfgte.res_handle, &ipr_cmd->ioarcb.res_handle, 39091da177e4SLinus Torvalds sizeof(res->cfgte.res_handle))) { 39101da177e4SLinus Torvalds scsi_report_bus_reset(ioa_cfg->host, res->cfgte.res_addr.bus); 39111da177e4SLinus Torvalds break; 39121da177e4SLinus Torvalds } 39131da177e4SLinus Torvalds } 39141da177e4SLinus Torvalds 39151da177e4SLinus Torvalds /* 39161da177e4SLinus Torvalds * If abort has not completed, indicate the reset has, else call the 39171da177e4SLinus Torvalds * abort's done function to wake the sleeping eh thread 39181da177e4SLinus Torvalds */ 39191da177e4SLinus Torvalds if (ipr_cmd->sibling->sibling) 39201da177e4SLinus Torvalds ipr_cmd->sibling->sibling = NULL; 39211da177e4SLinus Torvalds else 39221da177e4SLinus Torvalds ipr_cmd->sibling->done(ipr_cmd->sibling); 39231da177e4SLinus Torvalds 39241da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 39251da177e4SLinus Torvalds LEAVE; 39261da177e4SLinus Torvalds } 39271da177e4SLinus Torvalds 39281da177e4SLinus Torvalds /** 39291da177e4SLinus Torvalds * ipr_abort_timeout - An abort task has timed out 39301da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 39311da177e4SLinus Torvalds * 39321da177e4SLinus Torvalds * This function handles when an abort task times out. If this 39331da177e4SLinus Torvalds * happens we issue a bus reset since we have resources tied 39341da177e4SLinus Torvalds * up that must be freed before returning to the midlayer. 39351da177e4SLinus Torvalds * 39361da177e4SLinus Torvalds * Return value: 39371da177e4SLinus Torvalds * none 39381da177e4SLinus Torvalds **/ 39391da177e4SLinus Torvalds static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) 39401da177e4SLinus Torvalds { 39411da177e4SLinus Torvalds struct ipr_cmnd *reset_cmd; 39421da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 39431da177e4SLinus Torvalds struct ipr_cmd_pkt *cmd_pkt; 39441da177e4SLinus Torvalds unsigned long lock_flags = 0; 39451da177e4SLinus Torvalds 39461da177e4SLinus Torvalds ENTER; 39471da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 39481da177e4SLinus Torvalds if (ipr_cmd->completion.done || ioa_cfg->in_reset_reload) { 39491da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 39501da177e4SLinus Torvalds return; 39511da177e4SLinus Torvalds } 39521da177e4SLinus Torvalds 3953fb3ed3cbSBrian King sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n"); 39541da177e4SLinus Torvalds reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 39551da177e4SLinus Torvalds ipr_cmd->sibling = reset_cmd; 39561da177e4SLinus Torvalds reset_cmd->sibling = ipr_cmd; 39571da177e4SLinus Torvalds reset_cmd->ioarcb.res_handle = ipr_cmd->ioarcb.res_handle; 39581da177e4SLinus Torvalds cmd_pkt = &reset_cmd->ioarcb.cmd_pkt; 39591da177e4SLinus Torvalds cmd_pkt->request_type = IPR_RQTYPE_IOACMD; 39601da177e4SLinus Torvalds cmd_pkt->cdb[0] = IPR_RESET_DEVICE; 39611da177e4SLinus Torvalds cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET; 39621da177e4SLinus Torvalds 39631da177e4SLinus Torvalds ipr_do_req(reset_cmd, ipr_bus_reset_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); 39641da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 39651da177e4SLinus Torvalds LEAVE; 39661da177e4SLinus Torvalds } 39671da177e4SLinus Torvalds 39681da177e4SLinus Torvalds /** 39691da177e4SLinus Torvalds * ipr_cancel_op - Cancel specified op 39701da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 39711da177e4SLinus Torvalds * 39721da177e4SLinus Torvalds * This function cancels specified op. 39731da177e4SLinus Torvalds * 39741da177e4SLinus Torvalds * Return value: 39751da177e4SLinus Torvalds * SUCCESS / FAILED 39761da177e4SLinus Torvalds **/ 39771da177e4SLinus Torvalds static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) 39781da177e4SLinus Torvalds { 39791da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 39801da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 39811da177e4SLinus Torvalds struct ipr_resource_entry *res; 39821da177e4SLinus Torvalds struct ipr_cmd_pkt *cmd_pkt; 39831da177e4SLinus Torvalds u32 ioasc; 39841da177e4SLinus Torvalds int op_found = 0; 39851da177e4SLinus Torvalds 39861da177e4SLinus Torvalds ENTER; 39871da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; 39881da177e4SLinus Torvalds res = scsi_cmd->device->hostdata; 39891da177e4SLinus Torvalds 39908fa728a2SJeff Garzik /* If we are currently going through reset/reload, return failed. 39918fa728a2SJeff Garzik * This will force the mid-layer to call ipr_eh_host_reset, 39928fa728a2SJeff Garzik * which will then go to sleep and wait for the reset to complete 39938fa728a2SJeff Garzik */ 39948fa728a2SJeff Garzik if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead) 39958fa728a2SJeff Garzik return FAILED; 399604d9768fSBrian King if (!res || !ipr_is_gscsi(res)) 39971da177e4SLinus Torvalds return FAILED; 39981da177e4SLinus Torvalds 39991da177e4SLinus Torvalds list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { 40001da177e4SLinus Torvalds if (ipr_cmd->scsi_cmd == scsi_cmd) { 40011da177e4SLinus Torvalds ipr_cmd->done = ipr_scsi_eh_done; 40021da177e4SLinus Torvalds op_found = 1; 40031da177e4SLinus Torvalds break; 40041da177e4SLinus Torvalds } 40051da177e4SLinus Torvalds } 40061da177e4SLinus Torvalds 40071da177e4SLinus Torvalds if (!op_found) 40081da177e4SLinus Torvalds return SUCCESS; 40091da177e4SLinus Torvalds 40101da177e4SLinus Torvalds ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 40111da177e4SLinus Torvalds ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; 40121da177e4SLinus Torvalds cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; 40131da177e4SLinus Torvalds cmd_pkt->request_type = IPR_RQTYPE_IOACMD; 40141da177e4SLinus Torvalds cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; 40151da177e4SLinus Torvalds ipr_cmd->u.sdev = scsi_cmd->device; 40161da177e4SLinus Torvalds 4017fb3ed3cbSBrian King scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n", 4018fb3ed3cbSBrian King scsi_cmd->cmnd[0]); 40191da177e4SLinus Torvalds ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); 40201da177e4SLinus Torvalds ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 40211da177e4SLinus Torvalds 40221da177e4SLinus Torvalds /* 40231da177e4SLinus Torvalds * If the abort task timed out and we sent a bus reset, we will get 40241da177e4SLinus Torvalds * one the following responses to the abort 40251da177e4SLinus Torvalds */ 40261da177e4SLinus Torvalds if (ioasc == IPR_IOASC_BUS_WAS_RESET || ioasc == IPR_IOASC_SYNC_REQUIRED) { 40271da177e4SLinus Torvalds ioasc = 0; 40281da177e4SLinus Torvalds ipr_trace; 40291da177e4SLinus Torvalds } 40301da177e4SLinus Torvalds 40311da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 4032ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 40331da177e4SLinus Torvalds res->needs_sync_complete = 1; 40341da177e4SLinus Torvalds 40351da177e4SLinus Torvalds LEAVE; 40361da177e4SLinus Torvalds return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); 40371da177e4SLinus Torvalds } 40381da177e4SLinus Torvalds 40391da177e4SLinus Torvalds /** 40401da177e4SLinus Torvalds * ipr_eh_abort - Abort a single op 40411da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 40421da177e4SLinus Torvalds * 40431da177e4SLinus Torvalds * Return value: 40441da177e4SLinus Torvalds * SUCCESS / FAILED 40451da177e4SLinus Torvalds **/ 40461da177e4SLinus Torvalds static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) 40471da177e4SLinus Torvalds { 40488fa728a2SJeff Garzik unsigned long flags; 40498fa728a2SJeff Garzik int rc; 40501da177e4SLinus Torvalds 40511da177e4SLinus Torvalds ENTER; 40521da177e4SLinus Torvalds 40538fa728a2SJeff Garzik spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); 40548fa728a2SJeff Garzik rc = ipr_cancel_op(scsi_cmd); 40558fa728a2SJeff Garzik spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); 40561da177e4SLinus Torvalds 40571da177e4SLinus Torvalds LEAVE; 40588fa728a2SJeff Garzik return rc; 40591da177e4SLinus Torvalds } 40601da177e4SLinus Torvalds 40611da177e4SLinus Torvalds /** 40621da177e4SLinus Torvalds * ipr_handle_other_interrupt - Handle "other" interrupts 40631da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 40641da177e4SLinus Torvalds * @int_reg: interrupt register 40651da177e4SLinus Torvalds * 40661da177e4SLinus Torvalds * Return value: 40671da177e4SLinus Torvalds * IRQ_NONE / IRQ_HANDLED 40681da177e4SLinus Torvalds **/ 40691da177e4SLinus Torvalds static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, 40701da177e4SLinus Torvalds volatile u32 int_reg) 40711da177e4SLinus Torvalds { 40721da177e4SLinus Torvalds irqreturn_t rc = IRQ_HANDLED; 40731da177e4SLinus Torvalds 40741da177e4SLinus Torvalds if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { 40751da177e4SLinus Torvalds /* Mask the interrupt */ 40761da177e4SLinus Torvalds writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.set_interrupt_mask_reg); 40771da177e4SLinus Torvalds 40781da177e4SLinus Torvalds /* Clear the interrupt */ 40791da177e4SLinus Torvalds writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg); 40801da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 40811da177e4SLinus Torvalds 40821da177e4SLinus Torvalds list_del(&ioa_cfg->reset_cmd->queue); 40831da177e4SLinus Torvalds del_timer(&ioa_cfg->reset_cmd->timer); 40841da177e4SLinus Torvalds ipr_reset_ioa_job(ioa_cfg->reset_cmd); 40851da177e4SLinus Torvalds } else { 40861da177e4SLinus Torvalds if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) 40871da177e4SLinus Torvalds ioa_cfg->ioa_unit_checked = 1; 40881da177e4SLinus Torvalds else 40891da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 40901da177e4SLinus Torvalds "Permanent IOA failure. 0x%08X\n", int_reg); 40911da177e4SLinus Torvalds 40921da177e4SLinus Torvalds if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) 40931da177e4SLinus Torvalds ioa_cfg->sdt_state = GET_DUMP; 40941da177e4SLinus Torvalds 40951da177e4SLinus Torvalds ipr_mask_and_clear_interrupts(ioa_cfg, ~0); 40961da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 40971da177e4SLinus Torvalds } 40981da177e4SLinus Torvalds 40991da177e4SLinus Torvalds return rc; 41001da177e4SLinus Torvalds } 41011da177e4SLinus Torvalds 41021da177e4SLinus Torvalds /** 41031da177e4SLinus Torvalds * ipr_isr - Interrupt service routine 41041da177e4SLinus Torvalds * @irq: irq number 41051da177e4SLinus Torvalds * @devp: pointer to ioa config struct 41061da177e4SLinus Torvalds * 41071da177e4SLinus Torvalds * Return value: 41081da177e4SLinus Torvalds * IRQ_NONE / IRQ_HANDLED 41091da177e4SLinus Torvalds **/ 41107d12e780SDavid Howells static irqreturn_t ipr_isr(int irq, void *devp) 41111da177e4SLinus Torvalds { 41121da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; 41131da177e4SLinus Torvalds unsigned long lock_flags = 0; 41141da177e4SLinus Torvalds volatile u32 int_reg, int_mask_reg; 41151da177e4SLinus Torvalds u32 ioasc; 41161da177e4SLinus Torvalds u16 cmd_index; 41171da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 41181da177e4SLinus Torvalds irqreturn_t rc = IRQ_NONE; 41191da177e4SLinus Torvalds 41201da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 41211da177e4SLinus Torvalds 41221da177e4SLinus Torvalds /* If interrupts are disabled, ignore the interrupt */ 41231da177e4SLinus Torvalds if (!ioa_cfg->allow_interrupts) { 41241da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 41251da177e4SLinus Torvalds return IRQ_NONE; 41261da177e4SLinus Torvalds } 41271da177e4SLinus Torvalds 41281da177e4SLinus Torvalds int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); 41291da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; 41301da177e4SLinus Torvalds 41311da177e4SLinus Torvalds /* If an interrupt on the adapter did not occur, ignore it */ 41321da177e4SLinus Torvalds if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) { 41331da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 41341da177e4SLinus Torvalds return IRQ_NONE; 41351da177e4SLinus Torvalds } 41361da177e4SLinus Torvalds 41371da177e4SLinus Torvalds while (1) { 41381da177e4SLinus Torvalds ipr_cmd = NULL; 41391da177e4SLinus Torvalds 41401da177e4SLinus Torvalds while ((be32_to_cpu(*ioa_cfg->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) == 41411da177e4SLinus Torvalds ioa_cfg->toggle_bit) { 41421da177e4SLinus Torvalds 41431da177e4SLinus Torvalds cmd_index = (be32_to_cpu(*ioa_cfg->hrrq_curr) & 41441da177e4SLinus Torvalds IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT; 41451da177e4SLinus Torvalds 41461da177e4SLinus Torvalds if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) { 41471da177e4SLinus Torvalds ioa_cfg->errors_logged++; 41481da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n"); 41491da177e4SLinus Torvalds 41501da177e4SLinus Torvalds if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) 41511da177e4SLinus Torvalds ioa_cfg->sdt_state = GET_DUMP; 41521da177e4SLinus Torvalds 41531da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 41541da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 41551da177e4SLinus Torvalds return IRQ_HANDLED; 41561da177e4SLinus Torvalds } 41571da177e4SLinus Torvalds 41581da177e4SLinus Torvalds ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index]; 41591da177e4SLinus Torvalds 41601da177e4SLinus Torvalds ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 41611da177e4SLinus Torvalds 41621da177e4SLinus Torvalds ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc); 41631da177e4SLinus Torvalds 41641da177e4SLinus Torvalds list_del(&ipr_cmd->queue); 41651da177e4SLinus Torvalds del_timer(&ipr_cmd->timer); 41661da177e4SLinus Torvalds ipr_cmd->done(ipr_cmd); 41671da177e4SLinus Torvalds 41681da177e4SLinus Torvalds rc = IRQ_HANDLED; 41691da177e4SLinus Torvalds 41701da177e4SLinus Torvalds if (ioa_cfg->hrrq_curr < ioa_cfg->hrrq_end) { 41711da177e4SLinus Torvalds ioa_cfg->hrrq_curr++; 41721da177e4SLinus Torvalds } else { 41731da177e4SLinus Torvalds ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; 41741da177e4SLinus Torvalds ioa_cfg->toggle_bit ^= 1u; 41751da177e4SLinus Torvalds } 41761da177e4SLinus Torvalds } 41771da177e4SLinus Torvalds 41781da177e4SLinus Torvalds if (ipr_cmd != NULL) { 41791da177e4SLinus Torvalds /* Clear the PCI interrupt */ 41801da177e4SLinus Torvalds writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg); 41811da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; 41821da177e4SLinus Torvalds } else 41831da177e4SLinus Torvalds break; 41841da177e4SLinus Torvalds } 41851da177e4SLinus Torvalds 41861da177e4SLinus Torvalds if (unlikely(rc == IRQ_NONE)) 41871da177e4SLinus Torvalds rc = ipr_handle_other_interrupt(ioa_cfg, int_reg); 41881da177e4SLinus Torvalds 41891da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 41901da177e4SLinus Torvalds return rc; 41911da177e4SLinus Torvalds } 41921da177e4SLinus Torvalds 41931da177e4SLinus Torvalds /** 41941da177e4SLinus Torvalds * ipr_build_ioadl - Build a scatter/gather list and map the buffer 41951da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 41961da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 41971da177e4SLinus Torvalds * 41981da177e4SLinus Torvalds * Return value: 41991da177e4SLinus Torvalds * 0 on success / -1 on failure 42001da177e4SLinus Torvalds **/ 42011da177e4SLinus Torvalds static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, 42021da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd) 42031da177e4SLinus Torvalds { 42041da177e4SLinus Torvalds int i; 42051da177e4SLinus Torvalds struct scatterlist *sglist; 42061da177e4SLinus Torvalds u32 length; 42071da177e4SLinus Torvalds u32 ioadl_flags = 0; 42081da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 42091da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 42101da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 42111da177e4SLinus Torvalds 42121da177e4SLinus Torvalds length = scsi_cmd->request_bufflen; 42131da177e4SLinus Torvalds 42141da177e4SLinus Torvalds if (length == 0) 42151da177e4SLinus Torvalds return 0; 42161da177e4SLinus Torvalds 42171da177e4SLinus Torvalds if (scsi_cmd->use_sg) { 42181da177e4SLinus Torvalds ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, 42191da177e4SLinus Torvalds scsi_cmd->request_buffer, 42201da177e4SLinus Torvalds scsi_cmd->use_sg, 42211da177e4SLinus Torvalds scsi_cmd->sc_data_direction); 42221da177e4SLinus Torvalds 42231da177e4SLinus Torvalds if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { 42241da177e4SLinus Torvalds ioadl_flags = IPR_IOADL_FLAGS_WRITE; 42251da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 42261da177e4SLinus Torvalds ioarcb->write_data_transfer_length = cpu_to_be32(length); 42271da177e4SLinus Torvalds ioarcb->write_ioadl_len = 42281da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 42291da177e4SLinus Torvalds } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { 42301da177e4SLinus Torvalds ioadl_flags = IPR_IOADL_FLAGS_READ; 42311da177e4SLinus Torvalds ioarcb->read_data_transfer_length = cpu_to_be32(length); 42321da177e4SLinus Torvalds ioarcb->read_ioadl_len = 42331da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 42341da177e4SLinus Torvalds } 42351da177e4SLinus Torvalds 42361da177e4SLinus Torvalds sglist = scsi_cmd->request_buffer; 42371da177e4SLinus Torvalds 42381da177e4SLinus Torvalds for (i = 0; i < ipr_cmd->dma_use_sg; i++) { 42391da177e4SLinus Torvalds ioadl[i].flags_and_data_len = 42401da177e4SLinus Torvalds cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i])); 42411da177e4SLinus Torvalds ioadl[i].address = 42421da177e4SLinus Torvalds cpu_to_be32(sg_dma_address(&sglist[i])); 42431da177e4SLinus Torvalds } 42441da177e4SLinus Torvalds 42451da177e4SLinus Torvalds if (likely(ipr_cmd->dma_use_sg)) { 42461da177e4SLinus Torvalds ioadl[i-1].flags_and_data_len |= 42471da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_LAST); 42481da177e4SLinus Torvalds return 0; 42491da177e4SLinus Torvalds } else 42501da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); 42511da177e4SLinus Torvalds } else { 42521da177e4SLinus Torvalds if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { 42531da177e4SLinus Torvalds ioadl_flags = IPR_IOADL_FLAGS_WRITE; 42541da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 42551da177e4SLinus Torvalds ioarcb->write_data_transfer_length = cpu_to_be32(length); 42561da177e4SLinus Torvalds ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 42571da177e4SLinus Torvalds } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { 42581da177e4SLinus Torvalds ioadl_flags = IPR_IOADL_FLAGS_READ; 42591da177e4SLinus Torvalds ioarcb->read_data_transfer_length = cpu_to_be32(length); 42601da177e4SLinus Torvalds ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 42611da177e4SLinus Torvalds } 42621da177e4SLinus Torvalds 42631da177e4SLinus Torvalds ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev, 42641da177e4SLinus Torvalds scsi_cmd->request_buffer, length, 42651da177e4SLinus Torvalds scsi_cmd->sc_data_direction); 42661da177e4SLinus Torvalds 42671da177e4SLinus Torvalds if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) { 42681da177e4SLinus Torvalds ipr_cmd->dma_use_sg = 1; 42691da177e4SLinus Torvalds ioadl[0].flags_and_data_len = 42701da177e4SLinus Torvalds cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST); 42711da177e4SLinus Torvalds ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle); 42721da177e4SLinus Torvalds return 0; 42731da177e4SLinus Torvalds } else 42741da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n"); 42751da177e4SLinus Torvalds } 42761da177e4SLinus Torvalds 42771da177e4SLinus Torvalds return -1; 42781da177e4SLinus Torvalds } 42791da177e4SLinus Torvalds 42801da177e4SLinus Torvalds /** 42811da177e4SLinus Torvalds * ipr_get_task_attributes - Translate SPI Q-Tag to task attributes 42821da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 42831da177e4SLinus Torvalds * 42841da177e4SLinus Torvalds * Return value: 42851da177e4SLinus Torvalds * task attributes 42861da177e4SLinus Torvalds **/ 42871da177e4SLinus Torvalds static u8 ipr_get_task_attributes(struct scsi_cmnd *scsi_cmd) 42881da177e4SLinus Torvalds { 42891da177e4SLinus Torvalds u8 tag[2]; 42901da177e4SLinus Torvalds u8 rc = IPR_FLAGS_LO_UNTAGGED_TASK; 42911da177e4SLinus Torvalds 42921da177e4SLinus Torvalds if (scsi_populate_tag_msg(scsi_cmd, tag)) { 42931da177e4SLinus Torvalds switch (tag[0]) { 42941da177e4SLinus Torvalds case MSG_SIMPLE_TAG: 42951da177e4SLinus Torvalds rc = IPR_FLAGS_LO_SIMPLE_TASK; 42961da177e4SLinus Torvalds break; 42971da177e4SLinus Torvalds case MSG_HEAD_TAG: 42981da177e4SLinus Torvalds rc = IPR_FLAGS_LO_HEAD_OF_Q_TASK; 42991da177e4SLinus Torvalds break; 43001da177e4SLinus Torvalds case MSG_ORDERED_TAG: 43011da177e4SLinus Torvalds rc = IPR_FLAGS_LO_ORDERED_TASK; 43021da177e4SLinus Torvalds break; 43031da177e4SLinus Torvalds }; 43041da177e4SLinus Torvalds } 43051da177e4SLinus Torvalds 43061da177e4SLinus Torvalds return rc; 43071da177e4SLinus Torvalds } 43081da177e4SLinus Torvalds 43091da177e4SLinus Torvalds /** 43101da177e4SLinus Torvalds * ipr_erp_done - Process completion of ERP for a device 43111da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 43121da177e4SLinus Torvalds * 43131da177e4SLinus Torvalds * This function copies the sense buffer into the scsi_cmd 43141da177e4SLinus Torvalds * struct and pushes the scsi_done function. 43151da177e4SLinus Torvalds * 43161da177e4SLinus Torvalds * Return value: 43171da177e4SLinus Torvalds * nothing 43181da177e4SLinus Torvalds **/ 43191da177e4SLinus Torvalds static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) 43201da177e4SLinus Torvalds { 43211da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 43221da177e4SLinus Torvalds struct ipr_resource_entry *res = scsi_cmd->device->hostdata; 43231da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 43241da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 43251da177e4SLinus Torvalds 43261da177e4SLinus Torvalds if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { 43271da177e4SLinus Torvalds scsi_cmd->result |= (DID_ERROR << 16); 4328fb3ed3cbSBrian King scmd_printk(KERN_ERR, scsi_cmd, 43291da177e4SLinus Torvalds "Request Sense failed with IOASC: 0x%08X\n", ioasc); 43301da177e4SLinus Torvalds } else { 43311da177e4SLinus Torvalds memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, 43321da177e4SLinus Torvalds SCSI_SENSE_BUFFERSIZE); 43331da177e4SLinus Torvalds } 43341da177e4SLinus Torvalds 43351da177e4SLinus Torvalds if (res) { 4336ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 43371da177e4SLinus Torvalds res->needs_sync_complete = 1; 43381da177e4SLinus Torvalds res->in_erp = 0; 43391da177e4SLinus Torvalds } 43401da177e4SLinus Torvalds ipr_unmap_sglist(ioa_cfg, ipr_cmd); 43411da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 43421da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 43431da177e4SLinus Torvalds } 43441da177e4SLinus Torvalds 43451da177e4SLinus Torvalds /** 43461da177e4SLinus Torvalds * ipr_reinit_ipr_cmnd_for_erp - Re-initialize a cmnd block to be used for ERP 43471da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 43481da177e4SLinus Torvalds * 43491da177e4SLinus Torvalds * Return value: 43501da177e4SLinus Torvalds * none 43511da177e4SLinus Torvalds **/ 43521da177e4SLinus Torvalds static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) 43531da177e4SLinus Torvalds { 43541da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb; 43551da177e4SLinus Torvalds struct ipr_ioasa *ioasa; 43561da177e4SLinus Torvalds 43571da177e4SLinus Torvalds ioarcb = &ipr_cmd->ioarcb; 43581da177e4SLinus Torvalds ioasa = &ipr_cmd->ioasa; 43591da177e4SLinus Torvalds 43601da177e4SLinus Torvalds memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); 43611da177e4SLinus Torvalds ioarcb->write_data_transfer_length = 0; 43621da177e4SLinus Torvalds ioarcb->read_data_transfer_length = 0; 43631da177e4SLinus Torvalds ioarcb->write_ioadl_len = 0; 43641da177e4SLinus Torvalds ioarcb->read_ioadl_len = 0; 43651da177e4SLinus Torvalds ioasa->ioasc = 0; 43661da177e4SLinus Torvalds ioasa->residual_data_len = 0; 43671da177e4SLinus Torvalds } 43681da177e4SLinus Torvalds 43691da177e4SLinus Torvalds /** 43701da177e4SLinus Torvalds * ipr_erp_request_sense - Send request sense to a device 43711da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 43721da177e4SLinus Torvalds * 43731da177e4SLinus Torvalds * This function sends a request sense to a device as a result 43741da177e4SLinus Torvalds * of a check condition. 43751da177e4SLinus Torvalds * 43761da177e4SLinus Torvalds * Return value: 43771da177e4SLinus Torvalds * nothing 43781da177e4SLinus Torvalds **/ 43791da177e4SLinus Torvalds static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) 43801da177e4SLinus Torvalds { 43811da177e4SLinus Torvalds struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; 43821da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 43831da177e4SLinus Torvalds 43841da177e4SLinus Torvalds if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { 43851da177e4SLinus Torvalds ipr_erp_done(ipr_cmd); 43861da177e4SLinus Torvalds return; 43871da177e4SLinus Torvalds } 43881da177e4SLinus Torvalds 43891da177e4SLinus Torvalds ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); 43901da177e4SLinus Torvalds 43911da177e4SLinus Torvalds cmd_pkt->request_type = IPR_RQTYPE_SCSICDB; 43921da177e4SLinus Torvalds cmd_pkt->cdb[0] = REQUEST_SENSE; 43931da177e4SLinus Torvalds cmd_pkt->cdb[4] = SCSI_SENSE_BUFFERSIZE; 43941da177e4SLinus Torvalds cmd_pkt->flags_hi |= IPR_FLAGS_HI_SYNC_OVERRIDE; 43951da177e4SLinus Torvalds cmd_pkt->flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; 43961da177e4SLinus Torvalds cmd_pkt->timeout = cpu_to_be16(IPR_REQUEST_SENSE_TIMEOUT / HZ); 43971da177e4SLinus Torvalds 43981da177e4SLinus Torvalds ipr_cmd->ioadl[0].flags_and_data_len = 43991da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | SCSI_SENSE_BUFFERSIZE); 44001da177e4SLinus Torvalds ipr_cmd->ioadl[0].address = 44011da177e4SLinus Torvalds cpu_to_be32(ipr_cmd->sense_buffer_dma); 44021da177e4SLinus Torvalds 44031da177e4SLinus Torvalds ipr_cmd->ioarcb.read_ioadl_len = 44041da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 44051da177e4SLinus Torvalds ipr_cmd->ioarcb.read_data_transfer_length = 44061da177e4SLinus Torvalds cpu_to_be32(SCSI_SENSE_BUFFERSIZE); 44071da177e4SLinus Torvalds 44081da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_erp_done, ipr_timeout, 44091da177e4SLinus Torvalds IPR_REQUEST_SENSE_TIMEOUT * 2); 44101da177e4SLinus Torvalds } 44111da177e4SLinus Torvalds 44121da177e4SLinus Torvalds /** 44131da177e4SLinus Torvalds * ipr_erp_cancel_all - Send cancel all to a device 44141da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 44151da177e4SLinus Torvalds * 44161da177e4SLinus Torvalds * This function sends a cancel all to a device to clear the 44171da177e4SLinus Torvalds * queue. If we are running TCQ on the device, QERR is set to 1, 44181da177e4SLinus Torvalds * which means all outstanding ops have been dropped on the floor. 44191da177e4SLinus Torvalds * Cancel all will return them to us. 44201da177e4SLinus Torvalds * 44211da177e4SLinus Torvalds * Return value: 44221da177e4SLinus Torvalds * nothing 44231da177e4SLinus Torvalds **/ 44241da177e4SLinus Torvalds static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) 44251da177e4SLinus Torvalds { 44261da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 44271da177e4SLinus Torvalds struct ipr_resource_entry *res = scsi_cmd->device->hostdata; 44281da177e4SLinus Torvalds struct ipr_cmd_pkt *cmd_pkt; 44291da177e4SLinus Torvalds 44301da177e4SLinus Torvalds res->in_erp = 1; 44311da177e4SLinus Torvalds 44321da177e4SLinus Torvalds ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); 44331da177e4SLinus Torvalds 44341da177e4SLinus Torvalds if (!scsi_get_tag_type(scsi_cmd->device)) { 44351da177e4SLinus Torvalds ipr_erp_request_sense(ipr_cmd); 44361da177e4SLinus Torvalds return; 44371da177e4SLinus Torvalds } 44381da177e4SLinus Torvalds 44391da177e4SLinus Torvalds cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; 44401da177e4SLinus Torvalds cmd_pkt->request_type = IPR_RQTYPE_IOACMD; 44411da177e4SLinus Torvalds cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; 44421da177e4SLinus Torvalds 44431da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_erp_request_sense, ipr_timeout, 44441da177e4SLinus Torvalds IPR_CANCEL_ALL_TIMEOUT); 44451da177e4SLinus Torvalds } 44461da177e4SLinus Torvalds 44471da177e4SLinus Torvalds /** 44481da177e4SLinus Torvalds * ipr_dump_ioasa - Dump contents of IOASA 44491da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 44501da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 4451fe964d0aSBrian King * @res: resource entry struct 44521da177e4SLinus Torvalds * 44531da177e4SLinus Torvalds * This function is invoked by the interrupt handler when ops 44541da177e4SLinus Torvalds * fail. It will log the IOASA if appropriate. Only called 44551da177e4SLinus Torvalds * for GPDD ops. 44561da177e4SLinus Torvalds * 44571da177e4SLinus Torvalds * Return value: 44581da177e4SLinus Torvalds * none 44591da177e4SLinus Torvalds **/ 44601da177e4SLinus Torvalds static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, 4461fe964d0aSBrian King struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res) 44621da177e4SLinus Torvalds { 44631da177e4SLinus Torvalds int i; 44641da177e4SLinus Torvalds u16 data_len; 44651da177e4SLinus Torvalds u32 ioasc; 44661da177e4SLinus Torvalds struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; 44671da177e4SLinus Torvalds __be32 *ioasa_data = (__be32 *)ioasa; 44681da177e4SLinus Torvalds int error_index; 44691da177e4SLinus Torvalds 44701da177e4SLinus Torvalds ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK; 44711da177e4SLinus Torvalds 44721da177e4SLinus Torvalds if (0 == ioasc) 44731da177e4SLinus Torvalds return; 44741da177e4SLinus Torvalds 44751da177e4SLinus Torvalds if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) 44761da177e4SLinus Torvalds return; 44771da177e4SLinus Torvalds 44781da177e4SLinus Torvalds error_index = ipr_get_error(ioasc); 44791da177e4SLinus Torvalds 44801da177e4SLinus Torvalds if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) { 44811da177e4SLinus Torvalds /* Don't log an error if the IOA already logged one */ 44821da177e4SLinus Torvalds if (ioasa->ilid != 0) 44831da177e4SLinus Torvalds return; 44841da177e4SLinus Torvalds 44851da177e4SLinus Torvalds if (ipr_error_table[error_index].log_ioasa == 0) 44861da177e4SLinus Torvalds return; 44871da177e4SLinus Torvalds } 44881da177e4SLinus Torvalds 4489fe964d0aSBrian King ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error); 44901da177e4SLinus Torvalds 44911da177e4SLinus Torvalds if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len)) 44921da177e4SLinus Torvalds data_len = sizeof(struct ipr_ioasa); 44931da177e4SLinus Torvalds else 44941da177e4SLinus Torvalds data_len = be16_to_cpu(ioasa->ret_stat_len); 44951da177e4SLinus Torvalds 44961da177e4SLinus Torvalds ipr_err("IOASA Dump:\n"); 44971da177e4SLinus Torvalds 44981da177e4SLinus Torvalds for (i = 0; i < data_len / 4; i += 4) { 44991da177e4SLinus Torvalds ipr_err("%08X: %08X %08X %08X %08X\n", i*4, 45001da177e4SLinus Torvalds be32_to_cpu(ioasa_data[i]), 45011da177e4SLinus Torvalds be32_to_cpu(ioasa_data[i+1]), 45021da177e4SLinus Torvalds be32_to_cpu(ioasa_data[i+2]), 45031da177e4SLinus Torvalds be32_to_cpu(ioasa_data[i+3])); 45041da177e4SLinus Torvalds } 45051da177e4SLinus Torvalds } 45061da177e4SLinus Torvalds 45071da177e4SLinus Torvalds /** 45081da177e4SLinus Torvalds * ipr_gen_sense - Generate SCSI sense data from an IOASA 45091da177e4SLinus Torvalds * @ioasa: IOASA 45101da177e4SLinus Torvalds * @sense_buf: sense data buffer 45111da177e4SLinus Torvalds * 45121da177e4SLinus Torvalds * Return value: 45131da177e4SLinus Torvalds * none 45141da177e4SLinus Torvalds **/ 45151da177e4SLinus Torvalds static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd) 45161da177e4SLinus Torvalds { 45171da177e4SLinus Torvalds u32 failing_lba; 45181da177e4SLinus Torvalds u8 *sense_buf = ipr_cmd->scsi_cmd->sense_buffer; 45191da177e4SLinus Torvalds struct ipr_resource_entry *res = ipr_cmd->scsi_cmd->device->hostdata; 45201da177e4SLinus Torvalds struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; 45211da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ioasa->ioasc); 45221da177e4SLinus Torvalds 45231da177e4SLinus Torvalds memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); 45241da177e4SLinus Torvalds 45251da177e4SLinus Torvalds if (ioasc >= IPR_FIRST_DRIVER_IOASC) 45261da177e4SLinus Torvalds return; 45271da177e4SLinus Torvalds 45281da177e4SLinus Torvalds ipr_cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; 45291da177e4SLinus Torvalds 45301da177e4SLinus Torvalds if (ipr_is_vset_device(res) && 45311da177e4SLinus Torvalds ioasc == IPR_IOASC_MED_DO_NOT_REALLOC && 45321da177e4SLinus Torvalds ioasa->u.vset.failing_lba_hi != 0) { 45331da177e4SLinus Torvalds sense_buf[0] = 0x72; 45341da177e4SLinus Torvalds sense_buf[1] = IPR_IOASC_SENSE_KEY(ioasc); 45351da177e4SLinus Torvalds sense_buf[2] = IPR_IOASC_SENSE_CODE(ioasc); 45361da177e4SLinus Torvalds sense_buf[3] = IPR_IOASC_SENSE_QUAL(ioasc); 45371da177e4SLinus Torvalds 45381da177e4SLinus Torvalds sense_buf[7] = 12; 45391da177e4SLinus Torvalds sense_buf[8] = 0; 45401da177e4SLinus Torvalds sense_buf[9] = 0x0A; 45411da177e4SLinus Torvalds sense_buf[10] = 0x80; 45421da177e4SLinus Torvalds 45431da177e4SLinus Torvalds failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_hi); 45441da177e4SLinus Torvalds 45451da177e4SLinus Torvalds sense_buf[12] = (failing_lba & 0xff000000) >> 24; 45461da177e4SLinus Torvalds sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; 45471da177e4SLinus Torvalds sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; 45481da177e4SLinus Torvalds sense_buf[15] = failing_lba & 0x000000ff; 45491da177e4SLinus Torvalds 45501da177e4SLinus Torvalds failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); 45511da177e4SLinus Torvalds 45521da177e4SLinus Torvalds sense_buf[16] = (failing_lba & 0xff000000) >> 24; 45531da177e4SLinus Torvalds sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; 45541da177e4SLinus Torvalds sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; 45551da177e4SLinus Torvalds sense_buf[19] = failing_lba & 0x000000ff; 45561da177e4SLinus Torvalds } else { 45571da177e4SLinus Torvalds sense_buf[0] = 0x70; 45581da177e4SLinus Torvalds sense_buf[2] = IPR_IOASC_SENSE_KEY(ioasc); 45591da177e4SLinus Torvalds sense_buf[12] = IPR_IOASC_SENSE_CODE(ioasc); 45601da177e4SLinus Torvalds sense_buf[13] = IPR_IOASC_SENSE_QUAL(ioasc); 45611da177e4SLinus Torvalds 45621da177e4SLinus Torvalds /* Illegal request */ 45631da177e4SLinus Torvalds if ((IPR_IOASC_SENSE_KEY(ioasc) == 0x05) && 45641da177e4SLinus Torvalds (be32_to_cpu(ioasa->ioasc_specific) & IPR_FIELD_POINTER_VALID)) { 45651da177e4SLinus Torvalds sense_buf[7] = 10; /* additional length */ 45661da177e4SLinus Torvalds 45671da177e4SLinus Torvalds /* IOARCB was in error */ 45681da177e4SLinus Torvalds if (IPR_IOASC_SENSE_CODE(ioasc) == 0x24) 45691da177e4SLinus Torvalds sense_buf[15] = 0xC0; 45701da177e4SLinus Torvalds else /* Parameter data was invalid */ 45711da177e4SLinus Torvalds sense_buf[15] = 0x80; 45721da177e4SLinus Torvalds 45731da177e4SLinus Torvalds sense_buf[16] = 45741da177e4SLinus Torvalds ((IPR_FIELD_POINTER_MASK & 45751da177e4SLinus Torvalds be32_to_cpu(ioasa->ioasc_specific)) >> 8) & 0xff; 45761da177e4SLinus Torvalds sense_buf[17] = 45771da177e4SLinus Torvalds (IPR_FIELD_POINTER_MASK & 45781da177e4SLinus Torvalds be32_to_cpu(ioasa->ioasc_specific)) & 0xff; 45791da177e4SLinus Torvalds } else { 45801da177e4SLinus Torvalds if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) { 45811da177e4SLinus Torvalds if (ipr_is_vset_device(res)) 45821da177e4SLinus Torvalds failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); 45831da177e4SLinus Torvalds else 45841da177e4SLinus Torvalds failing_lba = be32_to_cpu(ioasa->u.dasd.failing_lba); 45851da177e4SLinus Torvalds 45861da177e4SLinus Torvalds sense_buf[0] |= 0x80; /* Or in the Valid bit */ 45871da177e4SLinus Torvalds sense_buf[3] = (failing_lba & 0xff000000) >> 24; 45881da177e4SLinus Torvalds sense_buf[4] = (failing_lba & 0x00ff0000) >> 16; 45891da177e4SLinus Torvalds sense_buf[5] = (failing_lba & 0x0000ff00) >> 8; 45901da177e4SLinus Torvalds sense_buf[6] = failing_lba & 0x000000ff; 45911da177e4SLinus Torvalds } 45921da177e4SLinus Torvalds 45931da177e4SLinus Torvalds sense_buf[7] = 6; /* additional length */ 45941da177e4SLinus Torvalds } 45951da177e4SLinus Torvalds } 45961da177e4SLinus Torvalds } 45971da177e4SLinus Torvalds 45981da177e4SLinus Torvalds /** 4599ee0a90faSbrking@us.ibm.com * ipr_get_autosense - Copy autosense data to sense buffer 4600ee0a90faSbrking@us.ibm.com * @ipr_cmd: ipr command struct 4601ee0a90faSbrking@us.ibm.com * 4602ee0a90faSbrking@us.ibm.com * This function copies the autosense buffer to the buffer 4603ee0a90faSbrking@us.ibm.com * in the scsi_cmd, if there is autosense available. 4604ee0a90faSbrking@us.ibm.com * 4605ee0a90faSbrking@us.ibm.com * Return value: 4606ee0a90faSbrking@us.ibm.com * 1 if autosense was available / 0 if not 4607ee0a90faSbrking@us.ibm.com **/ 4608ee0a90faSbrking@us.ibm.com static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd) 4609ee0a90faSbrking@us.ibm.com { 4610ee0a90faSbrking@us.ibm.com struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; 4611ee0a90faSbrking@us.ibm.com 4612117d2ce1SBrian King if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0) 4613ee0a90faSbrking@us.ibm.com return 0; 4614ee0a90faSbrking@us.ibm.com 4615ee0a90faSbrking@us.ibm.com memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data, 4616ee0a90faSbrking@us.ibm.com min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len), 4617ee0a90faSbrking@us.ibm.com SCSI_SENSE_BUFFERSIZE)); 4618ee0a90faSbrking@us.ibm.com return 1; 4619ee0a90faSbrking@us.ibm.com } 4620ee0a90faSbrking@us.ibm.com 4621ee0a90faSbrking@us.ibm.com /** 46221da177e4SLinus Torvalds * ipr_erp_start - Process an error response for a SCSI op 46231da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 46241da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 46251da177e4SLinus Torvalds * 46261da177e4SLinus Torvalds * This function determines whether or not to initiate ERP 46271da177e4SLinus Torvalds * on the affected device. 46281da177e4SLinus Torvalds * 46291da177e4SLinus Torvalds * Return value: 46301da177e4SLinus Torvalds * nothing 46311da177e4SLinus Torvalds **/ 46321da177e4SLinus Torvalds static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, 46331da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd) 46341da177e4SLinus Torvalds { 46351da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 46361da177e4SLinus Torvalds struct ipr_resource_entry *res = scsi_cmd->device->hostdata; 46371da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 46381da177e4SLinus Torvalds 46391da177e4SLinus Torvalds if (!res) { 46401da177e4SLinus Torvalds ipr_scsi_eh_done(ipr_cmd); 46411da177e4SLinus Torvalds return; 46421da177e4SLinus Torvalds } 46431da177e4SLinus Torvalds 46441da177e4SLinus Torvalds if (ipr_is_gscsi(res)) 4645fe964d0aSBrian King ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); 46461da177e4SLinus Torvalds else 46471da177e4SLinus Torvalds ipr_gen_sense(ipr_cmd); 46481da177e4SLinus Torvalds 46491da177e4SLinus Torvalds switch (ioasc & IPR_IOASC_IOASC_MASK) { 46501da177e4SLinus Torvalds case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: 4651ee0a90faSbrking@us.ibm.com if (ipr_is_naca_model(res)) 4652ee0a90faSbrking@us.ibm.com scsi_cmd->result |= (DID_ABORT << 16); 4653ee0a90faSbrking@us.ibm.com else 46541da177e4SLinus Torvalds scsi_cmd->result |= (DID_IMM_RETRY << 16); 46551da177e4SLinus Torvalds break; 46561da177e4SLinus Torvalds case IPR_IOASC_IR_RESOURCE_HANDLE: 4657b0df54bbSbrking@us.ibm.com case IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA: 46581da177e4SLinus Torvalds scsi_cmd->result |= (DID_NO_CONNECT << 16); 46591da177e4SLinus Torvalds break; 46601da177e4SLinus Torvalds case IPR_IOASC_HW_SEL_TIMEOUT: 46611da177e4SLinus Torvalds scsi_cmd->result |= (DID_NO_CONNECT << 16); 4662ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 46631da177e4SLinus Torvalds res->needs_sync_complete = 1; 46641da177e4SLinus Torvalds break; 46651da177e4SLinus Torvalds case IPR_IOASC_SYNC_REQUIRED: 46661da177e4SLinus Torvalds if (!res->in_erp) 46671da177e4SLinus Torvalds res->needs_sync_complete = 1; 46681da177e4SLinus Torvalds scsi_cmd->result |= (DID_IMM_RETRY << 16); 46691da177e4SLinus Torvalds break; 46701da177e4SLinus Torvalds case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */ 4671b0df54bbSbrking@us.ibm.com case IPR_IOASA_IR_DUAL_IOA_DISABLED: 46721da177e4SLinus Torvalds scsi_cmd->result |= (DID_PASSTHROUGH << 16); 46731da177e4SLinus Torvalds break; 46741da177e4SLinus Torvalds case IPR_IOASC_BUS_WAS_RESET: 46751da177e4SLinus Torvalds case IPR_IOASC_BUS_WAS_RESET_BY_OTHER: 46761da177e4SLinus Torvalds /* 46771da177e4SLinus Torvalds * Report the bus reset and ask for a retry. The device 46781da177e4SLinus Torvalds * will give CC/UA the next command. 46791da177e4SLinus Torvalds */ 46801da177e4SLinus Torvalds if (!res->resetting_device) 46811da177e4SLinus Torvalds scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel); 46821da177e4SLinus Torvalds scsi_cmd->result |= (DID_ERROR << 16); 4683ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 46841da177e4SLinus Torvalds res->needs_sync_complete = 1; 46851da177e4SLinus Torvalds break; 46861da177e4SLinus Torvalds case IPR_IOASC_HW_DEV_BUS_STATUS: 46871da177e4SLinus Torvalds scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc); 46881da177e4SLinus Torvalds if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) { 4689ee0a90faSbrking@us.ibm.com if (!ipr_get_autosense(ipr_cmd)) { 4690ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) { 46911da177e4SLinus Torvalds ipr_erp_cancel_all(ipr_cmd); 46921da177e4SLinus Torvalds return; 46931da177e4SLinus Torvalds } 4694ee0a90faSbrking@us.ibm.com } 4695ee0a90faSbrking@us.ibm.com } 4696ee0a90faSbrking@us.ibm.com if (!ipr_is_naca_model(res)) 46971da177e4SLinus Torvalds res->needs_sync_complete = 1; 46981da177e4SLinus Torvalds break; 46991da177e4SLinus Torvalds case IPR_IOASC_NR_INIT_CMD_REQUIRED: 47001da177e4SLinus Torvalds break; 47011da177e4SLinus Torvalds default: 47025b7304fbSBrian King if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 47031da177e4SLinus Torvalds scsi_cmd->result |= (DID_ERROR << 16); 4704ee0a90faSbrking@us.ibm.com if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res)) 47051da177e4SLinus Torvalds res->needs_sync_complete = 1; 47061da177e4SLinus Torvalds break; 47071da177e4SLinus Torvalds } 47081da177e4SLinus Torvalds 47091da177e4SLinus Torvalds ipr_unmap_sglist(ioa_cfg, ipr_cmd); 47101da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 47111da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 47121da177e4SLinus Torvalds } 47131da177e4SLinus Torvalds 47141da177e4SLinus Torvalds /** 47151da177e4SLinus Torvalds * ipr_scsi_done - mid-layer done function 47161da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 47171da177e4SLinus Torvalds * 47181da177e4SLinus Torvalds * This function is invoked by the interrupt handler for 47191da177e4SLinus Torvalds * ops generated by the SCSI mid-layer 47201da177e4SLinus Torvalds * 47211da177e4SLinus Torvalds * Return value: 47221da177e4SLinus Torvalds * none 47231da177e4SLinus Torvalds **/ 47241da177e4SLinus Torvalds static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) 47251da177e4SLinus Torvalds { 47261da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 47271da177e4SLinus Torvalds struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; 47281da177e4SLinus Torvalds u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 47291da177e4SLinus Torvalds 47301da177e4SLinus Torvalds scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len); 47311da177e4SLinus Torvalds 47321da177e4SLinus Torvalds if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) { 47331da177e4SLinus Torvalds ipr_unmap_sglist(ioa_cfg, ipr_cmd); 47341da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 47351da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 47361da177e4SLinus Torvalds } else 47371da177e4SLinus Torvalds ipr_erp_start(ioa_cfg, ipr_cmd); 47381da177e4SLinus Torvalds } 47391da177e4SLinus Torvalds 47401da177e4SLinus Torvalds /** 47411da177e4SLinus Torvalds * ipr_queuecommand - Queue a mid-layer request 47421da177e4SLinus Torvalds * @scsi_cmd: scsi command struct 47431da177e4SLinus Torvalds * @done: done function 47441da177e4SLinus Torvalds * 47451da177e4SLinus Torvalds * This function queues a request generated by the mid-layer. 47461da177e4SLinus Torvalds * 47471da177e4SLinus Torvalds * Return value: 47481da177e4SLinus Torvalds * 0 on success 47491da177e4SLinus Torvalds * SCSI_MLQUEUE_DEVICE_BUSY if device is busy 47501da177e4SLinus Torvalds * SCSI_MLQUEUE_HOST_BUSY if host is busy 47511da177e4SLinus Torvalds **/ 47521da177e4SLinus Torvalds static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, 47531da177e4SLinus Torvalds void (*done) (struct scsi_cmnd *)) 47541da177e4SLinus Torvalds { 47551da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 47561da177e4SLinus Torvalds struct ipr_resource_entry *res; 47571da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb; 47581da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 47591da177e4SLinus Torvalds int rc = 0; 47601da177e4SLinus Torvalds 47611da177e4SLinus Torvalds scsi_cmd->scsi_done = done; 47621da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; 47631da177e4SLinus Torvalds res = scsi_cmd->device->hostdata; 47641da177e4SLinus Torvalds scsi_cmd->result = (DID_OK << 16); 47651da177e4SLinus Torvalds 47661da177e4SLinus Torvalds /* 47671da177e4SLinus Torvalds * We are currently blocking all devices due to a host reset 47681da177e4SLinus Torvalds * We have told the host to stop giving us new requests, but 47691da177e4SLinus Torvalds * ERP ops don't count. FIXME 47701da177e4SLinus Torvalds */ 47711da177e4SLinus Torvalds if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead)) 47721da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 47731da177e4SLinus Torvalds 47741da177e4SLinus Torvalds /* 47751da177e4SLinus Torvalds * FIXME - Create scsi_set_host_offline interface 47761da177e4SLinus Torvalds * and the ioa_is_dead check can be removed 47771da177e4SLinus Torvalds */ 47781da177e4SLinus Torvalds if (unlikely(ioa_cfg->ioa_is_dead || !res)) { 47791da177e4SLinus Torvalds memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 47801da177e4SLinus Torvalds scsi_cmd->result = (DID_NO_CONNECT << 16); 47811da177e4SLinus Torvalds scsi_cmd->scsi_done(scsi_cmd); 47821da177e4SLinus Torvalds return 0; 47831da177e4SLinus Torvalds } 47841da177e4SLinus Torvalds 478535a39691SBrian King if (ipr_is_gata(res) && res->sata_port) 478635a39691SBrian King return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap); 478735a39691SBrian King 47881da177e4SLinus Torvalds ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 47891da177e4SLinus Torvalds ioarcb = &ipr_cmd->ioarcb; 47901da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); 47911da177e4SLinus Torvalds 47921da177e4SLinus Torvalds memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); 47931da177e4SLinus Torvalds ipr_cmd->scsi_cmd = scsi_cmd; 47941da177e4SLinus Torvalds ioarcb->res_handle = res->cfgte.res_handle; 47951da177e4SLinus Torvalds ipr_cmd->done = ipr_scsi_done; 47961da177e4SLinus Torvalds ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr)); 47971da177e4SLinus Torvalds 47981da177e4SLinus Torvalds if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { 47991da177e4SLinus Torvalds if (scsi_cmd->underflow == 0) 48001da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; 48011da177e4SLinus Torvalds 48021da177e4SLinus Torvalds if (res->needs_sync_complete) { 48031da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE; 48041da177e4SLinus Torvalds res->needs_sync_complete = 0; 48051da177e4SLinus Torvalds } 48061da177e4SLinus Torvalds 48071da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; 48081da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; 48091da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; 48101da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd); 48111da177e4SLinus Torvalds } 48121da177e4SLinus Torvalds 48131da177e4SLinus Torvalds if (scsi_cmd->cmnd[0] >= 0xC0 && 48141da177e4SLinus Torvalds (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE)) 48151da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 48161da177e4SLinus Torvalds 48171da177e4SLinus Torvalds if (likely(rc == 0)) 48181da177e4SLinus Torvalds rc = ipr_build_ioadl(ioa_cfg, ipr_cmd); 48191da177e4SLinus Torvalds 48201da177e4SLinus Torvalds if (likely(rc == 0)) { 48211da177e4SLinus Torvalds mb(); 48221da177e4SLinus Torvalds writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr), 48231da177e4SLinus Torvalds ioa_cfg->regs.ioarrin_reg); 48241da177e4SLinus Torvalds } else { 48251da177e4SLinus Torvalds list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 48261da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 48271da177e4SLinus Torvalds } 48281da177e4SLinus Torvalds 48291da177e4SLinus Torvalds return 0; 48301da177e4SLinus Torvalds } 48311da177e4SLinus Torvalds 48321da177e4SLinus Torvalds /** 483335a39691SBrian King * ipr_ioctl - IOCTL handler 483435a39691SBrian King * @sdev: scsi device struct 483535a39691SBrian King * @cmd: IOCTL cmd 483635a39691SBrian King * @arg: IOCTL arg 483735a39691SBrian King * 483835a39691SBrian King * Return value: 483935a39691SBrian King * 0 on success / other on failure 484035a39691SBrian King **/ 4841bd705f2dSAdrian Bunk static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) 484235a39691SBrian King { 484335a39691SBrian King struct ipr_resource_entry *res; 484435a39691SBrian King 484535a39691SBrian King res = (struct ipr_resource_entry *)sdev->hostdata; 484635a39691SBrian King if (res && ipr_is_gata(res)) 484735a39691SBrian King return ata_scsi_ioctl(sdev, cmd, arg); 484835a39691SBrian King 484935a39691SBrian King return -EINVAL; 485035a39691SBrian King } 485135a39691SBrian King 485235a39691SBrian King /** 48531da177e4SLinus Torvalds * ipr_info - Get information about the card/driver 48541da177e4SLinus Torvalds * @scsi_host: scsi host struct 48551da177e4SLinus Torvalds * 48561da177e4SLinus Torvalds * Return value: 48571da177e4SLinus Torvalds * pointer to buffer with description string 48581da177e4SLinus Torvalds **/ 48591da177e4SLinus Torvalds static const char * ipr_ioa_info(struct Scsi_Host *host) 48601da177e4SLinus Torvalds { 48611da177e4SLinus Torvalds static char buffer[512]; 48621da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 48631da177e4SLinus Torvalds unsigned long lock_flags = 0; 48641da177e4SLinus Torvalds 48651da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *) host->hostdata; 48661da177e4SLinus Torvalds 48671da177e4SLinus Torvalds spin_lock_irqsave(host->host_lock, lock_flags); 48681da177e4SLinus Torvalds sprintf(buffer, "IBM %X Storage Adapter", ioa_cfg->type); 48691da177e4SLinus Torvalds spin_unlock_irqrestore(host->host_lock, lock_flags); 48701da177e4SLinus Torvalds 48711da177e4SLinus Torvalds return buffer; 48721da177e4SLinus Torvalds } 48731da177e4SLinus Torvalds 48741da177e4SLinus Torvalds static struct scsi_host_template driver_template = { 48751da177e4SLinus Torvalds .module = THIS_MODULE, 48761da177e4SLinus Torvalds .name = "IPR", 48771da177e4SLinus Torvalds .info = ipr_ioa_info, 487835a39691SBrian King .ioctl = ipr_ioctl, 48791da177e4SLinus Torvalds .queuecommand = ipr_queuecommand, 48801da177e4SLinus Torvalds .eh_abort_handler = ipr_eh_abort, 48811da177e4SLinus Torvalds .eh_device_reset_handler = ipr_eh_dev_reset, 48821da177e4SLinus Torvalds .eh_host_reset_handler = ipr_eh_host_reset, 48831da177e4SLinus Torvalds .slave_alloc = ipr_slave_alloc, 48841da177e4SLinus Torvalds .slave_configure = ipr_slave_configure, 48851da177e4SLinus Torvalds .slave_destroy = ipr_slave_destroy, 488635a39691SBrian King .target_alloc = ipr_target_alloc, 488735a39691SBrian King .target_destroy = ipr_target_destroy, 48881da177e4SLinus Torvalds .change_queue_depth = ipr_change_queue_depth, 48891da177e4SLinus Torvalds .change_queue_type = ipr_change_queue_type, 48901da177e4SLinus Torvalds .bios_param = ipr_biosparam, 48911da177e4SLinus Torvalds .can_queue = IPR_MAX_COMMANDS, 48921da177e4SLinus Torvalds .this_id = -1, 48931da177e4SLinus Torvalds .sg_tablesize = IPR_MAX_SGLIST, 48941da177e4SLinus Torvalds .max_sectors = IPR_IOA_MAX_SECTORS, 48951da177e4SLinus Torvalds .cmd_per_lun = IPR_MAX_CMD_PER_LUN, 48961da177e4SLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 48971da177e4SLinus Torvalds .shost_attrs = ipr_ioa_attrs, 48981da177e4SLinus Torvalds .sdev_attrs = ipr_dev_attrs, 48991da177e4SLinus Torvalds .proc_name = IPR_NAME 49001da177e4SLinus Torvalds }; 49011da177e4SLinus Torvalds 490235a39691SBrian King /** 490335a39691SBrian King * ipr_ata_phy_reset - libata phy_reset handler 490435a39691SBrian King * @ap: ata port to reset 490535a39691SBrian King * 490635a39691SBrian King **/ 490735a39691SBrian King static void ipr_ata_phy_reset(struct ata_port *ap) 490835a39691SBrian King { 490935a39691SBrian King unsigned long flags; 491035a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 491135a39691SBrian King struct ipr_resource_entry *res = sata_port->res; 491235a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; 491335a39691SBrian King int rc; 491435a39691SBrian King 491535a39691SBrian King ENTER; 491635a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 491735a39691SBrian King while(ioa_cfg->in_reset_reload) { 491835a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 491935a39691SBrian King wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 492035a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 492135a39691SBrian King } 492235a39691SBrian King 492335a39691SBrian King if (!ioa_cfg->allow_cmds) 492435a39691SBrian King goto out_unlock; 492535a39691SBrian King 492635a39691SBrian King rc = ipr_device_reset(ioa_cfg, res); 492735a39691SBrian King 492835a39691SBrian King if (rc) { 492935a39691SBrian King ap->ops->port_disable(ap); 493035a39691SBrian King goto out_unlock; 493135a39691SBrian King } 493235a39691SBrian King 493335a39691SBrian King switch(res->cfgte.proto) { 493435a39691SBrian King case IPR_PROTO_SATA: 493535a39691SBrian King case IPR_PROTO_SAS_STP: 493635a39691SBrian King ap->device[0].class = ATA_DEV_ATA; 493735a39691SBrian King break; 493835a39691SBrian King case IPR_PROTO_SATA_ATAPI: 493935a39691SBrian King case IPR_PROTO_SAS_STP_ATAPI: 494035a39691SBrian King ap->device[0].class = ATA_DEV_ATAPI; 494135a39691SBrian King break; 494235a39691SBrian King default: 494335a39691SBrian King ap->device[0].class = ATA_DEV_UNKNOWN; 494435a39691SBrian King ap->ops->port_disable(ap); 494535a39691SBrian King break; 494635a39691SBrian King }; 494735a39691SBrian King 494835a39691SBrian King out_unlock: 494935a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 495035a39691SBrian King LEAVE; 495135a39691SBrian King } 495235a39691SBrian King 495335a39691SBrian King /** 495435a39691SBrian King * ipr_ata_post_internal - Cleanup after an internal command 495535a39691SBrian King * @qc: ATA queued command 495635a39691SBrian King * 495735a39691SBrian King * Return value: 495835a39691SBrian King * none 495935a39691SBrian King **/ 496035a39691SBrian King static void ipr_ata_post_internal(struct ata_queued_cmd *qc) 496135a39691SBrian King { 496235a39691SBrian King struct ipr_sata_port *sata_port = qc->ap->private_data; 496335a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; 496435a39691SBrian King struct ipr_cmnd *ipr_cmd; 496535a39691SBrian King unsigned long flags; 496635a39691SBrian King 496735a39691SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 496873d98ff0SBrian King while(ioa_cfg->in_reset_reload) { 496973d98ff0SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 497073d98ff0SBrian King wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 497173d98ff0SBrian King spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 497273d98ff0SBrian King } 497373d98ff0SBrian King 497435a39691SBrian King list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { 497535a39691SBrian King if (ipr_cmd->qc == qc) { 497635a39691SBrian King ipr_device_reset(ioa_cfg, sata_port->res); 497735a39691SBrian King break; 497835a39691SBrian King } 497935a39691SBrian King } 498035a39691SBrian King spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 498135a39691SBrian King } 498235a39691SBrian King 498335a39691SBrian King /** 498435a39691SBrian King * ipr_tf_read - Read the current ATA taskfile for the ATA port 498535a39691SBrian King * @ap: ATA port 498635a39691SBrian King * @tf: destination ATA taskfile 498735a39691SBrian King * 498835a39691SBrian King * Return value: 498935a39691SBrian King * none 499035a39691SBrian King **/ 499135a39691SBrian King static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 499235a39691SBrian King { 499335a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 499435a39691SBrian King struct ipr_ioasa_gata *g = &sata_port->ioasa; 499535a39691SBrian King 499635a39691SBrian King tf->feature = g->error; 499735a39691SBrian King tf->nsect = g->nsect; 499835a39691SBrian King tf->lbal = g->lbal; 499935a39691SBrian King tf->lbam = g->lbam; 500035a39691SBrian King tf->lbah = g->lbah; 500135a39691SBrian King tf->device = g->device; 500235a39691SBrian King tf->command = g->status; 500335a39691SBrian King tf->hob_nsect = g->hob_nsect; 500435a39691SBrian King tf->hob_lbal = g->hob_lbal; 500535a39691SBrian King tf->hob_lbam = g->hob_lbam; 500635a39691SBrian King tf->hob_lbah = g->hob_lbah; 500735a39691SBrian King tf->ctl = g->alt_status; 500835a39691SBrian King } 500935a39691SBrian King 501035a39691SBrian King /** 501135a39691SBrian King * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure 501235a39691SBrian King * @regs: destination 501335a39691SBrian King * @tf: source ATA taskfile 501435a39691SBrian King * 501535a39691SBrian King * Return value: 501635a39691SBrian King * none 501735a39691SBrian King **/ 501835a39691SBrian King static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs, 501935a39691SBrian King struct ata_taskfile *tf) 502035a39691SBrian King { 502135a39691SBrian King regs->feature = tf->feature; 502235a39691SBrian King regs->nsect = tf->nsect; 502335a39691SBrian King regs->lbal = tf->lbal; 502435a39691SBrian King regs->lbam = tf->lbam; 502535a39691SBrian King regs->lbah = tf->lbah; 502635a39691SBrian King regs->device = tf->device; 502735a39691SBrian King regs->command = tf->command; 502835a39691SBrian King regs->hob_feature = tf->hob_feature; 502935a39691SBrian King regs->hob_nsect = tf->hob_nsect; 503035a39691SBrian King regs->hob_lbal = tf->hob_lbal; 503135a39691SBrian King regs->hob_lbam = tf->hob_lbam; 503235a39691SBrian King regs->hob_lbah = tf->hob_lbah; 503335a39691SBrian King regs->ctl = tf->ctl; 503435a39691SBrian King } 503535a39691SBrian King 503635a39691SBrian King /** 503735a39691SBrian King * ipr_sata_done - done function for SATA commands 503835a39691SBrian King * @ipr_cmd: ipr command struct 503935a39691SBrian King * 504035a39691SBrian King * This function is invoked by the interrupt handler for 504135a39691SBrian King * ops generated by the SCSI mid-layer to SATA devices 504235a39691SBrian King * 504335a39691SBrian King * Return value: 504435a39691SBrian King * none 504535a39691SBrian King **/ 504635a39691SBrian King static void ipr_sata_done(struct ipr_cmnd *ipr_cmd) 504735a39691SBrian King { 504835a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 504935a39691SBrian King struct ata_queued_cmd *qc = ipr_cmd->qc; 505035a39691SBrian King struct ipr_sata_port *sata_port = qc->ap->private_data; 505135a39691SBrian King struct ipr_resource_entry *res = sata_port->res; 505235a39691SBrian King u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 505335a39691SBrian King 505435a39691SBrian King memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata, 505535a39691SBrian King sizeof(struct ipr_ioasa_gata)); 505635a39691SBrian King ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); 505735a39691SBrian King 505835a39691SBrian King if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET) 505935a39691SBrian King scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus, 506035a39691SBrian King res->cfgte.res_addr.target); 506135a39691SBrian King 506235a39691SBrian King if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) 506335a39691SBrian King qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status); 506435a39691SBrian King else 506535a39691SBrian King qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status); 506635a39691SBrian King list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 506735a39691SBrian King ata_qc_complete(qc); 506835a39691SBrian King } 506935a39691SBrian King 507035a39691SBrian King /** 507135a39691SBrian King * ipr_build_ata_ioadl - Build an ATA scatter/gather list 507235a39691SBrian King * @ipr_cmd: ipr command struct 507335a39691SBrian King * @qc: ATA queued command 507435a39691SBrian King * 507535a39691SBrian King **/ 507635a39691SBrian King static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, 507735a39691SBrian King struct ata_queued_cmd *qc) 507835a39691SBrian King { 507935a39691SBrian King u32 ioadl_flags = 0; 508035a39691SBrian King struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 508135a39691SBrian King struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 508235a39691SBrian King int len = qc->nbytes + qc->pad_len; 508335a39691SBrian King struct scatterlist *sg; 508435a39691SBrian King 508535a39691SBrian King if (len == 0) 508635a39691SBrian King return; 508735a39691SBrian King 508835a39691SBrian King if (qc->dma_dir == DMA_TO_DEVICE) { 508935a39691SBrian King ioadl_flags = IPR_IOADL_FLAGS_WRITE; 509035a39691SBrian King ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 509135a39691SBrian King ioarcb->write_data_transfer_length = cpu_to_be32(len); 509235a39691SBrian King ioarcb->write_ioadl_len = 509335a39691SBrian King cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 509435a39691SBrian King } else if (qc->dma_dir == DMA_FROM_DEVICE) { 509535a39691SBrian King ioadl_flags = IPR_IOADL_FLAGS_READ; 509635a39691SBrian King ioarcb->read_data_transfer_length = cpu_to_be32(len); 509735a39691SBrian King ioarcb->read_ioadl_len = 509835a39691SBrian King cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); 509935a39691SBrian King } 510035a39691SBrian King 510135a39691SBrian King ata_for_each_sg(sg, qc) { 510235a39691SBrian King ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); 510335a39691SBrian King ioadl->address = cpu_to_be32(sg_dma_address(sg)); 510435a39691SBrian King if (ata_sg_is_last(sg, qc)) 510535a39691SBrian King ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); 510635a39691SBrian King else 510735a39691SBrian King ioadl++; 510835a39691SBrian King } 510935a39691SBrian King } 511035a39691SBrian King 511135a39691SBrian King /** 511235a39691SBrian King * ipr_qc_issue - Issue a SATA qc to a device 511335a39691SBrian King * @qc: queued command 511435a39691SBrian King * 511535a39691SBrian King * Return value: 511635a39691SBrian King * 0 if success 511735a39691SBrian King **/ 511835a39691SBrian King static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) 511935a39691SBrian King { 512035a39691SBrian King struct ata_port *ap = qc->ap; 512135a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 512235a39691SBrian King struct ipr_resource_entry *res = sata_port->res; 512335a39691SBrian King struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; 512435a39691SBrian King struct ipr_cmnd *ipr_cmd; 512535a39691SBrian King struct ipr_ioarcb *ioarcb; 512635a39691SBrian King struct ipr_ioarcb_ata_regs *regs; 512735a39691SBrian King 512835a39691SBrian King if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) 512935a39691SBrian King return -EIO; 513035a39691SBrian King 513135a39691SBrian King ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 513235a39691SBrian King ioarcb = &ipr_cmd->ioarcb; 513335a39691SBrian King regs = &ioarcb->add_data.u.regs; 513435a39691SBrian King 513535a39691SBrian King memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data)); 513635a39691SBrian King ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs)); 513735a39691SBrian King 513835a39691SBrian King list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); 513935a39691SBrian King ipr_cmd->qc = qc; 514035a39691SBrian King ipr_cmd->done = ipr_sata_done; 514135a39691SBrian King ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; 514235a39691SBrian King ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU; 514335a39691SBrian King ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; 514435a39691SBrian King ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; 514535a39691SBrian King ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; 514635a39691SBrian King 514735a39691SBrian King ipr_build_ata_ioadl(ipr_cmd, qc); 514835a39691SBrian King regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; 514935a39691SBrian King ipr_copy_sata_tf(regs, &qc->tf); 515035a39691SBrian King memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN); 515135a39691SBrian King ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr)); 515235a39691SBrian King 515335a39691SBrian King switch (qc->tf.protocol) { 515435a39691SBrian King case ATA_PROT_NODATA: 515535a39691SBrian King case ATA_PROT_PIO: 515635a39691SBrian King break; 515735a39691SBrian King 515835a39691SBrian King case ATA_PROT_DMA: 515935a39691SBrian King regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; 516035a39691SBrian King break; 516135a39691SBrian King 516235a39691SBrian King case ATA_PROT_ATAPI: 516335a39691SBrian King case ATA_PROT_ATAPI_NODATA: 516435a39691SBrian King regs->flags |= IPR_ATA_FLAG_PACKET_CMD; 516535a39691SBrian King break; 516635a39691SBrian King 516735a39691SBrian King case ATA_PROT_ATAPI_DMA: 516835a39691SBrian King regs->flags |= IPR_ATA_FLAG_PACKET_CMD; 516935a39691SBrian King regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; 517035a39691SBrian King break; 517135a39691SBrian King 517235a39691SBrian King default: 517335a39691SBrian King WARN_ON(1); 517435a39691SBrian King return -1; 517535a39691SBrian King } 517635a39691SBrian King 517735a39691SBrian King mb(); 517835a39691SBrian King writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr), 517935a39691SBrian King ioa_cfg->regs.ioarrin_reg); 518035a39691SBrian King return 0; 518135a39691SBrian King } 518235a39691SBrian King 518335a39691SBrian King /** 518435a39691SBrian King * ipr_ata_check_status - Return last ATA status 518535a39691SBrian King * @ap: ATA port 518635a39691SBrian King * 518735a39691SBrian King * Return value: 518835a39691SBrian King * ATA status 518935a39691SBrian King **/ 519035a39691SBrian King static u8 ipr_ata_check_status(struct ata_port *ap) 519135a39691SBrian King { 519235a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 519335a39691SBrian King return sata_port->ioasa.status; 519435a39691SBrian King } 519535a39691SBrian King 519635a39691SBrian King /** 519735a39691SBrian King * ipr_ata_check_altstatus - Return last ATA altstatus 519835a39691SBrian King * @ap: ATA port 519935a39691SBrian King * 520035a39691SBrian King * Return value: 520135a39691SBrian King * Alt ATA status 520235a39691SBrian King **/ 520335a39691SBrian King static u8 ipr_ata_check_altstatus(struct ata_port *ap) 520435a39691SBrian King { 520535a39691SBrian King struct ipr_sata_port *sata_port = ap->private_data; 520635a39691SBrian King return sata_port->ioasa.alt_status; 520735a39691SBrian King } 520835a39691SBrian King 520935a39691SBrian King static struct ata_port_operations ipr_sata_ops = { 521035a39691SBrian King .port_disable = ata_port_disable, 521135a39691SBrian King .check_status = ipr_ata_check_status, 521235a39691SBrian King .check_altstatus = ipr_ata_check_altstatus, 521335a39691SBrian King .dev_select = ata_noop_dev_select, 521435a39691SBrian King .phy_reset = ipr_ata_phy_reset, 521535a39691SBrian King .post_internal_cmd = ipr_ata_post_internal, 521635a39691SBrian King .tf_read = ipr_tf_read, 521735a39691SBrian King .qc_prep = ata_noop_qc_prep, 521835a39691SBrian King .qc_issue = ipr_qc_issue, 521935a39691SBrian King .port_start = ata_sas_port_start, 522035a39691SBrian King .port_stop = ata_sas_port_stop 522135a39691SBrian King }; 522235a39691SBrian King 522335a39691SBrian King static struct ata_port_info sata_port_info = { 522435a39691SBrian King .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | 522535a39691SBrian King ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, 522635a39691SBrian King .pio_mask = 0x10, /* pio4 */ 522735a39691SBrian King .mwdma_mask = 0x07, 522835a39691SBrian King .udma_mask = 0x7f, /* udma0-6 */ 522935a39691SBrian King .port_ops = &ipr_sata_ops 523035a39691SBrian King }; 523135a39691SBrian King 52321da177e4SLinus Torvalds #ifdef CONFIG_PPC_PSERIES 52331da177e4SLinus Torvalds static const u16 ipr_blocked_processors[] = { 52341da177e4SLinus Torvalds PV_NORTHSTAR, 52351da177e4SLinus Torvalds PV_PULSAR, 52361da177e4SLinus Torvalds PV_POWER4, 52371da177e4SLinus Torvalds PV_ICESTAR, 52381da177e4SLinus Torvalds PV_SSTAR, 52391da177e4SLinus Torvalds PV_POWER4p, 52401da177e4SLinus Torvalds PV_630, 52411da177e4SLinus Torvalds PV_630p 52421da177e4SLinus Torvalds }; 52431da177e4SLinus Torvalds 52441da177e4SLinus Torvalds /** 52451da177e4SLinus Torvalds * ipr_invalid_adapter - Determine if this adapter is supported on this hardware 52461da177e4SLinus Torvalds * @ioa_cfg: ioa cfg struct 52471da177e4SLinus Torvalds * 52481da177e4SLinus Torvalds * Adapters that use Gemstone revision < 3.1 do not work reliably on 52491da177e4SLinus Torvalds * certain pSeries hardware. This function determines if the given 52501da177e4SLinus Torvalds * adapter is in one of these confgurations or not. 52511da177e4SLinus Torvalds * 52521da177e4SLinus Torvalds * Return value: 52531da177e4SLinus Torvalds * 1 if adapter is not supported / 0 if adapter is supported 52541da177e4SLinus Torvalds **/ 52551da177e4SLinus Torvalds static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) 52561da177e4SLinus Torvalds { 52571da177e4SLinus Torvalds u8 rev_id; 52581da177e4SLinus Torvalds int i; 52591da177e4SLinus Torvalds 52601da177e4SLinus Torvalds if (ioa_cfg->type == 0x5702) { 52611da177e4SLinus Torvalds if (pci_read_config_byte(ioa_cfg->pdev, PCI_REVISION_ID, 52621da177e4SLinus Torvalds &rev_id) == PCIBIOS_SUCCESSFUL) { 52631da177e4SLinus Torvalds if (rev_id < 4) { 52641da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ 52651da177e4SLinus Torvalds if (__is_processor(ipr_blocked_processors[i])) 52661da177e4SLinus Torvalds return 1; 52671da177e4SLinus Torvalds } 52681da177e4SLinus Torvalds } 52691da177e4SLinus Torvalds } 52701da177e4SLinus Torvalds } 52711da177e4SLinus Torvalds return 0; 52721da177e4SLinus Torvalds } 52731da177e4SLinus Torvalds #else 52741da177e4SLinus Torvalds #define ipr_invalid_adapter(ioa_cfg) 0 52751da177e4SLinus Torvalds #endif 52761da177e4SLinus Torvalds 52771da177e4SLinus Torvalds /** 52781da177e4SLinus Torvalds * ipr_ioa_bringdown_done - IOA bring down completion. 52791da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 52801da177e4SLinus Torvalds * 52811da177e4SLinus Torvalds * This function processes the completion of an adapter bring down. 52821da177e4SLinus Torvalds * It wakes any reset sleepers. 52831da177e4SLinus Torvalds * 52841da177e4SLinus Torvalds * Return value: 52851da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 52861da177e4SLinus Torvalds **/ 52871da177e4SLinus Torvalds static int ipr_ioa_bringdown_done(struct ipr_cmnd *ipr_cmd) 52881da177e4SLinus Torvalds { 52891da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 52901da177e4SLinus Torvalds 52911da177e4SLinus Torvalds ENTER; 52921da177e4SLinus Torvalds ioa_cfg->in_reset_reload = 0; 52931da177e4SLinus Torvalds ioa_cfg->reset_retries = 0; 52941da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 52951da177e4SLinus Torvalds wake_up_all(&ioa_cfg->reset_wait_q); 52961da177e4SLinus Torvalds 52971da177e4SLinus Torvalds spin_unlock_irq(ioa_cfg->host->host_lock); 52981da177e4SLinus Torvalds scsi_unblock_requests(ioa_cfg->host); 52991da177e4SLinus Torvalds spin_lock_irq(ioa_cfg->host->host_lock); 53001da177e4SLinus Torvalds LEAVE; 53011da177e4SLinus Torvalds 53021da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 53031da177e4SLinus Torvalds } 53041da177e4SLinus Torvalds 53051da177e4SLinus Torvalds /** 53061da177e4SLinus Torvalds * ipr_ioa_reset_done - IOA reset completion. 53071da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 53081da177e4SLinus Torvalds * 53091da177e4SLinus Torvalds * This function processes the completion of an adapter reset. 53101da177e4SLinus Torvalds * It schedules any necessary mid-layer add/removes and 53111da177e4SLinus Torvalds * wakes any reset sleepers. 53121da177e4SLinus Torvalds * 53131da177e4SLinus Torvalds * Return value: 53141da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 53151da177e4SLinus Torvalds **/ 53161da177e4SLinus Torvalds static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) 53171da177e4SLinus Torvalds { 53181da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 53191da177e4SLinus Torvalds struct ipr_resource_entry *res; 53201da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb, *temp; 53211da177e4SLinus Torvalds int i = 0; 53221da177e4SLinus Torvalds 53231da177e4SLinus Torvalds ENTER; 53241da177e4SLinus Torvalds ioa_cfg->in_reset_reload = 0; 53251da177e4SLinus Torvalds ioa_cfg->allow_cmds = 1; 53261da177e4SLinus Torvalds ioa_cfg->reset_cmd = NULL; 53273d1d0da6Sbrking@us.ibm.com ioa_cfg->doorbell |= IPR_RUNTIME_RESET; 53281da177e4SLinus Torvalds 53291da177e4SLinus Torvalds list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { 53301da177e4SLinus Torvalds if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) { 53311da177e4SLinus Torvalds ipr_trace; 53321da177e4SLinus Torvalds break; 53331da177e4SLinus Torvalds } 53341da177e4SLinus Torvalds } 53351da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 53361da177e4SLinus Torvalds 53371da177e4SLinus Torvalds list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) { 53381da177e4SLinus Torvalds list_del(&hostrcb->queue); 53391da177e4SLinus Torvalds if (i++ < IPR_NUM_LOG_HCAMS) 53401da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); 53411da177e4SLinus Torvalds else 53421da177e4SLinus Torvalds ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); 53431da177e4SLinus Torvalds } 53441da177e4SLinus Torvalds 53451da177e4SLinus Torvalds dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n"); 53461da177e4SLinus Torvalds 53471da177e4SLinus Torvalds ioa_cfg->reset_retries = 0; 53481da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 53491da177e4SLinus Torvalds wake_up_all(&ioa_cfg->reset_wait_q); 53501da177e4SLinus Torvalds 53511da177e4SLinus Torvalds spin_unlock_irq(ioa_cfg->host->host_lock); 53521da177e4SLinus Torvalds scsi_unblock_requests(ioa_cfg->host); 53531da177e4SLinus Torvalds spin_lock_irq(ioa_cfg->host->host_lock); 53541da177e4SLinus Torvalds 53551da177e4SLinus Torvalds if (!ioa_cfg->allow_cmds) 53561da177e4SLinus Torvalds scsi_block_requests(ioa_cfg->host); 53571da177e4SLinus Torvalds 53581da177e4SLinus Torvalds LEAVE; 53591da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 53601da177e4SLinus Torvalds } 53611da177e4SLinus Torvalds 53621da177e4SLinus Torvalds /** 53631da177e4SLinus Torvalds * ipr_set_sup_dev_dflt - Initialize a Set Supported Device buffer 53641da177e4SLinus Torvalds * @supported_dev: supported device struct 53651da177e4SLinus Torvalds * @vpids: vendor product id struct 53661da177e4SLinus Torvalds * 53671da177e4SLinus Torvalds * Return value: 53681da177e4SLinus Torvalds * none 53691da177e4SLinus Torvalds **/ 53701da177e4SLinus Torvalds static void ipr_set_sup_dev_dflt(struct ipr_supported_device *supported_dev, 53711da177e4SLinus Torvalds struct ipr_std_inq_vpids *vpids) 53721da177e4SLinus Torvalds { 53731da177e4SLinus Torvalds memset(supported_dev, 0, sizeof(struct ipr_supported_device)); 53741da177e4SLinus Torvalds memcpy(&supported_dev->vpids, vpids, sizeof(struct ipr_std_inq_vpids)); 53751da177e4SLinus Torvalds supported_dev->num_records = 1; 53761da177e4SLinus Torvalds supported_dev->data_length = 53771da177e4SLinus Torvalds cpu_to_be16(sizeof(struct ipr_supported_device)); 53781da177e4SLinus Torvalds supported_dev->reserved = 0; 53791da177e4SLinus Torvalds } 53801da177e4SLinus Torvalds 53811da177e4SLinus Torvalds /** 53821da177e4SLinus Torvalds * ipr_set_supported_devs - Send Set Supported Devices for a device 53831da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 53841da177e4SLinus Torvalds * 53851da177e4SLinus Torvalds * This function send a Set Supported Devices to the adapter 53861da177e4SLinus Torvalds * 53871da177e4SLinus Torvalds * Return value: 53881da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 53891da177e4SLinus Torvalds **/ 53901da177e4SLinus Torvalds static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd) 53911da177e4SLinus Torvalds { 53921da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 53931da177e4SLinus Torvalds struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev; 53941da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 53951da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 53961da177e4SLinus Torvalds struct ipr_resource_entry *res = ipr_cmd->u.res; 53971da177e4SLinus Torvalds 53981da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioa_reset_done; 53991da177e4SLinus Torvalds 54001da177e4SLinus Torvalds list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { 5401e4fbf44eSBrian King if (!ipr_is_scsi_disk(res)) 54021da177e4SLinus Torvalds continue; 54031da177e4SLinus Torvalds 54041da177e4SLinus Torvalds ipr_cmd->u.res = res; 54051da177e4SLinus Torvalds ipr_set_sup_dev_dflt(supp_dev, &res->cfgte.std_inq_data.vpids); 54061da177e4SLinus Torvalds 54071da177e4SLinus Torvalds ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 54081da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 54091da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 54101da177e4SLinus Torvalds 54111da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = IPR_SET_SUPPORTED_DEVICES; 54121da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_supported_device) >> 8) & 0xff; 54131da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_supported_device) & 0xff; 54141da177e4SLinus Torvalds 54151da177e4SLinus Torvalds ioadl->flags_and_data_len = cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | 54161da177e4SLinus Torvalds sizeof(struct ipr_supported_device)); 54171da177e4SLinus Torvalds ioadl->address = cpu_to_be32(ioa_cfg->vpd_cbs_dma + 54181da177e4SLinus Torvalds offsetof(struct ipr_misc_cbs, supp_dev)); 54191da177e4SLinus Torvalds ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 54201da177e4SLinus Torvalds ioarcb->write_data_transfer_length = 54211da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_supported_device)); 54221da177e4SLinus Torvalds 54231da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, 54241da177e4SLinus Torvalds IPR_SET_SUP_DEVICE_TIMEOUT); 54251da177e4SLinus Torvalds 54261da177e4SLinus Torvalds ipr_cmd->job_step = ipr_set_supported_devs; 54271da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 54281da177e4SLinus Torvalds } 54291da177e4SLinus Torvalds 54301da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 54311da177e4SLinus Torvalds } 54321da177e4SLinus Torvalds 54331da177e4SLinus Torvalds /** 543462275040Sbrking@us.ibm.com * ipr_setup_write_cache - Disable write cache if needed 543562275040Sbrking@us.ibm.com * @ipr_cmd: ipr command struct 543662275040Sbrking@us.ibm.com * 543762275040Sbrking@us.ibm.com * This function sets up adapters write cache to desired setting 543862275040Sbrking@us.ibm.com * 543962275040Sbrking@us.ibm.com * Return value: 544062275040Sbrking@us.ibm.com * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 544162275040Sbrking@us.ibm.com **/ 544262275040Sbrking@us.ibm.com static int ipr_setup_write_cache(struct ipr_cmnd *ipr_cmd) 544362275040Sbrking@us.ibm.com { 544462275040Sbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 544562275040Sbrking@us.ibm.com 544662275040Sbrking@us.ibm.com ipr_cmd->job_step = ipr_set_supported_devs; 544762275040Sbrking@us.ibm.com ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next, 544862275040Sbrking@us.ibm.com struct ipr_resource_entry, queue); 544962275040Sbrking@us.ibm.com 545062275040Sbrking@us.ibm.com if (ioa_cfg->cache_state != CACHE_DISABLED) 545162275040Sbrking@us.ibm.com return IPR_RC_JOB_CONTINUE; 545262275040Sbrking@us.ibm.com 545362275040Sbrking@us.ibm.com ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 545462275040Sbrking@us.ibm.com ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 545562275040Sbrking@us.ibm.com ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; 545662275040Sbrking@us.ibm.com ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_SHUTDOWN_PREPARE_FOR_NORMAL; 545762275040Sbrking@us.ibm.com 545862275040Sbrking@us.ibm.com ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 545962275040Sbrking@us.ibm.com 546062275040Sbrking@us.ibm.com return IPR_RC_JOB_RETURN; 546162275040Sbrking@us.ibm.com } 546262275040Sbrking@us.ibm.com 546362275040Sbrking@us.ibm.com /** 54641da177e4SLinus Torvalds * ipr_get_mode_page - Locate specified mode page 54651da177e4SLinus Torvalds * @mode_pages: mode page buffer 54661da177e4SLinus Torvalds * @page_code: page code to find 54671da177e4SLinus Torvalds * @len: minimum required length for mode page 54681da177e4SLinus Torvalds * 54691da177e4SLinus Torvalds * Return value: 54701da177e4SLinus Torvalds * pointer to mode page / NULL on failure 54711da177e4SLinus Torvalds **/ 54721da177e4SLinus Torvalds static void *ipr_get_mode_page(struct ipr_mode_pages *mode_pages, 54731da177e4SLinus Torvalds u32 page_code, u32 len) 54741da177e4SLinus Torvalds { 54751da177e4SLinus Torvalds struct ipr_mode_page_hdr *mode_hdr; 54761da177e4SLinus Torvalds u32 page_length; 54771da177e4SLinus Torvalds u32 length; 54781da177e4SLinus Torvalds 54791da177e4SLinus Torvalds if (!mode_pages || (mode_pages->hdr.length == 0)) 54801da177e4SLinus Torvalds return NULL; 54811da177e4SLinus Torvalds 54821da177e4SLinus Torvalds length = (mode_pages->hdr.length + 1) - 4 - mode_pages->hdr.block_desc_len; 54831da177e4SLinus Torvalds mode_hdr = (struct ipr_mode_page_hdr *) 54841da177e4SLinus Torvalds (mode_pages->data + mode_pages->hdr.block_desc_len); 54851da177e4SLinus Torvalds 54861da177e4SLinus Torvalds while (length) { 54871da177e4SLinus Torvalds if (IPR_GET_MODE_PAGE_CODE(mode_hdr) == page_code) { 54881da177e4SLinus Torvalds if (mode_hdr->page_length >= (len - sizeof(struct ipr_mode_page_hdr))) 54891da177e4SLinus Torvalds return mode_hdr; 54901da177e4SLinus Torvalds break; 54911da177e4SLinus Torvalds } else { 54921da177e4SLinus Torvalds page_length = (sizeof(struct ipr_mode_page_hdr) + 54931da177e4SLinus Torvalds mode_hdr->page_length); 54941da177e4SLinus Torvalds length -= page_length; 54951da177e4SLinus Torvalds mode_hdr = (struct ipr_mode_page_hdr *) 54961da177e4SLinus Torvalds ((unsigned long)mode_hdr + page_length); 54971da177e4SLinus Torvalds } 54981da177e4SLinus Torvalds } 54991da177e4SLinus Torvalds return NULL; 55001da177e4SLinus Torvalds } 55011da177e4SLinus Torvalds 55021da177e4SLinus Torvalds /** 55031da177e4SLinus Torvalds * ipr_check_term_power - Check for term power errors 55041da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 55051da177e4SLinus Torvalds * @mode_pages: IOAFP mode pages buffer 55061da177e4SLinus Torvalds * 55071da177e4SLinus Torvalds * Check the IOAFP's mode page 28 for term power errors 55081da177e4SLinus Torvalds * 55091da177e4SLinus Torvalds * Return value: 55101da177e4SLinus Torvalds * nothing 55111da177e4SLinus Torvalds **/ 55121da177e4SLinus Torvalds static void ipr_check_term_power(struct ipr_ioa_cfg *ioa_cfg, 55131da177e4SLinus Torvalds struct ipr_mode_pages *mode_pages) 55141da177e4SLinus Torvalds { 55151da177e4SLinus Torvalds int i; 55161da177e4SLinus Torvalds int entry_length; 55171da177e4SLinus Torvalds struct ipr_dev_bus_entry *bus; 55181da177e4SLinus Torvalds struct ipr_mode_page28 *mode_page; 55191da177e4SLinus Torvalds 55201da177e4SLinus Torvalds mode_page = ipr_get_mode_page(mode_pages, 0x28, 55211da177e4SLinus Torvalds sizeof(struct ipr_mode_page28)); 55221da177e4SLinus Torvalds 55231da177e4SLinus Torvalds entry_length = mode_page->entry_length; 55241da177e4SLinus Torvalds 55251da177e4SLinus Torvalds bus = mode_page->bus; 55261da177e4SLinus Torvalds 55271da177e4SLinus Torvalds for (i = 0; i < mode_page->num_entries; i++) { 55281da177e4SLinus Torvalds if (bus->flags & IPR_SCSI_ATTR_NO_TERM_PWR) { 55291da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 55301da177e4SLinus Torvalds "Term power is absent on scsi bus %d\n", 55311da177e4SLinus Torvalds bus->res_addr.bus); 55321da177e4SLinus Torvalds } 55331da177e4SLinus Torvalds 55341da177e4SLinus Torvalds bus = (struct ipr_dev_bus_entry *)((char *)bus + entry_length); 55351da177e4SLinus Torvalds } 55361da177e4SLinus Torvalds } 55371da177e4SLinus Torvalds 55381da177e4SLinus Torvalds /** 55391da177e4SLinus Torvalds * ipr_scsi_bus_speed_limit - Limit the SCSI speed based on SES table 55401da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 55411da177e4SLinus Torvalds * 55421da177e4SLinus Torvalds * Looks through the config table checking for SES devices. If 55431da177e4SLinus Torvalds * the SES device is in the SES table indicating a maximum SCSI 55441da177e4SLinus Torvalds * bus speed, the speed is limited for the bus. 55451da177e4SLinus Torvalds * 55461da177e4SLinus Torvalds * Return value: 55471da177e4SLinus Torvalds * none 55481da177e4SLinus Torvalds **/ 55491da177e4SLinus Torvalds static void ipr_scsi_bus_speed_limit(struct ipr_ioa_cfg *ioa_cfg) 55501da177e4SLinus Torvalds { 55511da177e4SLinus Torvalds u32 max_xfer_rate; 55521da177e4SLinus Torvalds int i; 55531da177e4SLinus Torvalds 55541da177e4SLinus Torvalds for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { 55551da177e4SLinus Torvalds max_xfer_rate = ipr_get_max_scsi_speed(ioa_cfg, i, 55561da177e4SLinus Torvalds ioa_cfg->bus_attr[i].bus_width); 55571da177e4SLinus Torvalds 55581da177e4SLinus Torvalds if (max_xfer_rate < ioa_cfg->bus_attr[i].max_xfer_rate) 55591da177e4SLinus Torvalds ioa_cfg->bus_attr[i].max_xfer_rate = max_xfer_rate; 55601da177e4SLinus Torvalds } 55611da177e4SLinus Torvalds } 55621da177e4SLinus Torvalds 55631da177e4SLinus Torvalds /** 55641da177e4SLinus Torvalds * ipr_modify_ioafp_mode_page_28 - Modify IOAFP Mode Page 28 55651da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 55661da177e4SLinus Torvalds * @mode_pages: mode page 28 buffer 55671da177e4SLinus Torvalds * 55681da177e4SLinus Torvalds * Updates mode page 28 based on driver configuration 55691da177e4SLinus Torvalds * 55701da177e4SLinus Torvalds * Return value: 55711da177e4SLinus Torvalds * none 55721da177e4SLinus Torvalds **/ 55731da177e4SLinus Torvalds static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg, 55741da177e4SLinus Torvalds struct ipr_mode_pages *mode_pages) 55751da177e4SLinus Torvalds { 55761da177e4SLinus Torvalds int i, entry_length; 55771da177e4SLinus Torvalds struct ipr_dev_bus_entry *bus; 55781da177e4SLinus Torvalds struct ipr_bus_attributes *bus_attr; 55791da177e4SLinus Torvalds struct ipr_mode_page28 *mode_page; 55801da177e4SLinus Torvalds 55811da177e4SLinus Torvalds mode_page = ipr_get_mode_page(mode_pages, 0x28, 55821da177e4SLinus Torvalds sizeof(struct ipr_mode_page28)); 55831da177e4SLinus Torvalds 55841da177e4SLinus Torvalds entry_length = mode_page->entry_length; 55851da177e4SLinus Torvalds 55861da177e4SLinus Torvalds /* Loop for each device bus entry */ 55871da177e4SLinus Torvalds for (i = 0, bus = mode_page->bus; 55881da177e4SLinus Torvalds i < mode_page->num_entries; 55891da177e4SLinus Torvalds i++, bus = (struct ipr_dev_bus_entry *)((u8 *)bus + entry_length)) { 55901da177e4SLinus Torvalds if (bus->res_addr.bus > IPR_MAX_NUM_BUSES) { 55911da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 55921da177e4SLinus Torvalds "Invalid resource address reported: 0x%08X\n", 55931da177e4SLinus Torvalds IPR_GET_PHYS_LOC(bus->res_addr)); 55941da177e4SLinus Torvalds continue; 55951da177e4SLinus Torvalds } 55961da177e4SLinus Torvalds 55971da177e4SLinus Torvalds bus_attr = &ioa_cfg->bus_attr[i]; 55981da177e4SLinus Torvalds bus->extended_reset_delay = IPR_EXTENDED_RESET_DELAY; 55991da177e4SLinus Torvalds bus->bus_width = bus_attr->bus_width; 56001da177e4SLinus Torvalds bus->max_xfer_rate = cpu_to_be32(bus_attr->max_xfer_rate); 56011da177e4SLinus Torvalds bus->flags &= ~IPR_SCSI_ATTR_QAS_MASK; 56021da177e4SLinus Torvalds if (bus_attr->qas_enabled) 56031da177e4SLinus Torvalds bus->flags |= IPR_SCSI_ATTR_ENABLE_QAS; 56041da177e4SLinus Torvalds else 56051da177e4SLinus Torvalds bus->flags |= IPR_SCSI_ATTR_DISABLE_QAS; 56061da177e4SLinus Torvalds } 56071da177e4SLinus Torvalds } 56081da177e4SLinus Torvalds 56091da177e4SLinus Torvalds /** 56101da177e4SLinus Torvalds * ipr_build_mode_select - Build a mode select command 56111da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 56121da177e4SLinus Torvalds * @res_handle: resource handle to send command to 56131da177e4SLinus Torvalds * @parm: Byte 2 of Mode Sense command 56141da177e4SLinus Torvalds * @dma_addr: DMA buffer address 56151da177e4SLinus Torvalds * @xfer_len: data transfer length 56161da177e4SLinus Torvalds * 56171da177e4SLinus Torvalds * Return value: 56181da177e4SLinus Torvalds * none 56191da177e4SLinus Torvalds **/ 56201da177e4SLinus Torvalds static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd, 56211da177e4SLinus Torvalds __be32 res_handle, u8 parm, u32 dma_addr, 56221da177e4SLinus Torvalds u8 xfer_len) 56231da177e4SLinus Torvalds { 56241da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 56251da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 56261da177e4SLinus Torvalds 56271da177e4SLinus Torvalds ioarcb->res_handle = res_handle; 56281da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; 56291da177e4SLinus Torvalds ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; 56301da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = MODE_SELECT; 56311da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[1] = parm; 56321da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[4] = xfer_len; 56331da177e4SLinus Torvalds 56341da177e4SLinus Torvalds ioadl->flags_and_data_len = 56351da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | xfer_len); 56361da177e4SLinus Torvalds ioadl->address = cpu_to_be32(dma_addr); 56371da177e4SLinus Torvalds ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 56381da177e4SLinus Torvalds ioarcb->write_data_transfer_length = cpu_to_be32(xfer_len); 56391da177e4SLinus Torvalds } 56401da177e4SLinus Torvalds 56411da177e4SLinus Torvalds /** 56421da177e4SLinus Torvalds * ipr_ioafp_mode_select_page28 - Issue Mode Select Page 28 to IOA 56431da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 56441da177e4SLinus Torvalds * 56451da177e4SLinus Torvalds * This function sets up the SCSI bus attributes and sends 56461da177e4SLinus Torvalds * a Mode Select for Page 28 to activate them. 56471da177e4SLinus Torvalds * 56481da177e4SLinus Torvalds * Return value: 56491da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 56501da177e4SLinus Torvalds **/ 56511da177e4SLinus Torvalds static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd) 56521da177e4SLinus Torvalds { 56531da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 56541da177e4SLinus Torvalds struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; 56551da177e4SLinus Torvalds int length; 56561da177e4SLinus Torvalds 56571da177e4SLinus Torvalds ENTER; 56581da177e4SLinus Torvalds ipr_scsi_bus_speed_limit(ioa_cfg); 56591da177e4SLinus Torvalds ipr_check_term_power(ioa_cfg, mode_pages); 56601da177e4SLinus Torvalds ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages); 56611da177e4SLinus Torvalds length = mode_pages->hdr.length + 1; 56621da177e4SLinus Torvalds mode_pages->hdr.length = 0; 56631da177e4SLinus Torvalds 56641da177e4SLinus Torvalds ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, 56651da177e4SLinus Torvalds ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), 56661da177e4SLinus Torvalds length); 56671da177e4SLinus Torvalds 566862275040Sbrking@us.ibm.com ipr_cmd->job_step = ipr_setup_write_cache; 56691da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 56701da177e4SLinus Torvalds 56711da177e4SLinus Torvalds LEAVE; 56721da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 56731da177e4SLinus Torvalds } 56741da177e4SLinus Torvalds 56751da177e4SLinus Torvalds /** 56761da177e4SLinus Torvalds * ipr_build_mode_sense - Builds a mode sense command 56771da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 56781da177e4SLinus Torvalds * @res: resource entry struct 56791da177e4SLinus Torvalds * @parm: Byte 2 of mode sense command 56801da177e4SLinus Torvalds * @dma_addr: DMA address of mode sense buffer 56811da177e4SLinus Torvalds * @xfer_len: Size of DMA buffer 56821da177e4SLinus Torvalds * 56831da177e4SLinus Torvalds * Return value: 56841da177e4SLinus Torvalds * none 56851da177e4SLinus Torvalds **/ 56861da177e4SLinus Torvalds static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd, 56871da177e4SLinus Torvalds __be32 res_handle, 56881da177e4SLinus Torvalds u8 parm, u32 dma_addr, u8 xfer_len) 56891da177e4SLinus Torvalds { 56901da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 56911da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 56921da177e4SLinus Torvalds 56931da177e4SLinus Torvalds ioarcb->res_handle = res_handle; 56941da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = MODE_SENSE; 56951da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[2] = parm; 56961da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[4] = xfer_len; 56971da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; 56981da177e4SLinus Torvalds 56991da177e4SLinus Torvalds ioadl->flags_and_data_len = 57001da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len); 57011da177e4SLinus Torvalds ioadl->address = cpu_to_be32(dma_addr); 57021da177e4SLinus Torvalds ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 57031da177e4SLinus Torvalds ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len); 57041da177e4SLinus Torvalds } 57051da177e4SLinus Torvalds 57061da177e4SLinus Torvalds /** 5707dfed823eSbrking@us.ibm.com * ipr_reset_cmd_failed - Handle failure of IOA reset command 5708dfed823eSbrking@us.ibm.com * @ipr_cmd: ipr command struct 5709dfed823eSbrking@us.ibm.com * 5710dfed823eSbrking@us.ibm.com * This function handles the failure of an IOA bringup command. 5711dfed823eSbrking@us.ibm.com * 5712dfed823eSbrking@us.ibm.com * Return value: 5713dfed823eSbrking@us.ibm.com * IPR_RC_JOB_RETURN 5714dfed823eSbrking@us.ibm.com **/ 5715dfed823eSbrking@us.ibm.com static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd) 5716dfed823eSbrking@us.ibm.com { 5717dfed823eSbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 5718dfed823eSbrking@us.ibm.com u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 5719dfed823eSbrking@us.ibm.com 5720dfed823eSbrking@us.ibm.com dev_err(&ioa_cfg->pdev->dev, 5721dfed823eSbrking@us.ibm.com "0x%02X failed with IOASC: 0x%08X\n", 5722dfed823eSbrking@us.ibm.com ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc); 5723dfed823eSbrking@us.ibm.com 5724dfed823eSbrking@us.ibm.com ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 5725dfed823eSbrking@us.ibm.com list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 5726dfed823eSbrking@us.ibm.com return IPR_RC_JOB_RETURN; 5727dfed823eSbrking@us.ibm.com } 5728dfed823eSbrking@us.ibm.com 5729dfed823eSbrking@us.ibm.com /** 5730dfed823eSbrking@us.ibm.com * ipr_reset_mode_sense_failed - Handle failure of IOAFP mode sense 5731dfed823eSbrking@us.ibm.com * @ipr_cmd: ipr command struct 5732dfed823eSbrking@us.ibm.com * 5733dfed823eSbrking@us.ibm.com * This function handles the failure of a Mode Sense to the IOAFP. 5734dfed823eSbrking@us.ibm.com * Some adapters do not handle all mode pages. 5735dfed823eSbrking@us.ibm.com * 5736dfed823eSbrking@us.ibm.com * Return value: 5737dfed823eSbrking@us.ibm.com * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 5738dfed823eSbrking@us.ibm.com **/ 5739dfed823eSbrking@us.ibm.com static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd) 5740dfed823eSbrking@us.ibm.com { 5741dfed823eSbrking@us.ibm.com u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 5742dfed823eSbrking@us.ibm.com 5743dfed823eSbrking@us.ibm.com if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { 5744dfed823eSbrking@us.ibm.com ipr_cmd->job_step = ipr_setup_write_cache; 5745dfed823eSbrking@us.ibm.com return IPR_RC_JOB_CONTINUE; 5746dfed823eSbrking@us.ibm.com } 5747dfed823eSbrking@us.ibm.com 5748dfed823eSbrking@us.ibm.com return ipr_reset_cmd_failed(ipr_cmd); 5749dfed823eSbrking@us.ibm.com } 5750dfed823eSbrking@us.ibm.com 5751dfed823eSbrking@us.ibm.com /** 57521da177e4SLinus Torvalds * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA 57531da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 57541da177e4SLinus Torvalds * 57551da177e4SLinus Torvalds * This function send a Page 28 mode sense to the IOA to 57561da177e4SLinus Torvalds * retrieve SCSI bus attributes. 57571da177e4SLinus Torvalds * 57581da177e4SLinus Torvalds * Return value: 57591da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 57601da177e4SLinus Torvalds **/ 57611da177e4SLinus Torvalds static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd) 57621da177e4SLinus Torvalds { 57631da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 57641da177e4SLinus Torvalds 57651da177e4SLinus Torvalds ENTER; 57661da177e4SLinus Torvalds ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 57671da177e4SLinus Torvalds 0x28, ioa_cfg->vpd_cbs_dma + 57681da177e4SLinus Torvalds offsetof(struct ipr_misc_cbs, mode_pages), 57691da177e4SLinus Torvalds sizeof(struct ipr_mode_pages)); 57701da177e4SLinus Torvalds 57711da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioafp_mode_select_page28; 5772dfed823eSbrking@us.ibm.com ipr_cmd->job_step_failed = ipr_reset_mode_sense_failed; 57731da177e4SLinus Torvalds 57741da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 57751da177e4SLinus Torvalds 57761da177e4SLinus Torvalds LEAVE; 57771da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 57781da177e4SLinus Torvalds } 57791da177e4SLinus Torvalds 57801da177e4SLinus Torvalds /** 57811da177e4SLinus Torvalds * ipr_init_res_table - Initialize the resource table 57821da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 57831da177e4SLinus Torvalds * 57841da177e4SLinus Torvalds * This function looks through the existing resource table, comparing 57851da177e4SLinus Torvalds * it with the config table. This function will take care of old/new 57861da177e4SLinus Torvalds * devices and schedule adding/removing them from the mid-layer 57871da177e4SLinus Torvalds * as appropriate. 57881da177e4SLinus Torvalds * 57891da177e4SLinus Torvalds * Return value: 57901da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE 57911da177e4SLinus Torvalds **/ 57921da177e4SLinus Torvalds static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) 57931da177e4SLinus Torvalds { 57941da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 57951da177e4SLinus Torvalds struct ipr_resource_entry *res, *temp; 57961da177e4SLinus Torvalds struct ipr_config_table_entry *cfgte; 57971da177e4SLinus Torvalds int found, i; 57981da177e4SLinus Torvalds LIST_HEAD(old_res); 57991da177e4SLinus Torvalds 58001da177e4SLinus Torvalds ENTER; 58011da177e4SLinus Torvalds if (ioa_cfg->cfg_table->hdr.flags & IPR_UCODE_DOWNLOAD_REQ) 58021da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Microcode download required\n"); 58031da177e4SLinus Torvalds 58041da177e4SLinus Torvalds list_for_each_entry_safe(res, temp, &ioa_cfg->used_res_q, queue) 58051da177e4SLinus Torvalds list_move_tail(&res->queue, &old_res); 58061da177e4SLinus Torvalds 58071da177e4SLinus Torvalds for (i = 0; i < ioa_cfg->cfg_table->hdr.num_entries; i++) { 58081da177e4SLinus Torvalds cfgte = &ioa_cfg->cfg_table->dev[i]; 58091da177e4SLinus Torvalds found = 0; 58101da177e4SLinus Torvalds 58111da177e4SLinus Torvalds list_for_each_entry_safe(res, temp, &old_res, queue) { 58121da177e4SLinus Torvalds if (!memcmp(&res->cfgte.res_addr, 58131da177e4SLinus Torvalds &cfgte->res_addr, sizeof(cfgte->res_addr))) { 58141da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->used_res_q); 58151da177e4SLinus Torvalds found = 1; 58161da177e4SLinus Torvalds break; 58171da177e4SLinus Torvalds } 58181da177e4SLinus Torvalds } 58191da177e4SLinus Torvalds 58201da177e4SLinus Torvalds if (!found) { 58211da177e4SLinus Torvalds if (list_empty(&ioa_cfg->free_res_q)) { 58221da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "Too many devices attached\n"); 58231da177e4SLinus Torvalds break; 58241da177e4SLinus Torvalds } 58251da177e4SLinus Torvalds 58261da177e4SLinus Torvalds found = 1; 58271da177e4SLinus Torvalds res = list_entry(ioa_cfg->free_res_q.next, 58281da177e4SLinus Torvalds struct ipr_resource_entry, queue); 58291da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->used_res_q); 58301da177e4SLinus Torvalds ipr_init_res_entry(res); 58311da177e4SLinus Torvalds res->add_to_ml = 1; 58321da177e4SLinus Torvalds } 58331da177e4SLinus Torvalds 58341da177e4SLinus Torvalds if (found) 58351da177e4SLinus Torvalds memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry)); 58361da177e4SLinus Torvalds } 58371da177e4SLinus Torvalds 58381da177e4SLinus Torvalds list_for_each_entry_safe(res, temp, &old_res, queue) { 58391da177e4SLinus Torvalds if (res->sdev) { 58401da177e4SLinus Torvalds res->del_from_ml = 1; 58411121b794SBrian King res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; 58421da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->used_res_q); 58431da177e4SLinus Torvalds } else { 58441da177e4SLinus Torvalds list_move_tail(&res->queue, &ioa_cfg->free_res_q); 58451da177e4SLinus Torvalds } 58461da177e4SLinus Torvalds } 58471da177e4SLinus Torvalds 58481da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; 58491da177e4SLinus Torvalds 58501da177e4SLinus Torvalds LEAVE; 58511da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 58521da177e4SLinus Torvalds } 58531da177e4SLinus Torvalds 58541da177e4SLinus Torvalds /** 58551da177e4SLinus Torvalds * ipr_ioafp_query_ioa_cfg - Send a Query IOA Config to the adapter. 58561da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 58571da177e4SLinus Torvalds * 58581da177e4SLinus Torvalds * This function sends a Query IOA Configuration command 58591da177e4SLinus Torvalds * to the adapter to retrieve the IOA configuration table. 58601da177e4SLinus Torvalds * 58611da177e4SLinus Torvalds * Return value: 58621da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 58631da177e4SLinus Torvalds **/ 58641da177e4SLinus Torvalds static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) 58651da177e4SLinus Torvalds { 58661da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 58671da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 58681da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 58691da177e4SLinus Torvalds struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; 58701da177e4SLinus Torvalds 58711da177e4SLinus Torvalds ENTER; 58721da177e4SLinus Torvalds dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n", 58731da177e4SLinus Torvalds ucode_vpd->major_release, ucode_vpd->card_type, 58741da177e4SLinus Torvalds ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]); 58751da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 58761da177e4SLinus Torvalds ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 58771da177e4SLinus Torvalds 58781da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG; 58791da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_config_table) >> 8) & 0xff; 58801da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_config_table) & 0xff; 58811da177e4SLinus Torvalds 58821da177e4SLinus Torvalds ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 58831da177e4SLinus Torvalds ioarcb->read_data_transfer_length = 58841da177e4SLinus Torvalds cpu_to_be32(sizeof(struct ipr_config_table)); 58851da177e4SLinus Torvalds 58861da177e4SLinus Torvalds ioadl->address = cpu_to_be32(ioa_cfg->cfg_table_dma); 58871da177e4SLinus Torvalds ioadl->flags_and_data_len = 58881da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(struct ipr_config_table)); 58891da177e4SLinus Torvalds 58901da177e4SLinus Torvalds ipr_cmd->job_step = ipr_init_res_table; 58911da177e4SLinus Torvalds 58921da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 58931da177e4SLinus Torvalds 58941da177e4SLinus Torvalds LEAVE; 58951da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 58961da177e4SLinus Torvalds } 58971da177e4SLinus Torvalds 58981da177e4SLinus Torvalds /** 58991da177e4SLinus Torvalds * ipr_ioafp_inquiry - Send an Inquiry to the adapter. 59001da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 59011da177e4SLinus Torvalds * 59021da177e4SLinus Torvalds * This utility function sends an inquiry to the adapter. 59031da177e4SLinus Torvalds * 59041da177e4SLinus Torvalds * Return value: 59051da177e4SLinus Torvalds * none 59061da177e4SLinus Torvalds **/ 59071da177e4SLinus Torvalds static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page, 59081da177e4SLinus Torvalds u32 dma_addr, u8 xfer_len) 59091da177e4SLinus Torvalds { 59101da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 59111da177e4SLinus Torvalds struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; 59121da177e4SLinus Torvalds 59131da177e4SLinus Torvalds ENTER; 59141da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; 59151da177e4SLinus Torvalds ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 59161da177e4SLinus Torvalds 59171da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = INQUIRY; 59181da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[1] = flags; 59191da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[2] = page; 59201da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[4] = xfer_len; 59211da177e4SLinus Torvalds 59221da177e4SLinus Torvalds ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); 59231da177e4SLinus Torvalds ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len); 59241da177e4SLinus Torvalds 59251da177e4SLinus Torvalds ioadl->address = cpu_to_be32(dma_addr); 59261da177e4SLinus Torvalds ioadl->flags_and_data_len = 59271da177e4SLinus Torvalds cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len); 59281da177e4SLinus Torvalds 59291da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 59301da177e4SLinus Torvalds LEAVE; 59311da177e4SLinus Torvalds } 59321da177e4SLinus Torvalds 59331da177e4SLinus Torvalds /** 593462275040Sbrking@us.ibm.com * ipr_inquiry_page_supported - Is the given inquiry page supported 593562275040Sbrking@us.ibm.com * @page0: inquiry page 0 buffer 593662275040Sbrking@us.ibm.com * @page: page code. 593762275040Sbrking@us.ibm.com * 593862275040Sbrking@us.ibm.com * This function determines if the specified inquiry page is supported. 593962275040Sbrking@us.ibm.com * 594062275040Sbrking@us.ibm.com * Return value: 594162275040Sbrking@us.ibm.com * 1 if page is supported / 0 if not 594262275040Sbrking@us.ibm.com **/ 594362275040Sbrking@us.ibm.com static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) 594462275040Sbrking@us.ibm.com { 594562275040Sbrking@us.ibm.com int i; 594662275040Sbrking@us.ibm.com 594762275040Sbrking@us.ibm.com for (i = 0; i < min_t(u8, page0->len, IPR_INQUIRY_PAGE0_ENTRIES); i++) 594862275040Sbrking@us.ibm.com if (page0->page[i] == page) 594962275040Sbrking@us.ibm.com return 1; 595062275040Sbrking@us.ibm.com 595162275040Sbrking@us.ibm.com return 0; 595262275040Sbrking@us.ibm.com } 595362275040Sbrking@us.ibm.com 595462275040Sbrking@us.ibm.com /** 59551da177e4SLinus Torvalds * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter. 59561da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 59571da177e4SLinus Torvalds * 59581da177e4SLinus Torvalds * This function sends a Page 3 inquiry to the adapter 59591da177e4SLinus Torvalds * to retrieve software VPD information. 59601da177e4SLinus Torvalds * 59611da177e4SLinus Torvalds * Return value: 59621da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 59631da177e4SLinus Torvalds **/ 59641da177e4SLinus Torvalds static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd) 59651da177e4SLinus Torvalds { 59661da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 596762275040Sbrking@us.ibm.com struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; 596862275040Sbrking@us.ibm.com 596962275040Sbrking@us.ibm.com ENTER; 597062275040Sbrking@us.ibm.com 597162275040Sbrking@us.ibm.com if (!ipr_inquiry_page_supported(page0, 1)) 597262275040Sbrking@us.ibm.com ioa_cfg->cache_state = CACHE_NONE; 597362275040Sbrking@us.ibm.com 597462275040Sbrking@us.ibm.com ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; 597562275040Sbrking@us.ibm.com 597662275040Sbrking@us.ibm.com ipr_ioafp_inquiry(ipr_cmd, 1, 3, 597762275040Sbrking@us.ibm.com ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data), 597862275040Sbrking@us.ibm.com sizeof(struct ipr_inquiry_page3)); 597962275040Sbrking@us.ibm.com 598062275040Sbrking@us.ibm.com LEAVE; 598162275040Sbrking@us.ibm.com return IPR_RC_JOB_RETURN; 598262275040Sbrking@us.ibm.com } 598362275040Sbrking@us.ibm.com 598462275040Sbrking@us.ibm.com /** 598562275040Sbrking@us.ibm.com * ipr_ioafp_page0_inquiry - Send a Page 0 Inquiry to the adapter. 598662275040Sbrking@us.ibm.com * @ipr_cmd: ipr command struct 598762275040Sbrking@us.ibm.com * 598862275040Sbrking@us.ibm.com * This function sends a Page 0 inquiry to the adapter 598962275040Sbrking@us.ibm.com * to retrieve supported inquiry pages. 599062275040Sbrking@us.ibm.com * 599162275040Sbrking@us.ibm.com * Return value: 599262275040Sbrking@us.ibm.com * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 599362275040Sbrking@us.ibm.com **/ 599462275040Sbrking@us.ibm.com static int ipr_ioafp_page0_inquiry(struct ipr_cmnd *ipr_cmd) 599562275040Sbrking@us.ibm.com { 599662275040Sbrking@us.ibm.com struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 59971da177e4SLinus Torvalds char type[5]; 59981da177e4SLinus Torvalds 59991da177e4SLinus Torvalds ENTER; 60001da177e4SLinus Torvalds 60011da177e4SLinus Torvalds /* Grab the type out of the VPD and store it away */ 60021da177e4SLinus Torvalds memcpy(type, ioa_cfg->vpd_cbs->ioa_vpd.std_inq_data.vpids.product_id, 4); 60031da177e4SLinus Torvalds type[4] = '\0'; 60041da177e4SLinus Torvalds ioa_cfg->type = simple_strtoul((char *)type, NULL, 16); 60051da177e4SLinus Torvalds 600662275040Sbrking@us.ibm.com ipr_cmd->job_step = ipr_ioafp_page3_inquiry; 60071da177e4SLinus Torvalds 600862275040Sbrking@us.ibm.com ipr_ioafp_inquiry(ipr_cmd, 1, 0, 600962275040Sbrking@us.ibm.com ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page0_data), 601062275040Sbrking@us.ibm.com sizeof(struct ipr_inquiry_page0)); 60111da177e4SLinus Torvalds 60121da177e4SLinus Torvalds LEAVE; 60131da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 60141da177e4SLinus Torvalds } 60151da177e4SLinus Torvalds 60161da177e4SLinus Torvalds /** 60171da177e4SLinus Torvalds * ipr_ioafp_std_inquiry - Send a Standard Inquiry to the adapter. 60181da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 60191da177e4SLinus Torvalds * 60201da177e4SLinus Torvalds * This function sends a standard inquiry to the adapter. 60211da177e4SLinus Torvalds * 60221da177e4SLinus Torvalds * Return value: 60231da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 60241da177e4SLinus Torvalds **/ 60251da177e4SLinus Torvalds static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd) 60261da177e4SLinus Torvalds { 60271da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 60281da177e4SLinus Torvalds 60291da177e4SLinus Torvalds ENTER; 603062275040Sbrking@us.ibm.com ipr_cmd->job_step = ipr_ioafp_page0_inquiry; 60311da177e4SLinus Torvalds 60321da177e4SLinus Torvalds ipr_ioafp_inquiry(ipr_cmd, 0, 0, 60331da177e4SLinus Torvalds ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, ioa_vpd), 60341da177e4SLinus Torvalds sizeof(struct ipr_ioa_vpd)); 60351da177e4SLinus Torvalds 60361da177e4SLinus Torvalds LEAVE; 60371da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 60381da177e4SLinus Torvalds } 60391da177e4SLinus Torvalds 60401da177e4SLinus Torvalds /** 60411da177e4SLinus Torvalds * ipr_ioafp_indentify_hrrq - Send Identify Host RRQ. 60421da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 60431da177e4SLinus Torvalds * 60441da177e4SLinus Torvalds * This function send an Identify Host Request Response Queue 60451da177e4SLinus Torvalds * command to establish the HRRQ with the adapter. 60461da177e4SLinus Torvalds * 60471da177e4SLinus Torvalds * Return value: 60481da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 60491da177e4SLinus Torvalds **/ 60501da177e4SLinus Torvalds static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd) 60511da177e4SLinus Torvalds { 60521da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 60531da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; 60541da177e4SLinus Torvalds 60551da177e4SLinus Torvalds ENTER; 60561da177e4SLinus Torvalds dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n"); 60571da177e4SLinus Torvalds 60581da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[0] = IPR_ID_HOST_RR_Q; 60591da177e4SLinus Torvalds ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 60601da177e4SLinus Torvalds 60611da177e4SLinus Torvalds ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 60621da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[2] = 60631da177e4SLinus Torvalds ((u32) ioa_cfg->host_rrq_dma >> 24) & 0xff; 60641da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[3] = 60651da177e4SLinus Torvalds ((u32) ioa_cfg->host_rrq_dma >> 16) & 0xff; 60661da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[4] = 60671da177e4SLinus Torvalds ((u32) ioa_cfg->host_rrq_dma >> 8) & 0xff; 60681da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[5] = 60691da177e4SLinus Torvalds ((u32) ioa_cfg->host_rrq_dma) & 0xff; 60701da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[7] = 60711da177e4SLinus Torvalds ((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff; 60721da177e4SLinus Torvalds ioarcb->cmd_pkt.cdb[8] = 60731da177e4SLinus Torvalds (sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff; 60741da177e4SLinus Torvalds 60751da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioafp_std_inquiry; 60761da177e4SLinus Torvalds 60771da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); 60781da177e4SLinus Torvalds 60791da177e4SLinus Torvalds LEAVE; 60801da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 60811da177e4SLinus Torvalds } 60821da177e4SLinus Torvalds 60831da177e4SLinus Torvalds /** 60841da177e4SLinus Torvalds * ipr_reset_timer_done - Adapter reset timer function 60851da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 60861da177e4SLinus Torvalds * 60871da177e4SLinus Torvalds * Description: This function is used in adapter reset processing 60881da177e4SLinus Torvalds * for timing events. If the reset_cmd pointer in the IOA 60891da177e4SLinus Torvalds * config struct is not this adapter's we are doing nested 60901da177e4SLinus Torvalds * resets and fail_all_ops will take care of freeing the 60911da177e4SLinus Torvalds * command block. 60921da177e4SLinus Torvalds * 60931da177e4SLinus Torvalds * Return value: 60941da177e4SLinus Torvalds * none 60951da177e4SLinus Torvalds **/ 60961da177e4SLinus Torvalds static void ipr_reset_timer_done(struct ipr_cmnd *ipr_cmd) 60971da177e4SLinus Torvalds { 60981da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 60991da177e4SLinus Torvalds unsigned long lock_flags = 0; 61001da177e4SLinus Torvalds 61011da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 61021da177e4SLinus Torvalds 61031da177e4SLinus Torvalds if (ioa_cfg->reset_cmd == ipr_cmd) { 61041da177e4SLinus Torvalds list_del(&ipr_cmd->queue); 61051da177e4SLinus Torvalds ipr_cmd->done(ipr_cmd); 61061da177e4SLinus Torvalds } 61071da177e4SLinus Torvalds 61081da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 61091da177e4SLinus Torvalds } 61101da177e4SLinus Torvalds 61111da177e4SLinus Torvalds /** 61121da177e4SLinus Torvalds * ipr_reset_start_timer - Start a timer for adapter reset job 61131da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 61141da177e4SLinus Torvalds * @timeout: timeout value 61151da177e4SLinus Torvalds * 61161da177e4SLinus Torvalds * Description: This function is used in adapter reset processing 61171da177e4SLinus Torvalds * for timing events. If the reset_cmd pointer in the IOA 61181da177e4SLinus Torvalds * config struct is not this adapter's we are doing nested 61191da177e4SLinus Torvalds * resets and fail_all_ops will take care of freeing the 61201da177e4SLinus Torvalds * command block. 61211da177e4SLinus Torvalds * 61221da177e4SLinus Torvalds * Return value: 61231da177e4SLinus Torvalds * none 61241da177e4SLinus Torvalds **/ 61251da177e4SLinus Torvalds static void ipr_reset_start_timer(struct ipr_cmnd *ipr_cmd, 61261da177e4SLinus Torvalds unsigned long timeout) 61271da177e4SLinus Torvalds { 61281da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); 61291da177e4SLinus Torvalds ipr_cmd->done = ipr_reset_ioa_job; 61301da177e4SLinus Torvalds 61311da177e4SLinus Torvalds ipr_cmd->timer.data = (unsigned long) ipr_cmd; 61321da177e4SLinus Torvalds ipr_cmd->timer.expires = jiffies + timeout; 61331da177e4SLinus Torvalds ipr_cmd->timer.function = (void (*)(unsigned long))ipr_reset_timer_done; 61341da177e4SLinus Torvalds add_timer(&ipr_cmd->timer); 61351da177e4SLinus Torvalds } 61361da177e4SLinus Torvalds 61371da177e4SLinus Torvalds /** 61381da177e4SLinus Torvalds * ipr_init_ioa_mem - Initialize ioa_cfg control block 61391da177e4SLinus Torvalds * @ioa_cfg: ioa cfg struct 61401da177e4SLinus Torvalds * 61411da177e4SLinus Torvalds * Return value: 61421da177e4SLinus Torvalds * nothing 61431da177e4SLinus Torvalds **/ 61441da177e4SLinus Torvalds static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg) 61451da177e4SLinus Torvalds { 61461da177e4SLinus Torvalds memset(ioa_cfg->host_rrq, 0, sizeof(u32) * IPR_NUM_CMD_BLKS); 61471da177e4SLinus Torvalds 61481da177e4SLinus Torvalds /* Initialize Host RRQ pointers */ 61491da177e4SLinus Torvalds ioa_cfg->hrrq_start = ioa_cfg->host_rrq; 61501da177e4SLinus Torvalds ioa_cfg->hrrq_end = &ioa_cfg->host_rrq[IPR_NUM_CMD_BLKS - 1]; 61511da177e4SLinus Torvalds ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; 61521da177e4SLinus Torvalds ioa_cfg->toggle_bit = 1; 61531da177e4SLinus Torvalds 61541da177e4SLinus Torvalds /* Zero out config table */ 61551da177e4SLinus Torvalds memset(ioa_cfg->cfg_table, 0, sizeof(struct ipr_config_table)); 61561da177e4SLinus Torvalds } 61571da177e4SLinus Torvalds 61581da177e4SLinus Torvalds /** 61591da177e4SLinus Torvalds * ipr_reset_enable_ioa - Enable the IOA following a reset. 61601da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 61611da177e4SLinus Torvalds * 61621da177e4SLinus Torvalds * This function reinitializes some control blocks and 61631da177e4SLinus Torvalds * enables destructive diagnostics on the adapter. 61641da177e4SLinus Torvalds * 61651da177e4SLinus Torvalds * Return value: 61661da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 61671da177e4SLinus Torvalds **/ 61681da177e4SLinus Torvalds static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) 61691da177e4SLinus Torvalds { 61701da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 61711da177e4SLinus Torvalds volatile u32 int_reg; 61721da177e4SLinus Torvalds 61731da177e4SLinus Torvalds ENTER; 61741da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioafp_indentify_hrrq; 61751da177e4SLinus Torvalds ipr_init_ioa_mem(ioa_cfg); 61761da177e4SLinus Torvalds 61771da177e4SLinus Torvalds ioa_cfg->allow_interrupts = 1; 61781da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 61791da177e4SLinus Torvalds 61801da177e4SLinus Torvalds if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { 61811da177e4SLinus Torvalds writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED), 61821da177e4SLinus Torvalds ioa_cfg->regs.clr_interrupt_mask_reg); 61831da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); 61841da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 61851da177e4SLinus Torvalds } 61861da177e4SLinus Torvalds 61871da177e4SLinus Torvalds /* Enable destructive diagnostics on IOA */ 61883d1d0da6Sbrking@us.ibm.com writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg); 61891da177e4SLinus Torvalds 61901da177e4SLinus Torvalds writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg); 61911da177e4SLinus Torvalds int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); 61921da177e4SLinus Torvalds 61931da177e4SLinus Torvalds dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n"); 61941da177e4SLinus Torvalds 61951da177e4SLinus Torvalds ipr_cmd->timer.data = (unsigned long) ipr_cmd; 61961da177e4SLinus Torvalds ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ); 61971da177e4SLinus Torvalds ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout; 61981da177e4SLinus Torvalds ipr_cmd->done = ipr_reset_ioa_job; 61991da177e4SLinus Torvalds add_timer(&ipr_cmd->timer); 62001da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); 62011da177e4SLinus Torvalds 62021da177e4SLinus Torvalds LEAVE; 62031da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 62041da177e4SLinus Torvalds } 62051da177e4SLinus Torvalds 62061da177e4SLinus Torvalds /** 62071da177e4SLinus Torvalds * ipr_reset_wait_for_dump - Wait for a dump to timeout. 62081da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 62091da177e4SLinus Torvalds * 62101da177e4SLinus Torvalds * This function is invoked when an adapter dump has run out 62111da177e4SLinus Torvalds * of processing time. 62121da177e4SLinus Torvalds * 62131da177e4SLinus Torvalds * Return value: 62141da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE 62151da177e4SLinus Torvalds **/ 62161da177e4SLinus Torvalds static int ipr_reset_wait_for_dump(struct ipr_cmnd *ipr_cmd) 62171da177e4SLinus Torvalds { 62181da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 62191da177e4SLinus Torvalds 62201da177e4SLinus Torvalds if (ioa_cfg->sdt_state == GET_DUMP) 62211da177e4SLinus Torvalds ioa_cfg->sdt_state = ABORT_DUMP; 62221da177e4SLinus Torvalds 62231da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_alert; 62241da177e4SLinus Torvalds 62251da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 62261da177e4SLinus Torvalds } 62271da177e4SLinus Torvalds 62281da177e4SLinus Torvalds /** 62291da177e4SLinus Torvalds * ipr_unit_check_no_data - Log a unit check/no data error log 62301da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 62311da177e4SLinus Torvalds * 62321da177e4SLinus Torvalds * Logs an error indicating the adapter unit checked, but for some 62331da177e4SLinus Torvalds * reason, we were unable to fetch the unit check buffer. 62341da177e4SLinus Torvalds * 62351da177e4SLinus Torvalds * Return value: 62361da177e4SLinus Torvalds * nothing 62371da177e4SLinus Torvalds **/ 62381da177e4SLinus Torvalds static void ipr_unit_check_no_data(struct ipr_ioa_cfg *ioa_cfg) 62391da177e4SLinus Torvalds { 62401da177e4SLinus Torvalds ioa_cfg->errors_logged++; 62411da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, "IOA unit check with no data\n"); 62421da177e4SLinus Torvalds } 62431da177e4SLinus Torvalds 62441da177e4SLinus Torvalds /** 62451da177e4SLinus Torvalds * ipr_get_unit_check_buffer - Get the unit check buffer from the IOA 62461da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 62471da177e4SLinus Torvalds * 62481da177e4SLinus Torvalds * Fetches the unit check buffer from the adapter by clocking the data 62491da177e4SLinus Torvalds * through the mailbox register. 62501da177e4SLinus Torvalds * 62511da177e4SLinus Torvalds * Return value: 62521da177e4SLinus Torvalds * nothing 62531da177e4SLinus Torvalds **/ 62541da177e4SLinus Torvalds static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) 62551da177e4SLinus Torvalds { 62561da177e4SLinus Torvalds unsigned long mailbox; 62571da177e4SLinus Torvalds struct ipr_hostrcb *hostrcb; 62581da177e4SLinus Torvalds struct ipr_uc_sdt sdt; 62591da177e4SLinus Torvalds int rc, length; 62601da177e4SLinus Torvalds 62611da177e4SLinus Torvalds mailbox = readl(ioa_cfg->ioa_mailbox); 62621da177e4SLinus Torvalds 62631da177e4SLinus Torvalds if (!ipr_sdt_is_fmt2(mailbox)) { 62641da177e4SLinus Torvalds ipr_unit_check_no_data(ioa_cfg); 62651da177e4SLinus Torvalds return; 62661da177e4SLinus Torvalds } 62671da177e4SLinus Torvalds 62681da177e4SLinus Torvalds memset(&sdt, 0, sizeof(struct ipr_uc_sdt)); 62691da177e4SLinus Torvalds rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt, 62701da177e4SLinus Torvalds (sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); 62711da177e4SLinus Torvalds 62721da177e4SLinus Torvalds if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) || 62731da177e4SLinus Torvalds !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) { 62741da177e4SLinus Torvalds ipr_unit_check_no_data(ioa_cfg); 62751da177e4SLinus Torvalds return; 62761da177e4SLinus Torvalds } 62771da177e4SLinus Torvalds 62781da177e4SLinus Torvalds /* Find length of the first sdt entry (UC buffer) */ 62791da177e4SLinus Torvalds length = (be32_to_cpu(sdt.entry[0].end_offset) - 62801da177e4SLinus Torvalds be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK; 62811da177e4SLinus Torvalds 62821da177e4SLinus Torvalds hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, 62831da177e4SLinus Torvalds struct ipr_hostrcb, queue); 62841da177e4SLinus Torvalds list_del(&hostrcb->queue); 62851da177e4SLinus Torvalds memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); 62861da177e4SLinus Torvalds 62871da177e4SLinus Torvalds rc = ipr_get_ldump_data_section(ioa_cfg, 62881da177e4SLinus Torvalds be32_to_cpu(sdt.entry[0].bar_str_offset), 62891da177e4SLinus Torvalds (__be32 *)&hostrcb->hcam, 62901da177e4SLinus Torvalds min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); 62911da177e4SLinus Torvalds 62921da177e4SLinus Torvalds if (!rc) 62931da177e4SLinus Torvalds ipr_handle_log_data(ioa_cfg, hostrcb); 62941da177e4SLinus Torvalds else 62951da177e4SLinus Torvalds ipr_unit_check_no_data(ioa_cfg); 62961da177e4SLinus Torvalds 62971da177e4SLinus Torvalds list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); 62981da177e4SLinus Torvalds } 62991da177e4SLinus Torvalds 63001da177e4SLinus Torvalds /** 63011da177e4SLinus Torvalds * ipr_reset_restore_cfg_space - Restore PCI config space. 63021da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 63031da177e4SLinus Torvalds * 63041da177e4SLinus Torvalds * Description: This function restores the saved PCI config space of 63051da177e4SLinus Torvalds * the adapter, fails all outstanding ops back to the callers, and 63061da177e4SLinus Torvalds * fetches the dump/unit check if applicable to this reset. 63071da177e4SLinus Torvalds * 63081da177e4SLinus Torvalds * Return value: 63091da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 63101da177e4SLinus Torvalds **/ 63111da177e4SLinus Torvalds static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) 63121da177e4SLinus Torvalds { 63131da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 63141da177e4SLinus Torvalds int rc; 63151da177e4SLinus Torvalds 63161da177e4SLinus Torvalds ENTER; 6317b30197d2SBrian King pci_unblock_user_cfg_access(ioa_cfg->pdev); 63181da177e4SLinus Torvalds rc = pci_restore_state(ioa_cfg->pdev); 63191da177e4SLinus Torvalds 63201da177e4SLinus Torvalds if (rc != PCIBIOS_SUCCESSFUL) { 63211da177e4SLinus Torvalds ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); 63221da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 63231da177e4SLinus Torvalds } 63241da177e4SLinus Torvalds 63251da177e4SLinus Torvalds if (ipr_set_pcix_cmd_reg(ioa_cfg)) { 63261da177e4SLinus Torvalds ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); 63271da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 63281da177e4SLinus Torvalds } 63291da177e4SLinus Torvalds 63301da177e4SLinus Torvalds ipr_fail_all_ops(ioa_cfg); 63311da177e4SLinus Torvalds 63321da177e4SLinus Torvalds if (ioa_cfg->ioa_unit_checked) { 63331da177e4SLinus Torvalds ioa_cfg->ioa_unit_checked = 0; 63341da177e4SLinus Torvalds ipr_get_unit_check_buffer(ioa_cfg); 63351da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_alert; 63361da177e4SLinus Torvalds ipr_reset_start_timer(ipr_cmd, 0); 63371da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 63381da177e4SLinus Torvalds } 63391da177e4SLinus Torvalds 63401da177e4SLinus Torvalds if (ioa_cfg->in_ioa_bringdown) { 63411da177e4SLinus Torvalds ipr_cmd->job_step = ipr_ioa_bringdown_done; 63421da177e4SLinus Torvalds } else { 63431da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_enable_ioa; 63441da177e4SLinus Torvalds 63451da177e4SLinus Torvalds if (GET_DUMP == ioa_cfg->sdt_state) { 63461da177e4SLinus Torvalds ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT); 63471da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_wait_for_dump; 63481da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 63491da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 63501da177e4SLinus Torvalds } 63511da177e4SLinus Torvalds } 63521da177e4SLinus Torvalds 63531da177e4SLinus Torvalds ENTER; 63541da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 63551da177e4SLinus Torvalds } 63561da177e4SLinus Torvalds 63571da177e4SLinus Torvalds /** 63581da177e4SLinus Torvalds * ipr_reset_start_bist - Run BIST on the adapter. 63591da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 63601da177e4SLinus Torvalds * 63611da177e4SLinus Torvalds * Description: This function runs BIST on the adapter, then delays 2 seconds. 63621da177e4SLinus Torvalds * 63631da177e4SLinus Torvalds * Return value: 63641da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 63651da177e4SLinus Torvalds **/ 63661da177e4SLinus Torvalds static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) 63671da177e4SLinus Torvalds { 63681da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 63691da177e4SLinus Torvalds int rc; 63701da177e4SLinus Torvalds 63711da177e4SLinus Torvalds ENTER; 6372b30197d2SBrian King pci_block_user_cfg_access(ioa_cfg->pdev); 63731da177e4SLinus Torvalds rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); 63741da177e4SLinus Torvalds 63751da177e4SLinus Torvalds if (rc != PCIBIOS_SUCCESSFUL) { 63761da177e4SLinus Torvalds ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); 63771da177e4SLinus Torvalds rc = IPR_RC_JOB_CONTINUE; 63781da177e4SLinus Torvalds } else { 63791da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_restore_cfg_space; 63801da177e4SLinus Torvalds ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); 63811da177e4SLinus Torvalds rc = IPR_RC_JOB_RETURN; 63821da177e4SLinus Torvalds } 63831da177e4SLinus Torvalds 63841da177e4SLinus Torvalds LEAVE; 63851da177e4SLinus Torvalds return rc; 63861da177e4SLinus Torvalds } 63871da177e4SLinus Torvalds 63881da177e4SLinus Torvalds /** 63891da177e4SLinus Torvalds * ipr_reset_allowed - Query whether or not IOA can be reset 63901da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 63911da177e4SLinus Torvalds * 63921da177e4SLinus Torvalds * Return value: 63931da177e4SLinus Torvalds * 0 if reset not allowed / non-zero if reset is allowed 63941da177e4SLinus Torvalds **/ 63951da177e4SLinus Torvalds static int ipr_reset_allowed(struct ipr_ioa_cfg *ioa_cfg) 63961da177e4SLinus Torvalds { 63971da177e4SLinus Torvalds volatile u32 temp_reg; 63981da177e4SLinus Torvalds 63991da177e4SLinus Torvalds temp_reg = readl(ioa_cfg->regs.sense_interrupt_reg); 64001da177e4SLinus Torvalds return ((temp_reg & IPR_PCII_CRITICAL_OPERATION) == 0); 64011da177e4SLinus Torvalds } 64021da177e4SLinus Torvalds 64031da177e4SLinus Torvalds /** 64041da177e4SLinus Torvalds * ipr_reset_wait_to_start_bist - Wait for permission to reset IOA. 64051da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 64061da177e4SLinus Torvalds * 64071da177e4SLinus Torvalds * Description: This function waits for adapter permission to run BIST, 64081da177e4SLinus Torvalds * then runs BIST. If the adapter does not give permission after a 64091da177e4SLinus Torvalds * reasonable time, we will reset the adapter anyway. The impact of 64101da177e4SLinus Torvalds * resetting the adapter without warning the adapter is the risk of 64111da177e4SLinus Torvalds * losing the persistent error log on the adapter. If the adapter is 64121da177e4SLinus Torvalds * reset while it is writing to the flash on the adapter, the flash 64131da177e4SLinus Torvalds * segment will have bad ECC and be zeroed. 64141da177e4SLinus Torvalds * 64151da177e4SLinus Torvalds * Return value: 64161da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 64171da177e4SLinus Torvalds **/ 64181da177e4SLinus Torvalds static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) 64191da177e4SLinus Torvalds { 64201da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 64211da177e4SLinus Torvalds int rc = IPR_RC_JOB_RETURN; 64221da177e4SLinus Torvalds 64231da177e4SLinus Torvalds if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->u.time_left) { 64241da177e4SLinus Torvalds ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; 64251da177e4SLinus Torvalds ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); 64261da177e4SLinus Torvalds } else { 64271da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_start_bist; 64281da177e4SLinus Torvalds rc = IPR_RC_JOB_CONTINUE; 64291da177e4SLinus Torvalds } 64301da177e4SLinus Torvalds 64311da177e4SLinus Torvalds return rc; 64321da177e4SLinus Torvalds } 64331da177e4SLinus Torvalds 64341da177e4SLinus Torvalds /** 64351da177e4SLinus Torvalds * ipr_reset_alert_part2 - Alert the adapter of a pending reset 64361da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 64371da177e4SLinus Torvalds * 64381da177e4SLinus Torvalds * Description: This function alerts the adapter that it will be reset. 64391da177e4SLinus Torvalds * If memory space is not currently enabled, proceed directly 64401da177e4SLinus Torvalds * to running BIST on the adapter. The timer must always be started 64411da177e4SLinus Torvalds * so we guarantee we do not run BIST from ipr_isr. 64421da177e4SLinus Torvalds * 64431da177e4SLinus Torvalds * Return value: 64441da177e4SLinus Torvalds * IPR_RC_JOB_RETURN 64451da177e4SLinus Torvalds **/ 64461da177e4SLinus Torvalds static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) 64471da177e4SLinus Torvalds { 64481da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 64491da177e4SLinus Torvalds u16 cmd_reg; 64501da177e4SLinus Torvalds int rc; 64511da177e4SLinus Torvalds 64521da177e4SLinus Torvalds ENTER; 64531da177e4SLinus Torvalds rc = pci_read_config_word(ioa_cfg->pdev, PCI_COMMAND, &cmd_reg); 64541da177e4SLinus Torvalds 64551da177e4SLinus Torvalds if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) { 64561da177e4SLinus Torvalds ipr_mask_and_clear_interrupts(ioa_cfg, ~0); 64571da177e4SLinus Torvalds writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg); 64581da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_wait_to_start_bist; 64591da177e4SLinus Torvalds } else { 64601da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_start_bist; 64611da177e4SLinus Torvalds } 64621da177e4SLinus Torvalds 64631da177e4SLinus Torvalds ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; 64641da177e4SLinus Torvalds ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); 64651da177e4SLinus Torvalds 64661da177e4SLinus Torvalds LEAVE; 64671da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 64681da177e4SLinus Torvalds } 64691da177e4SLinus Torvalds 64701da177e4SLinus Torvalds /** 64711da177e4SLinus Torvalds * ipr_reset_ucode_download_done - Microcode download completion 64721da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 64731da177e4SLinus Torvalds * 64741da177e4SLinus Torvalds * Description: This function unmaps the microcode download buffer. 64751da177e4SLinus Torvalds * 64761da177e4SLinus Torvalds * Return value: 64771da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE 64781da177e4SLinus Torvalds **/ 64791da177e4SLinus Torvalds static int ipr_reset_ucode_download_done(struct ipr_cmnd *ipr_cmd) 64801da177e4SLinus Torvalds { 64811da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 64821da177e4SLinus Torvalds struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; 64831da177e4SLinus Torvalds 64841da177e4SLinus Torvalds pci_unmap_sg(ioa_cfg->pdev, sglist->scatterlist, 64851da177e4SLinus Torvalds sglist->num_sg, DMA_TO_DEVICE); 64861da177e4SLinus Torvalds 64871da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_alert; 64881da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 64891da177e4SLinus Torvalds } 64901da177e4SLinus Torvalds 64911da177e4SLinus Torvalds /** 64921da177e4SLinus Torvalds * ipr_reset_ucode_download - Download microcode to the adapter 64931da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 64941da177e4SLinus Torvalds * 64951da177e4SLinus Torvalds * Description: This function checks to see if it there is microcode 64961da177e4SLinus Torvalds * to download to the adapter. If there is, a download is performed. 64971da177e4SLinus Torvalds * 64981da177e4SLinus Torvalds * Return value: 64991da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 65001da177e4SLinus Torvalds **/ 65011da177e4SLinus Torvalds static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd) 65021da177e4SLinus Torvalds { 65031da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 65041da177e4SLinus Torvalds struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; 65051da177e4SLinus Torvalds 65061da177e4SLinus Torvalds ENTER; 65071da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_alert; 65081da177e4SLinus Torvalds 65091da177e4SLinus Torvalds if (!sglist) 65101da177e4SLinus Torvalds return IPR_RC_JOB_CONTINUE; 65111da177e4SLinus Torvalds 65121da177e4SLinus Torvalds ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 65131da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; 65141da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[0] = WRITE_BUFFER; 65151da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_WR_BUF_DOWNLOAD_AND_SAVE; 65161da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[6] = (sglist->buffer_len & 0xff0000) >> 16; 65171da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8; 65181da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff; 65191da177e4SLinus Torvalds 652012baa420Sbrking@us.ibm.com ipr_build_ucode_ioadl(ipr_cmd, sglist); 65211da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_ucode_download_done; 65221da177e4SLinus Torvalds 65231da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, 65241da177e4SLinus Torvalds IPR_WRITE_BUFFER_TIMEOUT); 65251da177e4SLinus Torvalds 65261da177e4SLinus Torvalds LEAVE; 65271da177e4SLinus Torvalds return IPR_RC_JOB_RETURN; 65281da177e4SLinus Torvalds } 65291da177e4SLinus Torvalds 65301da177e4SLinus Torvalds /** 65311da177e4SLinus Torvalds * ipr_reset_shutdown_ioa - Shutdown the adapter 65321da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 65331da177e4SLinus Torvalds * 65341da177e4SLinus Torvalds * Description: This function issues an adapter shutdown of the 65351da177e4SLinus Torvalds * specified type to the specified adapter as part of the 65361da177e4SLinus Torvalds * adapter reset job. 65371da177e4SLinus Torvalds * 65381da177e4SLinus Torvalds * Return value: 65391da177e4SLinus Torvalds * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN 65401da177e4SLinus Torvalds **/ 65411da177e4SLinus Torvalds static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) 65421da177e4SLinus Torvalds { 65431da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 65441da177e4SLinus Torvalds enum ipr_shutdown_type shutdown_type = ipr_cmd->u.shutdown_type; 65451da177e4SLinus Torvalds unsigned long timeout; 65461da177e4SLinus Torvalds int rc = IPR_RC_JOB_CONTINUE; 65471da177e4SLinus Torvalds 65481da177e4SLinus Torvalds ENTER; 65491da177e4SLinus Torvalds if (shutdown_type != IPR_SHUTDOWN_NONE && !ioa_cfg->ioa_is_dead) { 65501da177e4SLinus Torvalds ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); 65511da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD; 65521da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; 65531da177e4SLinus Torvalds ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type; 65541da177e4SLinus Torvalds 65551da177e4SLinus Torvalds if (shutdown_type == IPR_SHUTDOWN_ABBREV) 65561da177e4SLinus Torvalds timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; 65571da177e4SLinus Torvalds else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL) 65581da177e4SLinus Torvalds timeout = IPR_INTERNAL_TIMEOUT; 65591da177e4SLinus Torvalds else 65601da177e4SLinus Torvalds timeout = IPR_SHUTDOWN_TIMEOUT; 65611da177e4SLinus Torvalds 65621da177e4SLinus Torvalds ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout); 65631da177e4SLinus Torvalds 65641da177e4SLinus Torvalds rc = IPR_RC_JOB_RETURN; 65651da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_ucode_download; 65661da177e4SLinus Torvalds } else 65671da177e4SLinus Torvalds ipr_cmd->job_step = ipr_reset_alert; 65681da177e4SLinus Torvalds 65691da177e4SLinus Torvalds LEAVE; 65701da177e4SLinus Torvalds return rc; 65711da177e4SLinus Torvalds } 65721da177e4SLinus Torvalds 65731da177e4SLinus Torvalds /** 65741da177e4SLinus Torvalds * ipr_reset_ioa_job - Adapter reset job 65751da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 65761da177e4SLinus Torvalds * 65771da177e4SLinus Torvalds * Description: This function is the job router for the adapter reset job. 65781da177e4SLinus Torvalds * 65791da177e4SLinus Torvalds * Return value: 65801da177e4SLinus Torvalds * none 65811da177e4SLinus Torvalds **/ 65821da177e4SLinus Torvalds static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) 65831da177e4SLinus Torvalds { 65841da177e4SLinus Torvalds u32 rc, ioasc; 65851da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; 65861da177e4SLinus Torvalds 65871da177e4SLinus Torvalds do { 65881da177e4SLinus Torvalds ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); 65891da177e4SLinus Torvalds 65901da177e4SLinus Torvalds if (ioa_cfg->reset_cmd != ipr_cmd) { 65911da177e4SLinus Torvalds /* 65921da177e4SLinus Torvalds * We are doing nested adapter resets and this is 65931da177e4SLinus Torvalds * not the current reset job. 65941da177e4SLinus Torvalds */ 65951da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 65961da177e4SLinus Torvalds return; 65971da177e4SLinus Torvalds } 65981da177e4SLinus Torvalds 65991da177e4SLinus Torvalds if (IPR_IOASC_SENSE_KEY(ioasc)) { 6600dfed823eSbrking@us.ibm.com rc = ipr_cmd->job_step_failed(ipr_cmd); 6601dfed823eSbrking@us.ibm.com if (rc == IPR_RC_JOB_RETURN) 66021da177e4SLinus Torvalds return; 66031da177e4SLinus Torvalds } 66041da177e4SLinus Torvalds 66051da177e4SLinus Torvalds ipr_reinit_ipr_cmnd(ipr_cmd); 6606dfed823eSbrking@us.ibm.com ipr_cmd->job_step_failed = ipr_reset_cmd_failed; 66071da177e4SLinus Torvalds rc = ipr_cmd->job_step(ipr_cmd); 66081da177e4SLinus Torvalds } while(rc == IPR_RC_JOB_CONTINUE); 66091da177e4SLinus Torvalds } 66101da177e4SLinus Torvalds 66111da177e4SLinus Torvalds /** 66121da177e4SLinus Torvalds * _ipr_initiate_ioa_reset - Initiate an adapter reset 66131da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 66141da177e4SLinus Torvalds * @job_step: first job step of reset job 66151da177e4SLinus Torvalds * @shutdown_type: shutdown type 66161da177e4SLinus Torvalds * 66171da177e4SLinus Torvalds * Description: This function will initiate the reset of the given adapter 66181da177e4SLinus Torvalds * starting at the selected job step. 66191da177e4SLinus Torvalds * If the caller needs to wait on the completion of the reset, 66201da177e4SLinus Torvalds * the caller must sleep on the reset_wait_q. 66211da177e4SLinus Torvalds * 66221da177e4SLinus Torvalds * Return value: 66231da177e4SLinus Torvalds * none 66241da177e4SLinus Torvalds **/ 66251da177e4SLinus Torvalds static void _ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, 66261da177e4SLinus Torvalds int (*job_step) (struct ipr_cmnd *), 66271da177e4SLinus Torvalds enum ipr_shutdown_type shutdown_type) 66281da177e4SLinus Torvalds { 66291da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 66301da177e4SLinus Torvalds 66311da177e4SLinus Torvalds ioa_cfg->in_reset_reload = 1; 66321da177e4SLinus Torvalds ioa_cfg->allow_cmds = 0; 66331da177e4SLinus Torvalds scsi_block_requests(ioa_cfg->host); 66341da177e4SLinus Torvalds 66351da177e4SLinus Torvalds ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); 66361da177e4SLinus Torvalds ioa_cfg->reset_cmd = ipr_cmd; 66371da177e4SLinus Torvalds ipr_cmd->job_step = job_step; 66381da177e4SLinus Torvalds ipr_cmd->u.shutdown_type = shutdown_type; 66391da177e4SLinus Torvalds 66401da177e4SLinus Torvalds ipr_reset_ioa_job(ipr_cmd); 66411da177e4SLinus Torvalds } 66421da177e4SLinus Torvalds 66431da177e4SLinus Torvalds /** 66441da177e4SLinus Torvalds * ipr_initiate_ioa_reset - Initiate an adapter reset 66451da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 66461da177e4SLinus Torvalds * @shutdown_type: shutdown type 66471da177e4SLinus Torvalds * 66481da177e4SLinus Torvalds * Description: This function will initiate the reset of the given adapter. 66491da177e4SLinus Torvalds * If the caller needs to wait on the completion of the reset, 66501da177e4SLinus Torvalds * the caller must sleep on the reset_wait_q. 66511da177e4SLinus Torvalds * 66521da177e4SLinus Torvalds * Return value: 66531da177e4SLinus Torvalds * none 66541da177e4SLinus Torvalds **/ 66551da177e4SLinus Torvalds static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, 66561da177e4SLinus Torvalds enum ipr_shutdown_type shutdown_type) 66571da177e4SLinus Torvalds { 66581da177e4SLinus Torvalds if (ioa_cfg->ioa_is_dead) 66591da177e4SLinus Torvalds return; 66601da177e4SLinus Torvalds 66611da177e4SLinus Torvalds if (ioa_cfg->in_reset_reload && ioa_cfg->sdt_state == GET_DUMP) 66621da177e4SLinus Torvalds ioa_cfg->sdt_state = ABORT_DUMP; 66631da177e4SLinus Torvalds 66641da177e4SLinus Torvalds if (ioa_cfg->reset_retries++ >= IPR_NUM_RESET_RELOAD_RETRIES) { 66651da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 66661da177e4SLinus Torvalds "IOA taken offline - error recovery failed\n"); 66671da177e4SLinus Torvalds 66681da177e4SLinus Torvalds ioa_cfg->reset_retries = 0; 66691da177e4SLinus Torvalds ioa_cfg->ioa_is_dead = 1; 66701da177e4SLinus Torvalds 66711da177e4SLinus Torvalds if (ioa_cfg->in_ioa_bringdown) { 66721da177e4SLinus Torvalds ioa_cfg->reset_cmd = NULL; 66731da177e4SLinus Torvalds ioa_cfg->in_reset_reload = 0; 66741da177e4SLinus Torvalds ipr_fail_all_ops(ioa_cfg); 66751da177e4SLinus Torvalds wake_up_all(&ioa_cfg->reset_wait_q); 66761da177e4SLinus Torvalds 66771da177e4SLinus Torvalds spin_unlock_irq(ioa_cfg->host->host_lock); 66781da177e4SLinus Torvalds scsi_unblock_requests(ioa_cfg->host); 66791da177e4SLinus Torvalds spin_lock_irq(ioa_cfg->host->host_lock); 66801da177e4SLinus Torvalds return; 66811da177e4SLinus Torvalds } else { 66821da177e4SLinus Torvalds ioa_cfg->in_ioa_bringdown = 1; 66831da177e4SLinus Torvalds shutdown_type = IPR_SHUTDOWN_NONE; 66841da177e4SLinus Torvalds } 66851da177e4SLinus Torvalds } 66861da177e4SLinus Torvalds 66871da177e4SLinus Torvalds _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_shutdown_ioa, 66881da177e4SLinus Torvalds shutdown_type); 66891da177e4SLinus Torvalds } 66901da177e4SLinus Torvalds 66911da177e4SLinus Torvalds /** 6692f8a88b19SLinas Vepstas * ipr_reset_freeze - Hold off all I/O activity 6693f8a88b19SLinas Vepstas * @ipr_cmd: ipr command struct 6694f8a88b19SLinas Vepstas * 6695f8a88b19SLinas Vepstas * Description: If the PCI slot is frozen, hold off all I/O 6696f8a88b19SLinas Vepstas * activity; then, as soon as the slot is available again, 6697f8a88b19SLinas Vepstas * initiate an adapter reset. 6698f8a88b19SLinas Vepstas */ 6699f8a88b19SLinas Vepstas static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd) 6700f8a88b19SLinas Vepstas { 6701f8a88b19SLinas Vepstas /* Disallow new interrupts, avoid loop */ 6702f8a88b19SLinas Vepstas ipr_cmd->ioa_cfg->allow_interrupts = 0; 6703f8a88b19SLinas Vepstas list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); 6704f8a88b19SLinas Vepstas ipr_cmd->done = ipr_reset_ioa_job; 6705f8a88b19SLinas Vepstas return IPR_RC_JOB_RETURN; 6706f8a88b19SLinas Vepstas } 6707f8a88b19SLinas Vepstas 6708f8a88b19SLinas Vepstas /** 6709f8a88b19SLinas Vepstas * ipr_pci_frozen - Called when slot has experienced a PCI bus error. 6710f8a88b19SLinas Vepstas * @pdev: PCI device struct 6711f8a88b19SLinas Vepstas * 6712f8a88b19SLinas Vepstas * Description: This routine is called to tell us that the PCI bus 6713f8a88b19SLinas Vepstas * is down. Can't do anything here, except put the device driver 6714f8a88b19SLinas Vepstas * into a holding pattern, waiting for the PCI bus to come back. 6715f8a88b19SLinas Vepstas */ 6716f8a88b19SLinas Vepstas static void ipr_pci_frozen(struct pci_dev *pdev) 6717f8a88b19SLinas Vepstas { 6718f8a88b19SLinas Vepstas unsigned long flags = 0; 6719f8a88b19SLinas Vepstas struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 6720f8a88b19SLinas Vepstas 6721f8a88b19SLinas Vepstas spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 6722f8a88b19SLinas Vepstas _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE); 6723f8a88b19SLinas Vepstas spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 6724f8a88b19SLinas Vepstas } 6725f8a88b19SLinas Vepstas 6726f8a88b19SLinas Vepstas /** 6727f8a88b19SLinas Vepstas * ipr_pci_slot_reset - Called when PCI slot has been reset. 6728f8a88b19SLinas Vepstas * @pdev: PCI device struct 6729f8a88b19SLinas Vepstas * 6730f8a88b19SLinas Vepstas * Description: This routine is called by the pci error recovery 6731f8a88b19SLinas Vepstas * code after the PCI slot has been reset, just before we 6732f8a88b19SLinas Vepstas * should resume normal operations. 6733f8a88b19SLinas Vepstas */ 6734f8a88b19SLinas Vepstas static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev) 6735f8a88b19SLinas Vepstas { 6736f8a88b19SLinas Vepstas unsigned long flags = 0; 6737f8a88b19SLinas Vepstas struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 6738f8a88b19SLinas Vepstas 6739f8a88b19SLinas Vepstas spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 6740f8a88b19SLinas Vepstas _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, 6741f8a88b19SLinas Vepstas IPR_SHUTDOWN_NONE); 6742f8a88b19SLinas Vepstas spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 6743f8a88b19SLinas Vepstas return PCI_ERS_RESULT_RECOVERED; 6744f8a88b19SLinas Vepstas } 6745f8a88b19SLinas Vepstas 6746f8a88b19SLinas Vepstas /** 6747f8a88b19SLinas Vepstas * ipr_pci_perm_failure - Called when PCI slot is dead for good. 6748f8a88b19SLinas Vepstas * @pdev: PCI device struct 6749f8a88b19SLinas Vepstas * 6750f8a88b19SLinas Vepstas * Description: This routine is called when the PCI bus has 6751f8a88b19SLinas Vepstas * permanently failed. 6752f8a88b19SLinas Vepstas */ 6753f8a88b19SLinas Vepstas static void ipr_pci_perm_failure(struct pci_dev *pdev) 6754f8a88b19SLinas Vepstas { 6755f8a88b19SLinas Vepstas unsigned long flags = 0; 6756f8a88b19SLinas Vepstas struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 6757f8a88b19SLinas Vepstas 6758f8a88b19SLinas Vepstas spin_lock_irqsave(ioa_cfg->host->host_lock, flags); 6759f8a88b19SLinas Vepstas if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) 6760f8a88b19SLinas Vepstas ioa_cfg->sdt_state = ABORT_DUMP; 6761f8a88b19SLinas Vepstas ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES; 6762f8a88b19SLinas Vepstas ioa_cfg->in_ioa_bringdown = 1; 6763f8a88b19SLinas Vepstas ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 6764f8a88b19SLinas Vepstas spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); 6765f8a88b19SLinas Vepstas } 6766f8a88b19SLinas Vepstas 6767f8a88b19SLinas Vepstas /** 6768f8a88b19SLinas Vepstas * ipr_pci_error_detected - Called when a PCI error is detected. 6769f8a88b19SLinas Vepstas * @pdev: PCI device struct 6770f8a88b19SLinas Vepstas * @state: PCI channel state 6771f8a88b19SLinas Vepstas * 6772f8a88b19SLinas Vepstas * Description: Called when a PCI error is detected. 6773f8a88b19SLinas Vepstas * 6774f8a88b19SLinas Vepstas * Return value: 6775f8a88b19SLinas Vepstas * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT 6776f8a88b19SLinas Vepstas */ 6777f8a88b19SLinas Vepstas static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev, 6778f8a88b19SLinas Vepstas pci_channel_state_t state) 6779f8a88b19SLinas Vepstas { 6780f8a88b19SLinas Vepstas switch (state) { 6781f8a88b19SLinas Vepstas case pci_channel_io_frozen: 6782f8a88b19SLinas Vepstas ipr_pci_frozen(pdev); 6783f8a88b19SLinas Vepstas return PCI_ERS_RESULT_NEED_RESET; 6784f8a88b19SLinas Vepstas case pci_channel_io_perm_failure: 6785f8a88b19SLinas Vepstas ipr_pci_perm_failure(pdev); 6786f8a88b19SLinas Vepstas return PCI_ERS_RESULT_DISCONNECT; 6787f8a88b19SLinas Vepstas break; 6788f8a88b19SLinas Vepstas default: 6789f8a88b19SLinas Vepstas break; 6790f8a88b19SLinas Vepstas } 6791f8a88b19SLinas Vepstas return PCI_ERS_RESULT_NEED_RESET; 6792f8a88b19SLinas Vepstas } 6793f8a88b19SLinas Vepstas 6794f8a88b19SLinas Vepstas /** 67951da177e4SLinus Torvalds * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) 67961da177e4SLinus Torvalds * @ioa_cfg: ioa cfg struct 67971da177e4SLinus Torvalds * 67981da177e4SLinus Torvalds * Description: This is the second phase of adapter intialization 67991da177e4SLinus Torvalds * This function takes care of initilizing the adapter to the point 68001da177e4SLinus Torvalds * where it can accept new commands. 68011da177e4SLinus Torvalds 68021da177e4SLinus Torvalds * Return value: 68031da177e4SLinus Torvalds * 0 on sucess / -EIO on failure 68041da177e4SLinus Torvalds **/ 68051da177e4SLinus Torvalds static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg) 68061da177e4SLinus Torvalds { 68071da177e4SLinus Torvalds int rc = 0; 68081da177e4SLinus Torvalds unsigned long host_lock_flags = 0; 68091da177e4SLinus Torvalds 68101da177e4SLinus Torvalds ENTER; 68111da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); 68121da177e4SLinus Torvalds dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg); 6813ce155cceSbrking@us.ibm.com if (ioa_cfg->needs_hard_reset) { 6814ce155cceSbrking@us.ibm.com ioa_cfg->needs_hard_reset = 0; 6815ce155cceSbrking@us.ibm.com ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); 6816ce155cceSbrking@us.ibm.com } else 6817ce155cceSbrking@us.ibm.com _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, 6818ce155cceSbrking@us.ibm.com IPR_SHUTDOWN_NONE); 68191da177e4SLinus Torvalds 68201da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); 68211da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 68221da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); 68231da177e4SLinus Torvalds 68241da177e4SLinus Torvalds if (ioa_cfg->ioa_is_dead) { 68251da177e4SLinus Torvalds rc = -EIO; 68261da177e4SLinus Torvalds } else if (ipr_invalid_adapter(ioa_cfg)) { 68271da177e4SLinus Torvalds if (!ipr_testmode) 68281da177e4SLinus Torvalds rc = -EIO; 68291da177e4SLinus Torvalds 68301da177e4SLinus Torvalds dev_err(&ioa_cfg->pdev->dev, 68311da177e4SLinus Torvalds "Adapter not supported in this hardware configuration.\n"); 68321da177e4SLinus Torvalds } 68331da177e4SLinus Torvalds 68341da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); 68351da177e4SLinus Torvalds 68361da177e4SLinus Torvalds LEAVE; 68371da177e4SLinus Torvalds return rc; 68381da177e4SLinus Torvalds } 68391da177e4SLinus Torvalds 68401da177e4SLinus Torvalds /** 68411da177e4SLinus Torvalds * ipr_free_cmd_blks - Frees command blocks allocated for an adapter 68421da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 68431da177e4SLinus Torvalds * 68441da177e4SLinus Torvalds * Return value: 68451da177e4SLinus Torvalds * none 68461da177e4SLinus Torvalds **/ 68471da177e4SLinus Torvalds static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) 68481da177e4SLinus Torvalds { 68491da177e4SLinus Torvalds int i; 68501da177e4SLinus Torvalds 68511da177e4SLinus Torvalds for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { 68521da177e4SLinus Torvalds if (ioa_cfg->ipr_cmnd_list[i]) 68531da177e4SLinus Torvalds pci_pool_free(ioa_cfg->ipr_cmd_pool, 68541da177e4SLinus Torvalds ioa_cfg->ipr_cmnd_list[i], 68551da177e4SLinus Torvalds ioa_cfg->ipr_cmnd_list_dma[i]); 68561da177e4SLinus Torvalds 68571da177e4SLinus Torvalds ioa_cfg->ipr_cmnd_list[i] = NULL; 68581da177e4SLinus Torvalds } 68591da177e4SLinus Torvalds 68601da177e4SLinus Torvalds if (ioa_cfg->ipr_cmd_pool) 68611da177e4SLinus Torvalds pci_pool_destroy (ioa_cfg->ipr_cmd_pool); 68621da177e4SLinus Torvalds 68631da177e4SLinus Torvalds ioa_cfg->ipr_cmd_pool = NULL; 68641da177e4SLinus Torvalds } 68651da177e4SLinus Torvalds 68661da177e4SLinus Torvalds /** 68671da177e4SLinus Torvalds * ipr_free_mem - Frees memory allocated for an adapter 68681da177e4SLinus Torvalds * @ioa_cfg: ioa cfg struct 68691da177e4SLinus Torvalds * 68701da177e4SLinus Torvalds * Return value: 68711da177e4SLinus Torvalds * nothing 68721da177e4SLinus Torvalds **/ 68731da177e4SLinus Torvalds static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) 68741da177e4SLinus Torvalds { 68751da177e4SLinus Torvalds int i; 68761da177e4SLinus Torvalds 68771da177e4SLinus Torvalds kfree(ioa_cfg->res_entries); 68781da177e4SLinus Torvalds pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_misc_cbs), 68791da177e4SLinus Torvalds ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); 68801da177e4SLinus Torvalds ipr_free_cmd_blks(ioa_cfg); 68811da177e4SLinus Torvalds pci_free_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, 68821da177e4SLinus Torvalds ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); 68831da177e4SLinus Torvalds pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table), 68841da177e4SLinus Torvalds ioa_cfg->cfg_table, 68851da177e4SLinus Torvalds ioa_cfg->cfg_table_dma); 68861da177e4SLinus Torvalds 68871da177e4SLinus Torvalds for (i = 0; i < IPR_NUM_HCAMS; i++) { 68881da177e4SLinus Torvalds pci_free_consistent(ioa_cfg->pdev, 68891da177e4SLinus Torvalds sizeof(struct ipr_hostrcb), 68901da177e4SLinus Torvalds ioa_cfg->hostrcb[i], 68911da177e4SLinus Torvalds ioa_cfg->hostrcb_dma[i]); 68921da177e4SLinus Torvalds } 68931da177e4SLinus Torvalds 68941da177e4SLinus Torvalds ipr_free_dump(ioa_cfg); 68951da177e4SLinus Torvalds kfree(ioa_cfg->trace); 68961da177e4SLinus Torvalds } 68971da177e4SLinus Torvalds 68981da177e4SLinus Torvalds /** 68991da177e4SLinus Torvalds * ipr_free_all_resources - Free all allocated resources for an adapter. 69001da177e4SLinus Torvalds * @ipr_cmd: ipr command struct 69011da177e4SLinus Torvalds * 69021da177e4SLinus Torvalds * This function frees all allocated resources for the 69031da177e4SLinus Torvalds * specified adapter. 69041da177e4SLinus Torvalds * 69051da177e4SLinus Torvalds * Return value: 69061da177e4SLinus Torvalds * none 69071da177e4SLinus Torvalds **/ 69081da177e4SLinus Torvalds static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) 69091da177e4SLinus Torvalds { 69101da177e4SLinus Torvalds struct pci_dev *pdev = ioa_cfg->pdev; 69111da177e4SLinus Torvalds 69121da177e4SLinus Torvalds ENTER; 69131da177e4SLinus Torvalds free_irq(pdev->irq, ioa_cfg); 69141da177e4SLinus Torvalds iounmap(ioa_cfg->hdw_dma_regs); 69151da177e4SLinus Torvalds pci_release_regions(pdev); 69161da177e4SLinus Torvalds ipr_free_mem(ioa_cfg); 69171da177e4SLinus Torvalds scsi_host_put(ioa_cfg->host); 69181da177e4SLinus Torvalds pci_disable_device(pdev); 69191da177e4SLinus Torvalds LEAVE; 69201da177e4SLinus Torvalds } 69211da177e4SLinus Torvalds 69221da177e4SLinus Torvalds /** 69231da177e4SLinus Torvalds * ipr_alloc_cmd_blks - Allocate command blocks for an adapter 69241da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 69251da177e4SLinus Torvalds * 69261da177e4SLinus Torvalds * Return value: 69271da177e4SLinus Torvalds * 0 on success / -ENOMEM on allocation failure 69281da177e4SLinus Torvalds **/ 69291da177e4SLinus Torvalds static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) 69301da177e4SLinus Torvalds { 69311da177e4SLinus Torvalds struct ipr_cmnd *ipr_cmd; 69321da177e4SLinus Torvalds struct ipr_ioarcb *ioarcb; 69331da177e4SLinus Torvalds dma_addr_t dma_addr; 69341da177e4SLinus Torvalds int i; 69351da177e4SLinus Torvalds 69361da177e4SLinus Torvalds ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, 69371da177e4SLinus Torvalds sizeof(struct ipr_cmnd), 8, 0); 69381da177e4SLinus Torvalds 69391da177e4SLinus Torvalds if (!ioa_cfg->ipr_cmd_pool) 69401da177e4SLinus Torvalds return -ENOMEM; 69411da177e4SLinus Torvalds 69421da177e4SLinus Torvalds for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { 6943e94b1766SChristoph Lameter ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); 69441da177e4SLinus Torvalds 69451da177e4SLinus Torvalds if (!ipr_cmd) { 69461da177e4SLinus Torvalds ipr_free_cmd_blks(ioa_cfg); 69471da177e4SLinus Torvalds return -ENOMEM; 69481da177e4SLinus Torvalds } 69491da177e4SLinus Torvalds 69501da177e4SLinus Torvalds memset(ipr_cmd, 0, sizeof(*ipr_cmd)); 69511da177e4SLinus Torvalds ioa_cfg->ipr_cmnd_list[i] = ipr_cmd; 69521da177e4SLinus Torvalds ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr; 69531da177e4SLinus Torvalds 69541da177e4SLinus Torvalds ioarcb = &ipr_cmd->ioarcb; 69551da177e4SLinus Torvalds ioarcb->ioarcb_host_pci_addr = cpu_to_be32(dma_addr); 69561da177e4SLinus Torvalds ioarcb->host_response_handle = cpu_to_be32(i << 2); 69571da177e4SLinus Torvalds ioarcb->write_ioadl_addr = 69581da177e4SLinus Torvalds cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); 69591da177e4SLinus Torvalds ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; 69601da177e4SLinus Torvalds ioarcb->ioasa_host_pci_addr = 69611da177e4SLinus Torvalds cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa)); 69621da177e4SLinus Torvalds ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa)); 69631da177e4SLinus Torvalds ipr_cmd->cmd_index = i; 69641da177e4SLinus Torvalds ipr_cmd->ioa_cfg = ioa_cfg; 69651da177e4SLinus Torvalds ipr_cmd->sense_buffer_dma = dma_addr + 69661da177e4SLinus Torvalds offsetof(struct ipr_cmnd, sense_buffer); 69671da177e4SLinus Torvalds 69681da177e4SLinus Torvalds list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); 69691da177e4SLinus Torvalds } 69701da177e4SLinus Torvalds 69711da177e4SLinus Torvalds return 0; 69721da177e4SLinus Torvalds } 69731da177e4SLinus Torvalds 69741da177e4SLinus Torvalds /** 69751da177e4SLinus Torvalds * ipr_alloc_mem - Allocate memory for an adapter 69761da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 69771da177e4SLinus Torvalds * 69781da177e4SLinus Torvalds * Return value: 69791da177e4SLinus Torvalds * 0 on success / non-zero for error 69801da177e4SLinus Torvalds **/ 69811da177e4SLinus Torvalds static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) 69821da177e4SLinus Torvalds { 69831da177e4SLinus Torvalds struct pci_dev *pdev = ioa_cfg->pdev; 69841da177e4SLinus Torvalds int i, rc = -ENOMEM; 69851da177e4SLinus Torvalds 69861da177e4SLinus Torvalds ENTER; 69870bc42e35Sbrking@us.ibm.com ioa_cfg->res_entries = kzalloc(sizeof(struct ipr_resource_entry) * 69881da177e4SLinus Torvalds IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL); 69891da177e4SLinus Torvalds 69901da177e4SLinus Torvalds if (!ioa_cfg->res_entries) 69911da177e4SLinus Torvalds goto out; 69921da177e4SLinus Torvalds 69931da177e4SLinus Torvalds for (i = 0; i < IPR_MAX_PHYSICAL_DEVS; i++) 69941da177e4SLinus Torvalds list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q); 69951da177e4SLinus Torvalds 69961da177e4SLinus Torvalds ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev, 69971da177e4SLinus Torvalds sizeof(struct ipr_misc_cbs), 69981da177e4SLinus Torvalds &ioa_cfg->vpd_cbs_dma); 69991da177e4SLinus Torvalds 70001da177e4SLinus Torvalds if (!ioa_cfg->vpd_cbs) 70011da177e4SLinus Torvalds goto out_free_res_entries; 70021da177e4SLinus Torvalds 70031da177e4SLinus Torvalds if (ipr_alloc_cmd_blks(ioa_cfg)) 70041da177e4SLinus Torvalds goto out_free_vpd_cbs; 70051da177e4SLinus Torvalds 70061da177e4SLinus Torvalds ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev, 70071da177e4SLinus Torvalds sizeof(u32) * IPR_NUM_CMD_BLKS, 70081da177e4SLinus Torvalds &ioa_cfg->host_rrq_dma); 70091da177e4SLinus Torvalds 70101da177e4SLinus Torvalds if (!ioa_cfg->host_rrq) 70111da177e4SLinus Torvalds goto out_ipr_free_cmd_blocks; 70121da177e4SLinus Torvalds 70131da177e4SLinus Torvalds ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev, 70141da177e4SLinus Torvalds sizeof(struct ipr_config_table), 70151da177e4SLinus Torvalds &ioa_cfg->cfg_table_dma); 70161da177e4SLinus Torvalds 70171da177e4SLinus Torvalds if (!ioa_cfg->cfg_table) 70181da177e4SLinus Torvalds goto out_free_host_rrq; 70191da177e4SLinus Torvalds 70201da177e4SLinus Torvalds for (i = 0; i < IPR_NUM_HCAMS; i++) { 70211da177e4SLinus Torvalds ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev, 70221da177e4SLinus Torvalds sizeof(struct ipr_hostrcb), 70231da177e4SLinus Torvalds &ioa_cfg->hostrcb_dma[i]); 70241da177e4SLinus Torvalds 70251da177e4SLinus Torvalds if (!ioa_cfg->hostrcb[i]) 70261da177e4SLinus Torvalds goto out_free_hostrcb_dma; 70271da177e4SLinus Torvalds 70281da177e4SLinus Torvalds ioa_cfg->hostrcb[i]->hostrcb_dma = 70291da177e4SLinus Torvalds ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); 703049dc6a18SBrian King ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg; 70311da177e4SLinus Torvalds list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); 70321da177e4SLinus Torvalds } 70331da177e4SLinus Torvalds 70340bc42e35Sbrking@us.ibm.com ioa_cfg->trace = kzalloc(sizeof(struct ipr_trace_entry) * 70351da177e4SLinus Torvalds IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); 70361da177e4SLinus Torvalds 70371da177e4SLinus Torvalds if (!ioa_cfg->trace) 70381da177e4SLinus Torvalds goto out_free_hostrcb_dma; 70391da177e4SLinus Torvalds 70401da177e4SLinus Torvalds rc = 0; 70411da177e4SLinus Torvalds out: 70421da177e4SLinus Torvalds LEAVE; 70431da177e4SLinus Torvalds return rc; 70441da177e4SLinus Torvalds 70451da177e4SLinus Torvalds out_free_hostrcb_dma: 70461da177e4SLinus Torvalds while (i-- > 0) { 70471da177e4SLinus Torvalds pci_free_consistent(pdev, sizeof(struct ipr_hostrcb), 70481da177e4SLinus Torvalds ioa_cfg->hostrcb[i], 70491da177e4SLinus Torvalds ioa_cfg->hostrcb_dma[i]); 70501da177e4SLinus Torvalds } 70511da177e4SLinus Torvalds pci_free_consistent(pdev, sizeof(struct ipr_config_table), 70521da177e4SLinus Torvalds ioa_cfg->cfg_table, ioa_cfg->cfg_table_dma); 70531da177e4SLinus Torvalds out_free_host_rrq: 70541da177e4SLinus Torvalds pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, 70551da177e4SLinus Torvalds ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); 70561da177e4SLinus Torvalds out_ipr_free_cmd_blocks: 70571da177e4SLinus Torvalds ipr_free_cmd_blks(ioa_cfg); 70581da177e4SLinus Torvalds out_free_vpd_cbs: 70591da177e4SLinus Torvalds pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs), 70601da177e4SLinus Torvalds ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); 70611da177e4SLinus Torvalds out_free_res_entries: 70621da177e4SLinus Torvalds kfree(ioa_cfg->res_entries); 70631da177e4SLinus Torvalds goto out; 70641da177e4SLinus Torvalds } 70651da177e4SLinus Torvalds 70661da177e4SLinus Torvalds /** 70671da177e4SLinus Torvalds * ipr_initialize_bus_attr - Initialize SCSI bus attributes to default values 70681da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 70691da177e4SLinus Torvalds * 70701da177e4SLinus Torvalds * Return value: 70711da177e4SLinus Torvalds * none 70721da177e4SLinus Torvalds **/ 70731da177e4SLinus Torvalds static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg) 70741da177e4SLinus Torvalds { 70751da177e4SLinus Torvalds int i; 70761da177e4SLinus Torvalds 70771da177e4SLinus Torvalds for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { 70781da177e4SLinus Torvalds ioa_cfg->bus_attr[i].bus = i; 70791da177e4SLinus Torvalds ioa_cfg->bus_attr[i].qas_enabled = 0; 70801da177e4SLinus Torvalds ioa_cfg->bus_attr[i].bus_width = IPR_DEFAULT_BUS_WIDTH; 70811da177e4SLinus Torvalds if (ipr_max_speed < ARRAY_SIZE(ipr_max_bus_speeds)) 70821da177e4SLinus Torvalds ioa_cfg->bus_attr[i].max_xfer_rate = ipr_max_bus_speeds[ipr_max_speed]; 70831da177e4SLinus Torvalds else 70841da177e4SLinus Torvalds ioa_cfg->bus_attr[i].max_xfer_rate = IPR_U160_SCSI_RATE; 70851da177e4SLinus Torvalds } 70861da177e4SLinus Torvalds } 70871da177e4SLinus Torvalds 70881da177e4SLinus Torvalds /** 70891da177e4SLinus Torvalds * ipr_init_ioa_cfg - Initialize IOA config struct 70901da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 70911da177e4SLinus Torvalds * @host: scsi host struct 70921da177e4SLinus Torvalds * @pdev: PCI dev struct 70931da177e4SLinus Torvalds * 70941da177e4SLinus Torvalds * Return value: 70951da177e4SLinus Torvalds * none 70961da177e4SLinus Torvalds **/ 70971da177e4SLinus Torvalds static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, 70981da177e4SLinus Torvalds struct Scsi_Host *host, struct pci_dev *pdev) 70991da177e4SLinus Torvalds { 71001da177e4SLinus Torvalds const struct ipr_interrupt_offsets *p; 71011da177e4SLinus Torvalds struct ipr_interrupts *t; 71021da177e4SLinus Torvalds void __iomem *base; 71031da177e4SLinus Torvalds 71041da177e4SLinus Torvalds ioa_cfg->host = host; 71051da177e4SLinus Torvalds ioa_cfg->pdev = pdev; 71061da177e4SLinus Torvalds ioa_cfg->log_level = ipr_log_level; 71073d1d0da6Sbrking@us.ibm.com ioa_cfg->doorbell = IPR_DOORBELL; 710832d29776Sbrking@us.ibm.com if (!ipr_auto_create) 710932d29776Sbrking@us.ibm.com ioa_cfg->doorbell |= IPR_RUNTIME_RESET; 71101da177e4SLinus Torvalds sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER); 71111da177e4SLinus Torvalds sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL); 71121da177e4SLinus Torvalds sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL); 71131da177e4SLinus Torvalds sprintf(ioa_cfg->ipr_pending_label, IPR_PENDQ_LABEL); 71141da177e4SLinus Torvalds sprintf(ioa_cfg->cfg_table_start, IPR_CFG_TBL_START); 71151da177e4SLinus Torvalds sprintf(ioa_cfg->resource_table_label, IPR_RES_TABLE_LABEL); 71161da177e4SLinus Torvalds sprintf(ioa_cfg->ipr_hcam_label, IPR_HCAM_LABEL); 71171da177e4SLinus Torvalds sprintf(ioa_cfg->ipr_cmd_label, IPR_CMD_LABEL); 71181da177e4SLinus Torvalds 71191da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->free_q); 71201da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->pending_q); 71211da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q); 71221da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); 71231da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->free_res_q); 71241da177e4SLinus Torvalds INIT_LIST_HEAD(&ioa_cfg->used_res_q); 7125c4028958SDavid Howells INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); 71261da177e4SLinus Torvalds init_waitqueue_head(&ioa_cfg->reset_wait_q); 71271da177e4SLinus Torvalds ioa_cfg->sdt_state = INACTIVE; 712862275040Sbrking@us.ibm.com if (ipr_enable_cache) 712962275040Sbrking@us.ibm.com ioa_cfg->cache_state = CACHE_ENABLED; 713062275040Sbrking@us.ibm.com else 713162275040Sbrking@us.ibm.com ioa_cfg->cache_state = CACHE_DISABLED; 71321da177e4SLinus Torvalds 71331da177e4SLinus Torvalds ipr_initialize_bus_attr(ioa_cfg); 71341da177e4SLinus Torvalds 71351da177e4SLinus Torvalds host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS; 71361da177e4SLinus Torvalds host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET; 71371da177e4SLinus Torvalds host->max_channel = IPR_MAX_BUS_TO_SCAN; 71381da177e4SLinus Torvalds host->unique_id = host->host_no; 71391da177e4SLinus Torvalds host->max_cmd_len = IPR_MAX_CDB_LEN; 71401da177e4SLinus Torvalds pci_set_drvdata(pdev, ioa_cfg); 71411da177e4SLinus Torvalds 71421da177e4SLinus Torvalds p = &ioa_cfg->chip_cfg->regs; 71431da177e4SLinus Torvalds t = &ioa_cfg->regs; 71441da177e4SLinus Torvalds base = ioa_cfg->hdw_dma_regs; 71451da177e4SLinus Torvalds 71461da177e4SLinus Torvalds t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg; 71471da177e4SLinus Torvalds t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg; 71481da177e4SLinus Torvalds t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg; 71491da177e4SLinus Torvalds t->clr_interrupt_reg = base + p->clr_interrupt_reg; 71501da177e4SLinus Torvalds t->sense_interrupt_reg = base + p->sense_interrupt_reg; 71511da177e4SLinus Torvalds t->ioarrin_reg = base + p->ioarrin_reg; 71521da177e4SLinus Torvalds t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg; 71531da177e4SLinus Torvalds t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg; 71541da177e4SLinus Torvalds t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg; 71551da177e4SLinus Torvalds } 71561da177e4SLinus Torvalds 71571da177e4SLinus Torvalds /** 71581da177e4SLinus Torvalds * ipr_get_chip_cfg - Find adapter chip configuration 71591da177e4SLinus Torvalds * @dev_id: PCI device id struct 71601da177e4SLinus Torvalds * 71611da177e4SLinus Torvalds * Return value: 71621da177e4SLinus Torvalds * ptr to chip config on success / NULL on failure 71631da177e4SLinus Torvalds **/ 71641da177e4SLinus Torvalds static const struct ipr_chip_cfg_t * __devinit 71651da177e4SLinus Torvalds ipr_get_chip_cfg(const struct pci_device_id *dev_id) 71661da177e4SLinus Torvalds { 71671da177e4SLinus Torvalds int i; 71681da177e4SLinus Torvalds 71691da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) 71701da177e4SLinus Torvalds if (ipr_chip[i].vendor == dev_id->vendor && 71711da177e4SLinus Torvalds ipr_chip[i].device == dev_id->device) 71721da177e4SLinus Torvalds return ipr_chip[i].cfg; 71731da177e4SLinus Torvalds return NULL; 71741da177e4SLinus Torvalds } 71751da177e4SLinus Torvalds 71761da177e4SLinus Torvalds /** 71771da177e4SLinus Torvalds * ipr_probe_ioa - Allocates memory and does first stage of initialization 71781da177e4SLinus Torvalds * @pdev: PCI device struct 71791da177e4SLinus Torvalds * @dev_id: PCI device id struct 71801da177e4SLinus Torvalds * 71811da177e4SLinus Torvalds * Return value: 71821da177e4SLinus Torvalds * 0 on success / non-zero on failure 71831da177e4SLinus Torvalds **/ 71841da177e4SLinus Torvalds static int __devinit ipr_probe_ioa(struct pci_dev *pdev, 71851da177e4SLinus Torvalds const struct pci_device_id *dev_id) 71861da177e4SLinus Torvalds { 71871da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 71881da177e4SLinus Torvalds struct Scsi_Host *host; 71891da177e4SLinus Torvalds unsigned long ipr_regs_pci; 71901da177e4SLinus Torvalds void __iomem *ipr_regs; 7191a2a65a3eSEric Sesterhenn int rc = PCIBIOS_SUCCESSFUL; 7192ce155cceSbrking@us.ibm.com volatile u32 mask, uproc; 71931da177e4SLinus Torvalds 71941da177e4SLinus Torvalds ENTER; 71951da177e4SLinus Torvalds 71961da177e4SLinus Torvalds if ((rc = pci_enable_device(pdev))) { 71971da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot enable adapter\n"); 71981da177e4SLinus Torvalds goto out; 71991da177e4SLinus Torvalds } 72001da177e4SLinus Torvalds 72011da177e4SLinus Torvalds dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); 72021da177e4SLinus Torvalds 72031da177e4SLinus Torvalds host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); 72041da177e4SLinus Torvalds 72051da177e4SLinus Torvalds if (!host) { 72061da177e4SLinus Torvalds dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n"); 72071da177e4SLinus Torvalds rc = -ENOMEM; 72081da177e4SLinus Torvalds goto out_disable; 72091da177e4SLinus Torvalds } 72101da177e4SLinus Torvalds 72111da177e4SLinus Torvalds ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; 72121da177e4SLinus Torvalds memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); 721335a39691SBrian King ata_host_init(&ioa_cfg->ata_host, &pdev->dev, 721435a39691SBrian King sata_port_info.flags, &ipr_sata_ops); 72151da177e4SLinus Torvalds 72161da177e4SLinus Torvalds ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id); 72171da177e4SLinus Torvalds 72181da177e4SLinus Torvalds if (!ioa_cfg->chip_cfg) { 72191da177e4SLinus Torvalds dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n", 72201da177e4SLinus Torvalds dev_id->vendor, dev_id->device); 72211da177e4SLinus Torvalds goto out_scsi_host_put; 72221da177e4SLinus Torvalds } 72231da177e4SLinus Torvalds 72241da177e4SLinus Torvalds ipr_regs_pci = pci_resource_start(pdev, 0); 72251da177e4SLinus Torvalds 72261da177e4SLinus Torvalds rc = pci_request_regions(pdev, IPR_NAME); 72271da177e4SLinus Torvalds if (rc < 0) { 72281da177e4SLinus Torvalds dev_err(&pdev->dev, 72291da177e4SLinus Torvalds "Couldn't register memory range of registers\n"); 72301da177e4SLinus Torvalds goto out_scsi_host_put; 72311da177e4SLinus Torvalds } 72321da177e4SLinus Torvalds 72331da177e4SLinus Torvalds ipr_regs = ioremap(ipr_regs_pci, pci_resource_len(pdev, 0)); 72341da177e4SLinus Torvalds 72351da177e4SLinus Torvalds if (!ipr_regs) { 72361da177e4SLinus Torvalds dev_err(&pdev->dev, 72371da177e4SLinus Torvalds "Couldn't map memory range of registers\n"); 72381da177e4SLinus Torvalds rc = -ENOMEM; 72391da177e4SLinus Torvalds goto out_release_regions; 72401da177e4SLinus Torvalds } 72411da177e4SLinus Torvalds 72421da177e4SLinus Torvalds ioa_cfg->hdw_dma_regs = ipr_regs; 72431da177e4SLinus Torvalds ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci; 72441da177e4SLinus Torvalds ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs; 72451da177e4SLinus Torvalds 72461da177e4SLinus Torvalds ipr_init_ioa_cfg(ioa_cfg, host, pdev); 72471da177e4SLinus Torvalds 72481da177e4SLinus Torvalds pci_set_master(pdev); 72491da177e4SLinus Torvalds 72501da177e4SLinus Torvalds rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 72511da177e4SLinus Torvalds if (rc < 0) { 72521da177e4SLinus Torvalds dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); 72531da177e4SLinus Torvalds goto cleanup_nomem; 72541da177e4SLinus Torvalds } 72551da177e4SLinus Torvalds 72561da177e4SLinus Torvalds rc = pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 72571da177e4SLinus Torvalds ioa_cfg->chip_cfg->cache_line_size); 72581da177e4SLinus Torvalds 72591da177e4SLinus Torvalds if (rc != PCIBIOS_SUCCESSFUL) { 72601da177e4SLinus Torvalds dev_err(&pdev->dev, "Write of cache line size failed\n"); 72611da177e4SLinus Torvalds rc = -EIO; 72621da177e4SLinus Torvalds goto cleanup_nomem; 72631da177e4SLinus Torvalds } 72641da177e4SLinus Torvalds 72651da177e4SLinus Torvalds /* Save away PCI config space for use following IOA reset */ 72661da177e4SLinus Torvalds rc = pci_save_state(pdev); 72671da177e4SLinus Torvalds 72681da177e4SLinus Torvalds if (rc != PCIBIOS_SUCCESSFUL) { 72691da177e4SLinus Torvalds dev_err(&pdev->dev, "Failed to save PCI config space\n"); 72701da177e4SLinus Torvalds rc = -EIO; 72711da177e4SLinus Torvalds goto cleanup_nomem; 72721da177e4SLinus Torvalds } 72731da177e4SLinus Torvalds 72741da177e4SLinus Torvalds if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg))) 72751da177e4SLinus Torvalds goto cleanup_nomem; 72761da177e4SLinus Torvalds 72771da177e4SLinus Torvalds if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg))) 72781da177e4SLinus Torvalds goto cleanup_nomem; 72791da177e4SLinus Torvalds 72801da177e4SLinus Torvalds rc = ipr_alloc_mem(ioa_cfg); 72811da177e4SLinus Torvalds if (rc < 0) { 72821da177e4SLinus Torvalds dev_err(&pdev->dev, 72831da177e4SLinus Torvalds "Couldn't allocate enough memory for device driver!\n"); 72841da177e4SLinus Torvalds goto cleanup_nomem; 72851da177e4SLinus Torvalds } 72861da177e4SLinus Torvalds 7287ce155cceSbrking@us.ibm.com /* 7288ce155cceSbrking@us.ibm.com * If HRRQ updated interrupt is not masked, or reset alert is set, 7289ce155cceSbrking@us.ibm.com * the card is in an unknown state and needs a hard reset 7290ce155cceSbrking@us.ibm.com */ 7291ce155cceSbrking@us.ibm.com mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg); 7292ce155cceSbrking@us.ibm.com uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg); 7293ce155cceSbrking@us.ibm.com if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT)) 7294ce155cceSbrking@us.ibm.com ioa_cfg->needs_hard_reset = 1; 7295ce155cceSbrking@us.ibm.com 72961da177e4SLinus Torvalds ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); 72971d6f359aSThomas Gleixner rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); 72981da177e4SLinus Torvalds 72991da177e4SLinus Torvalds if (rc) { 73001da177e4SLinus Torvalds dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", 73011da177e4SLinus Torvalds pdev->irq, rc); 73021da177e4SLinus Torvalds goto cleanup_nolog; 73031da177e4SLinus Torvalds } 73041da177e4SLinus Torvalds 73051da177e4SLinus Torvalds spin_lock(&ipr_driver_lock); 73061da177e4SLinus Torvalds list_add_tail(&ioa_cfg->queue, &ipr_ioa_head); 73071da177e4SLinus Torvalds spin_unlock(&ipr_driver_lock); 73081da177e4SLinus Torvalds 73091da177e4SLinus Torvalds LEAVE; 73101da177e4SLinus Torvalds out: 73111da177e4SLinus Torvalds return rc; 73121da177e4SLinus Torvalds 73131da177e4SLinus Torvalds cleanup_nolog: 73141da177e4SLinus Torvalds ipr_free_mem(ioa_cfg); 73151da177e4SLinus Torvalds cleanup_nomem: 73161da177e4SLinus Torvalds iounmap(ipr_regs); 73171da177e4SLinus Torvalds out_release_regions: 73181da177e4SLinus Torvalds pci_release_regions(pdev); 73191da177e4SLinus Torvalds out_scsi_host_put: 73201da177e4SLinus Torvalds scsi_host_put(host); 73211da177e4SLinus Torvalds out_disable: 73221da177e4SLinus Torvalds pci_disable_device(pdev); 73231da177e4SLinus Torvalds goto out; 73241da177e4SLinus Torvalds } 73251da177e4SLinus Torvalds 73261da177e4SLinus Torvalds /** 73271da177e4SLinus Torvalds * ipr_scan_vsets - Scans for VSET devices 73281da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 73291da177e4SLinus Torvalds * 73301da177e4SLinus Torvalds * Description: Since the VSET resources do not follow SAM in that we can have 73311da177e4SLinus Torvalds * sparse LUNs with no LUN 0, we have to scan for these ourselves. 73321da177e4SLinus Torvalds * 73331da177e4SLinus Torvalds * Return value: 73341da177e4SLinus Torvalds * none 73351da177e4SLinus Torvalds **/ 73361da177e4SLinus Torvalds static void ipr_scan_vsets(struct ipr_ioa_cfg *ioa_cfg) 73371da177e4SLinus Torvalds { 73381da177e4SLinus Torvalds int target, lun; 73391da177e4SLinus Torvalds 73401da177e4SLinus Torvalds for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++) 73411da177e4SLinus Torvalds for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ ) 73421da177e4SLinus Torvalds scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun); 73431da177e4SLinus Torvalds } 73441da177e4SLinus Torvalds 73451da177e4SLinus Torvalds /** 73461da177e4SLinus Torvalds * ipr_initiate_ioa_bringdown - Bring down an adapter 73471da177e4SLinus Torvalds * @ioa_cfg: ioa config struct 73481da177e4SLinus Torvalds * @shutdown_type: shutdown type 73491da177e4SLinus Torvalds * 73501da177e4SLinus Torvalds * Description: This function will initiate bringing down the adapter. 73511da177e4SLinus Torvalds * This consists of issuing an IOA shutdown to the adapter 73521da177e4SLinus Torvalds * to flush the cache, and running BIST. 73531da177e4SLinus Torvalds * If the caller needs to wait on the completion of the reset, 73541da177e4SLinus Torvalds * the caller must sleep on the reset_wait_q. 73551da177e4SLinus Torvalds * 73561da177e4SLinus Torvalds * Return value: 73571da177e4SLinus Torvalds * none 73581da177e4SLinus Torvalds **/ 73591da177e4SLinus Torvalds static void ipr_initiate_ioa_bringdown(struct ipr_ioa_cfg *ioa_cfg, 73601da177e4SLinus Torvalds enum ipr_shutdown_type shutdown_type) 73611da177e4SLinus Torvalds { 73621da177e4SLinus Torvalds ENTER; 73631da177e4SLinus Torvalds if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) 73641da177e4SLinus Torvalds ioa_cfg->sdt_state = ABORT_DUMP; 73651da177e4SLinus Torvalds ioa_cfg->reset_retries = 0; 73661da177e4SLinus Torvalds ioa_cfg->in_ioa_bringdown = 1; 73671da177e4SLinus Torvalds ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); 73681da177e4SLinus Torvalds LEAVE; 73691da177e4SLinus Torvalds } 73701da177e4SLinus Torvalds 73711da177e4SLinus Torvalds /** 73721da177e4SLinus Torvalds * __ipr_remove - Remove a single adapter 73731da177e4SLinus Torvalds * @pdev: pci device struct 73741da177e4SLinus Torvalds * 73751da177e4SLinus Torvalds * Adapter hot plug remove entry point. 73761da177e4SLinus Torvalds * 73771da177e4SLinus Torvalds * Return value: 73781da177e4SLinus Torvalds * none 73791da177e4SLinus Torvalds **/ 73801da177e4SLinus Torvalds static void __ipr_remove(struct pci_dev *pdev) 73811da177e4SLinus Torvalds { 73821da177e4SLinus Torvalds unsigned long host_lock_flags = 0; 73831da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 73841da177e4SLinus Torvalds ENTER; 73851da177e4SLinus Torvalds 73861da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); 73871da177e4SLinus Torvalds ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); 73881da177e4SLinus Torvalds 73891da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); 73901da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 73915cbf5eaeSbrking@us.ibm.com flush_scheduled_work(); 73921da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); 73931da177e4SLinus Torvalds 73941da177e4SLinus Torvalds spin_lock(&ipr_driver_lock); 73951da177e4SLinus Torvalds list_del(&ioa_cfg->queue); 73961da177e4SLinus Torvalds spin_unlock(&ipr_driver_lock); 73971da177e4SLinus Torvalds 73981da177e4SLinus Torvalds if (ioa_cfg->sdt_state == ABORT_DUMP) 73991da177e4SLinus Torvalds ioa_cfg->sdt_state = WAIT_FOR_DUMP; 74001da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); 74011da177e4SLinus Torvalds 74021da177e4SLinus Torvalds ipr_free_all_resources(ioa_cfg); 74031da177e4SLinus Torvalds 74041da177e4SLinus Torvalds LEAVE; 74051da177e4SLinus Torvalds } 74061da177e4SLinus Torvalds 74071da177e4SLinus Torvalds /** 74081da177e4SLinus Torvalds * ipr_remove - IOA hot plug remove entry point 74091da177e4SLinus Torvalds * @pdev: pci device struct 74101da177e4SLinus Torvalds * 74111da177e4SLinus Torvalds * Adapter hot plug remove entry point. 74121da177e4SLinus Torvalds * 74131da177e4SLinus Torvalds * Return value: 74141da177e4SLinus Torvalds * none 74151da177e4SLinus Torvalds **/ 74161da177e4SLinus Torvalds static void ipr_remove(struct pci_dev *pdev) 74171da177e4SLinus Torvalds { 74181da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 74191da177e4SLinus Torvalds 74201da177e4SLinus Torvalds ENTER; 74211da177e4SLinus Torvalds 74221da177e4SLinus Torvalds ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, 74231da177e4SLinus Torvalds &ipr_trace_attr); 74241da177e4SLinus Torvalds ipr_remove_dump_file(&ioa_cfg->host->shost_classdev.kobj, 74251da177e4SLinus Torvalds &ipr_dump_attr); 74261da177e4SLinus Torvalds scsi_remove_host(ioa_cfg->host); 74271da177e4SLinus Torvalds 74281da177e4SLinus Torvalds __ipr_remove(pdev); 74291da177e4SLinus Torvalds 74301da177e4SLinus Torvalds LEAVE; 74311da177e4SLinus Torvalds } 74321da177e4SLinus Torvalds 74331da177e4SLinus Torvalds /** 74341da177e4SLinus Torvalds * ipr_probe - Adapter hot plug add entry point 74351da177e4SLinus Torvalds * 74361da177e4SLinus Torvalds * Return value: 74371da177e4SLinus Torvalds * 0 on success / non-zero on failure 74381da177e4SLinus Torvalds **/ 74391da177e4SLinus Torvalds static int __devinit ipr_probe(struct pci_dev *pdev, 74401da177e4SLinus Torvalds const struct pci_device_id *dev_id) 74411da177e4SLinus Torvalds { 74421da177e4SLinus Torvalds struct ipr_ioa_cfg *ioa_cfg; 74431da177e4SLinus Torvalds int rc; 74441da177e4SLinus Torvalds 74451da177e4SLinus Torvalds rc = ipr_probe_ioa(pdev, dev_id); 74461da177e4SLinus Torvalds 74471da177e4SLinus Torvalds if (rc) 74481da177e4SLinus Torvalds return rc; 74491da177e4SLinus Torvalds 74501da177e4SLinus Torvalds ioa_cfg = pci_get_drvdata(pdev); 74511da177e4SLinus Torvalds rc = ipr_probe_ioa_part2(ioa_cfg); 74521da177e4SLinus Torvalds 74531da177e4SLinus Torvalds if (rc) { 74541da177e4SLinus Torvalds __ipr_remove(pdev); 74551da177e4SLinus Torvalds return rc; 74561da177e4SLinus Torvalds } 74571da177e4SLinus Torvalds 74581da177e4SLinus Torvalds rc = scsi_add_host(ioa_cfg->host, &pdev->dev); 74591da177e4SLinus Torvalds 74601da177e4SLinus Torvalds if (rc) { 74611da177e4SLinus Torvalds __ipr_remove(pdev); 74621da177e4SLinus Torvalds return rc; 74631da177e4SLinus Torvalds } 74641da177e4SLinus Torvalds 74651da177e4SLinus Torvalds rc = ipr_create_trace_file(&ioa_cfg->host->shost_classdev.kobj, 74661da177e4SLinus Torvalds &ipr_trace_attr); 74671da177e4SLinus Torvalds 74681da177e4SLinus Torvalds if (rc) { 74691da177e4SLinus Torvalds scsi_remove_host(ioa_cfg->host); 74701da177e4SLinus Torvalds __ipr_remove(pdev); 74711da177e4SLinus Torvalds return rc; 74721da177e4SLinus Torvalds } 74731da177e4SLinus Torvalds 74741da177e4SLinus Torvalds rc = ipr_create_dump_file(&ioa_cfg->host->shost_classdev.kobj, 74751da177e4SLinus Torvalds &ipr_dump_attr); 74761da177e4SLinus Torvalds 74771da177e4SLinus Torvalds if (rc) { 74781da177e4SLinus Torvalds ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, 74791da177e4SLinus Torvalds &ipr_trace_attr); 74801da177e4SLinus Torvalds scsi_remove_host(ioa_cfg->host); 74811da177e4SLinus Torvalds __ipr_remove(pdev); 74821da177e4SLinus Torvalds return rc; 74831da177e4SLinus Torvalds } 74841da177e4SLinus Torvalds 74851da177e4SLinus Torvalds scsi_scan_host(ioa_cfg->host); 74861da177e4SLinus Torvalds ipr_scan_vsets(ioa_cfg); 74871da177e4SLinus Torvalds scsi_add_device(ioa_cfg->host, IPR_IOA_BUS, IPR_IOA_TARGET, IPR_IOA_LUN); 74881da177e4SLinus Torvalds ioa_cfg->allow_ml_add_del = 1; 748911cd8f12Sbrking@us.ibm.com ioa_cfg->host->max_channel = IPR_VSET_BUS; 74901da177e4SLinus Torvalds schedule_work(&ioa_cfg->work_q); 74911da177e4SLinus Torvalds return 0; 74921da177e4SLinus Torvalds } 74931da177e4SLinus Torvalds 74941da177e4SLinus Torvalds /** 74951da177e4SLinus Torvalds * ipr_shutdown - Shutdown handler. 7496d18c3db5SGreg Kroah-Hartman * @pdev: pci device struct 74971da177e4SLinus Torvalds * 74981da177e4SLinus Torvalds * This function is invoked upon system shutdown/reboot. It will issue 74991da177e4SLinus Torvalds * an adapter shutdown to the adapter to flush the write cache. 75001da177e4SLinus Torvalds * 75011da177e4SLinus Torvalds * Return value: 75021da177e4SLinus Torvalds * none 75031da177e4SLinus Torvalds **/ 7504d18c3db5SGreg Kroah-Hartman static void ipr_shutdown(struct pci_dev *pdev) 75051da177e4SLinus Torvalds { 7506d18c3db5SGreg Kroah-Hartman struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); 75071da177e4SLinus Torvalds unsigned long lock_flags = 0; 75081da177e4SLinus Torvalds 75091da177e4SLinus Torvalds spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); 75101da177e4SLinus Torvalds ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); 75111da177e4SLinus Torvalds spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); 75121da177e4SLinus Torvalds wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); 75131da177e4SLinus Torvalds } 75141da177e4SLinus Torvalds 75151da177e4SLinus Torvalds static struct pci_device_id ipr_pci_table[] __devinitdata = { 75161da177e4SLinus Torvalds { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, 7517*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 }, 75181da177e4SLinus Torvalds { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, 7519*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, 0, 0, 0 }, 75201da177e4SLinus Torvalds { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, 7521*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, 0 }, 75221da177e4SLinus Torvalds { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, 7523*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, 0, 0, 0 }, 75241da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, 7525*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, 0, 0, 0 }, 75261da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, 7527*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, 0, 0, 0 }, 75281da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, 7529*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 }, 753086f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, 7531*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 }, 753286f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, 7533*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, 753486f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, 7535*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, 753660e7486bSBrian King { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, 7537*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, 753886f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, 7539*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, 754086f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, 7541*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, 754260e7486bSBrian King { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, 7543*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 }, 754460e7486bSBrian King { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, 7545*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8, 0, 0, 0 }, 754660e7486bSBrian King { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, 7547*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 }, 75481da177e4SLinus Torvalds { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, 7549*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, 75501da177e4SLinus Torvalds { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, 7551*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 }, 755286f51436Sbrking@us.ibm.com { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, 7553*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 }, 755460e7486bSBrian King { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, 7555*6d84c944SBrian King PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 }, 75561da177e4SLinus Torvalds { } 75571da177e4SLinus Torvalds }; 75581da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, ipr_pci_table); 75591da177e4SLinus Torvalds 7560f8a88b19SLinas Vepstas static struct pci_error_handlers ipr_err_handler = { 7561f8a88b19SLinas Vepstas .error_detected = ipr_pci_error_detected, 7562f8a88b19SLinas Vepstas .slot_reset = ipr_pci_slot_reset, 7563f8a88b19SLinas Vepstas }; 7564f8a88b19SLinas Vepstas 75651da177e4SLinus Torvalds static struct pci_driver ipr_driver = { 75661da177e4SLinus Torvalds .name = IPR_NAME, 75671da177e4SLinus Torvalds .id_table = ipr_pci_table, 75681da177e4SLinus Torvalds .probe = ipr_probe, 75691da177e4SLinus Torvalds .remove = ipr_remove, 75701da177e4SLinus Torvalds .shutdown = ipr_shutdown, 7571f8a88b19SLinas Vepstas .err_handler = &ipr_err_handler, 75721da177e4SLinus Torvalds }; 75731da177e4SLinus Torvalds 75741da177e4SLinus Torvalds /** 75751da177e4SLinus Torvalds * ipr_init - Module entry point 75761da177e4SLinus Torvalds * 75771da177e4SLinus Torvalds * Return value: 75781da177e4SLinus Torvalds * 0 on success / negative value on failure 75791da177e4SLinus Torvalds **/ 75801da177e4SLinus Torvalds static int __init ipr_init(void) 75811da177e4SLinus Torvalds { 75821da177e4SLinus Torvalds ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", 75831da177e4SLinus Torvalds IPR_DRIVER_VERSION, IPR_DRIVER_DATE); 75841da177e4SLinus Torvalds 7585dcbccbdeSHenrik Kretzschmar return pci_register_driver(&ipr_driver); 75861da177e4SLinus Torvalds } 75871da177e4SLinus Torvalds 75881da177e4SLinus Torvalds /** 75891da177e4SLinus Torvalds * ipr_exit - Module unload 75901da177e4SLinus Torvalds * 75911da177e4SLinus Torvalds * Module unload entry point. 75921da177e4SLinus Torvalds * 75931da177e4SLinus Torvalds * Return value: 75941da177e4SLinus Torvalds * none 75951da177e4SLinus Torvalds **/ 75961da177e4SLinus Torvalds static void __exit ipr_exit(void) 75971da177e4SLinus Torvalds { 75981da177e4SLinus Torvalds pci_unregister_driver(&ipr_driver); 75991da177e4SLinus Torvalds } 76001da177e4SLinus Torvalds 76011da177e4SLinus Torvalds module_init(ipr_init); 76021da177e4SLinus Torvalds module_exit(ipr_exit); 7603