xref: /openbmc/linux/drivers/scsi/ipr.c (revision 6d84c944fa17cf4e65660df50a0772f8a4836e0b)
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