162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *    Disk Array driver for HP Smart Array SAS controllers
362306a36Sopenharmony_ci *    Copyright (c) 2019-2020 Microchip Technology Inc. and its subsidiaries
462306a36Sopenharmony_ci *    Copyright 2016 Microsemi Corporation
562306a36Sopenharmony_ci *    Copyright 2014-2015 PMC-Sierra, Inc.
662306a36Sopenharmony_ci *    Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *    This program is free software; you can redistribute it and/or modify
962306a36Sopenharmony_ci *    it under the terms of the GNU General Public License as published by
1062306a36Sopenharmony_ci *    the Free Software Foundation; version 2 of the License.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *    This program is distributed in the hope that it will be useful,
1362306a36Sopenharmony_ci *    but WITHOUT ANY WARRANTY; without even the implied warranty of
1462306a36Sopenharmony_ci *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
1562306a36Sopenharmony_ci *    NON INFRINGEMENT.  See the GNU General Public License for more details.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *    Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/module.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci#include <linux/types.h>
2462306a36Sopenharmony_ci#include <linux/pci.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci#include <linux/delay.h>
2862306a36Sopenharmony_ci#include <linux/fs.h>
2962306a36Sopenharmony_ci#include <linux/timer.h>
3062306a36Sopenharmony_ci#include <linux/init.h>
3162306a36Sopenharmony_ci#include <linux/spinlock.h>
3262306a36Sopenharmony_ci#include <linux/compat.h>
3362306a36Sopenharmony_ci#include <linux/blktrace_api.h>
3462306a36Sopenharmony_ci#include <linux/uaccess.h>
3562306a36Sopenharmony_ci#include <linux/io.h>
3662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
3762306a36Sopenharmony_ci#include <linux/completion.h>
3862306a36Sopenharmony_ci#include <linux/moduleparam.h>
3962306a36Sopenharmony_ci#include <scsi/scsi.h>
4062306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
4162306a36Sopenharmony_ci#include <scsi/scsi_device.h>
4262306a36Sopenharmony_ci#include <scsi/scsi_host.h>
4362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
4462306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
4562306a36Sopenharmony_ci#include <scsi/scsi_transport_sas.h>
4662306a36Sopenharmony_ci#include <scsi/scsi_dbg.h>
4762306a36Sopenharmony_ci#include <linux/cciss_ioctl.h>
4862306a36Sopenharmony_ci#include <linux/string.h>
4962306a36Sopenharmony_ci#include <linux/bitmap.h>
5062306a36Sopenharmony_ci#include <linux/atomic.h>
5162306a36Sopenharmony_ci#include <linux/jiffies.h>
5262306a36Sopenharmony_ci#include <linux/percpu-defs.h>
5362306a36Sopenharmony_ci#include <linux/percpu.h>
5462306a36Sopenharmony_ci#include <asm/unaligned.h>
5562306a36Sopenharmony_ci#include <asm/div64.h>
5662306a36Sopenharmony_ci#include "hpsa_cmd.h"
5762306a36Sopenharmony_ci#include "hpsa.h"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
6162306a36Sopenharmony_ci * with an optional trailing '-' followed by a byte value (0-255).
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ci#define HPSA_DRIVER_VERSION "3.4.20-200"
6462306a36Sopenharmony_ci#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
6562306a36Sopenharmony_ci#define HPSA "hpsa"
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* How long to wait for CISS doorbell communication */
6862306a36Sopenharmony_ci#define CLEAR_EVENT_WAIT_INTERVAL 20	/* ms for each msleep() call */
6962306a36Sopenharmony_ci#define MODE_CHANGE_WAIT_INTERVAL 10	/* ms for each msleep() call */
7062306a36Sopenharmony_ci#define MAX_CLEAR_EVENT_WAIT 30000	/* times 20 ms = 600 s */
7162306a36Sopenharmony_ci#define MAX_MODE_CHANGE_WAIT 2000	/* times 10 ms = 20 s */
7262306a36Sopenharmony_ci#define MAX_IOCTL_CONFIG_WAIT 1000
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/*define how many times we will try a command because of bus resets */
7562306a36Sopenharmony_ci#define MAX_CMD_RETRIES 3
7662306a36Sopenharmony_ci/* How long to wait before giving up on a command */
7762306a36Sopenharmony_ci#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Embedded module documentation macros - see modules.h */
8062306a36Sopenharmony_ciMODULE_AUTHOR("Hewlett-Packard Company");
8162306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \
8262306a36Sopenharmony_ci	HPSA_DRIVER_VERSION);
8362306a36Sopenharmony_ciMODULE_VERSION(HPSA_DRIVER_VERSION);
8462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
8562306a36Sopenharmony_ciMODULE_ALIAS("cciss");
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int hpsa_simple_mode;
8862306a36Sopenharmony_cimodule_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
8962306a36Sopenharmony_ciMODULE_PARM_DESC(hpsa_simple_mode,
9062306a36Sopenharmony_ci	"Use 'simple mode' rather than 'performant mode'");
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* define the PCI info for the cards we can control */
9362306a36Sopenharmony_cistatic const struct pci_device_id hpsa_pci_device_id[] = {
9462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
9562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
9662306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
9762306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
9862306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
9962306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324A},
10062306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324B},
10162306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3233},
10262306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3350},
10362306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3351},
10462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3352},
10562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3353},
10662306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3354},
10762306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3355},
10862306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3356},
10962306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103c, 0x1920},
11062306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1921},
11162306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1922},
11262306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1923},
11362306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1924},
11462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103c, 0x1925},
11562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1926},
11662306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1928},
11762306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1929},
11862306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BD},
11962306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BE},
12062306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BF},
12162306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C0},
12262306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C1},
12362306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C2},
12462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C3},
12562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C4},
12662306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C5},
12762306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C6},
12862306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C7},
12962306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C8},
13062306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C9},
13162306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21CA},
13262306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21CB},
13362306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21CC},
13462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21CD},
13562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21CE},
13662306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0580},
13762306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0581},
13862306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0582},
13962306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0583},
14062306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0584},
14162306a36Sopenharmony_ci	{PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0585},
14262306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076},
14362306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087},
14462306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D},
14562306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0088},
14662306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP, 0x333f, 0x103c, 0x333f},
14762306a36Sopenharmony_ci	{PCI_VENDOR_ID_HP,     PCI_ANY_ID,	PCI_ANY_ID, PCI_ANY_ID,
14862306a36Sopenharmony_ci		PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
14962306a36Sopenharmony_ci	{PCI_VENDOR_ID_COMPAQ,     PCI_ANY_ID,	PCI_ANY_ID, PCI_ANY_ID,
15062306a36Sopenharmony_ci		PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
15162306a36Sopenharmony_ci	{0,}
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hpsa_pci_device_id);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*  board_id = Subsystem Device ID & Vendor ID
15762306a36Sopenharmony_ci *  product = Marketing Name for the board
15862306a36Sopenharmony_ci *  access = Address of the struct of function pointers
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_cistatic struct board_type products[] = {
16162306a36Sopenharmony_ci	{0x40700E11, "Smart Array 5300", &SA5A_access},
16262306a36Sopenharmony_ci	{0x40800E11, "Smart Array 5i", &SA5B_access},
16362306a36Sopenharmony_ci	{0x40820E11, "Smart Array 532", &SA5B_access},
16462306a36Sopenharmony_ci	{0x40830E11, "Smart Array 5312", &SA5B_access},
16562306a36Sopenharmony_ci	{0x409A0E11, "Smart Array 641", &SA5A_access},
16662306a36Sopenharmony_ci	{0x409B0E11, "Smart Array 642", &SA5A_access},
16762306a36Sopenharmony_ci	{0x409C0E11, "Smart Array 6400", &SA5A_access},
16862306a36Sopenharmony_ci	{0x409D0E11, "Smart Array 6400 EM", &SA5A_access},
16962306a36Sopenharmony_ci	{0x40910E11, "Smart Array 6i", &SA5A_access},
17062306a36Sopenharmony_ci	{0x3225103C, "Smart Array P600", &SA5A_access},
17162306a36Sopenharmony_ci	{0x3223103C, "Smart Array P800", &SA5A_access},
17262306a36Sopenharmony_ci	{0x3234103C, "Smart Array P400", &SA5A_access},
17362306a36Sopenharmony_ci	{0x3235103C, "Smart Array P400i", &SA5A_access},
17462306a36Sopenharmony_ci	{0x3211103C, "Smart Array E200i", &SA5A_access},
17562306a36Sopenharmony_ci	{0x3212103C, "Smart Array E200", &SA5A_access},
17662306a36Sopenharmony_ci	{0x3213103C, "Smart Array E200i", &SA5A_access},
17762306a36Sopenharmony_ci	{0x3214103C, "Smart Array E200i", &SA5A_access},
17862306a36Sopenharmony_ci	{0x3215103C, "Smart Array E200i", &SA5A_access},
17962306a36Sopenharmony_ci	{0x3237103C, "Smart Array E500", &SA5A_access},
18062306a36Sopenharmony_ci	{0x323D103C, "Smart Array P700m", &SA5A_access},
18162306a36Sopenharmony_ci	{0x3241103C, "Smart Array P212", &SA5_access},
18262306a36Sopenharmony_ci	{0x3243103C, "Smart Array P410", &SA5_access},
18362306a36Sopenharmony_ci	{0x3245103C, "Smart Array P410i", &SA5_access},
18462306a36Sopenharmony_ci	{0x3247103C, "Smart Array P411", &SA5_access},
18562306a36Sopenharmony_ci	{0x3249103C, "Smart Array P812", &SA5_access},
18662306a36Sopenharmony_ci	{0x324A103C, "Smart Array P712m", &SA5_access},
18762306a36Sopenharmony_ci	{0x324B103C, "Smart Array P711m", &SA5_access},
18862306a36Sopenharmony_ci	{0x3233103C, "HP StorageWorks 1210m", &SA5_access}, /* alias of 333f */
18962306a36Sopenharmony_ci	{0x3350103C, "Smart Array P222", &SA5_access},
19062306a36Sopenharmony_ci	{0x3351103C, "Smart Array P420", &SA5_access},
19162306a36Sopenharmony_ci	{0x3352103C, "Smart Array P421", &SA5_access},
19262306a36Sopenharmony_ci	{0x3353103C, "Smart Array P822", &SA5_access},
19362306a36Sopenharmony_ci	{0x3354103C, "Smart Array P420i", &SA5_access},
19462306a36Sopenharmony_ci	{0x3355103C, "Smart Array P220i", &SA5_access},
19562306a36Sopenharmony_ci	{0x3356103C, "Smart Array P721m", &SA5_access},
19662306a36Sopenharmony_ci	{0x1920103C, "Smart Array P430i", &SA5_access},
19762306a36Sopenharmony_ci	{0x1921103C, "Smart Array P830i", &SA5_access},
19862306a36Sopenharmony_ci	{0x1922103C, "Smart Array P430", &SA5_access},
19962306a36Sopenharmony_ci	{0x1923103C, "Smart Array P431", &SA5_access},
20062306a36Sopenharmony_ci	{0x1924103C, "Smart Array P830", &SA5_access},
20162306a36Sopenharmony_ci	{0x1925103C, "Smart Array P831", &SA5_access},
20262306a36Sopenharmony_ci	{0x1926103C, "Smart Array P731m", &SA5_access},
20362306a36Sopenharmony_ci	{0x1928103C, "Smart Array P230i", &SA5_access},
20462306a36Sopenharmony_ci	{0x1929103C, "Smart Array P530", &SA5_access},
20562306a36Sopenharmony_ci	{0x21BD103C, "Smart Array P244br", &SA5_access},
20662306a36Sopenharmony_ci	{0x21BE103C, "Smart Array P741m", &SA5_access},
20762306a36Sopenharmony_ci	{0x21BF103C, "Smart HBA H240ar", &SA5_access},
20862306a36Sopenharmony_ci	{0x21C0103C, "Smart Array P440ar", &SA5_access},
20962306a36Sopenharmony_ci	{0x21C1103C, "Smart Array P840ar", &SA5_access},
21062306a36Sopenharmony_ci	{0x21C2103C, "Smart Array P440", &SA5_access},
21162306a36Sopenharmony_ci	{0x21C3103C, "Smart Array P441", &SA5_access},
21262306a36Sopenharmony_ci	{0x21C4103C, "Smart Array", &SA5_access},
21362306a36Sopenharmony_ci	{0x21C5103C, "Smart Array P841", &SA5_access},
21462306a36Sopenharmony_ci	{0x21C6103C, "Smart HBA H244br", &SA5_access},
21562306a36Sopenharmony_ci	{0x21C7103C, "Smart HBA H240", &SA5_access},
21662306a36Sopenharmony_ci	{0x21C8103C, "Smart HBA H241", &SA5_access},
21762306a36Sopenharmony_ci	{0x21C9103C, "Smart Array", &SA5_access},
21862306a36Sopenharmony_ci	{0x21CA103C, "Smart Array P246br", &SA5_access},
21962306a36Sopenharmony_ci	{0x21CB103C, "Smart Array P840", &SA5_access},
22062306a36Sopenharmony_ci	{0x21CC103C, "Smart Array", &SA5_access},
22162306a36Sopenharmony_ci	{0x21CD103C, "Smart Array", &SA5_access},
22262306a36Sopenharmony_ci	{0x21CE103C, "Smart HBA", &SA5_access},
22362306a36Sopenharmony_ci	{0x05809005, "SmartHBA-SA", &SA5_access},
22462306a36Sopenharmony_ci	{0x05819005, "SmartHBA-SA 8i", &SA5_access},
22562306a36Sopenharmony_ci	{0x05829005, "SmartHBA-SA 8i8e", &SA5_access},
22662306a36Sopenharmony_ci	{0x05839005, "SmartHBA-SA 8e", &SA5_access},
22762306a36Sopenharmony_ci	{0x05849005, "SmartHBA-SA 16i", &SA5_access},
22862306a36Sopenharmony_ci	{0x05859005, "SmartHBA-SA 4i4e", &SA5_access},
22962306a36Sopenharmony_ci	{0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
23062306a36Sopenharmony_ci	{0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
23162306a36Sopenharmony_ci	{0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
23262306a36Sopenharmony_ci	{0x00881590, "HP Storage P1228e Array Controller", &SA5_access},
23362306a36Sopenharmony_ci	{0x333f103c, "HP StorageWorks 1210m Array Controller", &SA5_access},
23462306a36Sopenharmony_ci	{0xFFFF103C, "Unknown Smart Array", &SA5_access},
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic struct scsi_transport_template *hpsa_sas_transport_template;
23862306a36Sopenharmony_cistatic int hpsa_add_sas_host(struct ctlr_info *h);
23962306a36Sopenharmony_cistatic void hpsa_delete_sas_host(struct ctlr_info *h);
24062306a36Sopenharmony_cistatic int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
24162306a36Sopenharmony_ci			struct hpsa_scsi_dev_t *device);
24262306a36Sopenharmony_cistatic void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device);
24362306a36Sopenharmony_cistatic struct hpsa_scsi_dev_t
24462306a36Sopenharmony_ci	*hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
24562306a36Sopenharmony_ci		struct sas_rphy *rphy);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy)
24862306a36Sopenharmony_cistatic const struct scsi_cmnd hpsa_cmd_busy;
24962306a36Sopenharmony_ci#define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle)
25062306a36Sopenharmony_cistatic const struct scsi_cmnd hpsa_cmd_idle;
25162306a36Sopenharmony_cistatic int number_of_controllers;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
25462306a36Sopenharmony_cistatic irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
25562306a36Sopenharmony_cistatic int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
25662306a36Sopenharmony_ci		      void __user *arg);
25762306a36Sopenharmony_cistatic int hpsa_passthru_ioctl(struct ctlr_info *h,
25862306a36Sopenharmony_ci			       IOCTL_Command_struct *iocommand);
25962306a36Sopenharmony_cistatic int hpsa_big_passthru_ioctl(struct ctlr_info *h,
26062306a36Sopenharmony_ci				   BIG_IOCTL_Command_struct *ioc);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
26362306a36Sopenharmony_cistatic int hpsa_compat_ioctl(struct scsi_device *dev, unsigned int cmd,
26462306a36Sopenharmony_ci	void __user *arg);
26562306a36Sopenharmony_ci#endif
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void cmd_free(struct ctlr_info *h, struct CommandList *c);
26862306a36Sopenharmony_cistatic struct CommandList *cmd_alloc(struct ctlr_info *h);
26962306a36Sopenharmony_cistatic void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c);
27062306a36Sopenharmony_cistatic struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
27162306a36Sopenharmony_ci					    struct scsi_cmnd *scmd);
27262306a36Sopenharmony_cistatic int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
27362306a36Sopenharmony_ci	void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
27462306a36Sopenharmony_ci	int cmd_type);
27562306a36Sopenharmony_cistatic void hpsa_free_cmd_pool(struct ctlr_info *h);
27662306a36Sopenharmony_ci#define VPD_PAGE (1 << 8)
27762306a36Sopenharmony_ci#define HPSA_SIMPLE_ERROR_BITS 0x03
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
28062306a36Sopenharmony_cistatic void hpsa_scan_start(struct Scsi_Host *);
28162306a36Sopenharmony_cistatic int hpsa_scan_finished(struct Scsi_Host *sh,
28262306a36Sopenharmony_ci	unsigned long elapsed_time);
28362306a36Sopenharmony_cistatic int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
28662306a36Sopenharmony_cistatic int hpsa_slave_alloc(struct scsi_device *sdev);
28762306a36Sopenharmony_cistatic int hpsa_slave_configure(struct scsi_device *sdev);
28862306a36Sopenharmony_cistatic void hpsa_slave_destroy(struct scsi_device *sdev);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic void hpsa_update_scsi_devices(struct ctlr_info *h);
29162306a36Sopenharmony_cistatic int check_for_unit_attention(struct ctlr_info *h,
29262306a36Sopenharmony_ci	struct CommandList *c);
29362306a36Sopenharmony_cistatic void check_ioctl_unit_attention(struct ctlr_info *h,
29462306a36Sopenharmony_ci	struct CommandList *c);
29562306a36Sopenharmony_ci/* performant mode helper functions */
29662306a36Sopenharmony_cistatic void calc_bucket_map(int *bucket, int num_buckets,
29762306a36Sopenharmony_ci	int nsgs, int min_blocks, u32 *bucket_map);
29862306a36Sopenharmony_cistatic void hpsa_free_performant_mode(struct ctlr_info *h);
29962306a36Sopenharmony_cistatic int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
30062306a36Sopenharmony_cistatic inline u32 next_command(struct ctlr_info *h, u8 q);
30162306a36Sopenharmony_cistatic int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
30262306a36Sopenharmony_ci			       u32 *cfg_base_addr, u64 *cfg_base_addr_index,
30362306a36Sopenharmony_ci			       u64 *cfg_offset);
30462306a36Sopenharmony_cistatic int hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
30562306a36Sopenharmony_ci				    unsigned long *memory_bar);
30662306a36Sopenharmony_cistatic int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id,
30762306a36Sopenharmony_ci				bool *legacy_board);
30862306a36Sopenharmony_cistatic int wait_for_device_to_become_ready(struct ctlr_info *h,
30962306a36Sopenharmony_ci					   unsigned char lunaddr[],
31062306a36Sopenharmony_ci					   int reply_queue);
31162306a36Sopenharmony_cistatic int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
31262306a36Sopenharmony_ci				     int wait_for_ready);
31362306a36Sopenharmony_cistatic inline void finish_cmd(struct CommandList *c);
31462306a36Sopenharmony_cistatic int hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
31562306a36Sopenharmony_ci#define BOARD_NOT_READY 0
31662306a36Sopenharmony_ci#define BOARD_READY 1
31762306a36Sopenharmony_cistatic void hpsa_drain_accel_commands(struct ctlr_info *h);
31862306a36Sopenharmony_cistatic void hpsa_flush_cache(struct ctlr_info *h);
31962306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
32062306a36Sopenharmony_ci	struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
32162306a36Sopenharmony_ci	u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk);
32262306a36Sopenharmony_cistatic void hpsa_command_resubmit_worker(struct work_struct *work);
32362306a36Sopenharmony_cistatic u32 lockup_detected(struct ctlr_info *h);
32462306a36Sopenharmony_cistatic int detect_controller_lockup(struct ctlr_info *h);
32562306a36Sopenharmony_cistatic void hpsa_disable_rld_caching(struct ctlr_info *h);
32662306a36Sopenharmony_cistatic inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
32762306a36Sopenharmony_ci	struct ReportExtendedLUNdata *buf, int bufsize);
32862306a36Sopenharmony_cistatic bool hpsa_vpd_page_supported(struct ctlr_info *h,
32962306a36Sopenharmony_ci	unsigned char scsi3addr[], u8 page);
33062306a36Sopenharmony_cistatic int hpsa_luns_changed(struct ctlr_info *h);
33162306a36Sopenharmony_cistatic bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
33262306a36Sopenharmony_ci			       struct hpsa_scsi_dev_t *dev,
33362306a36Sopenharmony_ci			       unsigned char *scsi3addr);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	unsigned long *priv = shost_priv(sdev->host);
33862306a36Sopenharmony_ci	return (struct ctlr_info *) *priv;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	unsigned long *priv = shost_priv(sh);
34462306a36Sopenharmony_ci	return (struct ctlr_info *) *priv;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic inline bool hpsa_is_cmd_idle(struct CommandList *c)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	return c->scsi_cmd == SCSI_CMD_IDLE;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/* extract sense key, asc, and ascq from sense data.  -1 means invalid. */
35362306a36Sopenharmony_cistatic void decode_sense_data(const u8 *sense_data, int sense_data_len,
35462306a36Sopenharmony_ci			u8 *sense_key, u8 *asc, u8 *ascq)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct scsi_sense_hdr sshdr;
35762306a36Sopenharmony_ci	bool rc;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	*sense_key = -1;
36062306a36Sopenharmony_ci	*asc = -1;
36162306a36Sopenharmony_ci	*ascq = -1;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (sense_data_len < 1)
36462306a36Sopenharmony_ci		return;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	rc = scsi_normalize_sense(sense_data, sense_data_len, &sshdr);
36762306a36Sopenharmony_ci	if (rc) {
36862306a36Sopenharmony_ci		*sense_key = sshdr.sense_key;
36962306a36Sopenharmony_ci		*asc = sshdr.asc;
37062306a36Sopenharmony_ci		*ascq = sshdr.ascq;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic int check_for_unit_attention(struct ctlr_info *h,
37562306a36Sopenharmony_ci	struct CommandList *c)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	u8 sense_key, asc, ascq;
37862306a36Sopenharmony_ci	int sense_len;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
38162306a36Sopenharmony_ci		sense_len = sizeof(c->err_info->SenseInfo);
38262306a36Sopenharmony_ci	else
38362306a36Sopenharmony_ci		sense_len = c->err_info->SenseLen;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	decode_sense_data(c->err_info->SenseInfo, sense_len,
38662306a36Sopenharmony_ci				&sense_key, &asc, &ascq);
38762306a36Sopenharmony_ci	if (sense_key != UNIT_ATTENTION || asc == 0xff)
38862306a36Sopenharmony_ci		return 0;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	switch (asc) {
39162306a36Sopenharmony_ci	case STATE_CHANGED:
39262306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
39362306a36Sopenharmony_ci			"%s: a state change detected, command retried\n",
39462306a36Sopenharmony_ci			h->devname);
39562306a36Sopenharmony_ci		break;
39662306a36Sopenharmony_ci	case LUN_FAILED:
39762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
39862306a36Sopenharmony_ci			"%s: LUN failure detected\n", h->devname);
39962306a36Sopenharmony_ci		break;
40062306a36Sopenharmony_ci	case REPORT_LUNS_CHANGED:
40162306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
40262306a36Sopenharmony_ci			"%s: report LUN data changed\n", h->devname);
40362306a36Sopenharmony_ci	/*
40462306a36Sopenharmony_ci	 * Note: this REPORT_LUNS_CHANGED condition only occurs on the external
40562306a36Sopenharmony_ci	 * target (array) devices.
40662306a36Sopenharmony_ci	 */
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	case POWER_OR_RESET:
40962306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
41062306a36Sopenharmony_ci			"%s: a power on or device reset detected\n",
41162306a36Sopenharmony_ci			h->devname);
41262306a36Sopenharmony_ci		break;
41362306a36Sopenharmony_ci	case UNIT_ATTENTION_CLEARED:
41462306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
41562306a36Sopenharmony_ci			"%s: unit attention cleared by another initiator\n",
41662306a36Sopenharmony_ci			h->devname);
41762306a36Sopenharmony_ci		break;
41862306a36Sopenharmony_ci	default:
41962306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
42062306a36Sopenharmony_ci			"%s: unknown unit attention detected\n",
42162306a36Sopenharmony_ci			h->devname);
42262306a36Sopenharmony_ci		break;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci	return 1;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int check_for_busy(struct ctlr_info *h, struct CommandList *c)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	if (c->err_info->CommandStatus != CMD_TARGET_STATUS ||
43062306a36Sopenharmony_ci		(c->err_info->ScsiStatus != SAM_STAT_BUSY &&
43162306a36Sopenharmony_ci		 c->err_info->ScsiStatus != SAM_STAT_TASK_SET_FULL))
43262306a36Sopenharmony_ci		return 0;
43362306a36Sopenharmony_ci	dev_warn(&h->pdev->dev, HPSA "device busy");
43462306a36Sopenharmony_ci	return 1;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic u32 lockup_detected(struct ctlr_info *h);
43862306a36Sopenharmony_cistatic ssize_t host_show_lockup_detected(struct device *dev,
43962306a36Sopenharmony_ci		struct device_attribute *attr, char *buf)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	int ld;
44262306a36Sopenharmony_ci	struct ctlr_info *h;
44362306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	h = shost_to_hba(shost);
44662306a36Sopenharmony_ci	ld = lockup_detected(h);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return sprintf(buf, "ld=%d\n", ld);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
45262306a36Sopenharmony_ci					 struct device_attribute *attr,
45362306a36Sopenharmony_ci					 const char *buf, size_t count)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	int status, len;
45662306a36Sopenharmony_ci	struct ctlr_info *h;
45762306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
45862306a36Sopenharmony_ci	char tmpbuf[10];
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
46162306a36Sopenharmony_ci		return -EACCES;
46262306a36Sopenharmony_ci	len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
46362306a36Sopenharmony_ci	strncpy(tmpbuf, buf, len);
46462306a36Sopenharmony_ci	tmpbuf[len] = '\0';
46562306a36Sopenharmony_ci	if (sscanf(tmpbuf, "%d", &status) != 1)
46662306a36Sopenharmony_ci		return -EINVAL;
46762306a36Sopenharmony_ci	h = shost_to_hba(shost);
46862306a36Sopenharmony_ci	h->acciopath_status = !!status;
46962306a36Sopenharmony_ci	dev_warn(&h->pdev->dev,
47062306a36Sopenharmony_ci		"hpsa: HP SSD Smart Path %s via sysfs update.\n",
47162306a36Sopenharmony_ci		h->acciopath_status ? "enabled" : "disabled");
47262306a36Sopenharmony_ci	return count;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic ssize_t host_store_raid_offload_debug(struct device *dev,
47662306a36Sopenharmony_ci					 struct device_attribute *attr,
47762306a36Sopenharmony_ci					 const char *buf, size_t count)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	int debug_level, len;
48062306a36Sopenharmony_ci	struct ctlr_info *h;
48162306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
48262306a36Sopenharmony_ci	char tmpbuf[10];
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
48562306a36Sopenharmony_ci		return -EACCES;
48662306a36Sopenharmony_ci	len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
48762306a36Sopenharmony_ci	strncpy(tmpbuf, buf, len);
48862306a36Sopenharmony_ci	tmpbuf[len] = '\0';
48962306a36Sopenharmony_ci	if (sscanf(tmpbuf, "%d", &debug_level) != 1)
49062306a36Sopenharmony_ci		return -EINVAL;
49162306a36Sopenharmony_ci	if (debug_level < 0)
49262306a36Sopenharmony_ci		debug_level = 0;
49362306a36Sopenharmony_ci	h = shost_to_hba(shost);
49462306a36Sopenharmony_ci	h->raid_offload_debug = debug_level;
49562306a36Sopenharmony_ci	dev_warn(&h->pdev->dev, "hpsa: Set raid_offload_debug level = %d\n",
49662306a36Sopenharmony_ci		h->raid_offload_debug);
49762306a36Sopenharmony_ci	return count;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic ssize_t host_store_rescan(struct device *dev,
50162306a36Sopenharmony_ci				 struct device_attribute *attr,
50262306a36Sopenharmony_ci				 const char *buf, size_t count)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	struct ctlr_info *h;
50562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
50662306a36Sopenharmony_ci	h = shost_to_hba(shost);
50762306a36Sopenharmony_ci	hpsa_scan_start(h->scsi_host);
50862306a36Sopenharmony_ci	return count;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void hpsa_turn_off_ioaccel_for_device(struct hpsa_scsi_dev_t *device)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	device->offload_enabled = 0;
51462306a36Sopenharmony_ci	device->offload_to_be_enabled = 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic ssize_t host_show_firmware_revision(struct device *dev,
51862306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct ctlr_info *h;
52162306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
52262306a36Sopenharmony_ci	unsigned char *fwrev;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	h = shost_to_hba(shost);
52562306a36Sopenharmony_ci	if (!h->hba_inquiry_data)
52662306a36Sopenharmony_ci		return 0;
52762306a36Sopenharmony_ci	fwrev = &h->hba_inquiry_data[32];
52862306a36Sopenharmony_ci	return snprintf(buf, 20, "%c%c%c%c\n",
52962306a36Sopenharmony_ci		fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic ssize_t host_show_commands_outstanding(struct device *dev,
53362306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
53662306a36Sopenharmony_ci	struct ctlr_info *h = shost_to_hba(shost);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return snprintf(buf, 20, "%d\n",
53962306a36Sopenharmony_ci			atomic_read(&h->commands_outstanding));
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic ssize_t host_show_transport_mode(struct device *dev,
54362306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct ctlr_info *h;
54662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	h = shost_to_hba(shost);
54962306a36Sopenharmony_ci	return snprintf(buf, 20, "%s\n",
55062306a36Sopenharmony_ci		h->transMethod & CFGTBL_Trans_Performant ?
55162306a36Sopenharmony_ci			"performant" : "simple");
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic ssize_t host_show_hp_ssd_smart_path_status(struct device *dev,
55562306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct ctlr_info *h;
55862306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	h = shost_to_hba(shost);
56162306a36Sopenharmony_ci	return snprintf(buf, 30, "HP SSD Smart Path %s\n",
56262306a36Sopenharmony_ci		(h->acciopath_status == 1) ?  "enabled" : "disabled");
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/* List of controllers which cannot be hard reset on kexec with reset_devices */
56662306a36Sopenharmony_cistatic u32 unresettable_controller[] = {
56762306a36Sopenharmony_ci	0x324a103C, /* Smart Array P712m */
56862306a36Sopenharmony_ci	0x324b103C, /* Smart Array P711m */
56962306a36Sopenharmony_ci	0x3223103C, /* Smart Array P800 */
57062306a36Sopenharmony_ci	0x3234103C, /* Smart Array P400 */
57162306a36Sopenharmony_ci	0x3235103C, /* Smart Array P400i */
57262306a36Sopenharmony_ci	0x3211103C, /* Smart Array E200i */
57362306a36Sopenharmony_ci	0x3212103C, /* Smart Array E200 */
57462306a36Sopenharmony_ci	0x3213103C, /* Smart Array E200i */
57562306a36Sopenharmony_ci	0x3214103C, /* Smart Array E200i */
57662306a36Sopenharmony_ci	0x3215103C, /* Smart Array E200i */
57762306a36Sopenharmony_ci	0x3237103C, /* Smart Array E500 */
57862306a36Sopenharmony_ci	0x323D103C, /* Smart Array P700m */
57962306a36Sopenharmony_ci	0x40800E11, /* Smart Array 5i */
58062306a36Sopenharmony_ci	0x409C0E11, /* Smart Array 6400 */
58162306a36Sopenharmony_ci	0x409D0E11, /* Smart Array 6400 EM */
58262306a36Sopenharmony_ci	0x40700E11, /* Smart Array 5300 */
58362306a36Sopenharmony_ci	0x40820E11, /* Smart Array 532 */
58462306a36Sopenharmony_ci	0x40830E11, /* Smart Array 5312 */
58562306a36Sopenharmony_ci	0x409A0E11, /* Smart Array 641 */
58662306a36Sopenharmony_ci	0x409B0E11, /* Smart Array 642 */
58762306a36Sopenharmony_ci	0x40910E11, /* Smart Array 6i */
58862306a36Sopenharmony_ci};
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/* List of controllers which cannot even be soft reset */
59162306a36Sopenharmony_cistatic u32 soft_unresettable_controller[] = {
59262306a36Sopenharmony_ci	0x40800E11, /* Smart Array 5i */
59362306a36Sopenharmony_ci	0x40700E11, /* Smart Array 5300 */
59462306a36Sopenharmony_ci	0x40820E11, /* Smart Array 532 */
59562306a36Sopenharmony_ci	0x40830E11, /* Smart Array 5312 */
59662306a36Sopenharmony_ci	0x409A0E11, /* Smart Array 641 */
59762306a36Sopenharmony_ci	0x409B0E11, /* Smart Array 642 */
59862306a36Sopenharmony_ci	0x40910E11, /* Smart Array 6i */
59962306a36Sopenharmony_ci	/* Exclude 640x boards.  These are two pci devices in one slot
60062306a36Sopenharmony_ci	 * which share a battery backed cache module.  One controls the
60162306a36Sopenharmony_ci	 * cache, the other accesses the cache through the one that controls
60262306a36Sopenharmony_ci	 * it.  If we reset the one controlling the cache, the other will
60362306a36Sopenharmony_ci	 * likely not be happy.  Just forbid resetting this conjoined mess.
60462306a36Sopenharmony_ci	 * The 640x isn't really supported by hpsa anyway.
60562306a36Sopenharmony_ci	 */
60662306a36Sopenharmony_ci	0x409C0E11, /* Smart Array 6400 */
60762306a36Sopenharmony_ci	0x409D0E11, /* Smart Array 6400 EM */
60862306a36Sopenharmony_ci};
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic int board_id_in_array(u32 a[], int nelems, u32 board_id)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	int i;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	for (i = 0; i < nelems; i++)
61562306a36Sopenharmony_ci		if (a[i] == board_id)
61662306a36Sopenharmony_ci			return 1;
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic int ctlr_is_hard_resettable(u32 board_id)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	return !board_id_in_array(unresettable_controller,
62362306a36Sopenharmony_ci			ARRAY_SIZE(unresettable_controller), board_id);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int ctlr_is_soft_resettable(u32 board_id)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	return !board_id_in_array(soft_unresettable_controller,
62962306a36Sopenharmony_ci			ARRAY_SIZE(soft_unresettable_controller), board_id);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic int ctlr_is_resettable(u32 board_id)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	return ctlr_is_hard_resettable(board_id) ||
63562306a36Sopenharmony_ci		ctlr_is_soft_resettable(board_id);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic ssize_t host_show_resettable(struct device *dev,
63962306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct ctlr_info *h;
64262306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	h = shost_to_hba(shost);
64562306a36Sopenharmony_ci	return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	return (scsi3addr[3] & 0xC0) == 0x40;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
65462306a36Sopenharmony_ci	"1(+0)ADM", "UNKNOWN", "PHYS DRV"
65562306a36Sopenharmony_ci};
65662306a36Sopenharmony_ci#define HPSA_RAID_0	0
65762306a36Sopenharmony_ci#define HPSA_RAID_4	1
65862306a36Sopenharmony_ci#define HPSA_RAID_1	2	/* also used for RAID 10 */
65962306a36Sopenharmony_ci#define HPSA_RAID_5	3	/* also used for RAID 50 */
66062306a36Sopenharmony_ci#define HPSA_RAID_51	4
66162306a36Sopenharmony_ci#define HPSA_RAID_6	5	/* also used for RAID 60 */
66262306a36Sopenharmony_ci#define HPSA_RAID_ADM	6	/* also used for RAID 1+0 ADM */
66362306a36Sopenharmony_ci#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2)
66462306a36Sopenharmony_ci#define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1)
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic inline bool is_logical_device(struct hpsa_scsi_dev_t *device)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	return !device->physical_device;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic ssize_t raid_level_show(struct device *dev,
67262306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	ssize_t l = 0;
67562306a36Sopenharmony_ci	unsigned char rlevel;
67662306a36Sopenharmony_ci	struct ctlr_info *h;
67762306a36Sopenharmony_ci	struct scsi_device *sdev;
67862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
67962306a36Sopenharmony_ci	unsigned long flags;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
68262306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
68362306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
68462306a36Sopenharmony_ci	hdev = sdev->hostdata;
68562306a36Sopenharmony_ci	if (!hdev) {
68662306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
68762306a36Sopenharmony_ci		return -ENODEV;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/* Is this even a logical drive? */
69162306a36Sopenharmony_ci	if (!is_logical_device(hdev)) {
69262306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
69362306a36Sopenharmony_ci		l = snprintf(buf, PAGE_SIZE, "N/A\n");
69462306a36Sopenharmony_ci		return l;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	rlevel = hdev->raid_level;
69862306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
69962306a36Sopenharmony_ci	if (rlevel > RAID_UNKNOWN)
70062306a36Sopenharmony_ci		rlevel = RAID_UNKNOWN;
70162306a36Sopenharmony_ci	l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]);
70262306a36Sopenharmony_ci	return l;
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic ssize_t lunid_show(struct device *dev,
70662306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct ctlr_info *h;
70962306a36Sopenharmony_ci	struct scsi_device *sdev;
71062306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
71162306a36Sopenharmony_ci	unsigned long flags;
71262306a36Sopenharmony_ci	unsigned char lunid[8];
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
71562306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
71662306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
71762306a36Sopenharmony_ci	hdev = sdev->hostdata;
71862306a36Sopenharmony_ci	if (!hdev) {
71962306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
72062306a36Sopenharmony_ci		return -ENODEV;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	memcpy(lunid, hdev->scsi3addr, sizeof(lunid));
72362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
72462306a36Sopenharmony_ci	return snprintf(buf, 20, "0x%8phN\n", lunid);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic ssize_t unique_id_show(struct device *dev,
72862306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct ctlr_info *h;
73162306a36Sopenharmony_ci	struct scsi_device *sdev;
73262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
73362306a36Sopenharmony_ci	unsigned long flags;
73462306a36Sopenharmony_ci	unsigned char sn[16];
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
73762306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
73862306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
73962306a36Sopenharmony_ci	hdev = sdev->hostdata;
74062306a36Sopenharmony_ci	if (!hdev) {
74162306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
74262306a36Sopenharmony_ci		return -ENODEV;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci	memcpy(sn, hdev->device_id, sizeof(sn));
74562306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
74662306a36Sopenharmony_ci	return snprintf(buf, 16 * 2 + 2,
74762306a36Sopenharmony_ci			"%02X%02X%02X%02X%02X%02X%02X%02X"
74862306a36Sopenharmony_ci			"%02X%02X%02X%02X%02X%02X%02X%02X\n",
74962306a36Sopenharmony_ci			sn[0], sn[1], sn[2], sn[3],
75062306a36Sopenharmony_ci			sn[4], sn[5], sn[6], sn[7],
75162306a36Sopenharmony_ci			sn[8], sn[9], sn[10], sn[11],
75262306a36Sopenharmony_ci			sn[12], sn[13], sn[14], sn[15]);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic ssize_t sas_address_show(struct device *dev,
75662306a36Sopenharmony_ci	      struct device_attribute *attr, char *buf)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct ctlr_info *h;
75962306a36Sopenharmony_ci	struct scsi_device *sdev;
76062306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
76162306a36Sopenharmony_ci	unsigned long flags;
76262306a36Sopenharmony_ci	u64 sas_address;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
76562306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
76662306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
76762306a36Sopenharmony_ci	hdev = sdev->hostdata;
76862306a36Sopenharmony_ci	if (!hdev || is_logical_device(hdev) || !hdev->expose_device) {
76962306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
77062306a36Sopenharmony_ci		return -ENODEV;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	sas_address = hdev->sas_address;
77362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return snprintf(buf, PAGE_SIZE, "0x%016llx\n", sas_address);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_cistatic ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
77962306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct ctlr_info *h;
78262306a36Sopenharmony_ci	struct scsi_device *sdev;
78362306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
78462306a36Sopenharmony_ci	unsigned long flags;
78562306a36Sopenharmony_ci	int offload_enabled;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
78862306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
78962306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
79062306a36Sopenharmony_ci	hdev = sdev->hostdata;
79162306a36Sopenharmony_ci	if (!hdev) {
79262306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
79362306a36Sopenharmony_ci		return -ENODEV;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci	offload_enabled = hdev->offload_enabled;
79662306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (hdev->devtype == TYPE_DISK || hdev->devtype == TYPE_ZBC)
79962306a36Sopenharmony_ci		return snprintf(buf, 20, "%d\n", offload_enabled);
80062306a36Sopenharmony_ci	else
80162306a36Sopenharmony_ci		return snprintf(buf, 40, "%s\n",
80262306a36Sopenharmony_ci				"Not applicable for a controller");
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci#define MAX_PATHS 8
80662306a36Sopenharmony_cistatic ssize_t path_info_show(struct device *dev,
80762306a36Sopenharmony_ci	     struct device_attribute *attr, char *buf)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	struct ctlr_info *h;
81062306a36Sopenharmony_ci	struct scsi_device *sdev;
81162306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev;
81262306a36Sopenharmony_ci	unsigned long flags;
81362306a36Sopenharmony_ci	int i;
81462306a36Sopenharmony_ci	int output_len = 0;
81562306a36Sopenharmony_ci	u8 box;
81662306a36Sopenharmony_ci	u8 bay;
81762306a36Sopenharmony_ci	u8 path_map_index = 0;
81862306a36Sopenharmony_ci	char *active;
81962306a36Sopenharmony_ci	unsigned char phys_connector[2];
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	sdev = to_scsi_device(dev);
82262306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
82362306a36Sopenharmony_ci	spin_lock_irqsave(&h->devlock, flags);
82462306a36Sopenharmony_ci	hdev = sdev->hostdata;
82562306a36Sopenharmony_ci	if (!hdev) {
82662306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->devlock, flags);
82762306a36Sopenharmony_ci		return -ENODEV;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	bay = hdev->bay;
83162306a36Sopenharmony_ci	for (i = 0; i < MAX_PATHS; i++) {
83262306a36Sopenharmony_ci		path_map_index = 1<<i;
83362306a36Sopenharmony_ci		if (i == hdev->active_path_index)
83462306a36Sopenharmony_ci			active = "Active";
83562306a36Sopenharmony_ci		else if (hdev->path_map & path_map_index)
83662306a36Sopenharmony_ci			active = "Inactive";
83762306a36Sopenharmony_ci		else
83862306a36Sopenharmony_ci			continue;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		output_len += scnprintf(buf + output_len,
84162306a36Sopenharmony_ci				PAGE_SIZE - output_len,
84262306a36Sopenharmony_ci				"[%d:%d:%d:%d] %20.20s ",
84362306a36Sopenharmony_ci				h->scsi_host->host_no,
84462306a36Sopenharmony_ci				hdev->bus, hdev->target, hdev->lun,
84562306a36Sopenharmony_ci				scsi_device_type(hdev->devtype));
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
84862306a36Sopenharmony_ci			output_len += scnprintf(buf + output_len,
84962306a36Sopenharmony_ci						PAGE_SIZE - output_len,
85062306a36Sopenharmony_ci						"%s\n", active);
85162306a36Sopenharmony_ci			continue;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		box = hdev->box[i];
85562306a36Sopenharmony_ci		memcpy(&phys_connector, &hdev->phys_connector[i],
85662306a36Sopenharmony_ci			sizeof(phys_connector));
85762306a36Sopenharmony_ci		if (phys_connector[0] < '0')
85862306a36Sopenharmony_ci			phys_connector[0] = '0';
85962306a36Sopenharmony_ci		if (phys_connector[1] < '0')
86062306a36Sopenharmony_ci			phys_connector[1] = '0';
86162306a36Sopenharmony_ci		output_len += scnprintf(buf + output_len,
86262306a36Sopenharmony_ci				PAGE_SIZE - output_len,
86362306a36Sopenharmony_ci				"PORT: %.2s ",
86462306a36Sopenharmony_ci				phys_connector);
86562306a36Sopenharmony_ci		if ((hdev->devtype == TYPE_DISK || hdev->devtype == TYPE_ZBC) &&
86662306a36Sopenharmony_ci			hdev->expose_device) {
86762306a36Sopenharmony_ci			if (box == 0 || box == 0xFF) {
86862306a36Sopenharmony_ci				output_len += scnprintf(buf + output_len,
86962306a36Sopenharmony_ci					PAGE_SIZE - output_len,
87062306a36Sopenharmony_ci					"BAY: %hhu %s\n",
87162306a36Sopenharmony_ci					bay, active);
87262306a36Sopenharmony_ci			} else {
87362306a36Sopenharmony_ci				output_len += scnprintf(buf + output_len,
87462306a36Sopenharmony_ci					PAGE_SIZE - output_len,
87562306a36Sopenharmony_ci					"BOX: %hhu BAY: %hhu %s\n",
87662306a36Sopenharmony_ci					box, bay, active);
87762306a36Sopenharmony_ci			}
87862306a36Sopenharmony_ci		} else if (box != 0 && box != 0xFF) {
87962306a36Sopenharmony_ci			output_len += scnprintf(buf + output_len,
88062306a36Sopenharmony_ci				PAGE_SIZE - output_len, "BOX: %hhu %s\n",
88162306a36Sopenharmony_ci				box, active);
88262306a36Sopenharmony_ci		} else
88362306a36Sopenharmony_ci			output_len += scnprintf(buf + output_len,
88462306a36Sopenharmony_ci				PAGE_SIZE - output_len, "%s\n", active);
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->devlock, flags);
88862306a36Sopenharmony_ci	return output_len;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic ssize_t host_show_ctlr_num(struct device *dev,
89262306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	struct ctlr_info *h;
89562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	h = shost_to_hba(shost);
89862306a36Sopenharmony_ci	return snprintf(buf, 20, "%d\n", h->ctlr);
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic ssize_t host_show_legacy_board(struct device *dev,
90262306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct ctlr_info *h;
90562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	h = shost_to_hba(shost);
90862306a36Sopenharmony_ci	return snprintf(buf, 20, "%d\n", h->legacy_board ? 1 : 0);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(raid_level);
91262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(lunid);
91362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(unique_id);
91462306a36Sopenharmony_cistatic DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
91562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(sas_address);
91662306a36Sopenharmony_cistatic DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO,
91762306a36Sopenharmony_ci			host_show_hp_ssd_smart_path_enabled, NULL);
91862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(path_info);
91962306a36Sopenharmony_cistatic DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH,
92062306a36Sopenharmony_ci		host_show_hp_ssd_smart_path_status,
92162306a36Sopenharmony_ci		host_store_hp_ssd_smart_path_status);
92262306a36Sopenharmony_cistatic DEVICE_ATTR(raid_offload_debug, S_IWUSR, NULL,
92362306a36Sopenharmony_ci			host_store_raid_offload_debug);
92462306a36Sopenharmony_cistatic DEVICE_ATTR(firmware_revision, S_IRUGO,
92562306a36Sopenharmony_ci	host_show_firmware_revision, NULL);
92662306a36Sopenharmony_cistatic DEVICE_ATTR(commands_outstanding, S_IRUGO,
92762306a36Sopenharmony_ci	host_show_commands_outstanding, NULL);
92862306a36Sopenharmony_cistatic DEVICE_ATTR(transport_mode, S_IRUGO,
92962306a36Sopenharmony_ci	host_show_transport_mode, NULL);
93062306a36Sopenharmony_cistatic DEVICE_ATTR(resettable, S_IRUGO,
93162306a36Sopenharmony_ci	host_show_resettable, NULL);
93262306a36Sopenharmony_cistatic DEVICE_ATTR(lockup_detected, S_IRUGO,
93362306a36Sopenharmony_ci	host_show_lockup_detected, NULL);
93462306a36Sopenharmony_cistatic DEVICE_ATTR(ctlr_num, S_IRUGO,
93562306a36Sopenharmony_ci	host_show_ctlr_num, NULL);
93662306a36Sopenharmony_cistatic DEVICE_ATTR(legacy_board, S_IRUGO,
93762306a36Sopenharmony_ci	host_show_legacy_board, NULL);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic struct attribute *hpsa_sdev_attrs[] = {
94062306a36Sopenharmony_ci	&dev_attr_raid_level.attr,
94162306a36Sopenharmony_ci	&dev_attr_lunid.attr,
94262306a36Sopenharmony_ci	&dev_attr_unique_id.attr,
94362306a36Sopenharmony_ci	&dev_attr_hp_ssd_smart_path_enabled.attr,
94462306a36Sopenharmony_ci	&dev_attr_path_info.attr,
94562306a36Sopenharmony_ci	&dev_attr_sas_address.attr,
94662306a36Sopenharmony_ci	NULL,
94762306a36Sopenharmony_ci};
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ciATTRIBUTE_GROUPS(hpsa_sdev);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic struct attribute *hpsa_shost_attrs[] = {
95262306a36Sopenharmony_ci	&dev_attr_rescan.attr,
95362306a36Sopenharmony_ci	&dev_attr_firmware_revision.attr,
95462306a36Sopenharmony_ci	&dev_attr_commands_outstanding.attr,
95562306a36Sopenharmony_ci	&dev_attr_transport_mode.attr,
95662306a36Sopenharmony_ci	&dev_attr_resettable.attr,
95762306a36Sopenharmony_ci	&dev_attr_hp_ssd_smart_path_status.attr,
95862306a36Sopenharmony_ci	&dev_attr_raid_offload_debug.attr,
95962306a36Sopenharmony_ci	&dev_attr_lockup_detected.attr,
96062306a36Sopenharmony_ci	&dev_attr_ctlr_num.attr,
96162306a36Sopenharmony_ci	&dev_attr_legacy_board.attr,
96262306a36Sopenharmony_ci	NULL,
96362306a36Sopenharmony_ci};
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ciATTRIBUTE_GROUPS(hpsa_shost);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci#define HPSA_NRESERVED_CMDS	(HPSA_CMDS_RESERVED_FOR_DRIVER +\
96862306a36Sopenharmony_ci				 HPSA_MAX_CONCURRENT_PASSTHRUS)
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic const struct scsi_host_template hpsa_driver_template = {
97162306a36Sopenharmony_ci	.module			= THIS_MODULE,
97262306a36Sopenharmony_ci	.name			= HPSA,
97362306a36Sopenharmony_ci	.proc_name		= HPSA,
97462306a36Sopenharmony_ci	.queuecommand		= hpsa_scsi_queue_command,
97562306a36Sopenharmony_ci	.scan_start		= hpsa_scan_start,
97662306a36Sopenharmony_ci	.scan_finished		= hpsa_scan_finished,
97762306a36Sopenharmony_ci	.change_queue_depth	= hpsa_change_queue_depth,
97862306a36Sopenharmony_ci	.this_id		= -1,
97962306a36Sopenharmony_ci	.eh_device_reset_handler = hpsa_eh_device_reset_handler,
98062306a36Sopenharmony_ci	.ioctl			= hpsa_ioctl,
98162306a36Sopenharmony_ci	.slave_alloc		= hpsa_slave_alloc,
98262306a36Sopenharmony_ci	.slave_configure	= hpsa_slave_configure,
98362306a36Sopenharmony_ci	.slave_destroy		= hpsa_slave_destroy,
98462306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
98562306a36Sopenharmony_ci	.compat_ioctl		= hpsa_compat_ioctl,
98662306a36Sopenharmony_ci#endif
98762306a36Sopenharmony_ci	.sdev_groups = hpsa_sdev_groups,
98862306a36Sopenharmony_ci	.shost_groups = hpsa_shost_groups,
98962306a36Sopenharmony_ci	.max_sectors = 2048,
99062306a36Sopenharmony_ci	.no_write_same = 1,
99162306a36Sopenharmony_ci};
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic inline u32 next_command(struct ctlr_info *h, u8 q)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	u32 a;
99662306a36Sopenharmony_ci	struct reply_queue_buffer *rq = &h->reply_queue[q];
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (h->transMethod & CFGTBL_Trans_io_accel1)
99962306a36Sopenharmony_ci		return h->access.command_completed(h, q);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
100262306a36Sopenharmony_ci		return h->access.command_completed(h, q);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
100562306a36Sopenharmony_ci		a = rq->head[rq->current_entry];
100662306a36Sopenharmony_ci		rq->current_entry++;
100762306a36Sopenharmony_ci		atomic_dec(&h->commands_outstanding);
100862306a36Sopenharmony_ci	} else {
100962306a36Sopenharmony_ci		a = FIFO_EMPTY;
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci	/* Check for wraparound */
101262306a36Sopenharmony_ci	if (rq->current_entry == h->max_commands) {
101362306a36Sopenharmony_ci		rq->current_entry = 0;
101462306a36Sopenharmony_ci		rq->wraparound ^= 1;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci	return a;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci/*
102062306a36Sopenharmony_ci * There are some special bits in the bus address of the
102162306a36Sopenharmony_ci * command that we have to set for the controller to know
102262306a36Sopenharmony_ci * how to process the command:
102362306a36Sopenharmony_ci *
102462306a36Sopenharmony_ci * Normal performant mode:
102562306a36Sopenharmony_ci * bit 0: 1 means performant mode, 0 means simple mode.
102662306a36Sopenharmony_ci * bits 1-3 = block fetch table entry
102762306a36Sopenharmony_ci * bits 4-6 = command type (== 0)
102862306a36Sopenharmony_ci *
102962306a36Sopenharmony_ci * ioaccel1 mode:
103062306a36Sopenharmony_ci * bit 0 = "performant mode" bit.
103162306a36Sopenharmony_ci * bits 1-3 = block fetch table entry
103262306a36Sopenharmony_ci * bits 4-6 = command type (== 110)
103362306a36Sopenharmony_ci * (command type is needed because ioaccel1 mode
103462306a36Sopenharmony_ci * commands are submitted through the same register as normal
103562306a36Sopenharmony_ci * mode commands, so this is how the controller knows whether
103662306a36Sopenharmony_ci * the command is normal mode or ioaccel1 mode.)
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * ioaccel2 mode:
103962306a36Sopenharmony_ci * bit 0 = "performant mode" bit.
104062306a36Sopenharmony_ci * bits 1-4 = block fetch table entry (note extra bit)
104162306a36Sopenharmony_ci * bits 4-6 = not needed, because ioaccel2 mode has
104262306a36Sopenharmony_ci * a separate special register for submitting commands.
104362306a36Sopenharmony_ci */
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci/*
104662306a36Sopenharmony_ci * set_performant_mode: Modify the tag for cciss performant
104762306a36Sopenharmony_ci * set bit 0 for pull model, bits 3-1 for block fetch
104862306a36Sopenharmony_ci * register number
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_ci#define DEFAULT_REPLY_QUEUE (-1)
105162306a36Sopenharmony_cistatic void set_performant_mode(struct ctlr_info *h, struct CommandList *c,
105262306a36Sopenharmony_ci					int reply_queue)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
105562306a36Sopenharmony_ci		c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
105662306a36Sopenharmony_ci		if (unlikely(!h->msix_vectors))
105762306a36Sopenharmony_ci			return;
105862306a36Sopenharmony_ci		c->Header.ReplyQueue = reply_queue;
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic void set_ioaccel1_performant_mode(struct ctlr_info *h,
106362306a36Sopenharmony_ci						struct CommandList *c,
106462306a36Sopenharmony_ci						int reply_queue)
106562306a36Sopenharmony_ci{
106662306a36Sopenharmony_ci	struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	/*
106962306a36Sopenharmony_ci	 * Tell the controller to post the reply to the queue for this
107062306a36Sopenharmony_ci	 * processor.  This seems to give the best I/O throughput.
107162306a36Sopenharmony_ci	 */
107262306a36Sopenharmony_ci	cp->ReplyQueue = reply_queue;
107362306a36Sopenharmony_ci	/*
107462306a36Sopenharmony_ci	 * Set the bits in the address sent down to include:
107562306a36Sopenharmony_ci	 *  - performant mode bit (bit 0)
107662306a36Sopenharmony_ci	 *  - pull count (bits 1-3)
107762306a36Sopenharmony_ci	 *  - command type (bits 4-6)
107862306a36Sopenharmony_ci	 */
107962306a36Sopenharmony_ci	c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
108062306a36Sopenharmony_ci					IOACCEL1_BUSADDR_CMDTYPE;
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_cistatic void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h,
108462306a36Sopenharmony_ci						struct CommandList *c,
108562306a36Sopenharmony_ci						int reply_queue)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct hpsa_tmf_struct *cp = (struct hpsa_tmf_struct *)
108862306a36Sopenharmony_ci		&h->ioaccel2_cmd_pool[c->cmdindex];
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* Tell the controller to post the reply to the queue for this
109162306a36Sopenharmony_ci	 * processor.  This seems to give the best I/O throughput.
109262306a36Sopenharmony_ci	 */
109362306a36Sopenharmony_ci	cp->reply_queue = reply_queue;
109462306a36Sopenharmony_ci	/* Set the bits in the address sent down to include:
109562306a36Sopenharmony_ci	 *  - performant mode bit not used in ioaccel mode 2
109662306a36Sopenharmony_ci	 *  - pull count (bits 0-3)
109762306a36Sopenharmony_ci	 *  - command type isn't needed for ioaccel2
109862306a36Sopenharmony_ci	 */
109962306a36Sopenharmony_ci	c->busaddr |= h->ioaccel2_blockFetchTable[0];
110062306a36Sopenharmony_ci}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic void set_ioaccel2_performant_mode(struct ctlr_info *h,
110362306a36Sopenharmony_ci						struct CommandList *c,
110462306a36Sopenharmony_ci						int reply_queue)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/*
110962306a36Sopenharmony_ci	 * Tell the controller to post the reply to the queue for this
111062306a36Sopenharmony_ci	 * processor.  This seems to give the best I/O throughput.
111162306a36Sopenharmony_ci	 */
111262306a36Sopenharmony_ci	cp->reply_queue = reply_queue;
111362306a36Sopenharmony_ci	/*
111462306a36Sopenharmony_ci	 * Set the bits in the address sent down to include:
111562306a36Sopenharmony_ci	 *  - performant mode bit not used in ioaccel mode 2
111662306a36Sopenharmony_ci	 *  - pull count (bits 0-3)
111762306a36Sopenharmony_ci	 *  - command type isn't needed for ioaccel2
111862306a36Sopenharmony_ci	 */
111962306a36Sopenharmony_ci	c->busaddr |= (h->ioaccel2_blockFetchTable[cp->sg_count]);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic int is_firmware_flash_cmd(u8 *cdb)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci/*
112862306a36Sopenharmony_ci * During firmware flash, the heartbeat register may not update as frequently
112962306a36Sopenharmony_ci * as it should.  So we dial down lockup detection during firmware flash. and
113062306a36Sopenharmony_ci * dial it back up when firmware flash completes.
113162306a36Sopenharmony_ci */
113262306a36Sopenharmony_ci#define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
113362306a36Sopenharmony_ci#define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
113462306a36Sopenharmony_ci#define HPSA_EVENT_MONITOR_INTERVAL (15 * HZ)
113562306a36Sopenharmony_cistatic void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
113662306a36Sopenharmony_ci		struct CommandList *c)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	if (!is_firmware_flash_cmd(c->Request.CDB))
113962306a36Sopenharmony_ci		return;
114062306a36Sopenharmony_ci	atomic_inc(&h->firmware_flash_in_progress);
114162306a36Sopenharmony_ci	h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
114562306a36Sopenharmony_ci		struct CommandList *c)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	if (is_firmware_flash_cmd(c->Request.CDB) &&
114862306a36Sopenharmony_ci		atomic_dec_and_test(&h->firmware_flash_in_progress))
114962306a36Sopenharmony_ci		h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic void __enqueue_cmd_and_start_io(struct ctlr_info *h,
115362306a36Sopenharmony_ci	struct CommandList *c, int reply_queue)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	dial_down_lockup_detection_during_fw_flash(h, c);
115662306a36Sopenharmony_ci	atomic_inc(&h->commands_outstanding);
115762306a36Sopenharmony_ci	/*
115862306a36Sopenharmony_ci	 * Check to see if the command is being retried.
115962306a36Sopenharmony_ci	 */
116062306a36Sopenharmony_ci	if (c->device && !c->retry_pending)
116162306a36Sopenharmony_ci		atomic_inc(&c->device->commands_outstanding);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	reply_queue = h->reply_map[raw_smp_processor_id()];
116462306a36Sopenharmony_ci	switch (c->cmd_type) {
116562306a36Sopenharmony_ci	case CMD_IOACCEL1:
116662306a36Sopenharmony_ci		set_ioaccel1_performant_mode(h, c, reply_queue);
116762306a36Sopenharmony_ci		writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case CMD_IOACCEL2:
117062306a36Sopenharmony_ci		set_ioaccel2_performant_mode(h, c, reply_queue);
117162306a36Sopenharmony_ci		writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
117262306a36Sopenharmony_ci		break;
117362306a36Sopenharmony_ci	case IOACCEL2_TMF:
117462306a36Sopenharmony_ci		set_ioaccel2_tmf_performant_mode(h, c, reply_queue);
117562306a36Sopenharmony_ci		writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
117662306a36Sopenharmony_ci		break;
117762306a36Sopenharmony_ci	default:
117862306a36Sopenharmony_ci		set_performant_mode(h, c, reply_queue);
117962306a36Sopenharmony_ci		h->access.submit_command(h, c);
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	__enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_cistatic inline int is_hba_lunid(unsigned char scsi3addr[])
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0;
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_cistatic inline int is_scsi_rev_5(struct ctlr_info *h)
119462306a36Sopenharmony_ci{
119562306a36Sopenharmony_ci	if (!h->hba_inquiry_data)
119662306a36Sopenharmony_ci		return 0;
119762306a36Sopenharmony_ci	if ((h->hba_inquiry_data[2] & 0x07) == 5)
119862306a36Sopenharmony_ci		return 1;
119962306a36Sopenharmony_ci	return 0;
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic int hpsa_find_target_lun(struct ctlr_info *h,
120362306a36Sopenharmony_ci	unsigned char scsi3addr[], int bus, int *target, int *lun)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	/* finds an unused bus, target, lun for a new physical device
120662306a36Sopenharmony_ci	 * assumes h->devlock is held
120762306a36Sopenharmony_ci	 */
120862306a36Sopenharmony_ci	int i, found = 0;
120962306a36Sopenharmony_ci	DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	bitmap_zero(lun_taken, HPSA_MAX_DEVICES);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
121462306a36Sopenharmony_ci		if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
121562306a36Sopenharmony_ci			__set_bit(h->dev[i]->target, lun_taken);
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES);
121962306a36Sopenharmony_ci	if (i < HPSA_MAX_DEVICES) {
122062306a36Sopenharmony_ci		/* *bus = 1; */
122162306a36Sopenharmony_ci		*target = i;
122262306a36Sopenharmony_ci		*lun = 0;
122362306a36Sopenharmony_ci		found = 1;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci	return !found;
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
122962306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev, char *description)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci#define LABEL_SIZE 25
123262306a36Sopenharmony_ci	char label[LABEL_SIZE];
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	if (h == NULL || h->pdev == NULL || h->scsi_host == NULL)
123562306a36Sopenharmony_ci		return;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	switch (dev->devtype) {
123862306a36Sopenharmony_ci	case TYPE_RAID:
123962306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "controller");
124062306a36Sopenharmony_ci		break;
124162306a36Sopenharmony_ci	case TYPE_ENCLOSURE:
124262306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "enclosure");
124362306a36Sopenharmony_ci		break;
124462306a36Sopenharmony_ci	case TYPE_DISK:
124562306a36Sopenharmony_ci	case TYPE_ZBC:
124662306a36Sopenharmony_ci		if (dev->external)
124762306a36Sopenharmony_ci			snprintf(label, LABEL_SIZE, "external");
124862306a36Sopenharmony_ci		else if (!is_logical_dev_addr_mode(dev->scsi3addr))
124962306a36Sopenharmony_ci			snprintf(label, LABEL_SIZE, "%s",
125062306a36Sopenharmony_ci				raid_label[PHYSICAL_DRIVE]);
125162306a36Sopenharmony_ci		else
125262306a36Sopenharmony_ci			snprintf(label, LABEL_SIZE, "RAID-%s",
125362306a36Sopenharmony_ci				dev->raid_level > RAID_UNKNOWN ? "?" :
125462306a36Sopenharmony_ci				raid_label[dev->raid_level]);
125562306a36Sopenharmony_ci		break;
125662306a36Sopenharmony_ci	case TYPE_ROM:
125762306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "rom");
125862306a36Sopenharmony_ci		break;
125962306a36Sopenharmony_ci	case TYPE_TAPE:
126062306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "tape");
126162306a36Sopenharmony_ci		break;
126262306a36Sopenharmony_ci	case TYPE_MEDIUM_CHANGER:
126362306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "changer");
126462306a36Sopenharmony_ci		break;
126562306a36Sopenharmony_ci	default:
126662306a36Sopenharmony_ci		snprintf(label, LABEL_SIZE, "UNKNOWN");
126762306a36Sopenharmony_ci		break;
126862306a36Sopenharmony_ci	}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	dev_printk(level, &h->pdev->dev,
127162306a36Sopenharmony_ci			"scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n",
127262306a36Sopenharmony_ci			h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
127362306a36Sopenharmony_ci			description,
127462306a36Sopenharmony_ci			scsi_device_type(dev->devtype),
127562306a36Sopenharmony_ci			dev->vendor,
127662306a36Sopenharmony_ci			dev->model,
127762306a36Sopenharmony_ci			label,
127862306a36Sopenharmony_ci			dev->offload_config ? '+' : '-',
127962306a36Sopenharmony_ci			dev->offload_to_be_enabled ? '+' : '-',
128062306a36Sopenharmony_ci			dev->expose_device);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci/* Add an entry into h->dev[] array. */
128462306a36Sopenharmony_cistatic int hpsa_scsi_add_entry(struct ctlr_info *h,
128562306a36Sopenharmony_ci		struct hpsa_scsi_dev_t *device,
128662306a36Sopenharmony_ci		struct hpsa_scsi_dev_t *added[], int *nadded)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	/* assumes h->devlock is held */
128962306a36Sopenharmony_ci	int n = h->ndevices;
129062306a36Sopenharmony_ci	int i;
129162306a36Sopenharmony_ci	unsigned char addr1[8], addr2[8];
129262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	if (n >= HPSA_MAX_DEVICES) {
129562306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "too many devices, some will be "
129662306a36Sopenharmony_ci			"inaccessible.\n");
129762306a36Sopenharmony_ci		return -1;
129862306a36Sopenharmony_ci	}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* physical devices do not have lun or target assigned until now. */
130162306a36Sopenharmony_ci	if (device->lun != -1)
130262306a36Sopenharmony_ci		/* Logical device, lun is already assigned. */
130362306a36Sopenharmony_ci		goto lun_assigned;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* If this device a non-zero lun of a multi-lun device
130662306a36Sopenharmony_ci	 * byte 4 of the 8-byte LUN addr will contain the logical
130762306a36Sopenharmony_ci	 * unit no, zero otherwise.
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci	if (device->scsi3addr[4] == 0) {
131062306a36Sopenharmony_ci		/* This is not a non-zero lun of a multi-lun device */
131162306a36Sopenharmony_ci		if (hpsa_find_target_lun(h, device->scsi3addr,
131262306a36Sopenharmony_ci			device->bus, &device->target, &device->lun) != 0)
131362306a36Sopenharmony_ci			return -1;
131462306a36Sopenharmony_ci		goto lun_assigned;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* This is a non-zero lun of a multi-lun device.
131862306a36Sopenharmony_ci	 * Search through our list and find the device which
131962306a36Sopenharmony_ci	 * has the same 8 byte LUN address, excepting byte 4 and 5.
132062306a36Sopenharmony_ci	 * Assign the same bus and target for this new LUN.
132162306a36Sopenharmony_ci	 * Use the logical unit number from the firmware.
132262306a36Sopenharmony_ci	 */
132362306a36Sopenharmony_ci	memcpy(addr1, device->scsi3addr, 8);
132462306a36Sopenharmony_ci	addr1[4] = 0;
132562306a36Sopenharmony_ci	addr1[5] = 0;
132662306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
132762306a36Sopenharmony_ci		sd = h->dev[i];
132862306a36Sopenharmony_ci		memcpy(addr2, sd->scsi3addr, 8);
132962306a36Sopenharmony_ci		addr2[4] = 0;
133062306a36Sopenharmony_ci		addr2[5] = 0;
133162306a36Sopenharmony_ci		/* differ only in byte 4 and 5? */
133262306a36Sopenharmony_ci		if (memcmp(addr1, addr2, 8) == 0) {
133362306a36Sopenharmony_ci			device->bus = sd->bus;
133462306a36Sopenharmony_ci			device->target = sd->target;
133562306a36Sopenharmony_ci			device->lun = device->scsi3addr[4];
133662306a36Sopenharmony_ci			break;
133762306a36Sopenharmony_ci		}
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci	if (device->lun == -1) {
134062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "physical device with no LUN=0,"
134162306a36Sopenharmony_ci			" suspect firmware bug or unsupported hardware "
134262306a36Sopenharmony_ci			"configuration.\n");
134362306a36Sopenharmony_ci		return -1;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cilun_assigned:
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	h->dev[n] = device;
134962306a36Sopenharmony_ci	h->ndevices++;
135062306a36Sopenharmony_ci	added[*nadded] = device;
135162306a36Sopenharmony_ci	(*nadded)++;
135262306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_INFO, h, device,
135362306a36Sopenharmony_ci		device->expose_device ? "added" : "masked");
135462306a36Sopenharmony_ci	return 0;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci/*
135862306a36Sopenharmony_ci * Called during a scan operation.
135962306a36Sopenharmony_ci *
136062306a36Sopenharmony_ci * Update an entry in h->dev[] array.
136162306a36Sopenharmony_ci */
136262306a36Sopenharmony_cistatic void hpsa_scsi_update_entry(struct ctlr_info *h,
136362306a36Sopenharmony_ci	int entry, struct hpsa_scsi_dev_t *new_entry)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	/* assumes h->devlock is held */
136662306a36Sopenharmony_ci	BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	/* Raid level changed. */
136962306a36Sopenharmony_ci	h->dev[entry]->raid_level = new_entry->raid_level;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	/*
137262306a36Sopenharmony_ci	 * ioacccel_handle may have changed for a dual domain disk
137362306a36Sopenharmony_ci	 */
137462306a36Sopenharmony_ci	h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Raid offload parameters changed.  Careful about the ordering. */
137762306a36Sopenharmony_ci	if (new_entry->offload_config && new_entry->offload_to_be_enabled) {
137862306a36Sopenharmony_ci		/*
137962306a36Sopenharmony_ci		 * if drive is newly offload_enabled, we want to copy the
138062306a36Sopenharmony_ci		 * raid map data first.  If previously offload_enabled and
138162306a36Sopenharmony_ci		 * offload_config were set, raid map data had better be
138262306a36Sopenharmony_ci		 * the same as it was before. If raid map data has changed
138362306a36Sopenharmony_ci		 * then it had better be the case that
138462306a36Sopenharmony_ci		 * h->dev[entry]->offload_enabled is currently 0.
138562306a36Sopenharmony_ci		 */
138662306a36Sopenharmony_ci		h->dev[entry]->raid_map = new_entry->raid_map;
138762306a36Sopenharmony_ci		h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
138862306a36Sopenharmony_ci	}
138962306a36Sopenharmony_ci	if (new_entry->offload_to_be_enabled) {
139062306a36Sopenharmony_ci		h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
139162306a36Sopenharmony_ci		wmb(); /* set ioaccel_handle *before* hba_ioaccel_enabled */
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci	h->dev[entry]->hba_ioaccel_enabled = new_entry->hba_ioaccel_enabled;
139462306a36Sopenharmony_ci	h->dev[entry]->offload_config = new_entry->offload_config;
139562306a36Sopenharmony_ci	h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
139662306a36Sopenharmony_ci	h->dev[entry]->queue_depth = new_entry->queue_depth;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/*
139962306a36Sopenharmony_ci	 * We can turn off ioaccel offload now, but need to delay turning
140062306a36Sopenharmony_ci	 * ioaccel on until we can update h->dev[entry]->phys_disk[], but we
140162306a36Sopenharmony_ci	 * can't do that until all the devices are updated.
140262306a36Sopenharmony_ci	 */
140362306a36Sopenharmony_ci	h->dev[entry]->offload_to_be_enabled = new_entry->offload_to_be_enabled;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/*
140662306a36Sopenharmony_ci	 * turn ioaccel off immediately if told to do so.
140762306a36Sopenharmony_ci	 */
140862306a36Sopenharmony_ci	if (!new_entry->offload_to_be_enabled)
140962306a36Sopenharmony_ci		h->dev[entry]->offload_enabled = 0;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_INFO, h, h->dev[entry], "updated");
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci/* Replace an entry from h->dev[] array. */
141562306a36Sopenharmony_cistatic void hpsa_scsi_replace_entry(struct ctlr_info *h,
141662306a36Sopenharmony_ci	int entry, struct hpsa_scsi_dev_t *new_entry,
141762306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *added[], int *nadded,
141862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *removed[], int *nremoved)
141962306a36Sopenharmony_ci{
142062306a36Sopenharmony_ci	/* assumes h->devlock is held */
142162306a36Sopenharmony_ci	BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
142262306a36Sopenharmony_ci	removed[*nremoved] = h->dev[entry];
142362306a36Sopenharmony_ci	(*nremoved)++;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	/*
142662306a36Sopenharmony_ci	 * New physical devices won't have target/lun assigned yet
142762306a36Sopenharmony_ci	 * so we need to preserve the values in the slot we are replacing.
142862306a36Sopenharmony_ci	 */
142962306a36Sopenharmony_ci	if (new_entry->target == -1) {
143062306a36Sopenharmony_ci		new_entry->target = h->dev[entry]->target;
143162306a36Sopenharmony_ci		new_entry->lun = h->dev[entry]->lun;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	h->dev[entry] = new_entry;
143562306a36Sopenharmony_ci	added[*nadded] = new_entry;
143662306a36Sopenharmony_ci	(*nadded)++;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_INFO, h, new_entry, "replaced");
143962306a36Sopenharmony_ci}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci/* Remove an entry from h->dev[] array. */
144262306a36Sopenharmony_cistatic void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry,
144362306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *removed[], int *nremoved)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	/* assumes h->devlock is held */
144662306a36Sopenharmony_ci	int i;
144762306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	sd = h->dev[entry];
145262306a36Sopenharmony_ci	removed[*nremoved] = h->dev[entry];
145362306a36Sopenharmony_ci	(*nremoved)++;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	for (i = entry; i < h->ndevices-1; i++)
145662306a36Sopenharmony_ci		h->dev[i] = h->dev[i+1];
145762306a36Sopenharmony_ci	h->ndevices--;
145862306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_INFO, h, sd, "removed");
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci#define SCSI3ADDR_EQ(a, b) ( \
146262306a36Sopenharmony_ci	(a)[7] == (b)[7] && \
146362306a36Sopenharmony_ci	(a)[6] == (b)[6] && \
146462306a36Sopenharmony_ci	(a)[5] == (b)[5] && \
146562306a36Sopenharmony_ci	(a)[4] == (b)[4] && \
146662306a36Sopenharmony_ci	(a)[3] == (b)[3] && \
146762306a36Sopenharmony_ci	(a)[2] == (b)[2] && \
146862306a36Sopenharmony_ci	(a)[1] == (b)[1] && \
146962306a36Sopenharmony_ci	(a)[0] == (b)[0])
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_cistatic void fixup_botched_add(struct ctlr_info *h,
147262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *added)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci	/* called when scsi_add_device fails in order to re-adjust
147562306a36Sopenharmony_ci	 * h->dev[] to match the mid layer's view.
147662306a36Sopenharmony_ci	 */
147762306a36Sopenharmony_ci	unsigned long flags;
147862306a36Sopenharmony_ci	int i, j;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
148162306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
148262306a36Sopenharmony_ci		if (h->dev[i] == added) {
148362306a36Sopenharmony_ci			for (j = i; j < h->ndevices-1; j++)
148462306a36Sopenharmony_ci				h->dev[j] = h->dev[j+1];
148562306a36Sopenharmony_ci			h->ndevices--;
148662306a36Sopenharmony_ci			break;
148762306a36Sopenharmony_ci		}
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
149062306a36Sopenharmony_ci	kfree(added);
149162306a36Sopenharmony_ci}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_cistatic inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
149462306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev2)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci	/* we compare everything except lun and target as these
149762306a36Sopenharmony_ci	 * are not yet assigned.  Compare parts likely
149862306a36Sopenharmony_ci	 * to differ first
149962306a36Sopenharmony_ci	 */
150062306a36Sopenharmony_ci	if (memcmp(dev1->scsi3addr, dev2->scsi3addr,
150162306a36Sopenharmony_ci		sizeof(dev1->scsi3addr)) != 0)
150262306a36Sopenharmony_ci		return 0;
150362306a36Sopenharmony_ci	if (memcmp(dev1->device_id, dev2->device_id,
150462306a36Sopenharmony_ci		sizeof(dev1->device_id)) != 0)
150562306a36Sopenharmony_ci		return 0;
150662306a36Sopenharmony_ci	if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0)
150762306a36Sopenharmony_ci		return 0;
150862306a36Sopenharmony_ci	if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
150962306a36Sopenharmony_ci		return 0;
151062306a36Sopenharmony_ci	if (dev1->devtype != dev2->devtype)
151162306a36Sopenharmony_ci		return 0;
151262306a36Sopenharmony_ci	if (dev1->bus != dev2->bus)
151362306a36Sopenharmony_ci		return 0;
151462306a36Sopenharmony_ci	return 1;
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_cistatic inline int device_updated(struct hpsa_scsi_dev_t *dev1,
151862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev2)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	/* Device attributes that can change, but don't mean
152162306a36Sopenharmony_ci	 * that the device is a different device, nor that the OS
152262306a36Sopenharmony_ci	 * needs to be told anything about the change.
152362306a36Sopenharmony_ci	 */
152462306a36Sopenharmony_ci	if (dev1->raid_level != dev2->raid_level)
152562306a36Sopenharmony_ci		return 1;
152662306a36Sopenharmony_ci	if (dev1->offload_config != dev2->offload_config)
152762306a36Sopenharmony_ci		return 1;
152862306a36Sopenharmony_ci	if (dev1->offload_to_be_enabled != dev2->offload_to_be_enabled)
152962306a36Sopenharmony_ci		return 1;
153062306a36Sopenharmony_ci	if (!is_logical_dev_addr_mode(dev1->scsi3addr))
153162306a36Sopenharmony_ci		if (dev1->queue_depth != dev2->queue_depth)
153262306a36Sopenharmony_ci			return 1;
153362306a36Sopenharmony_ci	/*
153462306a36Sopenharmony_ci	 * This can happen for dual domain devices. An active
153562306a36Sopenharmony_ci	 * path change causes the ioaccel handle to change
153662306a36Sopenharmony_ci	 *
153762306a36Sopenharmony_ci	 * for example note the handle differences between p0 and p1
153862306a36Sopenharmony_ci	 * Device                    WWN               ,WWN hash,Handle
153962306a36Sopenharmony_ci	 * D016 p0|0x3 [02]P2E:01:01,0x5000C5005FC4DACA,0x9B5616,0x01030003
154062306a36Sopenharmony_ci	 *	p1                   0x5000C5005FC4DAC9,0x6798C0,0x00040004
154162306a36Sopenharmony_ci	 */
154262306a36Sopenharmony_ci	if (dev1->ioaccel_handle != dev2->ioaccel_handle)
154362306a36Sopenharmony_ci		return 1;
154462306a36Sopenharmony_ci	return 0;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci/* Find needle in haystack.  If exact match found, return DEVICE_SAME,
154862306a36Sopenharmony_ci * and return needle location in *index.  If scsi3addr matches, but not
154962306a36Sopenharmony_ci * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
155062306a36Sopenharmony_ci * location in *index.
155162306a36Sopenharmony_ci * In the case of a minor device attribute change, such as RAID level, just
155262306a36Sopenharmony_ci * return DEVICE_UPDATED, along with the updated device's location in index.
155362306a36Sopenharmony_ci * If needle not found, return DEVICE_NOT_FOUND.
155462306a36Sopenharmony_ci */
155562306a36Sopenharmony_cistatic int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
155662306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *haystack[], int haystack_size,
155762306a36Sopenharmony_ci	int *index)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	int i;
156062306a36Sopenharmony_ci#define DEVICE_NOT_FOUND 0
156162306a36Sopenharmony_ci#define DEVICE_CHANGED 1
156262306a36Sopenharmony_ci#define DEVICE_SAME 2
156362306a36Sopenharmony_ci#define DEVICE_UPDATED 3
156462306a36Sopenharmony_ci	if (needle == NULL)
156562306a36Sopenharmony_ci		return DEVICE_NOT_FOUND;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	for (i = 0; i < haystack_size; i++) {
156862306a36Sopenharmony_ci		if (haystack[i] == NULL) /* previously removed. */
156962306a36Sopenharmony_ci			continue;
157062306a36Sopenharmony_ci		if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
157162306a36Sopenharmony_ci			*index = i;
157262306a36Sopenharmony_ci			if (device_is_the_same(needle, haystack[i])) {
157362306a36Sopenharmony_ci				if (device_updated(needle, haystack[i]))
157462306a36Sopenharmony_ci					return DEVICE_UPDATED;
157562306a36Sopenharmony_ci				return DEVICE_SAME;
157662306a36Sopenharmony_ci			} else {
157762306a36Sopenharmony_ci				/* Keep offline devices offline */
157862306a36Sopenharmony_ci				if (needle->volume_offline)
157962306a36Sopenharmony_ci					return DEVICE_NOT_FOUND;
158062306a36Sopenharmony_ci				return DEVICE_CHANGED;
158162306a36Sopenharmony_ci			}
158262306a36Sopenharmony_ci		}
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci	*index = -1;
158562306a36Sopenharmony_ci	return DEVICE_NOT_FOUND;
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic void hpsa_monitor_offline_device(struct ctlr_info *h,
158962306a36Sopenharmony_ci					unsigned char scsi3addr[])
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	struct offline_device_entry *device;
159262306a36Sopenharmony_ci	unsigned long flags;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Check to see if device is already on the list */
159562306a36Sopenharmony_ci	spin_lock_irqsave(&h->offline_device_lock, flags);
159662306a36Sopenharmony_ci	list_for_each_entry(device, &h->offline_device_list, offline_list) {
159762306a36Sopenharmony_ci		if (memcmp(device->scsi3addr, scsi3addr,
159862306a36Sopenharmony_ci			sizeof(device->scsi3addr)) == 0) {
159962306a36Sopenharmony_ci			spin_unlock_irqrestore(&h->offline_device_lock, flags);
160062306a36Sopenharmony_ci			return;
160162306a36Sopenharmony_ci		}
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->offline_device_lock, flags);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	/* Device is not on the list, add it. */
160662306a36Sopenharmony_ci	device = kmalloc(sizeof(*device), GFP_KERNEL);
160762306a36Sopenharmony_ci	if (!device)
160862306a36Sopenharmony_ci		return;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
161162306a36Sopenharmony_ci	spin_lock_irqsave(&h->offline_device_lock, flags);
161262306a36Sopenharmony_ci	list_add_tail(&device->offline_list, &h->offline_device_list);
161362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->offline_device_lock, flags);
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci/* Print a message explaining various offline volume states */
161762306a36Sopenharmony_cistatic void hpsa_show_volume_status(struct ctlr_info *h,
161862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	if (sd->volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED)
162162306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
162262306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume status is not available through vital product data pages.\n",
162362306a36Sopenharmony_ci			h->scsi_host->host_no,
162462306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
162562306a36Sopenharmony_ci	switch (sd->volume_offline) {
162662306a36Sopenharmony_ci	case HPSA_LV_OK:
162762306a36Sopenharmony_ci		break;
162862306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ERASE:
162962306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
163062306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is undergoing background erase process.\n",
163162306a36Sopenharmony_ci			h->scsi_host->host_no,
163262306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
163362306a36Sopenharmony_ci		break;
163462306a36Sopenharmony_ci	case HPSA_LV_NOT_AVAILABLE:
163562306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
163662306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is waiting for transforming volume.\n",
163762306a36Sopenharmony_ci			h->scsi_host->host_no,
163862306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
163962306a36Sopenharmony_ci		break;
164062306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_RPI:
164162306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
164262306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is undergoing rapid parity init.\n",
164362306a36Sopenharmony_ci			h->scsi_host->host_no,
164462306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
164562306a36Sopenharmony_ci		break;
164662306a36Sopenharmony_ci	case HPSA_LV_PENDING_RPI:
164762306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
164862306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n",
164962306a36Sopenharmony_ci			h->scsi_host->host_no,
165062306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
165162306a36Sopenharmony_ci		break;
165262306a36Sopenharmony_ci	case HPSA_LV_ENCRYPTED_NO_KEY:
165362306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
165462306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because key is not present.\n",
165562306a36Sopenharmony_ci			h->scsi_host->host_no,
165662306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
165762306a36Sopenharmony_ci		break;
165862306a36Sopenharmony_ci	case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
165962306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
166062306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.\n",
166162306a36Sopenharmony_ci			h->scsi_host->host_no,
166262306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
166362306a36Sopenharmony_ci		break;
166462306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ENCRYPTION:
166562306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
166662306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is undergoing encryption process.\n",
166762306a36Sopenharmony_ci			h->scsi_host->host_no,
166862306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
166962306a36Sopenharmony_ci		break;
167062306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
167162306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
167262306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is undergoing encryption re-keying process.\n",
167362306a36Sopenharmony_ci			h->scsi_host->host_no,
167462306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
167562306a36Sopenharmony_ci		break;
167662306a36Sopenharmony_ci	case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
167762306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
167862306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because controller does not have encryption enabled.\n",
167962306a36Sopenharmony_ci			h->scsi_host->host_no,
168062306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
168162306a36Sopenharmony_ci		break;
168262306a36Sopenharmony_ci	case HPSA_LV_PENDING_ENCRYPTION:
168362306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
168462306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is pending migration to encrypted state, but process has not started.\n",
168562306a36Sopenharmony_ci			h->scsi_host->host_no,
168662306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
168762306a36Sopenharmony_ci		break;
168862306a36Sopenharmony_ci	case HPSA_LV_PENDING_ENCRYPTION_REKEYING:
168962306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
169062306a36Sopenharmony_ci			"C%d:B%d:T%d:L%d Volume is encrypted and is pending encryption rekeying.\n",
169162306a36Sopenharmony_ci			h->scsi_host->host_no,
169262306a36Sopenharmony_ci			sd->bus, sd->target, sd->lun);
169362306a36Sopenharmony_ci		break;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci/*
169862306a36Sopenharmony_ci * Figure the list of physical drive pointers for a logical drive with
169962306a36Sopenharmony_ci * raid offload configured.
170062306a36Sopenharmony_ci */
170162306a36Sopenharmony_cistatic void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h,
170262306a36Sopenharmony_ci				struct hpsa_scsi_dev_t *dev[], int ndevices,
170362306a36Sopenharmony_ci				struct hpsa_scsi_dev_t *logical_drive)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	struct raid_map_data *map = &logical_drive->raid_map;
170662306a36Sopenharmony_ci	struct raid_map_disk_data *dd = &map->data[0];
170762306a36Sopenharmony_ci	int i, j;
170862306a36Sopenharmony_ci	int total_disks_per_row = le16_to_cpu(map->data_disks_per_row) +
170962306a36Sopenharmony_ci				le16_to_cpu(map->metadata_disks_per_row);
171062306a36Sopenharmony_ci	int nraid_map_entries = le16_to_cpu(map->row_cnt) *
171162306a36Sopenharmony_ci				le16_to_cpu(map->layout_map_count) *
171262306a36Sopenharmony_ci				total_disks_per_row;
171362306a36Sopenharmony_ci	int nphys_disk = le16_to_cpu(map->layout_map_count) *
171462306a36Sopenharmony_ci				total_disks_per_row;
171562306a36Sopenharmony_ci	int qdepth;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	if (nraid_map_entries > RAID_MAP_MAX_ENTRIES)
171862306a36Sopenharmony_ci		nraid_map_entries = RAID_MAP_MAX_ENTRIES;
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	logical_drive->nphysical_disks = nraid_map_entries;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	qdepth = 0;
172362306a36Sopenharmony_ci	for (i = 0; i < nraid_map_entries; i++) {
172462306a36Sopenharmony_ci		logical_drive->phys_disk[i] = NULL;
172562306a36Sopenharmony_ci		if (!logical_drive->offload_config)
172662306a36Sopenharmony_ci			continue;
172762306a36Sopenharmony_ci		for (j = 0; j < ndevices; j++) {
172862306a36Sopenharmony_ci			if (dev[j] == NULL)
172962306a36Sopenharmony_ci				continue;
173062306a36Sopenharmony_ci			if (dev[j]->devtype != TYPE_DISK &&
173162306a36Sopenharmony_ci			    dev[j]->devtype != TYPE_ZBC)
173262306a36Sopenharmony_ci				continue;
173362306a36Sopenharmony_ci			if (is_logical_device(dev[j]))
173462306a36Sopenharmony_ci				continue;
173562306a36Sopenharmony_ci			if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle)
173662306a36Sopenharmony_ci				continue;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci			logical_drive->phys_disk[i] = dev[j];
173962306a36Sopenharmony_ci			if (i < nphys_disk)
174062306a36Sopenharmony_ci				qdepth = min(h->nr_cmds, qdepth +
174162306a36Sopenharmony_ci				    logical_drive->phys_disk[i]->queue_depth);
174262306a36Sopenharmony_ci			break;
174362306a36Sopenharmony_ci		}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci		/*
174662306a36Sopenharmony_ci		 * This can happen if a physical drive is removed and
174762306a36Sopenharmony_ci		 * the logical drive is degraded.  In that case, the RAID
174862306a36Sopenharmony_ci		 * map data will refer to a physical disk which isn't actually
174962306a36Sopenharmony_ci		 * present.  And in that case offload_enabled should already
175062306a36Sopenharmony_ci		 * be 0, but we'll turn it off here just in case
175162306a36Sopenharmony_ci		 */
175262306a36Sopenharmony_ci		if (!logical_drive->phys_disk[i]) {
175362306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
175462306a36Sopenharmony_ci				"%s: [%d:%d:%d:%d] A phys disk component of LV is missing, turning off offload_enabled for LV.\n",
175562306a36Sopenharmony_ci				__func__,
175662306a36Sopenharmony_ci				h->scsi_host->host_no, logical_drive->bus,
175762306a36Sopenharmony_ci				logical_drive->target, logical_drive->lun);
175862306a36Sopenharmony_ci			hpsa_turn_off_ioaccel_for_device(logical_drive);
175962306a36Sopenharmony_ci			logical_drive->queue_depth = 8;
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci	if (nraid_map_entries)
176362306a36Sopenharmony_ci		/*
176462306a36Sopenharmony_ci		 * This is correct for reads, too high for full stripe writes,
176562306a36Sopenharmony_ci		 * way too high for partial stripe writes
176662306a36Sopenharmony_ci		 */
176762306a36Sopenharmony_ci		logical_drive->queue_depth = qdepth;
176862306a36Sopenharmony_ci	else {
176962306a36Sopenharmony_ci		if (logical_drive->external)
177062306a36Sopenharmony_ci			logical_drive->queue_depth = EXTERNAL_QD;
177162306a36Sopenharmony_ci		else
177262306a36Sopenharmony_ci			logical_drive->queue_depth = h->nr_cmds;
177362306a36Sopenharmony_ci	}
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cistatic void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
177762306a36Sopenharmony_ci				struct hpsa_scsi_dev_t *dev[], int ndevices)
177862306a36Sopenharmony_ci{
177962306a36Sopenharmony_ci	int i;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	for (i = 0; i < ndevices; i++) {
178262306a36Sopenharmony_ci		if (dev[i] == NULL)
178362306a36Sopenharmony_ci			continue;
178462306a36Sopenharmony_ci		if (dev[i]->devtype != TYPE_DISK &&
178562306a36Sopenharmony_ci		    dev[i]->devtype != TYPE_ZBC)
178662306a36Sopenharmony_ci			continue;
178762306a36Sopenharmony_ci		if (!is_logical_device(dev[i]))
178862306a36Sopenharmony_ci			continue;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci		/*
179162306a36Sopenharmony_ci		 * If offload is currently enabled, the RAID map and
179262306a36Sopenharmony_ci		 * phys_disk[] assignment *better* not be changing
179362306a36Sopenharmony_ci		 * because we would be changing ioaccel phsy_disk[] pointers
179462306a36Sopenharmony_ci		 * on a ioaccel volume processing I/O requests.
179562306a36Sopenharmony_ci		 *
179662306a36Sopenharmony_ci		 * If an ioaccel volume status changed, initially because it was
179762306a36Sopenharmony_ci		 * re-configured and thus underwent a transformation, or
179862306a36Sopenharmony_ci		 * a drive failed, we would have received a state change
179962306a36Sopenharmony_ci		 * request and ioaccel should have been turned off. When the
180062306a36Sopenharmony_ci		 * transformation completes, we get another state change
180162306a36Sopenharmony_ci		 * request to turn ioaccel back on. In this case, we need
180262306a36Sopenharmony_ci		 * to update the ioaccel information.
180362306a36Sopenharmony_ci		 *
180462306a36Sopenharmony_ci		 * Thus: If it is not currently enabled, but will be after
180562306a36Sopenharmony_ci		 * the scan completes, make sure the ioaccel pointers
180662306a36Sopenharmony_ci		 * are up to date.
180762306a36Sopenharmony_ci		 */
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci		if (!dev[i]->offload_enabled && dev[i]->offload_to_be_enabled)
181062306a36Sopenharmony_ci			hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]);
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
181562306a36Sopenharmony_ci{
181662306a36Sopenharmony_ci	int rc = 0;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	if (!h->scsi_host)
181962306a36Sopenharmony_ci		return 1;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	if (is_logical_device(device)) /* RAID */
182262306a36Sopenharmony_ci		rc = scsi_add_device(h->scsi_host, device->bus,
182362306a36Sopenharmony_ci					device->target, device->lun);
182462306a36Sopenharmony_ci	else /* HBA */
182562306a36Sopenharmony_ci		rc = hpsa_add_sas_device(h->sas_host, device);
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	return rc;
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_cistatic int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h,
183162306a36Sopenharmony_ci						struct hpsa_scsi_dev_t *dev)
183262306a36Sopenharmony_ci{
183362306a36Sopenharmony_ci	int i;
183462306a36Sopenharmony_ci	int count = 0;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
183762306a36Sopenharmony_ci		struct CommandList *c = h->cmd_pool + i;
183862306a36Sopenharmony_ci		int refcount = atomic_inc_return(&c->refcount);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci		if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev,
184162306a36Sopenharmony_ci				dev->scsi3addr)) {
184262306a36Sopenharmony_ci			unsigned long flags;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci			spin_lock_irqsave(&h->lock, flags);	/* Implied MB */
184562306a36Sopenharmony_ci			if (!hpsa_is_cmd_idle(c))
184662306a36Sopenharmony_ci				++count;
184762306a36Sopenharmony_ci			spin_unlock_irqrestore(&h->lock, flags);
184862306a36Sopenharmony_ci		}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci		cmd_free(h, c);
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	return count;
185462306a36Sopenharmony_ci}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci#define NUM_WAIT 20
185762306a36Sopenharmony_cistatic void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h,
185862306a36Sopenharmony_ci						struct hpsa_scsi_dev_t *device)
185962306a36Sopenharmony_ci{
186062306a36Sopenharmony_ci	int cmds = 0;
186162306a36Sopenharmony_ci	int waits = 0;
186262306a36Sopenharmony_ci	int num_wait = NUM_WAIT;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (device->external)
186562306a36Sopenharmony_ci		num_wait = HPSA_EH_PTRAID_TIMEOUT;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	while (1) {
186862306a36Sopenharmony_ci		cmds = hpsa_find_outstanding_commands_for_dev(h, device);
186962306a36Sopenharmony_ci		if (cmds == 0)
187062306a36Sopenharmony_ci			break;
187162306a36Sopenharmony_ci		if (++waits > num_wait)
187262306a36Sopenharmony_ci			break;
187362306a36Sopenharmony_ci		msleep(1000);
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (waits > num_wait) {
187762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
187862306a36Sopenharmony_ci			"%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n",
187962306a36Sopenharmony_ci			__func__,
188062306a36Sopenharmony_ci			h->scsi_host->host_no,
188162306a36Sopenharmony_ci			device->bus, device->target, device->lun, cmds);
188262306a36Sopenharmony_ci	}
188362306a36Sopenharmony_ci}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_cistatic void hpsa_remove_device(struct ctlr_info *h,
188662306a36Sopenharmony_ci			struct hpsa_scsi_dev_t *device)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	struct scsi_device *sdev = NULL;
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	if (!h->scsi_host)
189162306a36Sopenharmony_ci		return;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/*
189462306a36Sopenharmony_ci	 * Allow for commands to drain
189562306a36Sopenharmony_ci	 */
189662306a36Sopenharmony_ci	device->removed = 1;
189762306a36Sopenharmony_ci	hpsa_wait_for_outstanding_commands_for_dev(h, device);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	if (is_logical_device(device)) { /* RAID */
190062306a36Sopenharmony_ci		sdev = scsi_device_lookup(h->scsi_host, device->bus,
190162306a36Sopenharmony_ci						device->target, device->lun);
190262306a36Sopenharmony_ci		if (sdev) {
190362306a36Sopenharmony_ci			scsi_remove_device(sdev);
190462306a36Sopenharmony_ci			scsi_device_put(sdev);
190562306a36Sopenharmony_ci		} else {
190662306a36Sopenharmony_ci			/*
190762306a36Sopenharmony_ci			 * We don't expect to get here.  Future commands
190862306a36Sopenharmony_ci			 * to this device will get a selection timeout as
190962306a36Sopenharmony_ci			 * if the device were gone.
191062306a36Sopenharmony_ci			 */
191162306a36Sopenharmony_ci			hpsa_show_dev_msg(KERN_WARNING, h, device,
191262306a36Sopenharmony_ci					"didn't find device for removal.");
191362306a36Sopenharmony_ci		}
191462306a36Sopenharmony_ci	} else { /* HBA */
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		hpsa_remove_sas_device(device);
191762306a36Sopenharmony_ci	}
191862306a36Sopenharmony_ci}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic void adjust_hpsa_scsi_table(struct ctlr_info *h,
192162306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd[], int nsds)
192262306a36Sopenharmony_ci{
192362306a36Sopenharmony_ci	/* sd contains scsi3 addresses and devtypes, and inquiry
192462306a36Sopenharmony_ci	 * data.  This function takes what's in sd to be the current
192562306a36Sopenharmony_ci	 * reality and updates h->dev[] to reflect that reality.
192662306a36Sopenharmony_ci	 */
192762306a36Sopenharmony_ci	int i, entry, device_change, changes = 0;
192862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *csd;
192962306a36Sopenharmony_ci	unsigned long flags;
193062306a36Sopenharmony_ci	struct hpsa_scsi_dev_t **added, **removed;
193162306a36Sopenharmony_ci	int nadded, nremoved;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	/*
193462306a36Sopenharmony_ci	 * A reset can cause a device status to change
193562306a36Sopenharmony_ci	 * re-schedule the scan to see what happened.
193662306a36Sopenharmony_ci	 */
193762306a36Sopenharmony_ci	spin_lock_irqsave(&h->reset_lock, flags);
193862306a36Sopenharmony_ci	if (h->reset_in_progress) {
193962306a36Sopenharmony_ci		h->drv_req_rescan = 1;
194062306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->reset_lock, flags);
194162306a36Sopenharmony_ci		return;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->reset_lock, flags);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	added = kcalloc(HPSA_MAX_DEVICES, sizeof(*added), GFP_KERNEL);
194662306a36Sopenharmony_ci	removed = kcalloc(HPSA_MAX_DEVICES, sizeof(*removed), GFP_KERNEL);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	if (!added || !removed) {
194962306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "out of memory in "
195062306a36Sopenharmony_ci			"adjust_hpsa_scsi_table\n");
195162306a36Sopenharmony_ci		goto free_and_out;
195262306a36Sopenharmony_ci	}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	spin_lock_irqsave(&h->devlock, flags);
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/* find any devices in h->dev[] that are not in
195762306a36Sopenharmony_ci	 * sd[] and remove them from h->dev[], and for any
195862306a36Sopenharmony_ci	 * devices which have changed, remove the old device
195962306a36Sopenharmony_ci	 * info and add the new device info.
196062306a36Sopenharmony_ci	 * If minor device attributes change, just update
196162306a36Sopenharmony_ci	 * the existing device structure.
196262306a36Sopenharmony_ci	 */
196362306a36Sopenharmony_ci	i = 0;
196462306a36Sopenharmony_ci	nremoved = 0;
196562306a36Sopenharmony_ci	nadded = 0;
196662306a36Sopenharmony_ci	while (i < h->ndevices) {
196762306a36Sopenharmony_ci		csd = h->dev[i];
196862306a36Sopenharmony_ci		device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry);
196962306a36Sopenharmony_ci		if (device_change == DEVICE_NOT_FOUND) {
197062306a36Sopenharmony_ci			changes++;
197162306a36Sopenharmony_ci			hpsa_scsi_remove_entry(h, i, removed, &nremoved);
197262306a36Sopenharmony_ci			continue; /* remove ^^^, hence i not incremented */
197362306a36Sopenharmony_ci		} else if (device_change == DEVICE_CHANGED) {
197462306a36Sopenharmony_ci			changes++;
197562306a36Sopenharmony_ci			hpsa_scsi_replace_entry(h, i, sd[entry],
197662306a36Sopenharmony_ci				added, &nadded, removed, &nremoved);
197762306a36Sopenharmony_ci			/* Set it to NULL to prevent it from being freed
197862306a36Sopenharmony_ci			 * at the bottom of hpsa_update_scsi_devices()
197962306a36Sopenharmony_ci			 */
198062306a36Sopenharmony_ci			sd[entry] = NULL;
198162306a36Sopenharmony_ci		} else if (device_change == DEVICE_UPDATED) {
198262306a36Sopenharmony_ci			hpsa_scsi_update_entry(h, i, sd[entry]);
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci		i++;
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	/* Now, make sure every device listed in sd[] is also
198862306a36Sopenharmony_ci	 * listed in h->dev[], adding them if they aren't found
198962306a36Sopenharmony_ci	 */
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	for (i = 0; i < nsds; i++) {
199262306a36Sopenharmony_ci		if (!sd[i]) /* if already added above. */
199362306a36Sopenharmony_ci			continue;
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci		/* Don't add devices which are NOT READY, FORMAT IN PROGRESS
199662306a36Sopenharmony_ci		 * as the SCSI mid-layer does not handle such devices well.
199762306a36Sopenharmony_ci		 * It relentlessly loops sending TUR at 3Hz, then READ(10)
199862306a36Sopenharmony_ci		 * at 160Hz, and prevents the system from coming up.
199962306a36Sopenharmony_ci		 */
200062306a36Sopenharmony_ci		if (sd[i]->volume_offline) {
200162306a36Sopenharmony_ci			hpsa_show_volume_status(h, sd[i]);
200262306a36Sopenharmony_ci			hpsa_show_dev_msg(KERN_INFO, h, sd[i], "offline");
200362306a36Sopenharmony_ci			continue;
200462306a36Sopenharmony_ci		}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci		device_change = hpsa_scsi_find_entry(sd[i], h->dev,
200762306a36Sopenharmony_ci					h->ndevices, &entry);
200862306a36Sopenharmony_ci		if (device_change == DEVICE_NOT_FOUND) {
200962306a36Sopenharmony_ci			changes++;
201062306a36Sopenharmony_ci			if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0)
201162306a36Sopenharmony_ci				break;
201262306a36Sopenharmony_ci			sd[i] = NULL; /* prevent from being freed later. */
201362306a36Sopenharmony_ci		} else if (device_change == DEVICE_CHANGED) {
201462306a36Sopenharmony_ci			/* should never happen... */
201562306a36Sopenharmony_ci			changes++;
201662306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
201762306a36Sopenharmony_ci				"device unexpectedly changed.\n");
201862306a36Sopenharmony_ci			/* but if it does happen, we just ignore that device */
201962306a36Sopenharmony_ci		}
202062306a36Sopenharmony_ci	}
202162306a36Sopenharmony_ci	hpsa_update_log_drive_phys_drive_ptrs(h, h->dev, h->ndevices);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	/*
202462306a36Sopenharmony_ci	 * Now that h->dev[]->phys_disk[] is coherent, we can enable
202562306a36Sopenharmony_ci	 * any logical drives that need it enabled.
202662306a36Sopenharmony_ci	 *
202762306a36Sopenharmony_ci	 * The raid map should be current by now.
202862306a36Sopenharmony_ci	 *
202962306a36Sopenharmony_ci	 * We are updating the device list used for I/O requests.
203062306a36Sopenharmony_ci	 */
203162306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
203262306a36Sopenharmony_ci		if (h->dev[i] == NULL)
203362306a36Sopenharmony_ci			continue;
203462306a36Sopenharmony_ci		h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->devlock, flags);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	/* Monitor devices which are in one of several NOT READY states to be
204062306a36Sopenharmony_ci	 * brought online later. This must be done without holding h->devlock,
204162306a36Sopenharmony_ci	 * so don't touch h->dev[]
204262306a36Sopenharmony_ci	 */
204362306a36Sopenharmony_ci	for (i = 0; i < nsds; i++) {
204462306a36Sopenharmony_ci		if (!sd[i]) /* if already added above. */
204562306a36Sopenharmony_ci			continue;
204662306a36Sopenharmony_ci		if (sd[i]->volume_offline)
204762306a36Sopenharmony_ci			hpsa_monitor_offline_device(h, sd[i]->scsi3addr);
204862306a36Sopenharmony_ci	}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci	/* Don't notify scsi mid layer of any changes the first time through
205162306a36Sopenharmony_ci	 * (or if there are no changes) scsi_scan_host will do it later the
205262306a36Sopenharmony_ci	 * first time through.
205362306a36Sopenharmony_ci	 */
205462306a36Sopenharmony_ci	if (!changes)
205562306a36Sopenharmony_ci		goto free_and_out;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/* Notify scsi mid layer of any removed devices */
205862306a36Sopenharmony_ci	for (i = 0; i < nremoved; i++) {
205962306a36Sopenharmony_ci		if (removed[i] == NULL)
206062306a36Sopenharmony_ci			continue;
206162306a36Sopenharmony_ci		if (removed[i]->expose_device)
206262306a36Sopenharmony_ci			hpsa_remove_device(h, removed[i]);
206362306a36Sopenharmony_ci		kfree(removed[i]);
206462306a36Sopenharmony_ci		removed[i] = NULL;
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	/* Notify scsi mid layer of any added devices */
206862306a36Sopenharmony_ci	for (i = 0; i < nadded; i++) {
206962306a36Sopenharmony_ci		int rc = 0;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci		if (added[i] == NULL)
207262306a36Sopenharmony_ci			continue;
207362306a36Sopenharmony_ci		if (!(added[i]->expose_device))
207462306a36Sopenharmony_ci			continue;
207562306a36Sopenharmony_ci		rc = hpsa_add_device(h, added[i]);
207662306a36Sopenharmony_ci		if (!rc)
207762306a36Sopenharmony_ci			continue;
207862306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
207962306a36Sopenharmony_ci			"addition failed %d, device not added.", rc);
208062306a36Sopenharmony_ci		/* now we have to remove it from h->dev,
208162306a36Sopenharmony_ci		 * since it didn't get added to scsi mid layer
208262306a36Sopenharmony_ci		 */
208362306a36Sopenharmony_ci		fixup_botched_add(h, added[i]);
208462306a36Sopenharmony_ci		h->drv_req_rescan = 1;
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cifree_and_out:
208862306a36Sopenharmony_ci	kfree(added);
208962306a36Sopenharmony_ci	kfree(removed);
209062306a36Sopenharmony_ci}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci/*
209362306a36Sopenharmony_ci * Lookup bus/target/lun and return corresponding struct hpsa_scsi_dev_t *
209462306a36Sopenharmony_ci * Assume's h->devlock is held.
209562306a36Sopenharmony_ci */
209662306a36Sopenharmony_cistatic struct hpsa_scsi_dev_t *lookup_hpsa_scsi_dev(struct ctlr_info *h,
209762306a36Sopenharmony_ci	int bus, int target, int lun)
209862306a36Sopenharmony_ci{
209962306a36Sopenharmony_ci	int i;
210062306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
210362306a36Sopenharmony_ci		sd = h->dev[i];
210462306a36Sopenharmony_ci		if (sd->bus == bus && sd->target == target && sd->lun == lun)
210562306a36Sopenharmony_ci			return sd;
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci	return NULL;
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_cistatic int hpsa_slave_alloc(struct scsi_device *sdev)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd = NULL;
211362306a36Sopenharmony_ci	unsigned long flags;
211462306a36Sopenharmony_ci	struct ctlr_info *h;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	h = sdev_to_hba(sdev);
211762306a36Sopenharmony_ci	spin_lock_irqsave(&h->devlock, flags);
211862306a36Sopenharmony_ci	if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) {
211962306a36Sopenharmony_ci		struct scsi_target *starget;
212062306a36Sopenharmony_ci		struct sas_rphy *rphy;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		starget = scsi_target(sdev);
212362306a36Sopenharmony_ci		rphy = target_to_rphy(starget);
212462306a36Sopenharmony_ci		sd = hpsa_find_device_by_sas_rphy(h, rphy);
212562306a36Sopenharmony_ci		if (sd) {
212662306a36Sopenharmony_ci			sd->target = sdev_id(sdev);
212762306a36Sopenharmony_ci			sd->lun = sdev->lun;
212862306a36Sopenharmony_ci		}
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci	if (!sd)
213162306a36Sopenharmony_ci		sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
213262306a36Sopenharmony_ci					sdev_id(sdev), sdev->lun);
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	if (sd && sd->expose_device) {
213562306a36Sopenharmony_ci		atomic_set(&sd->ioaccel_cmds_out, 0);
213662306a36Sopenharmony_ci		sdev->hostdata = sd;
213762306a36Sopenharmony_ci	} else
213862306a36Sopenharmony_ci		sdev->hostdata = NULL;
213962306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->devlock, flags);
214062306a36Sopenharmony_ci	return 0;
214162306a36Sopenharmony_ci}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci/* configure scsi device based on internal per-device structure */
214462306a36Sopenharmony_ci#define CTLR_TIMEOUT (120 * HZ)
214562306a36Sopenharmony_cistatic int hpsa_slave_configure(struct scsi_device *sdev)
214662306a36Sopenharmony_ci{
214762306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd;
214862306a36Sopenharmony_ci	int queue_depth;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	sd = sdev->hostdata;
215162306a36Sopenharmony_ci	sdev->no_uld_attach = !sd || !sd->expose_device;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	if (sd) {
215462306a36Sopenharmony_ci		sd->was_removed = 0;
215562306a36Sopenharmony_ci		queue_depth = sd->queue_depth != 0 ?
215662306a36Sopenharmony_ci				sd->queue_depth : sdev->host->can_queue;
215762306a36Sopenharmony_ci		if (sd->external) {
215862306a36Sopenharmony_ci			queue_depth = EXTERNAL_QD;
215962306a36Sopenharmony_ci			sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT;
216062306a36Sopenharmony_ci			blk_queue_rq_timeout(sdev->request_queue,
216162306a36Sopenharmony_ci						HPSA_EH_PTRAID_TIMEOUT);
216262306a36Sopenharmony_ci		}
216362306a36Sopenharmony_ci		if (is_hba_lunid(sd->scsi3addr)) {
216462306a36Sopenharmony_ci			sdev->eh_timeout = CTLR_TIMEOUT;
216562306a36Sopenharmony_ci			blk_queue_rq_timeout(sdev->request_queue, CTLR_TIMEOUT);
216662306a36Sopenharmony_ci		}
216762306a36Sopenharmony_ci	} else {
216862306a36Sopenharmony_ci		queue_depth = sdev->host->can_queue;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	scsi_change_queue_depth(sdev, queue_depth);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	return 0;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_cistatic void hpsa_slave_destroy(struct scsi_device *sdev)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *hdev = NULL;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	hdev = sdev->hostdata;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	if (hdev)
218362306a36Sopenharmony_ci		hdev->was_removed = 1;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_cistatic void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h)
218762306a36Sopenharmony_ci{
218862306a36Sopenharmony_ci	int i;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	if (!h->ioaccel2_cmd_sg_list)
219162306a36Sopenharmony_ci		return;
219262306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
219362306a36Sopenharmony_ci		kfree(h->ioaccel2_cmd_sg_list[i]);
219462306a36Sopenharmony_ci		h->ioaccel2_cmd_sg_list[i] = NULL;
219562306a36Sopenharmony_ci	}
219662306a36Sopenharmony_ci	kfree(h->ioaccel2_cmd_sg_list);
219762306a36Sopenharmony_ci	h->ioaccel2_cmd_sg_list = NULL;
219862306a36Sopenharmony_ci}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_cistatic int hpsa_allocate_ioaccel2_sg_chain_blocks(struct ctlr_info *h)
220162306a36Sopenharmony_ci{
220262306a36Sopenharmony_ci	int i;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	if (h->chainsize <= 0)
220562306a36Sopenharmony_ci		return 0;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	h->ioaccel2_cmd_sg_list =
220862306a36Sopenharmony_ci		kcalloc(h->nr_cmds, sizeof(*h->ioaccel2_cmd_sg_list),
220962306a36Sopenharmony_ci					GFP_KERNEL);
221062306a36Sopenharmony_ci	if (!h->ioaccel2_cmd_sg_list)
221162306a36Sopenharmony_ci		return -ENOMEM;
221262306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
221362306a36Sopenharmony_ci		h->ioaccel2_cmd_sg_list[i] =
221462306a36Sopenharmony_ci			kmalloc_array(h->maxsgentries,
221562306a36Sopenharmony_ci				      sizeof(*h->ioaccel2_cmd_sg_list[i]),
221662306a36Sopenharmony_ci				      GFP_KERNEL);
221762306a36Sopenharmony_ci		if (!h->ioaccel2_cmd_sg_list[i])
221862306a36Sopenharmony_ci			goto clean;
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci	return 0;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ciclean:
222362306a36Sopenharmony_ci	hpsa_free_ioaccel2_sg_chain_blocks(h);
222462306a36Sopenharmony_ci	return -ENOMEM;
222562306a36Sopenharmony_ci}
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_cistatic void hpsa_free_sg_chain_blocks(struct ctlr_info *h)
222862306a36Sopenharmony_ci{
222962306a36Sopenharmony_ci	int i;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	if (!h->cmd_sg_list)
223262306a36Sopenharmony_ci		return;
223362306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
223462306a36Sopenharmony_ci		kfree(h->cmd_sg_list[i]);
223562306a36Sopenharmony_ci		h->cmd_sg_list[i] = NULL;
223662306a36Sopenharmony_ci	}
223762306a36Sopenharmony_ci	kfree(h->cmd_sg_list);
223862306a36Sopenharmony_ci	h->cmd_sg_list = NULL;
223962306a36Sopenharmony_ci}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_cistatic int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	int i;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	if (h->chainsize <= 0)
224662306a36Sopenharmony_ci		return 0;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	h->cmd_sg_list = kcalloc(h->nr_cmds, sizeof(*h->cmd_sg_list),
224962306a36Sopenharmony_ci				 GFP_KERNEL);
225062306a36Sopenharmony_ci	if (!h->cmd_sg_list)
225162306a36Sopenharmony_ci		return -ENOMEM;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
225462306a36Sopenharmony_ci		h->cmd_sg_list[i] = kmalloc_array(h->chainsize,
225562306a36Sopenharmony_ci						  sizeof(*h->cmd_sg_list[i]),
225662306a36Sopenharmony_ci						  GFP_KERNEL);
225762306a36Sopenharmony_ci		if (!h->cmd_sg_list[i])
225862306a36Sopenharmony_ci			goto clean;
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	}
226162306a36Sopenharmony_ci	return 0;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ciclean:
226462306a36Sopenharmony_ci	hpsa_free_sg_chain_blocks(h);
226562306a36Sopenharmony_ci	return -ENOMEM;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h,
226962306a36Sopenharmony_ci	struct io_accel2_cmd *cp, struct CommandList *c)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	struct ioaccel2_sg_element *chain_block;
227262306a36Sopenharmony_ci	u64 temp64;
227362306a36Sopenharmony_ci	u32 chain_size;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex];
227662306a36Sopenharmony_ci	chain_size = le32_to_cpu(cp->sg[0].length);
227762306a36Sopenharmony_ci	temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_size,
227862306a36Sopenharmony_ci				DMA_TO_DEVICE);
227962306a36Sopenharmony_ci	if (dma_mapping_error(&h->pdev->dev, temp64)) {
228062306a36Sopenharmony_ci		/* prevent subsequent unmapping */
228162306a36Sopenharmony_ci		cp->sg->address = 0;
228262306a36Sopenharmony_ci		return -1;
228362306a36Sopenharmony_ci	}
228462306a36Sopenharmony_ci	cp->sg->address = cpu_to_le64(temp64);
228562306a36Sopenharmony_ci	return 0;
228662306a36Sopenharmony_ci}
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_cistatic void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h,
228962306a36Sopenharmony_ci	struct io_accel2_cmd *cp)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct ioaccel2_sg_element *chain_sg;
229262306a36Sopenharmony_ci	u64 temp64;
229362306a36Sopenharmony_ci	u32 chain_size;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	chain_sg = cp->sg;
229662306a36Sopenharmony_ci	temp64 = le64_to_cpu(chain_sg->address);
229762306a36Sopenharmony_ci	chain_size = le32_to_cpu(cp->sg[0].length);
229862306a36Sopenharmony_ci	dma_unmap_single(&h->pdev->dev, temp64, chain_size, DMA_TO_DEVICE);
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_cistatic int hpsa_map_sg_chain_block(struct ctlr_info *h,
230262306a36Sopenharmony_ci	struct CommandList *c)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	struct SGDescriptor *chain_sg, *chain_block;
230562306a36Sopenharmony_ci	u64 temp64;
230662306a36Sopenharmony_ci	u32 chain_len;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
230962306a36Sopenharmony_ci	chain_block = h->cmd_sg_list[c->cmdindex];
231062306a36Sopenharmony_ci	chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN);
231162306a36Sopenharmony_ci	chain_len = sizeof(*chain_sg) *
231262306a36Sopenharmony_ci		(le16_to_cpu(c->Header.SGTotal) - h->max_cmd_sg_entries);
231362306a36Sopenharmony_ci	chain_sg->Len = cpu_to_le32(chain_len);
231462306a36Sopenharmony_ci	temp64 = dma_map_single(&h->pdev->dev, chain_block, chain_len,
231562306a36Sopenharmony_ci				DMA_TO_DEVICE);
231662306a36Sopenharmony_ci	if (dma_mapping_error(&h->pdev->dev, temp64)) {
231762306a36Sopenharmony_ci		/* prevent subsequent unmapping */
231862306a36Sopenharmony_ci		chain_sg->Addr = cpu_to_le64(0);
231962306a36Sopenharmony_ci		return -1;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci	chain_sg->Addr = cpu_to_le64(temp64);
232262306a36Sopenharmony_ci	return 0;
232362306a36Sopenharmony_ci}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_cistatic void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
232662306a36Sopenharmony_ci	struct CommandList *c)
232762306a36Sopenharmony_ci{
232862306a36Sopenharmony_ci	struct SGDescriptor *chain_sg;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (le16_to_cpu(c->Header.SGTotal) <= h->max_cmd_sg_entries)
233162306a36Sopenharmony_ci		return;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
233462306a36Sopenharmony_ci	dma_unmap_single(&h->pdev->dev, le64_to_cpu(chain_sg->Addr),
233562306a36Sopenharmony_ci			le32_to_cpu(chain_sg->Len), DMA_TO_DEVICE);
233662306a36Sopenharmony_ci}
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci/* Decode the various types of errors on ioaccel2 path.
234062306a36Sopenharmony_ci * Return 1 for any error that should generate a RAID path retry.
234162306a36Sopenharmony_ci * Return 0 for errors that don't require a RAID path retry.
234262306a36Sopenharmony_ci */
234362306a36Sopenharmony_cistatic int handle_ioaccel_mode2_error(struct ctlr_info *h,
234462306a36Sopenharmony_ci					struct CommandList *c,
234562306a36Sopenharmony_ci					struct scsi_cmnd *cmd,
234662306a36Sopenharmony_ci					struct io_accel2_cmd *c2,
234762306a36Sopenharmony_ci					struct hpsa_scsi_dev_t *dev)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	int data_len;
235062306a36Sopenharmony_ci	int retry = 0;
235162306a36Sopenharmony_ci	u32 ioaccel2_resid = 0;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	switch (c2->error_data.serv_response) {
235462306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_COMPLETE:
235562306a36Sopenharmony_ci		switch (c2->error_data.status) {
235662306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_GOOD:
235762306a36Sopenharmony_ci			if (cmd)
235862306a36Sopenharmony_ci				cmd->result = 0;
235962306a36Sopenharmony_ci			break;
236062306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND:
236162306a36Sopenharmony_ci			cmd->result |= SAM_STAT_CHECK_CONDITION;
236262306a36Sopenharmony_ci			if (c2->error_data.data_present !=
236362306a36Sopenharmony_ci					IOACCEL2_SENSE_DATA_PRESENT) {
236462306a36Sopenharmony_ci				memset(cmd->sense_buffer, 0,
236562306a36Sopenharmony_ci					SCSI_SENSE_BUFFERSIZE);
236662306a36Sopenharmony_ci				break;
236762306a36Sopenharmony_ci			}
236862306a36Sopenharmony_ci			/* copy the sense data */
236962306a36Sopenharmony_ci			data_len = c2->error_data.sense_data_len;
237062306a36Sopenharmony_ci			if (data_len > SCSI_SENSE_BUFFERSIZE)
237162306a36Sopenharmony_ci				data_len = SCSI_SENSE_BUFFERSIZE;
237262306a36Sopenharmony_ci			if (data_len > sizeof(c2->error_data.sense_data_buff))
237362306a36Sopenharmony_ci				data_len =
237462306a36Sopenharmony_ci					sizeof(c2->error_data.sense_data_buff);
237562306a36Sopenharmony_ci			memcpy(cmd->sense_buffer,
237662306a36Sopenharmony_ci				c2->error_data.sense_data_buff, data_len);
237762306a36Sopenharmony_ci			retry = 1;
237862306a36Sopenharmony_ci			break;
237962306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_BUSY:
238062306a36Sopenharmony_ci			retry = 1;
238162306a36Sopenharmony_ci			break;
238262306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_RES_CON:
238362306a36Sopenharmony_ci			retry = 1;
238462306a36Sopenharmony_ci			break;
238562306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL:
238662306a36Sopenharmony_ci			retry = 1;
238762306a36Sopenharmony_ci			break;
238862306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_TASK_COMP_ABORTED:
238962306a36Sopenharmony_ci			retry = 1;
239062306a36Sopenharmony_ci			break;
239162306a36Sopenharmony_ci		default:
239262306a36Sopenharmony_ci			retry = 1;
239362306a36Sopenharmony_ci			break;
239462306a36Sopenharmony_ci		}
239562306a36Sopenharmony_ci		break;
239662306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_FAILURE:
239762306a36Sopenharmony_ci		switch (c2->error_data.status) {
239862306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_IO_ERROR:
239962306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_IO_ABORTED:
240062306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_OVERRUN:
240162306a36Sopenharmony_ci			retry = 1;
240262306a36Sopenharmony_ci			break;
240362306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_UNDERRUN:
240462306a36Sopenharmony_ci			cmd->result = (DID_OK << 16);		/* host byte */
240562306a36Sopenharmony_ci			ioaccel2_resid = get_unaligned_le32(
240662306a36Sopenharmony_ci						&c2->error_data.resid_cnt[0]);
240762306a36Sopenharmony_ci			scsi_set_resid(cmd, ioaccel2_resid);
240862306a36Sopenharmony_ci			break;
240962306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_NO_PATH_TO_DEVICE:
241062306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_INVALID_DEVICE:
241162306a36Sopenharmony_ci		case IOACCEL2_STATUS_SR_IOACCEL_DISABLED:
241262306a36Sopenharmony_ci			/*
241362306a36Sopenharmony_ci			 * Did an HBA disk disappear? We will eventually
241462306a36Sopenharmony_ci			 * get a state change event from the controller but
241562306a36Sopenharmony_ci			 * in the meantime, we need to tell the OS that the
241662306a36Sopenharmony_ci			 * HBA disk is no longer there and stop I/O
241762306a36Sopenharmony_ci			 * from going down. This allows the potential re-insert
241862306a36Sopenharmony_ci			 * of the disk to get the same device node.
241962306a36Sopenharmony_ci			 */
242062306a36Sopenharmony_ci			if (dev->physical_device && dev->expose_device) {
242162306a36Sopenharmony_ci				cmd->result = DID_NO_CONNECT << 16;
242262306a36Sopenharmony_ci				dev->removed = 1;
242362306a36Sopenharmony_ci				h->drv_req_rescan = 1;
242462306a36Sopenharmony_ci				dev_warn(&h->pdev->dev,
242562306a36Sopenharmony_ci					"%s: device is gone!\n", __func__);
242662306a36Sopenharmony_ci			} else
242762306a36Sopenharmony_ci				/*
242862306a36Sopenharmony_ci				 * Retry by sending down the RAID path.
242962306a36Sopenharmony_ci				 * We will get an event from ctlr to
243062306a36Sopenharmony_ci				 * trigger rescan regardless.
243162306a36Sopenharmony_ci				 */
243262306a36Sopenharmony_ci				retry = 1;
243362306a36Sopenharmony_ci			break;
243462306a36Sopenharmony_ci		default:
243562306a36Sopenharmony_ci			retry = 1;
243662306a36Sopenharmony_ci		}
243762306a36Sopenharmony_ci		break;
243862306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_TMF_COMPLETE:
243962306a36Sopenharmony_ci		break;
244062306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_TMF_SUCCESS:
244162306a36Sopenharmony_ci		break;
244262306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_TMF_REJECTED:
244362306a36Sopenharmony_ci		retry = 1;
244462306a36Sopenharmony_ci		break;
244562306a36Sopenharmony_ci	case IOACCEL2_SERV_RESPONSE_TMF_WRONG_LUN:
244662306a36Sopenharmony_ci		break;
244762306a36Sopenharmony_ci	default:
244862306a36Sopenharmony_ci		retry = 1;
244962306a36Sopenharmony_ci		break;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	if (dev->in_reset)
245362306a36Sopenharmony_ci		retry = 0;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	return retry;	/* retry on raid path? */
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_cistatic void hpsa_cmd_resolve_events(struct ctlr_info *h,
245962306a36Sopenharmony_ci		struct CommandList *c)
246062306a36Sopenharmony_ci{
246162306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = c->device;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	/*
246462306a36Sopenharmony_ci	 * Reset c->scsi_cmd here so that the reset handler will know
246562306a36Sopenharmony_ci	 * this command has completed.  Then, check to see if the handler is
246662306a36Sopenharmony_ci	 * waiting for this command, and, if so, wake it.
246762306a36Sopenharmony_ci	 */
246862306a36Sopenharmony_ci	c->scsi_cmd = SCSI_CMD_IDLE;
246962306a36Sopenharmony_ci	mb();	/* Declare command idle before checking for pending events. */
247062306a36Sopenharmony_ci	if (dev) {
247162306a36Sopenharmony_ci		atomic_dec(&dev->commands_outstanding);
247262306a36Sopenharmony_ci		if (dev->in_reset &&
247362306a36Sopenharmony_ci			atomic_read(&dev->commands_outstanding) <= 0)
247462306a36Sopenharmony_ci			wake_up_all(&h->event_sync_wait_queue);
247562306a36Sopenharmony_ci	}
247662306a36Sopenharmony_ci}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_cistatic void hpsa_cmd_resolve_and_free(struct ctlr_info *h,
247962306a36Sopenharmony_ci				      struct CommandList *c)
248062306a36Sopenharmony_ci{
248162306a36Sopenharmony_ci	hpsa_cmd_resolve_events(h, c);
248262306a36Sopenharmony_ci	cmd_tagged_free(h, c);
248362306a36Sopenharmony_ci}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_cistatic void hpsa_cmd_free_and_done(struct ctlr_info *h,
248662306a36Sopenharmony_ci		struct CommandList *c, struct scsi_cmnd *cmd)
248762306a36Sopenharmony_ci{
248862306a36Sopenharmony_ci	hpsa_cmd_resolve_and_free(h, c);
248962306a36Sopenharmony_ci	if (cmd)
249062306a36Sopenharmony_ci		scsi_done(cmd);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_cistatic void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c)
249462306a36Sopenharmony_ci{
249562306a36Sopenharmony_ci	INIT_WORK(&c->work, hpsa_command_resubmit_worker);
249662306a36Sopenharmony_ci	queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_cistatic void process_ioaccel2_completion(struct ctlr_info *h,
250062306a36Sopenharmony_ci		struct CommandList *c, struct scsi_cmnd *cmd,
250162306a36Sopenharmony_ci		struct hpsa_scsi_dev_t *dev)
250262306a36Sopenharmony_ci{
250362306a36Sopenharmony_ci	struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	/* check for good status */
250662306a36Sopenharmony_ci	if (likely(c2->error_data.serv_response == 0 &&
250762306a36Sopenharmony_ci			c2->error_data.status == 0)) {
250862306a36Sopenharmony_ci		cmd->result = 0;
250962306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(h, c, cmd);
251062306a36Sopenharmony_ci	}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	/*
251362306a36Sopenharmony_ci	 * Any RAID offload error results in retry which will use
251462306a36Sopenharmony_ci	 * the normal I/O path so the controller can handle whatever is
251562306a36Sopenharmony_ci	 * wrong.
251662306a36Sopenharmony_ci	 */
251762306a36Sopenharmony_ci	if (is_logical_device(dev) &&
251862306a36Sopenharmony_ci		c2->error_data.serv_response ==
251962306a36Sopenharmony_ci			IOACCEL2_SERV_RESPONSE_FAILURE) {
252062306a36Sopenharmony_ci		if (c2->error_data.status ==
252162306a36Sopenharmony_ci			IOACCEL2_STATUS_SR_IOACCEL_DISABLED) {
252262306a36Sopenharmony_ci			hpsa_turn_off_ioaccel_for_device(dev);
252362306a36Sopenharmony_ci		}
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci		if (dev->in_reset) {
252662306a36Sopenharmony_ci			cmd->result = DID_RESET << 16;
252762306a36Sopenharmony_ci			return hpsa_cmd_free_and_done(h, c, cmd);
252862306a36Sopenharmony_ci		}
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci		return hpsa_retry_cmd(h, c);
253162306a36Sopenharmony_ci	}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_ci	if (handle_ioaccel_mode2_error(h, c, cmd, c2, dev))
253462306a36Sopenharmony_ci		return hpsa_retry_cmd(h, c);
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	return hpsa_cmd_free_and_done(h, c, cmd);
253762306a36Sopenharmony_ci}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci/* Returns 0 on success, < 0 otherwise. */
254062306a36Sopenharmony_cistatic int hpsa_evaluate_tmf_status(struct ctlr_info *h,
254162306a36Sopenharmony_ci					struct CommandList *cp)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	u8 tmf_status = cp->err_info->ScsiStatus;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	switch (tmf_status) {
254662306a36Sopenharmony_ci	case CISS_TMF_COMPLETE:
254762306a36Sopenharmony_ci		/*
254862306a36Sopenharmony_ci		 * CISS_TMF_COMPLETE never happens, instead,
254962306a36Sopenharmony_ci		 * ei->CommandStatus == 0 for this case.
255062306a36Sopenharmony_ci		 */
255162306a36Sopenharmony_ci	case CISS_TMF_SUCCESS:
255262306a36Sopenharmony_ci		return 0;
255362306a36Sopenharmony_ci	case CISS_TMF_INVALID_FRAME:
255462306a36Sopenharmony_ci	case CISS_TMF_NOT_SUPPORTED:
255562306a36Sopenharmony_ci	case CISS_TMF_FAILED:
255662306a36Sopenharmony_ci	case CISS_TMF_WRONG_LUN:
255762306a36Sopenharmony_ci	case CISS_TMF_OVERLAPPED_TAG:
255862306a36Sopenharmony_ci		break;
255962306a36Sopenharmony_ci	default:
256062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Unknown TMF status: 0x%02x\n",
256162306a36Sopenharmony_ci				tmf_status);
256262306a36Sopenharmony_ci		break;
256362306a36Sopenharmony_ci	}
256462306a36Sopenharmony_ci	return -tmf_status;
256562306a36Sopenharmony_ci}
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_cistatic void complete_scsi_command(struct CommandList *cp)
256862306a36Sopenharmony_ci{
256962306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
257062306a36Sopenharmony_ci	struct ctlr_info *h;
257162306a36Sopenharmony_ci	struct ErrorInfo *ei;
257262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev;
257362306a36Sopenharmony_ci	struct io_accel2_cmd *c2;
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	u8 sense_key;
257662306a36Sopenharmony_ci	u8 asc;      /* additional sense code */
257762306a36Sopenharmony_ci	u8 ascq;     /* additional sense code qualifier */
257862306a36Sopenharmony_ci	unsigned long sense_data_size;
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	ei = cp->err_info;
258162306a36Sopenharmony_ci	cmd = cp->scsi_cmd;
258262306a36Sopenharmony_ci	h = cp->h;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (!cmd->device) {
258562306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
258662306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(h, cp, cmd);
258762306a36Sopenharmony_ci	}
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	dev = cmd->device->hostdata;
259062306a36Sopenharmony_ci	if (!dev) {
259162306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
259262306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(h, cp, cmd);
259362306a36Sopenharmony_ci	}
259462306a36Sopenharmony_ci	c2 = &h->ioaccel2_cmd_pool[cp->cmdindex];
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	scsi_dma_unmap(cmd); /* undo the DMA mappings */
259762306a36Sopenharmony_ci	if ((cp->cmd_type == CMD_SCSI) &&
259862306a36Sopenharmony_ci		(le16_to_cpu(cp->Header.SGTotal) > h->max_cmd_sg_entries))
259962306a36Sopenharmony_ci		hpsa_unmap_sg_chain_block(h, cp);
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	if ((cp->cmd_type == CMD_IOACCEL2) &&
260262306a36Sopenharmony_ci		(c2->sg[0].chain_indicator == IOACCEL2_CHAIN))
260362306a36Sopenharmony_ci		hpsa_unmap_ioaccel2_sg_chain_block(h, c2);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	cmd->result = (DID_OK << 16);		/* host byte */
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	/* SCSI command has already been cleaned up in SML */
260862306a36Sopenharmony_ci	if (dev->was_removed) {
260962306a36Sopenharmony_ci		hpsa_cmd_resolve_and_free(h, cp);
261062306a36Sopenharmony_ci		return;
261162306a36Sopenharmony_ci	}
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
261462306a36Sopenharmony_ci		if (dev->physical_device && dev->expose_device &&
261562306a36Sopenharmony_ci			dev->removed) {
261662306a36Sopenharmony_ci			cmd->result = DID_NO_CONNECT << 16;
261762306a36Sopenharmony_ci			return hpsa_cmd_free_and_done(h, cp, cmd);
261862306a36Sopenharmony_ci		}
261962306a36Sopenharmony_ci		if (likely(cp->phys_disk != NULL))
262062306a36Sopenharmony_ci			atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
262162306a36Sopenharmony_ci	}
262262306a36Sopenharmony_ci
262362306a36Sopenharmony_ci	/*
262462306a36Sopenharmony_ci	 * We check for lockup status here as it may be set for
262562306a36Sopenharmony_ci	 * CMD_SCSI, CMD_IOACCEL1 and CMD_IOACCEL2 commands by
262662306a36Sopenharmony_ci	 * fail_all_oustanding_cmds()
262762306a36Sopenharmony_ci	 */
262862306a36Sopenharmony_ci	if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) {
262962306a36Sopenharmony_ci		/* DID_NO_CONNECT will prevent a retry */
263062306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
263162306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(h, cp, cmd);
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	if (cp->cmd_type == CMD_IOACCEL2)
263562306a36Sopenharmony_ci		return process_ioaccel2_completion(h, cp, cmd, dev);
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	scsi_set_resid(cmd, ei->ResidualCnt);
263862306a36Sopenharmony_ci	if (ei->CommandStatus == 0)
263962306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(h, cp, cmd);
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	/* For I/O accelerator commands, copy over some fields to the normal
264262306a36Sopenharmony_ci	 * CISS header used below for error handling.
264362306a36Sopenharmony_ci	 */
264462306a36Sopenharmony_ci	if (cp->cmd_type == CMD_IOACCEL1) {
264562306a36Sopenharmony_ci		struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex];
264662306a36Sopenharmony_ci		cp->Header.SGList = scsi_sg_count(cmd);
264762306a36Sopenharmony_ci		cp->Header.SGTotal = cpu_to_le16(cp->Header.SGList);
264862306a36Sopenharmony_ci		cp->Request.CDBLen = le16_to_cpu(c->io_flags) &
264962306a36Sopenharmony_ci			IOACCEL1_IOFLAGS_CDBLEN_MASK;
265062306a36Sopenharmony_ci		cp->Header.tag = c->tag;
265162306a36Sopenharmony_ci		memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
265262306a36Sopenharmony_ci		memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci		/* Any RAID offload error results in retry which will use
265562306a36Sopenharmony_ci		 * the normal I/O path so the controller can handle whatever's
265662306a36Sopenharmony_ci		 * wrong.
265762306a36Sopenharmony_ci		 */
265862306a36Sopenharmony_ci		if (is_logical_device(dev)) {
265962306a36Sopenharmony_ci			if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
266062306a36Sopenharmony_ci				dev->offload_enabled = 0;
266162306a36Sopenharmony_ci			return hpsa_retry_cmd(h, cp);
266262306a36Sopenharmony_ci		}
266362306a36Sopenharmony_ci	}
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	/* an error has occurred */
266662306a36Sopenharmony_ci	switch (ei->CommandStatus) {
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci	case CMD_TARGET_STATUS:
266962306a36Sopenharmony_ci		cmd->result |= ei->ScsiStatus;
267062306a36Sopenharmony_ci		/* copy the sense data */
267162306a36Sopenharmony_ci		if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
267262306a36Sopenharmony_ci			sense_data_size = SCSI_SENSE_BUFFERSIZE;
267362306a36Sopenharmony_ci		else
267462306a36Sopenharmony_ci			sense_data_size = sizeof(ei->SenseInfo);
267562306a36Sopenharmony_ci		if (ei->SenseLen < sense_data_size)
267662306a36Sopenharmony_ci			sense_data_size = ei->SenseLen;
267762306a36Sopenharmony_ci		memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size);
267862306a36Sopenharmony_ci		if (ei->ScsiStatus)
267962306a36Sopenharmony_ci			decode_sense_data(ei->SenseInfo, sense_data_size,
268062306a36Sopenharmony_ci				&sense_key, &asc, &ascq);
268162306a36Sopenharmony_ci		if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
268262306a36Sopenharmony_ci			switch (sense_key) {
268362306a36Sopenharmony_ci			case ABORTED_COMMAND:
268462306a36Sopenharmony_ci				cmd->result |= DID_SOFT_ERROR << 16;
268562306a36Sopenharmony_ci				break;
268662306a36Sopenharmony_ci			case UNIT_ATTENTION:
268762306a36Sopenharmony_ci				if (asc == 0x3F && ascq == 0x0E)
268862306a36Sopenharmony_ci					h->drv_req_rescan = 1;
268962306a36Sopenharmony_ci				break;
269062306a36Sopenharmony_ci			case ILLEGAL_REQUEST:
269162306a36Sopenharmony_ci				if (asc == 0x25 && ascq == 0x00) {
269262306a36Sopenharmony_ci					dev->removed = 1;
269362306a36Sopenharmony_ci					cmd->result = DID_NO_CONNECT << 16;
269462306a36Sopenharmony_ci				}
269562306a36Sopenharmony_ci				break;
269662306a36Sopenharmony_ci			}
269762306a36Sopenharmony_ci			break;
269862306a36Sopenharmony_ci		}
269962306a36Sopenharmony_ci		/* Problem was not a check condition
270062306a36Sopenharmony_ci		 * Pass it up to the upper layers...
270162306a36Sopenharmony_ci		 */
270262306a36Sopenharmony_ci		if (ei->ScsiStatus) {
270362306a36Sopenharmony_ci			dev_warn(&h->pdev->dev, "cp %p has status 0x%x "
270462306a36Sopenharmony_ci				"Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
270562306a36Sopenharmony_ci				"Returning result: 0x%x\n",
270662306a36Sopenharmony_ci				cp, ei->ScsiStatus,
270762306a36Sopenharmony_ci				sense_key, asc, ascq,
270862306a36Sopenharmony_ci				cmd->result);
270962306a36Sopenharmony_ci		} else {  /* scsi status is zero??? How??? */
271062306a36Sopenharmony_ci			dev_warn(&h->pdev->dev, "cp %p SCSI status was 0. "
271162306a36Sopenharmony_ci				"Returning no connection.\n", cp),
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci			/* Ordinarily, this case should never happen,
271462306a36Sopenharmony_ci			 * but there is a bug in some released firmware
271562306a36Sopenharmony_ci			 * revisions that allows it to happen if, for
271662306a36Sopenharmony_ci			 * example, a 4100 backplane loses power and
271762306a36Sopenharmony_ci			 * the tape drive is in it.  We assume that
271862306a36Sopenharmony_ci			 * it's a fatal error of some kind because we
271962306a36Sopenharmony_ci			 * can't show that it wasn't. We will make it
272062306a36Sopenharmony_ci			 * look like selection timeout since that is
272162306a36Sopenharmony_ci			 * the most common reason for this to occur,
272262306a36Sopenharmony_ci			 * and it's severe enough.
272362306a36Sopenharmony_ci			 */
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci			cmd->result = DID_NO_CONNECT << 16;
272662306a36Sopenharmony_ci		}
272762306a36Sopenharmony_ci		break;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
273062306a36Sopenharmony_ci		break;
273162306a36Sopenharmony_ci	case CMD_DATA_OVERRUN:
273262306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
273362306a36Sopenharmony_ci			"CDB %16phN data overrun\n", cp->Request.CDB);
273462306a36Sopenharmony_ci		break;
273562306a36Sopenharmony_ci	case CMD_INVALID: {
273662306a36Sopenharmony_ci		/* print_bytes(cp, sizeof(*cp), 1, 0);
273762306a36Sopenharmony_ci		print_cmd(cp); */
273862306a36Sopenharmony_ci		/* We get CMD_INVALID if you address a non-existent device
273962306a36Sopenharmony_ci		 * instead of a selection timeout (no response).  You will
274062306a36Sopenharmony_ci		 * see this if you yank out a drive, then try to access it.
274162306a36Sopenharmony_ci		 * This is kind of a shame because it means that any other
274262306a36Sopenharmony_ci		 * CMD_INVALID (e.g. driver bug) will get interpreted as a
274362306a36Sopenharmony_ci		 * missing target. */
274462306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci		break;
274762306a36Sopenharmony_ci	case CMD_PROTOCOL_ERR:
274862306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
274962306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n",
275062306a36Sopenharmony_ci				cp->Request.CDB);
275162306a36Sopenharmony_ci		break;
275262306a36Sopenharmony_ci	case CMD_HARDWARE_ERR:
275362306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
275462306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n",
275562306a36Sopenharmony_ci			cp->Request.CDB);
275662306a36Sopenharmony_ci		break;
275762306a36Sopenharmony_ci	case CMD_CONNECTION_LOST:
275862306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
275962306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n",
276062306a36Sopenharmony_ci			cp->Request.CDB);
276162306a36Sopenharmony_ci		break;
276262306a36Sopenharmony_ci	case CMD_ABORTED:
276362306a36Sopenharmony_ci		cmd->result = DID_ABORT << 16;
276462306a36Sopenharmony_ci		break;
276562306a36Sopenharmony_ci	case CMD_ABORT_FAILED:
276662306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
276762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n",
276862306a36Sopenharmony_ci			cp->Request.CDB);
276962306a36Sopenharmony_ci		break;
277062306a36Sopenharmony_ci	case CMD_UNSOLICITED_ABORT:
277162306a36Sopenharmony_ci		cmd->result = DID_SOFT_ERROR << 16; /* retry the command */
277262306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n",
277362306a36Sopenharmony_ci			cp->Request.CDB);
277462306a36Sopenharmony_ci		break;
277562306a36Sopenharmony_ci	case CMD_TIMEOUT:
277662306a36Sopenharmony_ci		cmd->result = DID_TIME_OUT << 16;
277762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "CDB %16phN timed out\n",
277862306a36Sopenharmony_ci			cp->Request.CDB);
277962306a36Sopenharmony_ci		break;
278062306a36Sopenharmony_ci	case CMD_UNABORTABLE:
278162306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
278262306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Command unabortable\n");
278362306a36Sopenharmony_ci		break;
278462306a36Sopenharmony_ci	case CMD_TMF_STATUS:
278562306a36Sopenharmony_ci		if (hpsa_evaluate_tmf_status(h, cp)) /* TMF failed? */
278662306a36Sopenharmony_ci			cmd->result = DID_ERROR << 16;
278762306a36Sopenharmony_ci		break;
278862306a36Sopenharmony_ci	case CMD_IOACCEL_DISABLED:
278962306a36Sopenharmony_ci		/* This only handles the direct pass-through case since RAID
279062306a36Sopenharmony_ci		 * offload is handled above.  Just attempt a retry.
279162306a36Sopenharmony_ci		 */
279262306a36Sopenharmony_ci		cmd->result = DID_SOFT_ERROR << 16;
279362306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
279462306a36Sopenharmony_ci				"cp %p had HP SSD Smart Path error\n", cp);
279562306a36Sopenharmony_ci		break;
279662306a36Sopenharmony_ci	default:
279762306a36Sopenharmony_ci		cmd->result = DID_ERROR << 16;
279862306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
279962306a36Sopenharmony_ci				cp, ei->CommandStatus);
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	return hpsa_cmd_free_and_done(h, cp, cmd);
280362306a36Sopenharmony_ci}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_cistatic void hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c,
280662306a36Sopenharmony_ci		int sg_used, enum dma_data_direction data_direction)
280762306a36Sopenharmony_ci{
280862306a36Sopenharmony_ci	int i;
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	for (i = 0; i < sg_used; i++)
281162306a36Sopenharmony_ci		dma_unmap_single(&pdev->dev, le64_to_cpu(c->SG[i].Addr),
281262306a36Sopenharmony_ci				le32_to_cpu(c->SG[i].Len),
281362306a36Sopenharmony_ci				data_direction);
281462306a36Sopenharmony_ci}
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_cistatic int hpsa_map_one(struct pci_dev *pdev,
281762306a36Sopenharmony_ci		struct CommandList *cp,
281862306a36Sopenharmony_ci		unsigned char *buf,
281962306a36Sopenharmony_ci		size_t buflen,
282062306a36Sopenharmony_ci		enum dma_data_direction data_direction)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	u64 addr64;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	if (buflen == 0 || data_direction == DMA_NONE) {
282562306a36Sopenharmony_ci		cp->Header.SGList = 0;
282662306a36Sopenharmony_ci		cp->Header.SGTotal = cpu_to_le16(0);
282762306a36Sopenharmony_ci		return 0;
282862306a36Sopenharmony_ci	}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	addr64 = dma_map_single(&pdev->dev, buf, buflen, data_direction);
283162306a36Sopenharmony_ci	if (dma_mapping_error(&pdev->dev, addr64)) {
283262306a36Sopenharmony_ci		/* Prevent subsequent unmap of something never mapped */
283362306a36Sopenharmony_ci		cp->Header.SGList = 0;
283462306a36Sopenharmony_ci		cp->Header.SGTotal = cpu_to_le16(0);
283562306a36Sopenharmony_ci		return -1;
283662306a36Sopenharmony_ci	}
283762306a36Sopenharmony_ci	cp->SG[0].Addr = cpu_to_le64(addr64);
283862306a36Sopenharmony_ci	cp->SG[0].Len = cpu_to_le32(buflen);
283962306a36Sopenharmony_ci	cp->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* we are not chaining */
284062306a36Sopenharmony_ci	cp->Header.SGList = 1;   /* no. SGs contig in this cmd */
284162306a36Sopenharmony_ci	cp->Header.SGTotal = cpu_to_le16(1); /* total sgs in cmd list */
284262306a36Sopenharmony_ci	return 0;
284362306a36Sopenharmony_ci}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci#define NO_TIMEOUT ((unsigned long) -1)
284662306a36Sopenharmony_ci#define DEFAULT_TIMEOUT 30000 /* milliseconds */
284762306a36Sopenharmony_cistatic int hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h,
284862306a36Sopenharmony_ci	struct CommandList *c, int reply_queue, unsigned long timeout_msecs)
284962306a36Sopenharmony_ci{
285062306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(wait);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	c->waiting = &wait;
285362306a36Sopenharmony_ci	__enqueue_cmd_and_start_io(h, c, reply_queue);
285462306a36Sopenharmony_ci	if (timeout_msecs == NO_TIMEOUT) {
285562306a36Sopenharmony_ci		/* TODO: get rid of this no-timeout thing */
285662306a36Sopenharmony_ci		wait_for_completion_io(&wait);
285762306a36Sopenharmony_ci		return IO_OK;
285862306a36Sopenharmony_ci	}
285962306a36Sopenharmony_ci	if (!wait_for_completion_io_timeout(&wait,
286062306a36Sopenharmony_ci					msecs_to_jiffies(timeout_msecs))) {
286162306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Command timed out.\n");
286262306a36Sopenharmony_ci		return -ETIMEDOUT;
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci	return IO_OK;
286562306a36Sopenharmony_ci}
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_cistatic int hpsa_scsi_do_simple_cmd(struct ctlr_info *h, struct CommandList *c,
286862306a36Sopenharmony_ci				   int reply_queue, unsigned long timeout_msecs)
286962306a36Sopenharmony_ci{
287062306a36Sopenharmony_ci	if (unlikely(lockup_detected(h))) {
287162306a36Sopenharmony_ci		c->err_info->CommandStatus = CMD_CTLR_LOCKUP;
287262306a36Sopenharmony_ci		return IO_OK;
287362306a36Sopenharmony_ci	}
287462306a36Sopenharmony_ci	return hpsa_scsi_do_simple_cmd_core(h, c, reply_queue, timeout_msecs);
287562306a36Sopenharmony_ci}
287662306a36Sopenharmony_ci
287762306a36Sopenharmony_cistatic u32 lockup_detected(struct ctlr_info *h)
287862306a36Sopenharmony_ci{
287962306a36Sopenharmony_ci	int cpu;
288062306a36Sopenharmony_ci	u32 rc, *lockup_detected;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	cpu = get_cpu();
288362306a36Sopenharmony_ci	lockup_detected = per_cpu_ptr(h->lockup_detected, cpu);
288462306a36Sopenharmony_ci	rc = *lockup_detected;
288562306a36Sopenharmony_ci	put_cpu();
288662306a36Sopenharmony_ci	return rc;
288762306a36Sopenharmony_ci}
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci#define MAX_DRIVER_CMD_RETRIES 25
289062306a36Sopenharmony_cistatic int hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
289162306a36Sopenharmony_ci		struct CommandList *c, enum dma_data_direction data_direction,
289262306a36Sopenharmony_ci		unsigned long timeout_msecs)
289362306a36Sopenharmony_ci{
289462306a36Sopenharmony_ci	int backoff_time = 10, retry_count = 0;
289562306a36Sopenharmony_ci	int rc;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	do {
289862306a36Sopenharmony_ci		memset(c->err_info, 0, sizeof(*c->err_info));
289962306a36Sopenharmony_ci		rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
290062306a36Sopenharmony_ci						  timeout_msecs);
290162306a36Sopenharmony_ci		if (rc)
290262306a36Sopenharmony_ci			break;
290362306a36Sopenharmony_ci		retry_count++;
290462306a36Sopenharmony_ci		if (retry_count > 3) {
290562306a36Sopenharmony_ci			msleep(backoff_time);
290662306a36Sopenharmony_ci			if (backoff_time < 1000)
290762306a36Sopenharmony_ci				backoff_time *= 2;
290862306a36Sopenharmony_ci		}
290962306a36Sopenharmony_ci	} while ((check_for_unit_attention(h, c) ||
291062306a36Sopenharmony_ci			check_for_busy(h, c)) &&
291162306a36Sopenharmony_ci			retry_count <= MAX_DRIVER_CMD_RETRIES);
291262306a36Sopenharmony_ci	hpsa_pci_unmap(h->pdev, c, 1, data_direction);
291362306a36Sopenharmony_ci	if (retry_count > MAX_DRIVER_CMD_RETRIES)
291462306a36Sopenharmony_ci		rc = -EIO;
291562306a36Sopenharmony_ci	return rc;
291662306a36Sopenharmony_ci}
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_cistatic void hpsa_print_cmd(struct ctlr_info *h, char *txt,
291962306a36Sopenharmony_ci				struct CommandList *c)
292062306a36Sopenharmony_ci{
292162306a36Sopenharmony_ci	const u8 *cdb = c->Request.CDB;
292262306a36Sopenharmony_ci	const u8 *lun = c->Header.LUN.LunAddrBytes;
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci	dev_warn(&h->pdev->dev, "%s: LUN:%8phN CDB:%16phN\n",
292562306a36Sopenharmony_ci		 txt, lun, cdb);
292662306a36Sopenharmony_ci}
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_cistatic void hpsa_scsi_interpret_error(struct ctlr_info *h,
292962306a36Sopenharmony_ci			struct CommandList *cp)
293062306a36Sopenharmony_ci{
293162306a36Sopenharmony_ci	const struct ErrorInfo *ei = cp->err_info;
293262306a36Sopenharmony_ci	struct device *d = &cp->h->pdev->dev;
293362306a36Sopenharmony_ci	u8 sense_key, asc, ascq;
293462306a36Sopenharmony_ci	int sense_len;
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	switch (ei->CommandStatus) {
293762306a36Sopenharmony_ci	case CMD_TARGET_STATUS:
293862306a36Sopenharmony_ci		if (ei->SenseLen > sizeof(ei->SenseInfo))
293962306a36Sopenharmony_ci			sense_len = sizeof(ei->SenseInfo);
294062306a36Sopenharmony_ci		else
294162306a36Sopenharmony_ci			sense_len = ei->SenseLen;
294262306a36Sopenharmony_ci		decode_sense_data(ei->SenseInfo, sense_len,
294362306a36Sopenharmony_ci					&sense_key, &asc, &ascq);
294462306a36Sopenharmony_ci		hpsa_print_cmd(h, "SCSI status", cp);
294562306a36Sopenharmony_ci		if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION)
294662306a36Sopenharmony_ci			dev_warn(d, "SCSI Status = 02, Sense key = 0x%02x, ASC = 0x%02x, ASCQ = 0x%02x\n",
294762306a36Sopenharmony_ci				sense_key, asc, ascq);
294862306a36Sopenharmony_ci		else
294962306a36Sopenharmony_ci			dev_warn(d, "SCSI Status = 0x%02x\n", ei->ScsiStatus);
295062306a36Sopenharmony_ci		if (ei->ScsiStatus == 0)
295162306a36Sopenharmony_ci			dev_warn(d, "SCSI status is abnormally zero.  "
295262306a36Sopenharmony_ci			"(probably indicates selection timeout "
295362306a36Sopenharmony_ci			"reported incorrectly due to a known "
295462306a36Sopenharmony_ci			"firmware bug, circa July, 2001.)\n");
295562306a36Sopenharmony_ci		break;
295662306a36Sopenharmony_ci	case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
295762306a36Sopenharmony_ci		break;
295862306a36Sopenharmony_ci	case CMD_DATA_OVERRUN:
295962306a36Sopenharmony_ci		hpsa_print_cmd(h, "overrun condition", cp);
296062306a36Sopenharmony_ci		break;
296162306a36Sopenharmony_ci	case CMD_INVALID: {
296262306a36Sopenharmony_ci		/* controller unfortunately reports SCSI passthru's
296362306a36Sopenharmony_ci		 * to non-existent targets as invalid commands.
296462306a36Sopenharmony_ci		 */
296562306a36Sopenharmony_ci		hpsa_print_cmd(h, "invalid command", cp);
296662306a36Sopenharmony_ci		dev_warn(d, "probably means device no longer present\n");
296762306a36Sopenharmony_ci		}
296862306a36Sopenharmony_ci		break;
296962306a36Sopenharmony_ci	case CMD_PROTOCOL_ERR:
297062306a36Sopenharmony_ci		hpsa_print_cmd(h, "protocol error", cp);
297162306a36Sopenharmony_ci		break;
297262306a36Sopenharmony_ci	case CMD_HARDWARE_ERR:
297362306a36Sopenharmony_ci		hpsa_print_cmd(h, "hardware error", cp);
297462306a36Sopenharmony_ci		break;
297562306a36Sopenharmony_ci	case CMD_CONNECTION_LOST:
297662306a36Sopenharmony_ci		hpsa_print_cmd(h, "connection lost", cp);
297762306a36Sopenharmony_ci		break;
297862306a36Sopenharmony_ci	case CMD_ABORTED:
297962306a36Sopenharmony_ci		hpsa_print_cmd(h, "aborted", cp);
298062306a36Sopenharmony_ci		break;
298162306a36Sopenharmony_ci	case CMD_ABORT_FAILED:
298262306a36Sopenharmony_ci		hpsa_print_cmd(h, "abort failed", cp);
298362306a36Sopenharmony_ci		break;
298462306a36Sopenharmony_ci	case CMD_UNSOLICITED_ABORT:
298562306a36Sopenharmony_ci		hpsa_print_cmd(h, "unsolicited abort", cp);
298662306a36Sopenharmony_ci		break;
298762306a36Sopenharmony_ci	case CMD_TIMEOUT:
298862306a36Sopenharmony_ci		hpsa_print_cmd(h, "timed out", cp);
298962306a36Sopenharmony_ci		break;
299062306a36Sopenharmony_ci	case CMD_UNABORTABLE:
299162306a36Sopenharmony_ci		hpsa_print_cmd(h, "unabortable", cp);
299262306a36Sopenharmony_ci		break;
299362306a36Sopenharmony_ci	case CMD_CTLR_LOCKUP:
299462306a36Sopenharmony_ci		hpsa_print_cmd(h, "controller lockup detected", cp);
299562306a36Sopenharmony_ci		break;
299662306a36Sopenharmony_ci	default:
299762306a36Sopenharmony_ci		hpsa_print_cmd(h, "unknown status", cp);
299862306a36Sopenharmony_ci		dev_warn(d, "Unknown command status %x\n",
299962306a36Sopenharmony_ci				ei->CommandStatus);
300062306a36Sopenharmony_ci	}
300162306a36Sopenharmony_ci}
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_cistatic int hpsa_do_receive_diagnostic(struct ctlr_info *h, u8 *scsi3addr,
300462306a36Sopenharmony_ci					u8 page, u8 *buf, size_t bufsize)
300562306a36Sopenharmony_ci{
300662306a36Sopenharmony_ci	int rc = IO_OK;
300762306a36Sopenharmony_ci	struct CommandList *c;
300862306a36Sopenharmony_ci	struct ErrorInfo *ei;
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	c = cmd_alloc(h);
301162306a36Sopenharmony_ci	if (fill_cmd(c, RECEIVE_DIAGNOSTIC, h, buf, bufsize,
301262306a36Sopenharmony_ci			page, scsi3addr, TYPE_CMD)) {
301362306a36Sopenharmony_ci		rc = -1;
301462306a36Sopenharmony_ci		goto out;
301562306a36Sopenharmony_ci	}
301662306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
301762306a36Sopenharmony_ci			NO_TIMEOUT);
301862306a36Sopenharmony_ci	if (rc)
301962306a36Sopenharmony_ci		goto out;
302062306a36Sopenharmony_ci	ei = c->err_info;
302162306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
302262306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
302362306a36Sopenharmony_ci		rc = -1;
302462306a36Sopenharmony_ci	}
302562306a36Sopenharmony_ciout:
302662306a36Sopenharmony_ci	cmd_free(h, c);
302762306a36Sopenharmony_ci	return rc;
302862306a36Sopenharmony_ci}
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_cistatic u64 hpsa_get_enclosure_logical_identifier(struct ctlr_info *h,
303162306a36Sopenharmony_ci						u8 *scsi3addr)
303262306a36Sopenharmony_ci{
303362306a36Sopenharmony_ci	u8 *buf;
303462306a36Sopenharmony_ci	u64 sa = 0;
303562306a36Sopenharmony_ci	int rc = 0;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	buf = kzalloc(1024, GFP_KERNEL);
303862306a36Sopenharmony_ci	if (!buf)
303962306a36Sopenharmony_ci		return 0;
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci	rc = hpsa_do_receive_diagnostic(h, scsi3addr, RECEIVE_DIAGNOSTIC,
304262306a36Sopenharmony_ci					buf, 1024);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	if (rc)
304562306a36Sopenharmony_ci		goto out;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	sa = get_unaligned_be64(buf+12);
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ciout:
305062306a36Sopenharmony_ci	kfree(buf);
305162306a36Sopenharmony_ci	return sa;
305262306a36Sopenharmony_ci}
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_cistatic int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
305562306a36Sopenharmony_ci			u16 page, unsigned char *buf,
305662306a36Sopenharmony_ci			unsigned char bufsize)
305762306a36Sopenharmony_ci{
305862306a36Sopenharmony_ci	int rc = IO_OK;
305962306a36Sopenharmony_ci	struct CommandList *c;
306062306a36Sopenharmony_ci	struct ErrorInfo *ei;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	c = cmd_alloc(h);
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci	if (fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize,
306562306a36Sopenharmony_ci			page, scsi3addr, TYPE_CMD)) {
306662306a36Sopenharmony_ci		rc = -1;
306762306a36Sopenharmony_ci		goto out;
306862306a36Sopenharmony_ci	}
306962306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
307062306a36Sopenharmony_ci			NO_TIMEOUT);
307162306a36Sopenharmony_ci	if (rc)
307262306a36Sopenharmony_ci		goto out;
307362306a36Sopenharmony_ci	ei = c->err_info;
307462306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
307562306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
307662306a36Sopenharmony_ci		rc = -1;
307762306a36Sopenharmony_ci	}
307862306a36Sopenharmony_ciout:
307962306a36Sopenharmony_ci	cmd_free(h, c);
308062306a36Sopenharmony_ci	return rc;
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_cistatic int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
308462306a36Sopenharmony_ci	u8 reset_type, int reply_queue)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	int rc = IO_OK;
308762306a36Sopenharmony_ci	struct CommandList *c;
308862306a36Sopenharmony_ci	struct ErrorInfo *ei;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	c = cmd_alloc(h);
309162306a36Sopenharmony_ci	c->device = dev;
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	/* fill_cmd can't fail here, no data buffer to map. */
309462306a36Sopenharmony_ci	(void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG);
309562306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
309662306a36Sopenharmony_ci	if (rc) {
309762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Failed to send reset command\n");
309862306a36Sopenharmony_ci		goto out;
309962306a36Sopenharmony_ci	}
310062306a36Sopenharmony_ci	/* no unmap needed here because no data xfer. */
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	ei = c->err_info;
310362306a36Sopenharmony_ci	if (ei->CommandStatus != 0) {
310462306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
310562306a36Sopenharmony_ci		rc = -1;
310662306a36Sopenharmony_ci	}
310762306a36Sopenharmony_ciout:
310862306a36Sopenharmony_ci	cmd_free(h, c);
310962306a36Sopenharmony_ci	return rc;
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_cistatic bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
311362306a36Sopenharmony_ci			       struct hpsa_scsi_dev_t *dev,
311462306a36Sopenharmony_ci			       unsigned char *scsi3addr)
311562306a36Sopenharmony_ci{
311662306a36Sopenharmony_ci	int i;
311762306a36Sopenharmony_ci	bool match = false;
311862306a36Sopenharmony_ci	struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
311962306a36Sopenharmony_ci	struct hpsa_tmf_struct *ac = (struct hpsa_tmf_struct *) c2;
312062306a36Sopenharmony_ci
312162306a36Sopenharmony_ci	if (hpsa_is_cmd_idle(c))
312262306a36Sopenharmony_ci		return false;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci	switch (c->cmd_type) {
312562306a36Sopenharmony_ci	case CMD_SCSI:
312662306a36Sopenharmony_ci	case CMD_IOCTL_PEND:
312762306a36Sopenharmony_ci		match = !memcmp(scsi3addr, &c->Header.LUN.LunAddrBytes,
312862306a36Sopenharmony_ci				sizeof(c->Header.LUN.LunAddrBytes));
312962306a36Sopenharmony_ci		break;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	case CMD_IOACCEL1:
313262306a36Sopenharmony_ci	case CMD_IOACCEL2:
313362306a36Sopenharmony_ci		if (c->phys_disk == dev) {
313462306a36Sopenharmony_ci			/* HBA mode match */
313562306a36Sopenharmony_ci			match = true;
313662306a36Sopenharmony_ci		} else {
313762306a36Sopenharmony_ci			/* Possible RAID mode -- check each phys dev. */
313862306a36Sopenharmony_ci			/* FIXME:  Do we need to take out a lock here?  If
313962306a36Sopenharmony_ci			 * so, we could just call hpsa_get_pdisk_of_ioaccel2()
314062306a36Sopenharmony_ci			 * instead. */
314162306a36Sopenharmony_ci			for (i = 0; i < dev->nphysical_disks && !match; i++) {
314262306a36Sopenharmony_ci				/* FIXME: an alternate test might be
314362306a36Sopenharmony_ci				 *
314462306a36Sopenharmony_ci				 * match = dev->phys_disk[i]->ioaccel_handle
314562306a36Sopenharmony_ci				 *              == c2->scsi_nexus;      */
314662306a36Sopenharmony_ci				match = dev->phys_disk[i] == c->phys_disk;
314762306a36Sopenharmony_ci			}
314862306a36Sopenharmony_ci		}
314962306a36Sopenharmony_ci		break;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	case IOACCEL2_TMF:
315262306a36Sopenharmony_ci		for (i = 0; i < dev->nphysical_disks && !match; i++) {
315362306a36Sopenharmony_ci			match = dev->phys_disk[i]->ioaccel_handle ==
315462306a36Sopenharmony_ci					le32_to_cpu(ac->it_nexus);
315562306a36Sopenharmony_ci		}
315662306a36Sopenharmony_ci		break;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	case 0:		/* The command is in the middle of being initialized. */
315962306a36Sopenharmony_ci		match = false;
316062306a36Sopenharmony_ci		break;
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_ci	default:
316362306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "unexpected cmd_type: %d\n",
316462306a36Sopenharmony_ci			c->cmd_type);
316562306a36Sopenharmony_ci		BUG();
316662306a36Sopenharmony_ci	}
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	return match;
316962306a36Sopenharmony_ci}
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_cistatic int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
317262306a36Sopenharmony_ci	u8 reset_type, int reply_queue)
317362306a36Sopenharmony_ci{
317462306a36Sopenharmony_ci	int rc = 0;
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	/* We can really only handle one reset at a time */
317762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&h->reset_mutex) == -EINTR) {
317862306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "concurrent reset wait interrupted.\n");
317962306a36Sopenharmony_ci		return -EINTR;
318062306a36Sopenharmony_ci	}
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	rc = hpsa_send_reset(h, dev, reset_type, reply_queue);
318362306a36Sopenharmony_ci	if (!rc) {
318462306a36Sopenharmony_ci		/* incremented by sending the reset request */
318562306a36Sopenharmony_ci		atomic_dec(&dev->commands_outstanding);
318662306a36Sopenharmony_ci		wait_event(h->event_sync_wait_queue,
318762306a36Sopenharmony_ci			atomic_read(&dev->commands_outstanding) <= 0 ||
318862306a36Sopenharmony_ci			lockup_detected(h));
318962306a36Sopenharmony_ci	}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	if (unlikely(lockup_detected(h))) {
319262306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
319362306a36Sopenharmony_ci			 "Controller lockup detected during reset wait\n");
319462306a36Sopenharmony_ci		rc = -ENODEV;
319562306a36Sopenharmony_ci	}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	if (!rc)
319862306a36Sopenharmony_ci		rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0);
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	mutex_unlock(&h->reset_mutex);
320162306a36Sopenharmony_ci	return rc;
320262306a36Sopenharmony_ci}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_cistatic void hpsa_get_raid_level(struct ctlr_info *h,
320562306a36Sopenharmony_ci	unsigned char *scsi3addr, unsigned char *raid_level)
320662306a36Sopenharmony_ci{
320762306a36Sopenharmony_ci	int rc;
320862306a36Sopenharmony_ci	unsigned char *buf;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	*raid_level = RAID_UNKNOWN;
321162306a36Sopenharmony_ci	buf = kzalloc(64, GFP_KERNEL);
321262306a36Sopenharmony_ci	if (!buf)
321362306a36Sopenharmony_ci		return;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	if (!hpsa_vpd_page_supported(h, scsi3addr,
321662306a36Sopenharmony_ci		HPSA_VPD_LV_DEVICE_GEOMETRY))
321762306a36Sopenharmony_ci		goto exit;
321862306a36Sopenharmony_ci
321962306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
322062306a36Sopenharmony_ci		HPSA_VPD_LV_DEVICE_GEOMETRY, buf, 64);
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	if (rc == 0)
322362306a36Sopenharmony_ci		*raid_level = buf[8];
322462306a36Sopenharmony_ci	if (*raid_level > RAID_UNKNOWN)
322562306a36Sopenharmony_ci		*raid_level = RAID_UNKNOWN;
322662306a36Sopenharmony_ciexit:
322762306a36Sopenharmony_ci	kfree(buf);
322862306a36Sopenharmony_ci	return;
322962306a36Sopenharmony_ci}
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci#define HPSA_MAP_DEBUG
323262306a36Sopenharmony_ci#ifdef HPSA_MAP_DEBUG
323362306a36Sopenharmony_cistatic void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
323462306a36Sopenharmony_ci				struct raid_map_data *map_buff)
323562306a36Sopenharmony_ci{
323662306a36Sopenharmony_ci	struct raid_map_disk_data *dd = &map_buff->data[0];
323762306a36Sopenharmony_ci	int map, row, col;
323862306a36Sopenharmony_ci	u16 map_cnt, row_cnt, disks_per_row;
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci	if (rc != 0)
324162306a36Sopenharmony_ci		return;
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	/* Show details only if debugging has been activated. */
324462306a36Sopenharmony_ci	if (h->raid_offload_debug < 2)
324562306a36Sopenharmony_ci		return;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "structure_size = %u\n",
324862306a36Sopenharmony_ci				le32_to_cpu(map_buff->structure_size));
324962306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "volume_blk_size = %u\n",
325062306a36Sopenharmony_ci			le32_to_cpu(map_buff->volume_blk_size));
325162306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "volume_blk_cnt = 0x%llx\n",
325262306a36Sopenharmony_ci			le64_to_cpu(map_buff->volume_blk_cnt));
325362306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "physicalBlockShift = %u\n",
325462306a36Sopenharmony_ci			map_buff->phys_blk_shift);
325562306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "parity_rotation_shift = %u\n",
325662306a36Sopenharmony_ci			map_buff->parity_rotation_shift);
325762306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "strip_size = %u\n",
325862306a36Sopenharmony_ci			le16_to_cpu(map_buff->strip_size));
325962306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "disk_starting_blk = 0x%llx\n",
326062306a36Sopenharmony_ci			le64_to_cpu(map_buff->disk_starting_blk));
326162306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "disk_blk_cnt = 0x%llx\n",
326262306a36Sopenharmony_ci			le64_to_cpu(map_buff->disk_blk_cnt));
326362306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "data_disks_per_row = %u\n",
326462306a36Sopenharmony_ci			le16_to_cpu(map_buff->data_disks_per_row));
326562306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "metadata_disks_per_row = %u\n",
326662306a36Sopenharmony_ci			le16_to_cpu(map_buff->metadata_disks_per_row));
326762306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "row_cnt = %u\n",
326862306a36Sopenharmony_ci			le16_to_cpu(map_buff->row_cnt));
326962306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "layout_map_count = %u\n",
327062306a36Sopenharmony_ci			le16_to_cpu(map_buff->layout_map_count));
327162306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "flags = 0x%x\n",
327262306a36Sopenharmony_ci			le16_to_cpu(map_buff->flags));
327362306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "encryption = %s\n",
327462306a36Sopenharmony_ci			le16_to_cpu(map_buff->flags) &
327562306a36Sopenharmony_ci			RAID_MAP_FLAG_ENCRYPT_ON ?  "ON" : "OFF");
327662306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "dekindex = %u\n",
327762306a36Sopenharmony_ci			le16_to_cpu(map_buff->dekindex));
327862306a36Sopenharmony_ci	map_cnt = le16_to_cpu(map_buff->layout_map_count);
327962306a36Sopenharmony_ci	for (map = 0; map < map_cnt; map++) {
328062306a36Sopenharmony_ci		dev_info(&h->pdev->dev, "Map%u:\n", map);
328162306a36Sopenharmony_ci		row_cnt = le16_to_cpu(map_buff->row_cnt);
328262306a36Sopenharmony_ci		for (row = 0; row < row_cnt; row++) {
328362306a36Sopenharmony_ci			dev_info(&h->pdev->dev, "  Row%u:\n", row);
328462306a36Sopenharmony_ci			disks_per_row =
328562306a36Sopenharmony_ci				le16_to_cpu(map_buff->data_disks_per_row);
328662306a36Sopenharmony_ci			for (col = 0; col < disks_per_row; col++, dd++)
328762306a36Sopenharmony_ci				dev_info(&h->pdev->dev,
328862306a36Sopenharmony_ci					"    D%02u: h=0x%04x xor=%u,%u\n",
328962306a36Sopenharmony_ci					col, dd->ioaccel_handle,
329062306a36Sopenharmony_ci					dd->xor_mult[0], dd->xor_mult[1]);
329162306a36Sopenharmony_ci			disks_per_row =
329262306a36Sopenharmony_ci				le16_to_cpu(map_buff->metadata_disks_per_row);
329362306a36Sopenharmony_ci			for (col = 0; col < disks_per_row; col++, dd++)
329462306a36Sopenharmony_ci				dev_info(&h->pdev->dev,
329562306a36Sopenharmony_ci					"    M%02u: h=0x%04x xor=%u,%u\n",
329662306a36Sopenharmony_ci					col, dd->ioaccel_handle,
329762306a36Sopenharmony_ci					dd->xor_mult[0], dd->xor_mult[1]);
329862306a36Sopenharmony_ci		}
329962306a36Sopenharmony_ci	}
330062306a36Sopenharmony_ci}
330162306a36Sopenharmony_ci#else
330262306a36Sopenharmony_cistatic void hpsa_debug_map_buff(__attribute__((unused)) struct ctlr_info *h,
330362306a36Sopenharmony_ci			__attribute__((unused)) int rc,
330462306a36Sopenharmony_ci			__attribute__((unused)) struct raid_map_data *map_buff)
330562306a36Sopenharmony_ci{
330662306a36Sopenharmony_ci}
330762306a36Sopenharmony_ci#endif
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_cistatic int hpsa_get_raid_map(struct ctlr_info *h,
331062306a36Sopenharmony_ci	unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
331162306a36Sopenharmony_ci{
331262306a36Sopenharmony_ci	int rc = 0;
331362306a36Sopenharmony_ci	struct CommandList *c;
331462306a36Sopenharmony_ci	struct ErrorInfo *ei;
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci	c = cmd_alloc(h);
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map,
331962306a36Sopenharmony_ci			sizeof(this_device->raid_map), 0,
332062306a36Sopenharmony_ci			scsi3addr, TYPE_CMD)) {
332162306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "hpsa_get_raid_map fill_cmd failed\n");
332262306a36Sopenharmony_ci		cmd_free(h, c);
332362306a36Sopenharmony_ci		return -1;
332462306a36Sopenharmony_ci	}
332562306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
332662306a36Sopenharmony_ci			NO_TIMEOUT);
332762306a36Sopenharmony_ci	if (rc)
332862306a36Sopenharmony_ci		goto out;
332962306a36Sopenharmony_ci	ei = c->err_info;
333062306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
333162306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
333262306a36Sopenharmony_ci		rc = -1;
333362306a36Sopenharmony_ci		goto out;
333462306a36Sopenharmony_ci	}
333562306a36Sopenharmony_ci	cmd_free(h, c);
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	/* @todo in the future, dynamically allocate RAID map memory */
333862306a36Sopenharmony_ci	if (le32_to_cpu(this_device->raid_map.structure_size) >
333962306a36Sopenharmony_ci				sizeof(this_device->raid_map)) {
334062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "RAID map size is too large!\n");
334162306a36Sopenharmony_ci		rc = -1;
334262306a36Sopenharmony_ci	}
334362306a36Sopenharmony_ci	hpsa_debug_map_buff(h, rc, &this_device->raid_map);
334462306a36Sopenharmony_ci	return rc;
334562306a36Sopenharmony_ciout:
334662306a36Sopenharmony_ci	cmd_free(h, c);
334762306a36Sopenharmony_ci	return rc;
334862306a36Sopenharmony_ci}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_cistatic int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h,
335162306a36Sopenharmony_ci		unsigned char scsi3addr[], u16 bmic_device_index,
335262306a36Sopenharmony_ci		struct bmic_sense_subsystem_info *buf, size_t bufsize)
335362306a36Sopenharmony_ci{
335462306a36Sopenharmony_ci	int rc = IO_OK;
335562306a36Sopenharmony_ci	struct CommandList *c;
335662306a36Sopenharmony_ci	struct ErrorInfo *ei;
335762306a36Sopenharmony_ci
335862306a36Sopenharmony_ci	c = cmd_alloc(h);
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize,
336162306a36Sopenharmony_ci		0, RAID_CTLR_LUNID, TYPE_CMD);
336262306a36Sopenharmony_ci	if (rc)
336362306a36Sopenharmony_ci		goto out;
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	c->Request.CDB[2] = bmic_device_index & 0xff;
336662306a36Sopenharmony_ci	c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
336962306a36Sopenharmony_ci			NO_TIMEOUT);
337062306a36Sopenharmony_ci	if (rc)
337162306a36Sopenharmony_ci		goto out;
337262306a36Sopenharmony_ci	ei = c->err_info;
337362306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
337462306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
337562306a36Sopenharmony_ci		rc = -1;
337662306a36Sopenharmony_ci	}
337762306a36Sopenharmony_ciout:
337862306a36Sopenharmony_ci	cmd_free(h, c);
337962306a36Sopenharmony_ci	return rc;
338062306a36Sopenharmony_ci}
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_cistatic int hpsa_bmic_id_controller(struct ctlr_info *h,
338362306a36Sopenharmony_ci	struct bmic_identify_controller *buf, size_t bufsize)
338462306a36Sopenharmony_ci{
338562306a36Sopenharmony_ci	int rc = IO_OK;
338662306a36Sopenharmony_ci	struct CommandList *c;
338762306a36Sopenharmony_ci	struct ErrorInfo *ei;
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	c = cmd_alloc(h);
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_ci	rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize,
339262306a36Sopenharmony_ci		0, RAID_CTLR_LUNID, TYPE_CMD);
339362306a36Sopenharmony_ci	if (rc)
339462306a36Sopenharmony_ci		goto out;
339562306a36Sopenharmony_ci
339662306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
339762306a36Sopenharmony_ci			NO_TIMEOUT);
339862306a36Sopenharmony_ci	if (rc)
339962306a36Sopenharmony_ci		goto out;
340062306a36Sopenharmony_ci	ei = c->err_info;
340162306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
340262306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
340362306a36Sopenharmony_ci		rc = -1;
340462306a36Sopenharmony_ci	}
340562306a36Sopenharmony_ciout:
340662306a36Sopenharmony_ci	cmd_free(h, c);
340762306a36Sopenharmony_ci	return rc;
340862306a36Sopenharmony_ci}
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_cistatic int hpsa_bmic_id_physical_device(struct ctlr_info *h,
341162306a36Sopenharmony_ci		unsigned char scsi3addr[], u16 bmic_device_index,
341262306a36Sopenharmony_ci		struct bmic_identify_physical_device *buf, size_t bufsize)
341362306a36Sopenharmony_ci{
341462306a36Sopenharmony_ci	int rc = IO_OK;
341562306a36Sopenharmony_ci	struct CommandList *c;
341662306a36Sopenharmony_ci	struct ErrorInfo *ei;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	c = cmd_alloc(h);
341962306a36Sopenharmony_ci	rc = fill_cmd(c, BMIC_IDENTIFY_PHYSICAL_DEVICE, h, buf, bufsize,
342062306a36Sopenharmony_ci		0, RAID_CTLR_LUNID, TYPE_CMD);
342162306a36Sopenharmony_ci	if (rc)
342262306a36Sopenharmony_ci		goto out;
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	c->Request.CDB[2] = bmic_device_index & 0xff;
342562306a36Sopenharmony_ci	c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
342662306a36Sopenharmony_ci
342762306a36Sopenharmony_ci	hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
342862306a36Sopenharmony_ci						NO_TIMEOUT);
342962306a36Sopenharmony_ci	ei = c->err_info;
343062306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
343162306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
343262306a36Sopenharmony_ci		rc = -1;
343362306a36Sopenharmony_ci	}
343462306a36Sopenharmony_ciout:
343562306a36Sopenharmony_ci	cmd_free(h, c);
343662306a36Sopenharmony_ci
343762306a36Sopenharmony_ci	return rc;
343862306a36Sopenharmony_ci}
343962306a36Sopenharmony_ci
344062306a36Sopenharmony_ci/*
344162306a36Sopenharmony_ci * get enclosure information
344262306a36Sopenharmony_ci * struct ReportExtendedLUNdata *rlep - Used for BMIC drive number
344362306a36Sopenharmony_ci * struct hpsa_scsi_dev_t *encl_dev - device entry for enclosure
344462306a36Sopenharmony_ci * Uses id_physical_device to determine the box_index.
344562306a36Sopenharmony_ci */
344662306a36Sopenharmony_cistatic void hpsa_get_enclosure_info(struct ctlr_info *h,
344762306a36Sopenharmony_ci			unsigned char *scsi3addr,
344862306a36Sopenharmony_ci			struct ReportExtendedLUNdata *rlep, int rle_index,
344962306a36Sopenharmony_ci			struct hpsa_scsi_dev_t *encl_dev)
345062306a36Sopenharmony_ci{
345162306a36Sopenharmony_ci	int rc = -1;
345262306a36Sopenharmony_ci	struct CommandList *c = NULL;
345362306a36Sopenharmony_ci	struct ErrorInfo *ei = NULL;
345462306a36Sopenharmony_ci	struct bmic_sense_storage_box_params *bssbp = NULL;
345562306a36Sopenharmony_ci	struct bmic_identify_physical_device *id_phys = NULL;
345662306a36Sopenharmony_ci	struct ext_report_lun_entry *rle;
345762306a36Sopenharmony_ci	u16 bmic_device_index = 0;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	if (rle_index < 0 || rle_index >= HPSA_MAX_PHYS_LUN)
346062306a36Sopenharmony_ci		return;
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci	rle = &rlep->LUN[rle_index];
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	encl_dev->eli =
346562306a36Sopenharmony_ci		hpsa_get_enclosure_logical_identifier(h, scsi3addr);
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	bmic_device_index = GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]);
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	if (encl_dev->target == -1 || encl_dev->lun == -1) {
347062306a36Sopenharmony_ci		rc = IO_OK;
347162306a36Sopenharmony_ci		goto out;
347262306a36Sopenharmony_ci	}
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	if (bmic_device_index == 0xFF00 || MASKED_DEVICE(&rle->lunid[0])) {
347562306a36Sopenharmony_ci		rc = IO_OK;
347662306a36Sopenharmony_ci		goto out;
347762306a36Sopenharmony_ci	}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	bssbp = kzalloc(sizeof(*bssbp), GFP_KERNEL);
348062306a36Sopenharmony_ci	if (!bssbp)
348162306a36Sopenharmony_ci		goto out;
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
348462306a36Sopenharmony_ci	if (!id_phys)
348562306a36Sopenharmony_ci		goto out;
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	rc = hpsa_bmic_id_physical_device(h, scsi3addr, bmic_device_index,
348862306a36Sopenharmony_ci						id_phys, sizeof(*id_phys));
348962306a36Sopenharmony_ci	if (rc) {
349062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "%s: id_phys failed %d bdi[0x%x]\n",
349162306a36Sopenharmony_ci			__func__, encl_dev->external, bmic_device_index);
349262306a36Sopenharmony_ci		goto out;
349362306a36Sopenharmony_ci	}
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	c = cmd_alloc(h);
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	rc = fill_cmd(c, BMIC_SENSE_STORAGE_BOX_PARAMS, h, bssbp,
349862306a36Sopenharmony_ci			sizeof(*bssbp), 0, RAID_CTLR_LUNID, TYPE_CMD);
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ci	if (rc)
350162306a36Sopenharmony_ci		goto out;
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci	if (id_phys->phys_connector[1] == 'E')
350462306a36Sopenharmony_ci		c->Request.CDB[5] = id_phys->box_index;
350562306a36Sopenharmony_ci	else
350662306a36Sopenharmony_ci		c->Request.CDB[5] = 0;
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
350962306a36Sopenharmony_ci						NO_TIMEOUT);
351062306a36Sopenharmony_ci	if (rc)
351162306a36Sopenharmony_ci		goto out;
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	ei = c->err_info;
351462306a36Sopenharmony_ci	if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
351562306a36Sopenharmony_ci		rc = -1;
351662306a36Sopenharmony_ci		goto out;
351762306a36Sopenharmony_ci	}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_ci	encl_dev->box[id_phys->active_path_number] = bssbp->phys_box_on_port;
352062306a36Sopenharmony_ci	memcpy(&encl_dev->phys_connector[id_phys->active_path_number],
352162306a36Sopenharmony_ci		bssbp->phys_connector, sizeof(bssbp->phys_connector));
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	rc = IO_OK;
352462306a36Sopenharmony_ciout:
352562306a36Sopenharmony_ci	kfree(bssbp);
352662306a36Sopenharmony_ci	kfree(id_phys);
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	if (c)
352962306a36Sopenharmony_ci		cmd_free(h, c);
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	if (rc != IO_OK)
353262306a36Sopenharmony_ci		hpsa_show_dev_msg(KERN_INFO, h, encl_dev,
353362306a36Sopenharmony_ci			"Error, could not get enclosure information");
353462306a36Sopenharmony_ci}
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_cistatic u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
353762306a36Sopenharmony_ci						unsigned char *scsi3addr)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	struct ReportExtendedLUNdata *physdev;
354062306a36Sopenharmony_ci	u32 nphysicals;
354162306a36Sopenharmony_ci	u64 sa = 0;
354262306a36Sopenharmony_ci	int i;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	physdev = kzalloc(sizeof(*physdev), GFP_KERNEL);
354562306a36Sopenharmony_ci	if (!physdev)
354662306a36Sopenharmony_ci		return 0;
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci	if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) {
354962306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
355062306a36Sopenharmony_ci		kfree(physdev);
355162306a36Sopenharmony_ci		return 0;
355262306a36Sopenharmony_ci	}
355362306a36Sopenharmony_ci	nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24;
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	for (i = 0; i < nphysicals; i++)
355662306a36Sopenharmony_ci		if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) {
355762306a36Sopenharmony_ci			sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]);
355862306a36Sopenharmony_ci			break;
355962306a36Sopenharmony_ci		}
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	kfree(physdev);
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	return sa;
356462306a36Sopenharmony_ci}
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_cistatic void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr,
356762306a36Sopenharmony_ci					struct hpsa_scsi_dev_t *dev)
356862306a36Sopenharmony_ci{
356962306a36Sopenharmony_ci	int rc;
357062306a36Sopenharmony_ci	u64 sa = 0;
357162306a36Sopenharmony_ci
357262306a36Sopenharmony_ci	if (is_hba_lunid(scsi3addr)) {
357362306a36Sopenharmony_ci		struct bmic_sense_subsystem_info *ssi;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci		ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
357662306a36Sopenharmony_ci		if (!ssi)
357762306a36Sopenharmony_ci			return;
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci		rc = hpsa_bmic_sense_subsystem_information(h,
358062306a36Sopenharmony_ci					scsi3addr, 0, ssi, sizeof(*ssi));
358162306a36Sopenharmony_ci		if (rc == 0) {
358262306a36Sopenharmony_ci			sa = get_unaligned_be64(ssi->primary_world_wide_id);
358362306a36Sopenharmony_ci			h->sas_address = sa;
358462306a36Sopenharmony_ci		}
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci		kfree(ssi);
358762306a36Sopenharmony_ci	} else
358862306a36Sopenharmony_ci		sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr);
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	dev->sas_address = sa;
359162306a36Sopenharmony_ci}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_cistatic void hpsa_ext_ctrl_present(struct ctlr_info *h,
359462306a36Sopenharmony_ci	struct ReportExtendedLUNdata *physdev)
359562306a36Sopenharmony_ci{
359662306a36Sopenharmony_ci	u32 nphysicals;
359762306a36Sopenharmony_ci	int i;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	if (h->discovery_polling)
360062306a36Sopenharmony_ci		return;
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	nphysicals = (get_unaligned_be32(physdev->LUNListLength) / 24) + 1;
360362306a36Sopenharmony_ci
360462306a36Sopenharmony_ci	for (i = 0; i < nphysicals; i++) {
360562306a36Sopenharmony_ci		if (physdev->LUN[i].device_type ==
360662306a36Sopenharmony_ci			BMIC_DEVICE_TYPE_CONTROLLER
360762306a36Sopenharmony_ci			&& !is_hba_lunid(physdev->LUN[i].lunid)) {
360862306a36Sopenharmony_ci			dev_info(&h->pdev->dev,
360962306a36Sopenharmony_ci				"External controller present, activate discovery polling and disable rld caching\n");
361062306a36Sopenharmony_ci			hpsa_disable_rld_caching(h);
361162306a36Sopenharmony_ci			h->discovery_polling = 1;
361262306a36Sopenharmony_ci			break;
361362306a36Sopenharmony_ci		}
361462306a36Sopenharmony_ci	}
361562306a36Sopenharmony_ci}
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci/* Get a device id from inquiry page 0x83 */
361862306a36Sopenharmony_cistatic bool hpsa_vpd_page_supported(struct ctlr_info *h,
361962306a36Sopenharmony_ci	unsigned char scsi3addr[], u8 page)
362062306a36Sopenharmony_ci{
362162306a36Sopenharmony_ci	int rc;
362262306a36Sopenharmony_ci	int i;
362362306a36Sopenharmony_ci	int pages;
362462306a36Sopenharmony_ci	unsigned char *buf, bufsize;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	buf = kzalloc(256, GFP_KERNEL);
362762306a36Sopenharmony_ci	if (!buf)
362862306a36Sopenharmony_ci		return false;
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci	/* Get the size of the page list first */
363162306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr,
363262306a36Sopenharmony_ci				VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
363362306a36Sopenharmony_ci				buf, HPSA_VPD_HEADER_SZ);
363462306a36Sopenharmony_ci	if (rc != 0)
363562306a36Sopenharmony_ci		goto exit_unsupported;
363662306a36Sopenharmony_ci	pages = buf[3];
363762306a36Sopenharmony_ci	if ((pages + HPSA_VPD_HEADER_SZ) <= 255)
363862306a36Sopenharmony_ci		bufsize = pages + HPSA_VPD_HEADER_SZ;
363962306a36Sopenharmony_ci	else
364062306a36Sopenharmony_ci		bufsize = 255;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	/* Get the whole VPD page list */
364362306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr,
364462306a36Sopenharmony_ci				VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
364562306a36Sopenharmony_ci				buf, bufsize);
364662306a36Sopenharmony_ci	if (rc != 0)
364762306a36Sopenharmony_ci		goto exit_unsupported;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	pages = buf[3];
365062306a36Sopenharmony_ci	for (i = 1; i <= pages; i++)
365162306a36Sopenharmony_ci		if (buf[3 + i] == page)
365262306a36Sopenharmony_ci			goto exit_supported;
365362306a36Sopenharmony_ciexit_unsupported:
365462306a36Sopenharmony_ci	kfree(buf);
365562306a36Sopenharmony_ci	return false;
365662306a36Sopenharmony_ciexit_supported:
365762306a36Sopenharmony_ci	kfree(buf);
365862306a36Sopenharmony_ci	return true;
365962306a36Sopenharmony_ci}
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci/*
366262306a36Sopenharmony_ci * Called during a scan operation.
366362306a36Sopenharmony_ci * Sets ioaccel status on the new device list, not the existing device list
366462306a36Sopenharmony_ci *
366562306a36Sopenharmony_ci * The device list used during I/O will be updated later in
366662306a36Sopenharmony_ci * adjust_hpsa_scsi_table.
366762306a36Sopenharmony_ci */
366862306a36Sopenharmony_cistatic void hpsa_get_ioaccel_status(struct ctlr_info *h,
366962306a36Sopenharmony_ci	unsigned char *scsi3addr, struct hpsa_scsi_dev_t *this_device)
367062306a36Sopenharmony_ci{
367162306a36Sopenharmony_ci	int rc;
367262306a36Sopenharmony_ci	unsigned char *buf;
367362306a36Sopenharmony_ci	u8 ioaccel_status;
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	this_device->offload_config = 0;
367662306a36Sopenharmony_ci	this_device->offload_enabled = 0;
367762306a36Sopenharmony_ci	this_device->offload_to_be_enabled = 0;
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci	buf = kzalloc(64, GFP_KERNEL);
368062306a36Sopenharmony_ci	if (!buf)
368162306a36Sopenharmony_ci		return;
368262306a36Sopenharmony_ci	if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_IOACCEL_STATUS))
368362306a36Sopenharmony_ci		goto out;
368462306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr,
368562306a36Sopenharmony_ci			VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS, buf, 64);
368662306a36Sopenharmony_ci	if (rc != 0)
368762306a36Sopenharmony_ci		goto out;
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci#define IOACCEL_STATUS_BYTE 4
369062306a36Sopenharmony_ci#define OFFLOAD_CONFIGURED_BIT 0x01
369162306a36Sopenharmony_ci#define OFFLOAD_ENABLED_BIT 0x02
369262306a36Sopenharmony_ci	ioaccel_status = buf[IOACCEL_STATUS_BYTE];
369362306a36Sopenharmony_ci	this_device->offload_config =
369462306a36Sopenharmony_ci		!!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
369562306a36Sopenharmony_ci	if (this_device->offload_config) {
369662306a36Sopenharmony_ci		bool offload_enabled =
369762306a36Sopenharmony_ci			!!(ioaccel_status & OFFLOAD_ENABLED_BIT);
369862306a36Sopenharmony_ci		/*
369962306a36Sopenharmony_ci		 * Check to see if offload can be enabled.
370062306a36Sopenharmony_ci		 */
370162306a36Sopenharmony_ci		if (offload_enabled) {
370262306a36Sopenharmony_ci			rc = hpsa_get_raid_map(h, scsi3addr, this_device);
370362306a36Sopenharmony_ci			if (rc) /* could not load raid_map */
370462306a36Sopenharmony_ci				goto out;
370562306a36Sopenharmony_ci			this_device->offload_to_be_enabled = 1;
370662306a36Sopenharmony_ci		}
370762306a36Sopenharmony_ci	}
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ciout:
371062306a36Sopenharmony_ci	kfree(buf);
371162306a36Sopenharmony_ci	return;
371262306a36Sopenharmony_ci}
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci/* Get the device id from inquiry page 0x83 */
371562306a36Sopenharmony_cistatic int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
371662306a36Sopenharmony_ci	unsigned char *device_id, int index, int buflen)
371762306a36Sopenharmony_ci{
371862306a36Sopenharmony_ci	int rc;
371962306a36Sopenharmony_ci	unsigned char *buf;
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci	/* Does controller have VPD for device id? */
372262306a36Sopenharmony_ci	if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_DEVICE_ID))
372362306a36Sopenharmony_ci		return 1; /* not supported */
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	buf = kzalloc(64, GFP_KERNEL);
372662306a36Sopenharmony_ci	if (!buf)
372762306a36Sopenharmony_ci		return -ENOMEM;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
373062306a36Sopenharmony_ci					HPSA_VPD_LV_DEVICE_ID, buf, 64);
373162306a36Sopenharmony_ci	if (rc == 0) {
373262306a36Sopenharmony_ci		if (buflen > 16)
373362306a36Sopenharmony_ci			buflen = 16;
373462306a36Sopenharmony_ci		memcpy(device_id, &buf[8], buflen);
373562306a36Sopenharmony_ci	}
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci	kfree(buf);
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	return rc; /*0 - got id,  otherwise, didn't */
374062306a36Sopenharmony_ci}
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_cistatic int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
374362306a36Sopenharmony_ci		void *buf, int bufsize,
374462306a36Sopenharmony_ci		int extended_response)
374562306a36Sopenharmony_ci{
374662306a36Sopenharmony_ci	int rc = IO_OK;
374762306a36Sopenharmony_ci	struct CommandList *c;
374862306a36Sopenharmony_ci	unsigned char scsi3addr[8];
374962306a36Sopenharmony_ci	struct ErrorInfo *ei;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci	c = cmd_alloc(h);
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	/* address the controller */
375462306a36Sopenharmony_ci	memset(scsi3addr, 0, sizeof(scsi3addr));
375562306a36Sopenharmony_ci	if (fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
375662306a36Sopenharmony_ci		buf, bufsize, 0, scsi3addr, TYPE_CMD)) {
375762306a36Sopenharmony_ci		rc = -EAGAIN;
375862306a36Sopenharmony_ci		goto out;
375962306a36Sopenharmony_ci	}
376062306a36Sopenharmony_ci	if (extended_response)
376162306a36Sopenharmony_ci		c->Request.CDB[1] = extended_response;
376262306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
376362306a36Sopenharmony_ci			NO_TIMEOUT);
376462306a36Sopenharmony_ci	if (rc)
376562306a36Sopenharmony_ci		goto out;
376662306a36Sopenharmony_ci	ei = c->err_info;
376762306a36Sopenharmony_ci	if (ei->CommandStatus != 0 &&
376862306a36Sopenharmony_ci	    ei->CommandStatus != CMD_DATA_UNDERRUN) {
376962306a36Sopenharmony_ci		hpsa_scsi_interpret_error(h, c);
377062306a36Sopenharmony_ci		rc = -EIO;
377162306a36Sopenharmony_ci	} else {
377262306a36Sopenharmony_ci		struct ReportLUNdata *rld = buf;
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci		if (rld->extended_response_flag != extended_response) {
377562306a36Sopenharmony_ci			if (!h->legacy_board) {
377662306a36Sopenharmony_ci				dev_err(&h->pdev->dev,
377762306a36Sopenharmony_ci					"report luns requested format %u, got %u\n",
377862306a36Sopenharmony_ci					extended_response,
377962306a36Sopenharmony_ci					rld->extended_response_flag);
378062306a36Sopenharmony_ci				rc = -EINVAL;
378162306a36Sopenharmony_ci			} else
378262306a36Sopenharmony_ci				rc = -EOPNOTSUPP;
378362306a36Sopenharmony_ci		}
378462306a36Sopenharmony_ci	}
378562306a36Sopenharmony_ciout:
378662306a36Sopenharmony_ci	cmd_free(h, c);
378762306a36Sopenharmony_ci	return rc;
378862306a36Sopenharmony_ci}
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_cistatic inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
379162306a36Sopenharmony_ci		struct ReportExtendedLUNdata *buf, int bufsize)
379262306a36Sopenharmony_ci{
379362306a36Sopenharmony_ci	int rc;
379462306a36Sopenharmony_ci	struct ReportLUNdata *lbuf;
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	rc = hpsa_scsi_do_report_luns(h, 0, buf, bufsize,
379762306a36Sopenharmony_ci				      HPSA_REPORT_PHYS_EXTENDED);
379862306a36Sopenharmony_ci	if (!rc || rc != -EOPNOTSUPP)
379962306a36Sopenharmony_ci		return rc;
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	/* REPORT PHYS EXTENDED is not supported */
380262306a36Sopenharmony_ci	lbuf = kzalloc(sizeof(*lbuf), GFP_KERNEL);
380362306a36Sopenharmony_ci	if (!lbuf)
380462306a36Sopenharmony_ci		return -ENOMEM;
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	rc = hpsa_scsi_do_report_luns(h, 0, lbuf, sizeof(*lbuf), 0);
380762306a36Sopenharmony_ci	if (!rc) {
380862306a36Sopenharmony_ci		int i;
380962306a36Sopenharmony_ci		u32 nphys;
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci		/* Copy ReportLUNdata header */
381262306a36Sopenharmony_ci		memcpy(buf, lbuf, 8);
381362306a36Sopenharmony_ci		nphys = be32_to_cpu(*((__be32 *)lbuf->LUNListLength)) / 8;
381462306a36Sopenharmony_ci		for (i = 0; i < nphys; i++)
381562306a36Sopenharmony_ci			memcpy(buf->LUN[i].lunid, lbuf->LUN[i], 8);
381662306a36Sopenharmony_ci	}
381762306a36Sopenharmony_ci	kfree(lbuf);
381862306a36Sopenharmony_ci	return rc;
381962306a36Sopenharmony_ci}
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_cistatic inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h,
382262306a36Sopenharmony_ci		struct ReportLUNdata *buf, int bufsize)
382362306a36Sopenharmony_ci{
382462306a36Sopenharmony_ci	return hpsa_scsi_do_report_luns(h, 1, buf, bufsize, 0);
382562306a36Sopenharmony_ci}
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_cistatic inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device,
382862306a36Sopenharmony_ci	int bus, int target, int lun)
382962306a36Sopenharmony_ci{
383062306a36Sopenharmony_ci	device->bus = bus;
383162306a36Sopenharmony_ci	device->target = target;
383262306a36Sopenharmony_ci	device->lun = lun;
383362306a36Sopenharmony_ci}
383462306a36Sopenharmony_ci
383562306a36Sopenharmony_ci/* Use VPD inquiry to get details of volume status */
383662306a36Sopenharmony_cistatic int hpsa_get_volume_status(struct ctlr_info *h,
383762306a36Sopenharmony_ci					unsigned char scsi3addr[])
383862306a36Sopenharmony_ci{
383962306a36Sopenharmony_ci	int rc;
384062306a36Sopenharmony_ci	int status;
384162306a36Sopenharmony_ci	int size;
384262306a36Sopenharmony_ci	unsigned char *buf;
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci	buf = kzalloc(64, GFP_KERNEL);
384562306a36Sopenharmony_ci	if (!buf)
384662306a36Sopenharmony_ci		return HPSA_VPD_LV_STATUS_UNSUPPORTED;
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci	/* Does controller have VPD for logical volume status? */
384962306a36Sopenharmony_ci	if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS))
385062306a36Sopenharmony_ci		goto exit_failed;
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ci	/* Get the size of the VPD return buffer */
385362306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
385462306a36Sopenharmony_ci					buf, HPSA_VPD_HEADER_SZ);
385562306a36Sopenharmony_ci	if (rc != 0)
385662306a36Sopenharmony_ci		goto exit_failed;
385762306a36Sopenharmony_ci	size = buf[3];
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	/* Now get the whole VPD buffer */
386062306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
386162306a36Sopenharmony_ci					buf, size + HPSA_VPD_HEADER_SZ);
386262306a36Sopenharmony_ci	if (rc != 0)
386362306a36Sopenharmony_ci		goto exit_failed;
386462306a36Sopenharmony_ci	status = buf[4]; /* status byte */
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	kfree(buf);
386762306a36Sopenharmony_ci	return status;
386862306a36Sopenharmony_ciexit_failed:
386962306a36Sopenharmony_ci	kfree(buf);
387062306a36Sopenharmony_ci	return HPSA_VPD_LV_STATUS_UNSUPPORTED;
387162306a36Sopenharmony_ci}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci/* Determine offline status of a volume.
387462306a36Sopenharmony_ci * Return either:
387562306a36Sopenharmony_ci *  0 (not offline)
387662306a36Sopenharmony_ci *  0xff (offline for unknown reasons)
387762306a36Sopenharmony_ci *  # (integer code indicating one of several NOT READY states
387862306a36Sopenharmony_ci *     describing why a volume is to be kept offline)
387962306a36Sopenharmony_ci */
388062306a36Sopenharmony_cistatic unsigned char hpsa_volume_offline(struct ctlr_info *h,
388162306a36Sopenharmony_ci					unsigned char scsi3addr[])
388262306a36Sopenharmony_ci{
388362306a36Sopenharmony_ci	struct CommandList *c;
388462306a36Sopenharmony_ci	unsigned char *sense;
388562306a36Sopenharmony_ci	u8 sense_key, asc, ascq;
388662306a36Sopenharmony_ci	int sense_len;
388762306a36Sopenharmony_ci	int rc, ldstat = 0;
388862306a36Sopenharmony_ci#define ASC_LUN_NOT_READY 0x04
388962306a36Sopenharmony_ci#define ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS 0x04
389062306a36Sopenharmony_ci#define ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ 0x02
389162306a36Sopenharmony_ci
389262306a36Sopenharmony_ci	c = cmd_alloc(h);
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ci	(void) fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, scsi3addr, TYPE_CMD);
389562306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
389662306a36Sopenharmony_ci					NO_TIMEOUT);
389762306a36Sopenharmony_ci	if (rc) {
389862306a36Sopenharmony_ci		cmd_free(h, c);
389962306a36Sopenharmony_ci		return HPSA_VPD_LV_STATUS_UNSUPPORTED;
390062306a36Sopenharmony_ci	}
390162306a36Sopenharmony_ci	sense = c->err_info->SenseInfo;
390262306a36Sopenharmony_ci	if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
390362306a36Sopenharmony_ci		sense_len = sizeof(c->err_info->SenseInfo);
390462306a36Sopenharmony_ci	else
390562306a36Sopenharmony_ci		sense_len = c->err_info->SenseLen;
390662306a36Sopenharmony_ci	decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq);
390762306a36Sopenharmony_ci	cmd_free(h, c);
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	/* Determine the reason for not ready state */
391062306a36Sopenharmony_ci	ldstat = hpsa_get_volume_status(h, scsi3addr);
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	/* Keep volume offline in certain cases: */
391362306a36Sopenharmony_ci	switch (ldstat) {
391462306a36Sopenharmony_ci	case HPSA_LV_FAILED:
391562306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ERASE:
391662306a36Sopenharmony_ci	case HPSA_LV_NOT_AVAILABLE:
391762306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_RPI:
391862306a36Sopenharmony_ci	case HPSA_LV_PENDING_RPI:
391962306a36Sopenharmony_ci	case HPSA_LV_ENCRYPTED_NO_KEY:
392062306a36Sopenharmony_ci	case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
392162306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ENCRYPTION:
392262306a36Sopenharmony_ci	case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
392362306a36Sopenharmony_ci	case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
392462306a36Sopenharmony_ci		return ldstat;
392562306a36Sopenharmony_ci	case HPSA_VPD_LV_STATUS_UNSUPPORTED:
392662306a36Sopenharmony_ci		/* If VPD status page isn't available,
392762306a36Sopenharmony_ci		 * use ASC/ASCQ to determine state
392862306a36Sopenharmony_ci		 */
392962306a36Sopenharmony_ci		if ((ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS) ||
393062306a36Sopenharmony_ci			(ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ))
393162306a36Sopenharmony_ci			return ldstat;
393262306a36Sopenharmony_ci		break;
393362306a36Sopenharmony_ci	default:
393462306a36Sopenharmony_ci		break;
393562306a36Sopenharmony_ci	}
393662306a36Sopenharmony_ci	return HPSA_LV_OK;
393762306a36Sopenharmony_ci}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_cistatic int hpsa_update_device_info(struct ctlr_info *h,
394062306a36Sopenharmony_ci	unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
394162306a36Sopenharmony_ci	unsigned char *is_OBDR_device)
394262306a36Sopenharmony_ci{
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci#define OBDR_SIG_OFFSET 43
394562306a36Sopenharmony_ci#define OBDR_TAPE_SIG "$DR-10"
394662306a36Sopenharmony_ci#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1)
394762306a36Sopenharmony_ci#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN)
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci	unsigned char *inq_buff;
395062306a36Sopenharmony_ci	unsigned char *obdr_sig;
395162306a36Sopenharmony_ci	int rc = 0;
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_ci	inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
395462306a36Sopenharmony_ci	if (!inq_buff) {
395562306a36Sopenharmony_ci		rc = -ENOMEM;
395662306a36Sopenharmony_ci		goto bail_out;
395762306a36Sopenharmony_ci	}
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci	/* Do an inquiry to the device to see what it is. */
396062306a36Sopenharmony_ci	if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
396162306a36Sopenharmony_ci		(unsigned char) OBDR_TAPE_INQ_SIZE) != 0) {
396262306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
396362306a36Sopenharmony_ci			"%s: inquiry failed, device will be skipped.\n",
396462306a36Sopenharmony_ci			__func__);
396562306a36Sopenharmony_ci		rc = HPSA_INQUIRY_FAILED;
396662306a36Sopenharmony_ci		goto bail_out;
396762306a36Sopenharmony_ci	}
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci	scsi_sanitize_inquiry_string(&inq_buff[8], 8);
397062306a36Sopenharmony_ci	scsi_sanitize_inquiry_string(&inq_buff[16], 16);
397162306a36Sopenharmony_ci
397262306a36Sopenharmony_ci	this_device->devtype = (inq_buff[0] & 0x1f);
397362306a36Sopenharmony_ci	memcpy(this_device->scsi3addr, scsi3addr, 8);
397462306a36Sopenharmony_ci	memcpy(this_device->vendor, &inq_buff[8],
397562306a36Sopenharmony_ci		sizeof(this_device->vendor));
397662306a36Sopenharmony_ci	memcpy(this_device->model, &inq_buff[16],
397762306a36Sopenharmony_ci		sizeof(this_device->model));
397862306a36Sopenharmony_ci	this_device->rev = inq_buff[2];
397962306a36Sopenharmony_ci	memset(this_device->device_id, 0,
398062306a36Sopenharmony_ci		sizeof(this_device->device_id));
398162306a36Sopenharmony_ci	if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
398262306a36Sopenharmony_ci		sizeof(this_device->device_id)) < 0) {
398362306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
398462306a36Sopenharmony_ci			"hpsa%d: %s: can't get device id for [%d:%d:%d:%d]\t%s\t%.16s\n",
398562306a36Sopenharmony_ci			h->ctlr, __func__,
398662306a36Sopenharmony_ci			h->scsi_host->host_no,
398762306a36Sopenharmony_ci			this_device->bus, this_device->target,
398862306a36Sopenharmony_ci			this_device->lun,
398962306a36Sopenharmony_ci			scsi_device_type(this_device->devtype),
399062306a36Sopenharmony_ci			this_device->model);
399162306a36Sopenharmony_ci		rc = HPSA_LV_FAILED;
399262306a36Sopenharmony_ci		goto bail_out;
399362306a36Sopenharmony_ci	}
399462306a36Sopenharmony_ci
399562306a36Sopenharmony_ci	if ((this_device->devtype == TYPE_DISK ||
399662306a36Sopenharmony_ci		this_device->devtype == TYPE_ZBC) &&
399762306a36Sopenharmony_ci		is_logical_dev_addr_mode(scsi3addr)) {
399862306a36Sopenharmony_ci		unsigned char volume_offline;
399962306a36Sopenharmony_ci
400062306a36Sopenharmony_ci		hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level);
400162306a36Sopenharmony_ci		if (h->fw_support & MISC_FW_RAID_OFFLOAD_BASIC)
400262306a36Sopenharmony_ci			hpsa_get_ioaccel_status(h, scsi3addr, this_device);
400362306a36Sopenharmony_ci		volume_offline = hpsa_volume_offline(h, scsi3addr);
400462306a36Sopenharmony_ci		if (volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED &&
400562306a36Sopenharmony_ci		    h->legacy_board) {
400662306a36Sopenharmony_ci			/*
400762306a36Sopenharmony_ci			 * Legacy boards might not support volume status
400862306a36Sopenharmony_ci			 */
400962306a36Sopenharmony_ci			dev_info(&h->pdev->dev,
401062306a36Sopenharmony_ci				 "C0:T%d:L%d Volume status not available, assuming online.\n",
401162306a36Sopenharmony_ci				 this_device->target, this_device->lun);
401262306a36Sopenharmony_ci			volume_offline = 0;
401362306a36Sopenharmony_ci		}
401462306a36Sopenharmony_ci		this_device->volume_offline = volume_offline;
401562306a36Sopenharmony_ci		if (volume_offline == HPSA_LV_FAILED) {
401662306a36Sopenharmony_ci			rc = HPSA_LV_FAILED;
401762306a36Sopenharmony_ci			dev_err(&h->pdev->dev,
401862306a36Sopenharmony_ci				"%s: LV failed, device will be skipped.\n",
401962306a36Sopenharmony_ci				__func__);
402062306a36Sopenharmony_ci			goto bail_out;
402162306a36Sopenharmony_ci		}
402262306a36Sopenharmony_ci	} else {
402362306a36Sopenharmony_ci		this_device->raid_level = RAID_UNKNOWN;
402462306a36Sopenharmony_ci		this_device->offload_config = 0;
402562306a36Sopenharmony_ci		hpsa_turn_off_ioaccel_for_device(this_device);
402662306a36Sopenharmony_ci		this_device->hba_ioaccel_enabled = 0;
402762306a36Sopenharmony_ci		this_device->volume_offline = 0;
402862306a36Sopenharmony_ci		this_device->queue_depth = h->nr_cmds;
402962306a36Sopenharmony_ci	}
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_ci	if (this_device->external)
403262306a36Sopenharmony_ci		this_device->queue_depth = EXTERNAL_QD;
403362306a36Sopenharmony_ci
403462306a36Sopenharmony_ci	if (is_OBDR_device) {
403562306a36Sopenharmony_ci		/* See if this is a One-Button-Disaster-Recovery device
403662306a36Sopenharmony_ci		 * by looking for "$DR-10" at offset 43 in inquiry data.
403762306a36Sopenharmony_ci		 */
403862306a36Sopenharmony_ci		obdr_sig = &inq_buff[OBDR_SIG_OFFSET];
403962306a36Sopenharmony_ci		*is_OBDR_device = (this_device->devtype == TYPE_ROM &&
404062306a36Sopenharmony_ci					strncmp(obdr_sig, OBDR_TAPE_SIG,
404162306a36Sopenharmony_ci						OBDR_SIG_LEN) == 0);
404262306a36Sopenharmony_ci	}
404362306a36Sopenharmony_ci	kfree(inq_buff);
404462306a36Sopenharmony_ci	return 0;
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_cibail_out:
404762306a36Sopenharmony_ci	kfree(inq_buff);
404862306a36Sopenharmony_ci	return rc;
404962306a36Sopenharmony_ci}
405062306a36Sopenharmony_ci
405162306a36Sopenharmony_ci/*
405262306a36Sopenharmony_ci * Helper function to assign bus, target, lun mapping of devices.
405362306a36Sopenharmony_ci * Logical drive target and lun are assigned at this time, but
405462306a36Sopenharmony_ci * physical device lun and target assignment are deferred (assigned
405562306a36Sopenharmony_ci * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
405662306a36Sopenharmony_ci*/
405762306a36Sopenharmony_cistatic void figure_bus_target_lun(struct ctlr_info *h,
405862306a36Sopenharmony_ci	u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device)
405962306a36Sopenharmony_ci{
406062306a36Sopenharmony_ci	u32 lunid = get_unaligned_le32(lunaddrbytes);
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	if (!is_logical_dev_addr_mode(lunaddrbytes)) {
406362306a36Sopenharmony_ci		/* physical device, target and lun filled in later */
406462306a36Sopenharmony_ci		if (is_hba_lunid(lunaddrbytes)) {
406562306a36Sopenharmony_ci			int bus = HPSA_HBA_BUS;
406662306a36Sopenharmony_ci
406762306a36Sopenharmony_ci			if (!device->rev)
406862306a36Sopenharmony_ci				bus = HPSA_LEGACY_HBA_BUS;
406962306a36Sopenharmony_ci			hpsa_set_bus_target_lun(device,
407062306a36Sopenharmony_ci					bus, 0, lunid & 0x3fff);
407162306a36Sopenharmony_ci		} else
407262306a36Sopenharmony_ci			/* defer target, lun assignment for physical devices */
407362306a36Sopenharmony_ci			hpsa_set_bus_target_lun(device,
407462306a36Sopenharmony_ci					HPSA_PHYSICAL_DEVICE_BUS, -1, -1);
407562306a36Sopenharmony_ci		return;
407662306a36Sopenharmony_ci	}
407762306a36Sopenharmony_ci	/* It's a logical device */
407862306a36Sopenharmony_ci	if (device->external) {
407962306a36Sopenharmony_ci		hpsa_set_bus_target_lun(device,
408062306a36Sopenharmony_ci			HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff,
408162306a36Sopenharmony_ci			lunid & 0x00ff);
408262306a36Sopenharmony_ci		return;
408362306a36Sopenharmony_ci	}
408462306a36Sopenharmony_ci	hpsa_set_bus_target_lun(device, HPSA_RAID_VOLUME_BUS,
408562306a36Sopenharmony_ci				0, lunid & 0x3fff);
408662306a36Sopenharmony_ci}
408762306a36Sopenharmony_ci
408862306a36Sopenharmony_cistatic int  figure_external_status(struct ctlr_info *h, int raid_ctlr_position,
408962306a36Sopenharmony_ci	int i, int nphysicals, int nlocal_logicals)
409062306a36Sopenharmony_ci{
409162306a36Sopenharmony_ci	/* In report logicals, local logicals are listed first,
409262306a36Sopenharmony_ci	* then any externals.
409362306a36Sopenharmony_ci	*/
409462306a36Sopenharmony_ci	int logicals_start = nphysicals + (raid_ctlr_position == 0);
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_ci	if (i == raid_ctlr_position)
409762306a36Sopenharmony_ci		return 0;
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	if (i < logicals_start)
410062306a36Sopenharmony_ci		return 0;
410162306a36Sopenharmony_ci
410262306a36Sopenharmony_ci	/* i is in logicals range, but still within local logicals */
410362306a36Sopenharmony_ci	if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals)
410462306a36Sopenharmony_ci		return 0;
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	return 1; /* it's an external lun */
410762306a36Sopenharmony_ci}
410862306a36Sopenharmony_ci
410962306a36Sopenharmony_ci/*
411062306a36Sopenharmony_ci * Do CISS_REPORT_PHYS and CISS_REPORT_LOG.  Data is returned in physdev,
411162306a36Sopenharmony_ci * logdev.  The number of luns in physdev and logdev are returned in
411262306a36Sopenharmony_ci * *nphysicals and *nlogicals, respectively.
411362306a36Sopenharmony_ci * Returns 0 on success, -1 otherwise.
411462306a36Sopenharmony_ci */
411562306a36Sopenharmony_cistatic int hpsa_gather_lun_info(struct ctlr_info *h,
411662306a36Sopenharmony_ci	struct ReportExtendedLUNdata *physdev, u32 *nphysicals,
411762306a36Sopenharmony_ci	struct ReportLUNdata *logdev, u32 *nlogicals)
411862306a36Sopenharmony_ci{
411962306a36Sopenharmony_ci	if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) {
412062306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
412162306a36Sopenharmony_ci		return -1;
412262306a36Sopenharmony_ci	}
412362306a36Sopenharmony_ci	*nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24;
412462306a36Sopenharmony_ci	if (*nphysicals > HPSA_MAX_PHYS_LUN) {
412562306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded. %d LUNs ignored.\n",
412662306a36Sopenharmony_ci			HPSA_MAX_PHYS_LUN, *nphysicals - HPSA_MAX_PHYS_LUN);
412762306a36Sopenharmony_ci		*nphysicals = HPSA_MAX_PHYS_LUN;
412862306a36Sopenharmony_ci	}
412962306a36Sopenharmony_ci	if (hpsa_scsi_do_report_log_luns(h, logdev, sizeof(*logdev))) {
413062306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
413162306a36Sopenharmony_ci		return -1;
413262306a36Sopenharmony_ci	}
413362306a36Sopenharmony_ci	*nlogicals = be32_to_cpu(*((__be32 *) logdev->LUNListLength)) / 8;
413462306a36Sopenharmony_ci	/* Reject Logicals in excess of our max capability. */
413562306a36Sopenharmony_ci	if (*nlogicals > HPSA_MAX_LUN) {
413662306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
413762306a36Sopenharmony_ci			"maximum logical LUNs (%d) exceeded.  "
413862306a36Sopenharmony_ci			"%d LUNs ignored.\n", HPSA_MAX_LUN,
413962306a36Sopenharmony_ci			*nlogicals - HPSA_MAX_LUN);
414062306a36Sopenharmony_ci		*nlogicals = HPSA_MAX_LUN;
414162306a36Sopenharmony_ci	}
414262306a36Sopenharmony_ci	if (*nlogicals + *nphysicals > HPSA_MAX_PHYS_LUN) {
414362306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
414462306a36Sopenharmony_ci			"maximum logical + physical LUNs (%d) exceeded. "
414562306a36Sopenharmony_ci			"%d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
414662306a36Sopenharmony_ci			*nphysicals + *nlogicals - HPSA_MAX_PHYS_LUN);
414762306a36Sopenharmony_ci		*nlogicals = HPSA_MAX_PHYS_LUN - *nphysicals;
414862306a36Sopenharmony_ci	}
414962306a36Sopenharmony_ci	return 0;
415062306a36Sopenharmony_ci}
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_cistatic u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position,
415362306a36Sopenharmony_ci	int i, int nphysicals, int nlogicals,
415462306a36Sopenharmony_ci	struct ReportExtendedLUNdata *physdev_list,
415562306a36Sopenharmony_ci	struct ReportLUNdata *logdev_list)
415662306a36Sopenharmony_ci{
415762306a36Sopenharmony_ci	/* Helper function, figure out where the LUN ID info is coming from
415862306a36Sopenharmony_ci	 * given index i, lists of physical and logical devices, where in
415962306a36Sopenharmony_ci	 * the list the raid controller is supposed to appear (first or last)
416062306a36Sopenharmony_ci	 */
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci	int logicals_start = nphysicals + (raid_ctlr_position == 0);
416362306a36Sopenharmony_ci	int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0);
416462306a36Sopenharmony_ci
416562306a36Sopenharmony_ci	if (i == raid_ctlr_position)
416662306a36Sopenharmony_ci		return RAID_CTLR_LUNID;
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_ci	if (i < logicals_start)
416962306a36Sopenharmony_ci		return &physdev_list->LUN[i -
417062306a36Sopenharmony_ci				(raid_ctlr_position == 0)].lunid[0];
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	if (i < last_device)
417362306a36Sopenharmony_ci		return &logdev_list->LUN[i - nphysicals -
417462306a36Sopenharmony_ci			(raid_ctlr_position == 0)][0];
417562306a36Sopenharmony_ci	BUG();
417662306a36Sopenharmony_ci	return NULL;
417762306a36Sopenharmony_ci}
417862306a36Sopenharmony_ci
417962306a36Sopenharmony_ci/* get physical drive ioaccel handle and queue depth */
418062306a36Sopenharmony_cistatic void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
418162306a36Sopenharmony_ci		struct hpsa_scsi_dev_t *dev,
418262306a36Sopenharmony_ci		struct ReportExtendedLUNdata *rlep, int rle_index,
418362306a36Sopenharmony_ci		struct bmic_identify_physical_device *id_phys)
418462306a36Sopenharmony_ci{
418562306a36Sopenharmony_ci	int rc;
418662306a36Sopenharmony_ci	struct ext_report_lun_entry *rle;
418762306a36Sopenharmony_ci
418862306a36Sopenharmony_ci	if (rle_index < 0 || rle_index >= HPSA_MAX_PHYS_LUN)
418962306a36Sopenharmony_ci		return;
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	rle = &rlep->LUN[rle_index];
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	dev->ioaccel_handle = rle->ioaccel_handle;
419462306a36Sopenharmony_ci	if ((rle->device_flags & 0x08) && dev->ioaccel_handle)
419562306a36Sopenharmony_ci		dev->hba_ioaccel_enabled = 1;
419662306a36Sopenharmony_ci	memset(id_phys, 0, sizeof(*id_phys));
419762306a36Sopenharmony_ci	rc = hpsa_bmic_id_physical_device(h, &rle->lunid[0],
419862306a36Sopenharmony_ci			GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]), id_phys,
419962306a36Sopenharmony_ci			sizeof(*id_phys));
420062306a36Sopenharmony_ci	if (!rc)
420162306a36Sopenharmony_ci		/* Reserve space for FW operations */
420262306a36Sopenharmony_ci#define DRIVE_CMDS_RESERVED_FOR_FW 2
420362306a36Sopenharmony_ci#define DRIVE_QUEUE_DEPTH 7
420462306a36Sopenharmony_ci		dev->queue_depth =
420562306a36Sopenharmony_ci			le16_to_cpu(id_phys->current_queue_depth_limit) -
420662306a36Sopenharmony_ci				DRIVE_CMDS_RESERVED_FOR_FW;
420762306a36Sopenharmony_ci	else
420862306a36Sopenharmony_ci		dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */
420962306a36Sopenharmony_ci}
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_cistatic void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
421262306a36Sopenharmony_ci	struct ReportExtendedLUNdata *rlep, int rle_index,
421362306a36Sopenharmony_ci	struct bmic_identify_physical_device *id_phys)
421462306a36Sopenharmony_ci{
421562306a36Sopenharmony_ci	struct ext_report_lun_entry *rle;
421662306a36Sopenharmony_ci
421762306a36Sopenharmony_ci	if (rle_index < 0 || rle_index >= HPSA_MAX_PHYS_LUN)
421862306a36Sopenharmony_ci		return;
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_ci	rle = &rlep->LUN[rle_index];
422162306a36Sopenharmony_ci
422262306a36Sopenharmony_ci	if ((rle->device_flags & 0x08) && this_device->ioaccel_handle)
422362306a36Sopenharmony_ci		this_device->hba_ioaccel_enabled = 1;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci	memcpy(&this_device->active_path_index,
422662306a36Sopenharmony_ci		&id_phys->active_path_number,
422762306a36Sopenharmony_ci		sizeof(this_device->active_path_index));
422862306a36Sopenharmony_ci	memcpy(&this_device->path_map,
422962306a36Sopenharmony_ci		&id_phys->redundant_path_present_map,
423062306a36Sopenharmony_ci		sizeof(this_device->path_map));
423162306a36Sopenharmony_ci	memcpy(&this_device->box,
423262306a36Sopenharmony_ci		&id_phys->alternate_paths_phys_box_on_port,
423362306a36Sopenharmony_ci		sizeof(this_device->box));
423462306a36Sopenharmony_ci	memcpy(&this_device->phys_connector,
423562306a36Sopenharmony_ci		&id_phys->alternate_paths_phys_connector,
423662306a36Sopenharmony_ci		sizeof(this_device->phys_connector));
423762306a36Sopenharmony_ci	memcpy(&this_device->bay,
423862306a36Sopenharmony_ci		&id_phys->phys_bay_in_box,
423962306a36Sopenharmony_ci		sizeof(this_device->bay));
424062306a36Sopenharmony_ci}
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci/* get number of local logical disks. */
424362306a36Sopenharmony_cistatic int hpsa_set_local_logical_count(struct ctlr_info *h,
424462306a36Sopenharmony_ci	struct bmic_identify_controller *id_ctlr,
424562306a36Sopenharmony_ci	u32 *nlocals)
424662306a36Sopenharmony_ci{
424762306a36Sopenharmony_ci	int rc;
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	if (!id_ctlr) {
425062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n",
425162306a36Sopenharmony_ci			__func__);
425262306a36Sopenharmony_ci		return -ENOMEM;
425362306a36Sopenharmony_ci	}
425462306a36Sopenharmony_ci	memset(id_ctlr, 0, sizeof(*id_ctlr));
425562306a36Sopenharmony_ci	rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr));
425662306a36Sopenharmony_ci	if (!rc)
425762306a36Sopenharmony_ci		if (id_ctlr->configured_logical_drive_count < 255)
425862306a36Sopenharmony_ci			*nlocals = id_ctlr->configured_logical_drive_count;
425962306a36Sopenharmony_ci		else
426062306a36Sopenharmony_ci			*nlocals = le16_to_cpu(
426162306a36Sopenharmony_ci					id_ctlr->extended_logical_unit_count);
426262306a36Sopenharmony_ci	else
426362306a36Sopenharmony_ci		*nlocals = -1;
426462306a36Sopenharmony_ci	return rc;
426562306a36Sopenharmony_ci}
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_cistatic bool hpsa_is_disk_spare(struct ctlr_info *h, u8 *lunaddrbytes)
426862306a36Sopenharmony_ci{
426962306a36Sopenharmony_ci	struct bmic_identify_physical_device *id_phys;
427062306a36Sopenharmony_ci	bool is_spare = false;
427162306a36Sopenharmony_ci	int rc;
427262306a36Sopenharmony_ci
427362306a36Sopenharmony_ci	id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
427462306a36Sopenharmony_ci	if (!id_phys)
427562306a36Sopenharmony_ci		return false;
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	rc = hpsa_bmic_id_physical_device(h,
427862306a36Sopenharmony_ci					lunaddrbytes,
427962306a36Sopenharmony_ci					GET_BMIC_DRIVE_NUMBER(lunaddrbytes),
428062306a36Sopenharmony_ci					id_phys, sizeof(*id_phys));
428162306a36Sopenharmony_ci	if (rc == 0)
428262306a36Sopenharmony_ci		is_spare = (id_phys->more_flags >> 6) & 0x01;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	kfree(id_phys);
428562306a36Sopenharmony_ci	return is_spare;
428662306a36Sopenharmony_ci}
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci#define RPL_DEV_FLAG_NON_DISK                           0x1
428962306a36Sopenharmony_ci#define RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED  0x2
429062306a36Sopenharmony_ci#define RPL_DEV_FLAG_UNCONFIG_DISK                      0x4
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ci#define BMIC_DEVICE_TYPE_ENCLOSURE  6
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_cistatic bool hpsa_skip_device(struct ctlr_info *h, u8 *lunaddrbytes,
429562306a36Sopenharmony_ci				struct ext_report_lun_entry *rle)
429662306a36Sopenharmony_ci{
429762306a36Sopenharmony_ci	u8 device_flags;
429862306a36Sopenharmony_ci	u8 device_type;
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	if (!MASKED_DEVICE(lunaddrbytes))
430162306a36Sopenharmony_ci		return false;
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	device_flags = rle->device_flags;
430462306a36Sopenharmony_ci	device_type = rle->device_type;
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci	if (device_flags & RPL_DEV_FLAG_NON_DISK) {
430762306a36Sopenharmony_ci		if (device_type == BMIC_DEVICE_TYPE_ENCLOSURE)
430862306a36Sopenharmony_ci			return false;
430962306a36Sopenharmony_ci		return true;
431062306a36Sopenharmony_ci	}
431162306a36Sopenharmony_ci
431262306a36Sopenharmony_ci	if (!(device_flags & RPL_DEV_FLAG_UNCONFIG_DISK_REPORTING_SUPPORTED))
431362306a36Sopenharmony_ci		return false;
431462306a36Sopenharmony_ci
431562306a36Sopenharmony_ci	if (device_flags & RPL_DEV_FLAG_UNCONFIG_DISK)
431662306a36Sopenharmony_ci		return false;
431762306a36Sopenharmony_ci
431862306a36Sopenharmony_ci	/*
431962306a36Sopenharmony_ci	 * Spares may be spun down, we do not want to
432062306a36Sopenharmony_ci	 * do an Inquiry to a RAID set spare drive as
432162306a36Sopenharmony_ci	 * that would have them spun up, that is a
432262306a36Sopenharmony_ci	 * performance hit because I/O to the RAID device
432362306a36Sopenharmony_ci	 * stops while the spin up occurs which can take
432462306a36Sopenharmony_ci	 * over 50 seconds.
432562306a36Sopenharmony_ci	 */
432662306a36Sopenharmony_ci	if (hpsa_is_disk_spare(h, lunaddrbytes))
432762306a36Sopenharmony_ci		return true;
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	return false;
433062306a36Sopenharmony_ci}
433162306a36Sopenharmony_ci
433262306a36Sopenharmony_cistatic void hpsa_update_scsi_devices(struct ctlr_info *h)
433362306a36Sopenharmony_ci{
433462306a36Sopenharmony_ci	/* the idea here is we could get notified
433562306a36Sopenharmony_ci	 * that some devices have changed, so we do a report
433662306a36Sopenharmony_ci	 * physical luns and report logical luns cmd, and adjust
433762306a36Sopenharmony_ci	 * our list of devices accordingly.
433862306a36Sopenharmony_ci	 *
433962306a36Sopenharmony_ci	 * The scsi3addr's of devices won't change so long as the
434062306a36Sopenharmony_ci	 * adapter is not reset.  That means we can rescan and
434162306a36Sopenharmony_ci	 * tell which devices we already know about, vs. new
434262306a36Sopenharmony_ci	 * devices, vs.  disappearing devices.
434362306a36Sopenharmony_ci	 */
434462306a36Sopenharmony_ci	struct ReportExtendedLUNdata *physdev_list = NULL;
434562306a36Sopenharmony_ci	struct ReportLUNdata *logdev_list = NULL;
434662306a36Sopenharmony_ci	struct bmic_identify_physical_device *id_phys = NULL;
434762306a36Sopenharmony_ci	struct bmic_identify_controller *id_ctlr = NULL;
434862306a36Sopenharmony_ci	u32 nphysicals = 0;
434962306a36Sopenharmony_ci	u32 nlogicals = 0;
435062306a36Sopenharmony_ci	u32 nlocal_logicals = 0;
435162306a36Sopenharmony_ci	u32 ndev_allocated = 0;
435262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
435362306a36Sopenharmony_ci	int ncurrent = 0;
435462306a36Sopenharmony_ci	int i, ndevs_to_allocate;
435562306a36Sopenharmony_ci	int raid_ctlr_position;
435662306a36Sopenharmony_ci	bool physical_device;
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci	currentsd = kcalloc(HPSA_MAX_DEVICES, sizeof(*currentsd), GFP_KERNEL);
435962306a36Sopenharmony_ci	physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL);
436062306a36Sopenharmony_ci	logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
436162306a36Sopenharmony_ci	tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
436262306a36Sopenharmony_ci	id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
436362306a36Sopenharmony_ci	id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL);
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci	if (!currentsd || !physdev_list || !logdev_list ||
436662306a36Sopenharmony_ci		!tmpdevice || !id_phys || !id_ctlr) {
436762306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "out of memory\n");
436862306a36Sopenharmony_ci		goto out;
436962306a36Sopenharmony_ci	}
437062306a36Sopenharmony_ci
437162306a36Sopenharmony_ci	h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	if (hpsa_gather_lun_info(h, physdev_list, &nphysicals,
437462306a36Sopenharmony_ci			logdev_list, &nlogicals)) {
437562306a36Sopenharmony_ci		h->drv_req_rescan = 1;
437662306a36Sopenharmony_ci		goto out;
437762306a36Sopenharmony_ci	}
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	/* Set number of local logicals (non PTRAID) */
438062306a36Sopenharmony_ci	if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) {
438162306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
438262306a36Sopenharmony_ci			"%s: Can't determine number of local logical devices.\n",
438362306a36Sopenharmony_ci			__func__);
438462306a36Sopenharmony_ci	}
438562306a36Sopenharmony_ci
438662306a36Sopenharmony_ci	/* We might see up to the maximum number of logical and physical disks
438762306a36Sopenharmony_ci	 * plus external target devices, and a device for the local RAID
438862306a36Sopenharmony_ci	 * controller.
438962306a36Sopenharmony_ci	 */
439062306a36Sopenharmony_ci	ndevs_to_allocate = nphysicals + nlogicals + MAX_EXT_TARGETS + 1;
439162306a36Sopenharmony_ci
439262306a36Sopenharmony_ci	hpsa_ext_ctrl_present(h, physdev_list);
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci	/* Allocate the per device structures */
439562306a36Sopenharmony_ci	for (i = 0; i < ndevs_to_allocate; i++) {
439662306a36Sopenharmony_ci		if (i >= HPSA_MAX_DEVICES) {
439762306a36Sopenharmony_ci			dev_warn(&h->pdev->dev, "maximum devices (%d) exceeded."
439862306a36Sopenharmony_ci				"  %d devices ignored.\n", HPSA_MAX_DEVICES,
439962306a36Sopenharmony_ci				ndevs_to_allocate - HPSA_MAX_DEVICES);
440062306a36Sopenharmony_ci			break;
440162306a36Sopenharmony_ci		}
440262306a36Sopenharmony_ci
440362306a36Sopenharmony_ci		currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL);
440462306a36Sopenharmony_ci		if (!currentsd[i]) {
440562306a36Sopenharmony_ci			h->drv_req_rescan = 1;
440662306a36Sopenharmony_ci			goto out;
440762306a36Sopenharmony_ci		}
440862306a36Sopenharmony_ci		ndev_allocated++;
440962306a36Sopenharmony_ci	}
441062306a36Sopenharmony_ci
441162306a36Sopenharmony_ci	if (is_scsi_rev_5(h))
441262306a36Sopenharmony_ci		raid_ctlr_position = 0;
441362306a36Sopenharmony_ci	else
441462306a36Sopenharmony_ci		raid_ctlr_position = nphysicals + nlogicals;
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	/* adjust our table of devices */
441762306a36Sopenharmony_ci	for (i = 0; i < nphysicals + nlogicals + 1; i++) {
441862306a36Sopenharmony_ci		u8 *lunaddrbytes, is_OBDR = 0;
441962306a36Sopenharmony_ci		int rc = 0;
442062306a36Sopenharmony_ci		int phys_dev_index = i - (raid_ctlr_position == 0);
442162306a36Sopenharmony_ci		bool skip_device = false;
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci		memset(tmpdevice, 0, sizeof(*tmpdevice));
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci		physical_device = i < nphysicals + (raid_ctlr_position == 0);
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci		/* Figure out where the LUN ID info is coming from */
442862306a36Sopenharmony_ci		lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
442962306a36Sopenharmony_ci			i, nphysicals, nlogicals, physdev_list, logdev_list);
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_ci		/* Determine if this is a lun from an external target array */
443262306a36Sopenharmony_ci		tmpdevice->external =
443362306a36Sopenharmony_ci			figure_external_status(h, raid_ctlr_position, i,
443462306a36Sopenharmony_ci						nphysicals, nlocal_logicals);
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci		/*
443762306a36Sopenharmony_ci		 * Skip over some devices such as a spare.
443862306a36Sopenharmony_ci		 */
443962306a36Sopenharmony_ci		if (phys_dev_index >= 0 && !tmpdevice->external &&
444062306a36Sopenharmony_ci			physical_device) {
444162306a36Sopenharmony_ci			skip_device = hpsa_skip_device(h, lunaddrbytes,
444262306a36Sopenharmony_ci					&physdev_list->LUN[phys_dev_index]);
444362306a36Sopenharmony_ci			if (skip_device)
444462306a36Sopenharmony_ci				continue;
444562306a36Sopenharmony_ci		}
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci		/* Get device type, vendor, model, device id, raid_map */
444862306a36Sopenharmony_ci		rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
444962306a36Sopenharmony_ci							&is_OBDR);
445062306a36Sopenharmony_ci		if (rc == -ENOMEM) {
445162306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
445262306a36Sopenharmony_ci				"Out of memory, rescan deferred.\n");
445362306a36Sopenharmony_ci			h->drv_req_rescan = 1;
445462306a36Sopenharmony_ci			goto out;
445562306a36Sopenharmony_ci		}
445662306a36Sopenharmony_ci		if (rc) {
445762306a36Sopenharmony_ci			h->drv_req_rescan = 1;
445862306a36Sopenharmony_ci			continue;
445962306a36Sopenharmony_ci		}
446062306a36Sopenharmony_ci
446162306a36Sopenharmony_ci		figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
446262306a36Sopenharmony_ci		this_device = currentsd[ncurrent];
446362306a36Sopenharmony_ci
446462306a36Sopenharmony_ci		*this_device = *tmpdevice;
446562306a36Sopenharmony_ci		this_device->physical_device = physical_device;
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci		/*
446862306a36Sopenharmony_ci		 * Expose all devices except for physical devices that
446962306a36Sopenharmony_ci		 * are masked.
447062306a36Sopenharmony_ci		 */
447162306a36Sopenharmony_ci		if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device)
447262306a36Sopenharmony_ci			this_device->expose_device = 0;
447362306a36Sopenharmony_ci		else
447462306a36Sopenharmony_ci			this_device->expose_device = 1;
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci		/*
447862306a36Sopenharmony_ci		 * Get the SAS address for physical devices that are exposed.
447962306a36Sopenharmony_ci		 */
448062306a36Sopenharmony_ci		if (this_device->physical_device && this_device->expose_device)
448162306a36Sopenharmony_ci			hpsa_get_sas_address(h, lunaddrbytes, this_device);
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci		switch (this_device->devtype) {
448462306a36Sopenharmony_ci		case TYPE_ROM:
448562306a36Sopenharmony_ci			/* We don't *really* support actual CD-ROM devices,
448662306a36Sopenharmony_ci			 * just "One Button Disaster Recovery" tape drive
448762306a36Sopenharmony_ci			 * which temporarily pretends to be a CD-ROM drive.
448862306a36Sopenharmony_ci			 * So we check that the device is really an OBDR tape
448962306a36Sopenharmony_ci			 * device by checking for "$DR-10" in bytes 43-48 of
449062306a36Sopenharmony_ci			 * the inquiry data.
449162306a36Sopenharmony_ci			 */
449262306a36Sopenharmony_ci			if (is_OBDR)
449362306a36Sopenharmony_ci				ncurrent++;
449462306a36Sopenharmony_ci			break;
449562306a36Sopenharmony_ci		case TYPE_DISK:
449662306a36Sopenharmony_ci		case TYPE_ZBC:
449762306a36Sopenharmony_ci			if (this_device->physical_device) {
449862306a36Sopenharmony_ci				/* The disk is in HBA mode. */
449962306a36Sopenharmony_ci				/* Never use RAID mapper in HBA mode. */
450062306a36Sopenharmony_ci				this_device->offload_enabled = 0;
450162306a36Sopenharmony_ci				hpsa_get_ioaccel_drive_info(h, this_device,
450262306a36Sopenharmony_ci					physdev_list, phys_dev_index, id_phys);
450362306a36Sopenharmony_ci				hpsa_get_path_info(this_device,
450462306a36Sopenharmony_ci					physdev_list, phys_dev_index, id_phys);
450562306a36Sopenharmony_ci			}
450662306a36Sopenharmony_ci			ncurrent++;
450762306a36Sopenharmony_ci			break;
450862306a36Sopenharmony_ci		case TYPE_TAPE:
450962306a36Sopenharmony_ci		case TYPE_MEDIUM_CHANGER:
451062306a36Sopenharmony_ci			ncurrent++;
451162306a36Sopenharmony_ci			break;
451262306a36Sopenharmony_ci		case TYPE_ENCLOSURE:
451362306a36Sopenharmony_ci			if (!this_device->external)
451462306a36Sopenharmony_ci				hpsa_get_enclosure_info(h, lunaddrbytes,
451562306a36Sopenharmony_ci						physdev_list, phys_dev_index,
451662306a36Sopenharmony_ci						this_device);
451762306a36Sopenharmony_ci			ncurrent++;
451862306a36Sopenharmony_ci			break;
451962306a36Sopenharmony_ci		case TYPE_RAID:
452062306a36Sopenharmony_ci			/* Only present the Smartarray HBA as a RAID controller.
452162306a36Sopenharmony_ci			 * If it's a RAID controller other than the HBA itself
452262306a36Sopenharmony_ci			 * (an external RAID controller, MSA500 or similar)
452362306a36Sopenharmony_ci			 * don't present it.
452462306a36Sopenharmony_ci			 */
452562306a36Sopenharmony_ci			if (!is_hba_lunid(lunaddrbytes))
452662306a36Sopenharmony_ci				break;
452762306a36Sopenharmony_ci			ncurrent++;
452862306a36Sopenharmony_ci			break;
452962306a36Sopenharmony_ci		default:
453062306a36Sopenharmony_ci			break;
453162306a36Sopenharmony_ci		}
453262306a36Sopenharmony_ci		if (ncurrent >= HPSA_MAX_DEVICES)
453362306a36Sopenharmony_ci			break;
453462306a36Sopenharmony_ci	}
453562306a36Sopenharmony_ci
453662306a36Sopenharmony_ci	if (h->sas_host == NULL) {
453762306a36Sopenharmony_ci		int rc = 0;
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_ci		rc = hpsa_add_sas_host(h);
454062306a36Sopenharmony_ci		if (rc) {
454162306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
454262306a36Sopenharmony_ci				"Could not add sas host %d\n", rc);
454362306a36Sopenharmony_ci			goto out;
454462306a36Sopenharmony_ci		}
454562306a36Sopenharmony_ci	}
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	adjust_hpsa_scsi_table(h, currentsd, ncurrent);
454862306a36Sopenharmony_ciout:
454962306a36Sopenharmony_ci	kfree(tmpdevice);
455062306a36Sopenharmony_ci	for (i = 0; i < ndev_allocated; i++)
455162306a36Sopenharmony_ci		kfree(currentsd[i]);
455262306a36Sopenharmony_ci	kfree(currentsd);
455362306a36Sopenharmony_ci	kfree(physdev_list);
455462306a36Sopenharmony_ci	kfree(logdev_list);
455562306a36Sopenharmony_ci	kfree(id_ctlr);
455662306a36Sopenharmony_ci	kfree(id_phys);
455762306a36Sopenharmony_ci}
455862306a36Sopenharmony_ci
455962306a36Sopenharmony_cistatic void hpsa_set_sg_descriptor(struct SGDescriptor *desc,
456062306a36Sopenharmony_ci				   struct scatterlist *sg)
456162306a36Sopenharmony_ci{
456262306a36Sopenharmony_ci	u64 addr64 = (u64) sg_dma_address(sg);
456362306a36Sopenharmony_ci	unsigned int len = sg_dma_len(sg);
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	desc->Addr = cpu_to_le64(addr64);
456662306a36Sopenharmony_ci	desc->Len = cpu_to_le32(len);
456762306a36Sopenharmony_ci	desc->Ext = 0;
456862306a36Sopenharmony_ci}
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci/*
457162306a36Sopenharmony_ci * hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
457262306a36Sopenharmony_ci * dma mapping  and fills in the scatter gather entries of the
457362306a36Sopenharmony_ci * hpsa command, cp.
457462306a36Sopenharmony_ci */
457562306a36Sopenharmony_cistatic int hpsa_scatter_gather(struct ctlr_info *h,
457662306a36Sopenharmony_ci		struct CommandList *cp,
457762306a36Sopenharmony_ci		struct scsi_cmnd *cmd)
457862306a36Sopenharmony_ci{
457962306a36Sopenharmony_ci	struct scatterlist *sg;
458062306a36Sopenharmony_ci	int use_sg, i, sg_limit, chained;
458162306a36Sopenharmony_ci	struct SGDescriptor *curr_sg;
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_ci	use_sg = scsi_dma_map(cmd);
458662306a36Sopenharmony_ci	if (use_sg < 0)
458762306a36Sopenharmony_ci		return use_sg;
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	if (!use_sg)
459062306a36Sopenharmony_ci		goto sglist_finished;
459162306a36Sopenharmony_ci
459262306a36Sopenharmony_ci	/*
459362306a36Sopenharmony_ci	 * If the number of entries is greater than the max for a single list,
459462306a36Sopenharmony_ci	 * then we have a chained list; we will set up all but one entry in the
459562306a36Sopenharmony_ci	 * first list (the last entry is saved for link information);
459662306a36Sopenharmony_ci	 * otherwise, we don't have a chained list and we'll set up at each of
459762306a36Sopenharmony_ci	 * the entries in the one list.
459862306a36Sopenharmony_ci	 */
459962306a36Sopenharmony_ci	curr_sg = cp->SG;
460062306a36Sopenharmony_ci	chained = use_sg > h->max_cmd_sg_entries;
460162306a36Sopenharmony_ci	sg_limit = chained ? h->max_cmd_sg_entries - 1 : use_sg;
460262306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, sg_limit, i) {
460362306a36Sopenharmony_ci		hpsa_set_sg_descriptor(curr_sg, sg);
460462306a36Sopenharmony_ci		curr_sg++;
460562306a36Sopenharmony_ci	}
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	if (chained) {
460862306a36Sopenharmony_ci		/*
460962306a36Sopenharmony_ci		 * Continue with the chained list.  Set curr_sg to the chained
461062306a36Sopenharmony_ci		 * list.  Modify the limit to the total count less the entries
461162306a36Sopenharmony_ci		 * we've already set up.  Resume the scan at the list entry
461262306a36Sopenharmony_ci		 * where the previous loop left off.
461362306a36Sopenharmony_ci		 */
461462306a36Sopenharmony_ci		curr_sg = h->cmd_sg_list[cp->cmdindex];
461562306a36Sopenharmony_ci		sg_limit = use_sg - sg_limit;
461662306a36Sopenharmony_ci		for_each_sg(sg, sg, sg_limit, i) {
461762306a36Sopenharmony_ci			hpsa_set_sg_descriptor(curr_sg, sg);
461862306a36Sopenharmony_ci			curr_sg++;
461962306a36Sopenharmony_ci		}
462062306a36Sopenharmony_ci	}
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci	/* Back the pointer up to the last entry and mark it as "last". */
462362306a36Sopenharmony_ci	(curr_sg - 1)->Ext = cpu_to_le32(HPSA_SG_LAST);
462462306a36Sopenharmony_ci
462562306a36Sopenharmony_ci	if (use_sg + chained > h->maxSG)
462662306a36Sopenharmony_ci		h->maxSG = use_sg + chained;
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ci	if (chained) {
462962306a36Sopenharmony_ci		cp->Header.SGList = h->max_cmd_sg_entries;
463062306a36Sopenharmony_ci		cp->Header.SGTotal = cpu_to_le16(use_sg + 1);
463162306a36Sopenharmony_ci		if (hpsa_map_sg_chain_block(h, cp)) {
463262306a36Sopenharmony_ci			scsi_dma_unmap(cmd);
463362306a36Sopenharmony_ci			return -1;
463462306a36Sopenharmony_ci		}
463562306a36Sopenharmony_ci		return 0;
463662306a36Sopenharmony_ci	}
463762306a36Sopenharmony_ci
463862306a36Sopenharmony_cisglist_finished:
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci	cp->Header.SGList = (u8) use_sg;   /* no. SGs contig in this cmd */
464162306a36Sopenharmony_ci	cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in cmd list */
464262306a36Sopenharmony_ci	return 0;
464362306a36Sopenharmony_ci}
464462306a36Sopenharmony_ci
464562306a36Sopenharmony_cistatic inline void warn_zero_length_transfer(struct ctlr_info *h,
464662306a36Sopenharmony_ci						u8 *cdb, int cdb_len,
464762306a36Sopenharmony_ci						const char *func)
464862306a36Sopenharmony_ci{
464962306a36Sopenharmony_ci	dev_warn(&h->pdev->dev,
465062306a36Sopenharmony_ci		 "%s: Blocking zero-length request: CDB:%*phN\n",
465162306a36Sopenharmony_ci		 func, cdb_len, cdb);
465262306a36Sopenharmony_ci}
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_ci#define IO_ACCEL_INELIGIBLE 1
465562306a36Sopenharmony_ci/* zero-length transfers trigger hardware errors. */
465662306a36Sopenharmony_cistatic bool is_zero_length_transfer(u8 *cdb)
465762306a36Sopenharmony_ci{
465862306a36Sopenharmony_ci	u32 block_cnt;
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	/* Block zero-length transfer sizes on certain commands. */
466162306a36Sopenharmony_ci	switch (cdb[0]) {
466262306a36Sopenharmony_ci	case READ_10:
466362306a36Sopenharmony_ci	case WRITE_10:
466462306a36Sopenharmony_ci	case VERIFY:		/* 0x2F */
466562306a36Sopenharmony_ci	case WRITE_VERIFY:	/* 0x2E */
466662306a36Sopenharmony_ci		block_cnt = get_unaligned_be16(&cdb[7]);
466762306a36Sopenharmony_ci		break;
466862306a36Sopenharmony_ci	case READ_12:
466962306a36Sopenharmony_ci	case WRITE_12:
467062306a36Sopenharmony_ci	case VERIFY_12: /* 0xAF */
467162306a36Sopenharmony_ci	case WRITE_VERIFY_12:	/* 0xAE */
467262306a36Sopenharmony_ci		block_cnt = get_unaligned_be32(&cdb[6]);
467362306a36Sopenharmony_ci		break;
467462306a36Sopenharmony_ci	case READ_16:
467562306a36Sopenharmony_ci	case WRITE_16:
467662306a36Sopenharmony_ci	case VERIFY_16:		/* 0x8F */
467762306a36Sopenharmony_ci		block_cnt = get_unaligned_be32(&cdb[10]);
467862306a36Sopenharmony_ci		break;
467962306a36Sopenharmony_ci	default:
468062306a36Sopenharmony_ci		return false;
468162306a36Sopenharmony_ci	}
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_ci	return block_cnt == 0;
468462306a36Sopenharmony_ci}
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_cistatic int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
468762306a36Sopenharmony_ci{
468862306a36Sopenharmony_ci	int is_write = 0;
468962306a36Sopenharmony_ci	u32 block;
469062306a36Sopenharmony_ci	u32 block_cnt;
469162306a36Sopenharmony_ci
469262306a36Sopenharmony_ci	/* Perform some CDB fixups if needed using 10 byte reads/writes only */
469362306a36Sopenharmony_ci	switch (cdb[0]) {
469462306a36Sopenharmony_ci	case WRITE_6:
469562306a36Sopenharmony_ci	case WRITE_12:
469662306a36Sopenharmony_ci		is_write = 1;
469762306a36Sopenharmony_ci		fallthrough;
469862306a36Sopenharmony_ci	case READ_6:
469962306a36Sopenharmony_ci	case READ_12:
470062306a36Sopenharmony_ci		if (*cdb_len == 6) {
470162306a36Sopenharmony_ci			block = (((cdb[1] & 0x1F) << 16) |
470262306a36Sopenharmony_ci				(cdb[2] << 8) |
470362306a36Sopenharmony_ci				cdb[3]);
470462306a36Sopenharmony_ci			block_cnt = cdb[4];
470562306a36Sopenharmony_ci			if (block_cnt == 0)
470662306a36Sopenharmony_ci				block_cnt = 256;
470762306a36Sopenharmony_ci		} else {
470862306a36Sopenharmony_ci			BUG_ON(*cdb_len != 12);
470962306a36Sopenharmony_ci			block = get_unaligned_be32(&cdb[2]);
471062306a36Sopenharmony_ci			block_cnt = get_unaligned_be32(&cdb[6]);
471162306a36Sopenharmony_ci		}
471262306a36Sopenharmony_ci		if (block_cnt > 0xffff)
471362306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci		cdb[0] = is_write ? WRITE_10 : READ_10;
471662306a36Sopenharmony_ci		cdb[1] = 0;
471762306a36Sopenharmony_ci		cdb[2] = (u8) (block >> 24);
471862306a36Sopenharmony_ci		cdb[3] = (u8) (block >> 16);
471962306a36Sopenharmony_ci		cdb[4] = (u8) (block >> 8);
472062306a36Sopenharmony_ci		cdb[5] = (u8) (block);
472162306a36Sopenharmony_ci		cdb[6] = 0;
472262306a36Sopenharmony_ci		cdb[7] = (u8) (block_cnt >> 8);
472362306a36Sopenharmony_ci		cdb[8] = (u8) (block_cnt);
472462306a36Sopenharmony_ci		cdb[9] = 0;
472562306a36Sopenharmony_ci		*cdb_len = 10;
472662306a36Sopenharmony_ci		break;
472762306a36Sopenharmony_ci	}
472862306a36Sopenharmony_ci	return 0;
472962306a36Sopenharmony_ci}
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
473262306a36Sopenharmony_ci	struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
473362306a36Sopenharmony_ci	u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
473462306a36Sopenharmony_ci{
473562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = c->scsi_cmd;
473662306a36Sopenharmony_ci	struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
473762306a36Sopenharmony_ci	unsigned int len;
473862306a36Sopenharmony_ci	unsigned int total_len = 0;
473962306a36Sopenharmony_ci	struct scatterlist *sg;
474062306a36Sopenharmony_ci	u64 addr64;
474162306a36Sopenharmony_ci	int use_sg, i;
474262306a36Sopenharmony_ci	struct SGDescriptor *curr_sg;
474362306a36Sopenharmony_ci	u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	/* TODO: implement chaining support */
474662306a36Sopenharmony_ci	if (scsi_sg_count(cmd) > h->ioaccel_maxsg) {
474762306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
474862306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
474962306a36Sopenharmony_ci	}
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
475262306a36Sopenharmony_ci
475362306a36Sopenharmony_ci	if (is_zero_length_transfer(cdb)) {
475462306a36Sopenharmony_ci		warn_zero_length_transfer(h, cdb, cdb_len, __func__);
475562306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
475662306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
475762306a36Sopenharmony_ci	}
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
476062306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
476162306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
476262306a36Sopenharmony_ci	}
476362306a36Sopenharmony_ci
476462306a36Sopenharmony_ci	c->cmd_type = CMD_IOACCEL1;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci	/* Adjust the DMA address to point to the accelerated command buffer */
476762306a36Sopenharmony_ci	c->busaddr = (u32) h->ioaccel_cmd_pool_dhandle +
476862306a36Sopenharmony_ci				(c->cmdindex * sizeof(*cp));
476962306a36Sopenharmony_ci	BUG_ON(c->busaddr & 0x0000007F);
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci	use_sg = scsi_dma_map(cmd);
477262306a36Sopenharmony_ci	if (use_sg < 0) {
477362306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
477462306a36Sopenharmony_ci		return use_sg;
477562306a36Sopenharmony_ci	}
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_ci	if (use_sg) {
477862306a36Sopenharmony_ci		curr_sg = cp->SG;
477962306a36Sopenharmony_ci		scsi_for_each_sg(cmd, sg, use_sg, i) {
478062306a36Sopenharmony_ci			addr64 = (u64) sg_dma_address(sg);
478162306a36Sopenharmony_ci			len  = sg_dma_len(sg);
478262306a36Sopenharmony_ci			total_len += len;
478362306a36Sopenharmony_ci			curr_sg->Addr = cpu_to_le64(addr64);
478462306a36Sopenharmony_ci			curr_sg->Len = cpu_to_le32(len);
478562306a36Sopenharmony_ci			curr_sg->Ext = cpu_to_le32(0);
478662306a36Sopenharmony_ci			curr_sg++;
478762306a36Sopenharmony_ci		}
478862306a36Sopenharmony_ci		(--curr_sg)->Ext = cpu_to_le32(HPSA_SG_LAST);
478962306a36Sopenharmony_ci
479062306a36Sopenharmony_ci		switch (cmd->sc_data_direction) {
479162306a36Sopenharmony_ci		case DMA_TO_DEVICE:
479262306a36Sopenharmony_ci			control |= IOACCEL1_CONTROL_DATA_OUT;
479362306a36Sopenharmony_ci			break;
479462306a36Sopenharmony_ci		case DMA_FROM_DEVICE:
479562306a36Sopenharmony_ci			control |= IOACCEL1_CONTROL_DATA_IN;
479662306a36Sopenharmony_ci			break;
479762306a36Sopenharmony_ci		case DMA_NONE:
479862306a36Sopenharmony_ci			control |= IOACCEL1_CONTROL_NODATAXFER;
479962306a36Sopenharmony_ci			break;
480062306a36Sopenharmony_ci		default:
480162306a36Sopenharmony_ci			dev_err(&h->pdev->dev, "unknown data direction: %d\n",
480262306a36Sopenharmony_ci			cmd->sc_data_direction);
480362306a36Sopenharmony_ci			BUG();
480462306a36Sopenharmony_ci			break;
480562306a36Sopenharmony_ci		}
480662306a36Sopenharmony_ci	} else {
480762306a36Sopenharmony_ci		control |= IOACCEL1_CONTROL_NODATAXFER;
480862306a36Sopenharmony_ci	}
480962306a36Sopenharmony_ci
481062306a36Sopenharmony_ci	c->Header.SGList = use_sg;
481162306a36Sopenharmony_ci	/* Fill out the command structure to submit */
481262306a36Sopenharmony_ci	cp->dev_handle = cpu_to_le16(ioaccel_handle & 0xFFFF);
481362306a36Sopenharmony_ci	cp->transfer_len = cpu_to_le32(total_len);
481462306a36Sopenharmony_ci	cp->io_flags = cpu_to_le16(IOACCEL1_IOFLAGS_IO_REQ |
481562306a36Sopenharmony_ci			(cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK));
481662306a36Sopenharmony_ci	cp->control = cpu_to_le32(control);
481762306a36Sopenharmony_ci	memcpy(cp->CDB, cdb, cdb_len);
481862306a36Sopenharmony_ci	memcpy(cp->CISS_LUN, scsi3addr, 8);
481962306a36Sopenharmony_ci	/* Tag was already set at init time. */
482062306a36Sopenharmony_ci	enqueue_cmd_and_start_io(h, c);
482162306a36Sopenharmony_ci	return 0;
482262306a36Sopenharmony_ci}
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_ci/*
482562306a36Sopenharmony_ci * Queue a command directly to a device behind the controller using the
482662306a36Sopenharmony_ci * I/O accelerator path.
482762306a36Sopenharmony_ci */
482862306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
482962306a36Sopenharmony_ci	struct CommandList *c)
483062306a36Sopenharmony_ci{
483162306a36Sopenharmony_ci	struct scsi_cmnd *cmd = c->scsi_cmd;
483262306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_ci	if (!dev)
483562306a36Sopenharmony_ci		return -1;
483662306a36Sopenharmony_ci
483762306a36Sopenharmony_ci	c->phys_disk = dev;
483862306a36Sopenharmony_ci
483962306a36Sopenharmony_ci	if (dev->in_reset)
484062306a36Sopenharmony_ci		return -1;
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
484362306a36Sopenharmony_ci		cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev);
484462306a36Sopenharmony_ci}
484562306a36Sopenharmony_ci
484662306a36Sopenharmony_ci/*
484762306a36Sopenharmony_ci * Set encryption parameters for the ioaccel2 request
484862306a36Sopenharmony_ci */
484962306a36Sopenharmony_cistatic void set_encrypt_ioaccel2(struct ctlr_info *h,
485062306a36Sopenharmony_ci	struct CommandList *c, struct io_accel2_cmd *cp)
485162306a36Sopenharmony_ci{
485262306a36Sopenharmony_ci	struct scsi_cmnd *cmd = c->scsi_cmd;
485362306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
485462306a36Sopenharmony_ci	struct raid_map_data *map = &dev->raid_map;
485562306a36Sopenharmony_ci	u64 first_block;
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci	/* Are we doing encryption on this device */
485862306a36Sopenharmony_ci	if (!(le16_to_cpu(map->flags) & RAID_MAP_FLAG_ENCRYPT_ON))
485962306a36Sopenharmony_ci		return;
486062306a36Sopenharmony_ci	/* Set the data encryption key index. */
486162306a36Sopenharmony_ci	cp->dekindex = map->dekindex;
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_ci	/* Set the encryption enable flag, encoded into direction field. */
486462306a36Sopenharmony_ci	cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK;
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_ci	/* Set encryption tweak values based on logical block address
486762306a36Sopenharmony_ci	 * If block size is 512, tweak value is LBA.
486862306a36Sopenharmony_ci	 * For other block sizes, tweak is (LBA * block size)/ 512)
486962306a36Sopenharmony_ci	 */
487062306a36Sopenharmony_ci	switch (cmd->cmnd[0]) {
487162306a36Sopenharmony_ci	/* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
487262306a36Sopenharmony_ci	case READ_6:
487362306a36Sopenharmony_ci	case WRITE_6:
487462306a36Sopenharmony_ci		first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
487562306a36Sopenharmony_ci				(cmd->cmnd[2] << 8) |
487662306a36Sopenharmony_ci				cmd->cmnd[3]);
487762306a36Sopenharmony_ci		break;
487862306a36Sopenharmony_ci	case WRITE_10:
487962306a36Sopenharmony_ci	case READ_10:
488062306a36Sopenharmony_ci	/* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */
488162306a36Sopenharmony_ci	case WRITE_12:
488262306a36Sopenharmony_ci	case READ_12:
488362306a36Sopenharmony_ci		first_block = get_unaligned_be32(&cmd->cmnd[2]);
488462306a36Sopenharmony_ci		break;
488562306a36Sopenharmony_ci	case WRITE_16:
488662306a36Sopenharmony_ci	case READ_16:
488762306a36Sopenharmony_ci		first_block = get_unaligned_be64(&cmd->cmnd[2]);
488862306a36Sopenharmony_ci		break;
488962306a36Sopenharmony_ci	default:
489062306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
489162306a36Sopenharmony_ci			"ERROR: %s: size (0x%x) not supported for encryption\n",
489262306a36Sopenharmony_ci			__func__, cmd->cmnd[0]);
489362306a36Sopenharmony_ci		BUG();
489462306a36Sopenharmony_ci		break;
489562306a36Sopenharmony_ci	}
489662306a36Sopenharmony_ci
489762306a36Sopenharmony_ci	if (le32_to_cpu(map->volume_blk_size) != 512)
489862306a36Sopenharmony_ci		first_block = first_block *
489962306a36Sopenharmony_ci				le32_to_cpu(map->volume_blk_size)/512;
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	cp->tweak_lower = cpu_to_le32(first_block);
490262306a36Sopenharmony_ci	cp->tweak_upper = cpu_to_le32(first_block >> 32);
490362306a36Sopenharmony_ci}
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
490662306a36Sopenharmony_ci	struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
490762306a36Sopenharmony_ci	u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
490862306a36Sopenharmony_ci{
490962306a36Sopenharmony_ci	struct scsi_cmnd *cmd = c->scsi_cmd;
491062306a36Sopenharmony_ci	struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
491162306a36Sopenharmony_ci	struct ioaccel2_sg_element *curr_sg;
491262306a36Sopenharmony_ci	int use_sg, i;
491362306a36Sopenharmony_ci	struct scatterlist *sg;
491462306a36Sopenharmony_ci	u64 addr64;
491562306a36Sopenharmony_ci	u32 len;
491662306a36Sopenharmony_ci	u32 total_len = 0;
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	if (!cmd->device)
491962306a36Sopenharmony_ci		return -1;
492062306a36Sopenharmony_ci
492162306a36Sopenharmony_ci	if (!cmd->device->hostdata)
492262306a36Sopenharmony_ci		return -1;
492362306a36Sopenharmony_ci
492462306a36Sopenharmony_ci	BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
492562306a36Sopenharmony_ci
492662306a36Sopenharmony_ci	if (is_zero_length_transfer(cdb)) {
492762306a36Sopenharmony_ci		warn_zero_length_transfer(h, cdb, cdb_len, __func__);
492862306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
492962306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
493062306a36Sopenharmony_ci	}
493162306a36Sopenharmony_ci
493262306a36Sopenharmony_ci	if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
493362306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
493462306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
493562306a36Sopenharmony_ci	}
493662306a36Sopenharmony_ci
493762306a36Sopenharmony_ci	c->cmd_type = CMD_IOACCEL2;
493862306a36Sopenharmony_ci	/* Adjust the DMA address to point to the accelerated command buffer */
493962306a36Sopenharmony_ci	c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
494062306a36Sopenharmony_ci				(c->cmdindex * sizeof(*cp));
494162306a36Sopenharmony_ci	BUG_ON(c->busaddr & 0x0000007F);
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_ci	memset(cp, 0, sizeof(*cp));
494462306a36Sopenharmony_ci	cp->IU_type = IOACCEL2_IU_TYPE;
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_ci	use_sg = scsi_dma_map(cmd);
494762306a36Sopenharmony_ci	if (use_sg < 0) {
494862306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
494962306a36Sopenharmony_ci		return use_sg;
495062306a36Sopenharmony_ci	}
495162306a36Sopenharmony_ci
495262306a36Sopenharmony_ci	if (use_sg) {
495362306a36Sopenharmony_ci		curr_sg = cp->sg;
495462306a36Sopenharmony_ci		if (use_sg > h->ioaccel_maxsg) {
495562306a36Sopenharmony_ci			addr64 = le64_to_cpu(
495662306a36Sopenharmony_ci				h->ioaccel2_cmd_sg_list[c->cmdindex]->address);
495762306a36Sopenharmony_ci			curr_sg->address = cpu_to_le64(addr64);
495862306a36Sopenharmony_ci			curr_sg->length = 0;
495962306a36Sopenharmony_ci			curr_sg->reserved[0] = 0;
496062306a36Sopenharmony_ci			curr_sg->reserved[1] = 0;
496162306a36Sopenharmony_ci			curr_sg->reserved[2] = 0;
496262306a36Sopenharmony_ci			curr_sg->chain_indicator = IOACCEL2_CHAIN;
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci			curr_sg = h->ioaccel2_cmd_sg_list[c->cmdindex];
496562306a36Sopenharmony_ci		}
496662306a36Sopenharmony_ci		scsi_for_each_sg(cmd, sg, use_sg, i) {
496762306a36Sopenharmony_ci			addr64 = (u64) sg_dma_address(sg);
496862306a36Sopenharmony_ci			len  = sg_dma_len(sg);
496962306a36Sopenharmony_ci			total_len += len;
497062306a36Sopenharmony_ci			curr_sg->address = cpu_to_le64(addr64);
497162306a36Sopenharmony_ci			curr_sg->length = cpu_to_le32(len);
497262306a36Sopenharmony_ci			curr_sg->reserved[0] = 0;
497362306a36Sopenharmony_ci			curr_sg->reserved[1] = 0;
497462306a36Sopenharmony_ci			curr_sg->reserved[2] = 0;
497562306a36Sopenharmony_ci			curr_sg->chain_indicator = 0;
497662306a36Sopenharmony_ci			curr_sg++;
497762306a36Sopenharmony_ci		}
497862306a36Sopenharmony_ci
497962306a36Sopenharmony_ci		/*
498062306a36Sopenharmony_ci		 * Set the last s/g element bit
498162306a36Sopenharmony_ci		 */
498262306a36Sopenharmony_ci		(curr_sg - 1)->chain_indicator = IOACCEL2_LAST_SG;
498362306a36Sopenharmony_ci
498462306a36Sopenharmony_ci		switch (cmd->sc_data_direction) {
498562306a36Sopenharmony_ci		case DMA_TO_DEVICE:
498662306a36Sopenharmony_ci			cp->direction &= ~IOACCEL2_DIRECTION_MASK;
498762306a36Sopenharmony_ci			cp->direction |= IOACCEL2_DIR_DATA_OUT;
498862306a36Sopenharmony_ci			break;
498962306a36Sopenharmony_ci		case DMA_FROM_DEVICE:
499062306a36Sopenharmony_ci			cp->direction &= ~IOACCEL2_DIRECTION_MASK;
499162306a36Sopenharmony_ci			cp->direction |= IOACCEL2_DIR_DATA_IN;
499262306a36Sopenharmony_ci			break;
499362306a36Sopenharmony_ci		case DMA_NONE:
499462306a36Sopenharmony_ci			cp->direction &= ~IOACCEL2_DIRECTION_MASK;
499562306a36Sopenharmony_ci			cp->direction |= IOACCEL2_DIR_NO_DATA;
499662306a36Sopenharmony_ci			break;
499762306a36Sopenharmony_ci		default:
499862306a36Sopenharmony_ci			dev_err(&h->pdev->dev, "unknown data direction: %d\n",
499962306a36Sopenharmony_ci				cmd->sc_data_direction);
500062306a36Sopenharmony_ci			BUG();
500162306a36Sopenharmony_ci			break;
500262306a36Sopenharmony_ci		}
500362306a36Sopenharmony_ci	} else {
500462306a36Sopenharmony_ci		cp->direction &= ~IOACCEL2_DIRECTION_MASK;
500562306a36Sopenharmony_ci		cp->direction |= IOACCEL2_DIR_NO_DATA;
500662306a36Sopenharmony_ci	}
500762306a36Sopenharmony_ci
500862306a36Sopenharmony_ci	/* Set encryption parameters, if necessary */
500962306a36Sopenharmony_ci	set_encrypt_ioaccel2(h, c, cp);
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	cp->scsi_nexus = cpu_to_le32(ioaccel_handle);
501262306a36Sopenharmony_ci	cp->Tag = cpu_to_le32(c->cmdindex << DIRECT_LOOKUP_SHIFT);
501362306a36Sopenharmony_ci	memcpy(cp->cdb, cdb, sizeof(cp->cdb));
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci	cp->data_len = cpu_to_le32(total_len);
501662306a36Sopenharmony_ci	cp->err_ptr = cpu_to_le64(c->busaddr +
501762306a36Sopenharmony_ci			offsetof(struct io_accel2_cmd, error_data));
501862306a36Sopenharmony_ci	cp->err_len = cpu_to_le32(sizeof(cp->error_data));
501962306a36Sopenharmony_ci
502062306a36Sopenharmony_ci	/* fill in sg elements */
502162306a36Sopenharmony_ci	if (use_sg > h->ioaccel_maxsg) {
502262306a36Sopenharmony_ci		cp->sg_count = 1;
502362306a36Sopenharmony_ci		cp->sg[0].length = cpu_to_le32(use_sg * sizeof(cp->sg[0]));
502462306a36Sopenharmony_ci		if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) {
502562306a36Sopenharmony_ci			atomic_dec(&phys_disk->ioaccel_cmds_out);
502662306a36Sopenharmony_ci			scsi_dma_unmap(cmd);
502762306a36Sopenharmony_ci			return -1;
502862306a36Sopenharmony_ci		}
502962306a36Sopenharmony_ci	} else
503062306a36Sopenharmony_ci		cp->sg_count = (u8) use_sg;
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	if (phys_disk->in_reset) {
503362306a36Sopenharmony_ci		cmd->result = DID_RESET << 16;
503462306a36Sopenharmony_ci		return -1;
503562306a36Sopenharmony_ci	}
503662306a36Sopenharmony_ci
503762306a36Sopenharmony_ci	enqueue_cmd_and_start_io(h, c);
503862306a36Sopenharmony_ci	return 0;
503962306a36Sopenharmony_ci}
504062306a36Sopenharmony_ci
504162306a36Sopenharmony_ci/*
504262306a36Sopenharmony_ci * Queue a command to the correct I/O accelerator path.
504362306a36Sopenharmony_ci */
504462306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
504562306a36Sopenharmony_ci	struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
504662306a36Sopenharmony_ci	u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
504762306a36Sopenharmony_ci{
504862306a36Sopenharmony_ci	if (!c->scsi_cmd->device)
504962306a36Sopenharmony_ci		return -1;
505062306a36Sopenharmony_ci
505162306a36Sopenharmony_ci	if (!c->scsi_cmd->device->hostdata)
505262306a36Sopenharmony_ci		return -1;
505362306a36Sopenharmony_ci
505462306a36Sopenharmony_ci	if (phys_disk->in_reset)
505562306a36Sopenharmony_ci		return -1;
505662306a36Sopenharmony_ci
505762306a36Sopenharmony_ci	/* Try to honor the device's queue depth */
505862306a36Sopenharmony_ci	if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
505962306a36Sopenharmony_ci					phys_disk->queue_depth) {
506062306a36Sopenharmony_ci		atomic_dec(&phys_disk->ioaccel_cmds_out);
506162306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
506262306a36Sopenharmony_ci	}
506362306a36Sopenharmony_ci	if (h->transMethod & CFGTBL_Trans_io_accel1)
506462306a36Sopenharmony_ci		return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
506562306a36Sopenharmony_ci						cdb, cdb_len, scsi3addr,
506662306a36Sopenharmony_ci						phys_disk);
506762306a36Sopenharmony_ci	else
506862306a36Sopenharmony_ci		return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
506962306a36Sopenharmony_ci						cdb, cdb_len, scsi3addr,
507062306a36Sopenharmony_ci						phys_disk);
507162306a36Sopenharmony_ci}
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_cistatic void raid_map_helper(struct raid_map_data *map,
507462306a36Sopenharmony_ci		int offload_to_mirror, u32 *map_index, u32 *current_group)
507562306a36Sopenharmony_ci{
507662306a36Sopenharmony_ci	if (offload_to_mirror == 0)  {
507762306a36Sopenharmony_ci		/* use physical disk in the first mirrored group. */
507862306a36Sopenharmony_ci		*map_index %= le16_to_cpu(map->data_disks_per_row);
507962306a36Sopenharmony_ci		return;
508062306a36Sopenharmony_ci	}
508162306a36Sopenharmony_ci	do {
508262306a36Sopenharmony_ci		/* determine mirror group that *map_index indicates */
508362306a36Sopenharmony_ci		*current_group = *map_index /
508462306a36Sopenharmony_ci			le16_to_cpu(map->data_disks_per_row);
508562306a36Sopenharmony_ci		if (offload_to_mirror == *current_group)
508662306a36Sopenharmony_ci			continue;
508762306a36Sopenharmony_ci		if (*current_group < le16_to_cpu(map->layout_map_count) - 1) {
508862306a36Sopenharmony_ci			/* select map index from next group */
508962306a36Sopenharmony_ci			*map_index += le16_to_cpu(map->data_disks_per_row);
509062306a36Sopenharmony_ci			(*current_group)++;
509162306a36Sopenharmony_ci		} else {
509262306a36Sopenharmony_ci			/* select map index from first group */
509362306a36Sopenharmony_ci			*map_index %= le16_to_cpu(map->data_disks_per_row);
509462306a36Sopenharmony_ci			*current_group = 0;
509562306a36Sopenharmony_ci		}
509662306a36Sopenharmony_ci	} while (offload_to_mirror != *current_group);
509762306a36Sopenharmony_ci}
509862306a36Sopenharmony_ci
509962306a36Sopenharmony_ci/*
510062306a36Sopenharmony_ci * Attempt to perform offload RAID mapping for a logical volume I/O.
510162306a36Sopenharmony_ci */
510262306a36Sopenharmony_cistatic int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
510362306a36Sopenharmony_ci	struct CommandList *c)
510462306a36Sopenharmony_ci{
510562306a36Sopenharmony_ci	struct scsi_cmnd *cmd = c->scsi_cmd;
510662306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
510762306a36Sopenharmony_ci	struct raid_map_data *map = &dev->raid_map;
510862306a36Sopenharmony_ci	struct raid_map_disk_data *dd = &map->data[0];
510962306a36Sopenharmony_ci	int is_write = 0;
511062306a36Sopenharmony_ci	u32 map_index;
511162306a36Sopenharmony_ci	u64 first_block, last_block;
511262306a36Sopenharmony_ci	u32 block_cnt;
511362306a36Sopenharmony_ci	u32 blocks_per_row;
511462306a36Sopenharmony_ci	u64 first_row, last_row;
511562306a36Sopenharmony_ci	u32 first_row_offset, last_row_offset;
511662306a36Sopenharmony_ci	u32 first_column, last_column;
511762306a36Sopenharmony_ci	u64 r0_first_row, r0_last_row;
511862306a36Sopenharmony_ci	u32 r5or6_blocks_per_row;
511962306a36Sopenharmony_ci	u64 r5or6_first_row, r5or6_last_row;
512062306a36Sopenharmony_ci	u32 r5or6_first_row_offset, r5or6_last_row_offset;
512162306a36Sopenharmony_ci	u32 r5or6_first_column, r5or6_last_column;
512262306a36Sopenharmony_ci	u32 total_disks_per_row;
512362306a36Sopenharmony_ci	u32 stripesize;
512462306a36Sopenharmony_ci	u32 first_group, last_group, current_group;
512562306a36Sopenharmony_ci	u32 map_row;
512662306a36Sopenharmony_ci	u32 disk_handle;
512762306a36Sopenharmony_ci	u64 disk_block;
512862306a36Sopenharmony_ci	u32 disk_block_cnt;
512962306a36Sopenharmony_ci	u8 cdb[16];
513062306a36Sopenharmony_ci	u8 cdb_len;
513162306a36Sopenharmony_ci	u16 strip_size;
513262306a36Sopenharmony_ci#if BITS_PER_LONG == 32
513362306a36Sopenharmony_ci	u64 tmpdiv;
513462306a36Sopenharmony_ci#endif
513562306a36Sopenharmony_ci	int offload_to_mirror;
513662306a36Sopenharmony_ci
513762306a36Sopenharmony_ci	if (!dev)
513862306a36Sopenharmony_ci		return -1;
513962306a36Sopenharmony_ci
514062306a36Sopenharmony_ci	if (dev->in_reset)
514162306a36Sopenharmony_ci		return -1;
514262306a36Sopenharmony_ci
514362306a36Sopenharmony_ci	/* check for valid opcode, get LBA and block count */
514462306a36Sopenharmony_ci	switch (cmd->cmnd[0]) {
514562306a36Sopenharmony_ci	case WRITE_6:
514662306a36Sopenharmony_ci		is_write = 1;
514762306a36Sopenharmony_ci		fallthrough;
514862306a36Sopenharmony_ci	case READ_6:
514962306a36Sopenharmony_ci		first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
515062306a36Sopenharmony_ci				(cmd->cmnd[2] << 8) |
515162306a36Sopenharmony_ci				cmd->cmnd[3]);
515262306a36Sopenharmony_ci		block_cnt = cmd->cmnd[4];
515362306a36Sopenharmony_ci		if (block_cnt == 0)
515462306a36Sopenharmony_ci			block_cnt = 256;
515562306a36Sopenharmony_ci		break;
515662306a36Sopenharmony_ci	case WRITE_10:
515762306a36Sopenharmony_ci		is_write = 1;
515862306a36Sopenharmony_ci		fallthrough;
515962306a36Sopenharmony_ci	case READ_10:
516062306a36Sopenharmony_ci		first_block =
516162306a36Sopenharmony_ci			(((u64) cmd->cmnd[2]) << 24) |
516262306a36Sopenharmony_ci			(((u64) cmd->cmnd[3]) << 16) |
516362306a36Sopenharmony_ci			(((u64) cmd->cmnd[4]) << 8) |
516462306a36Sopenharmony_ci			cmd->cmnd[5];
516562306a36Sopenharmony_ci		block_cnt =
516662306a36Sopenharmony_ci			(((u32) cmd->cmnd[7]) << 8) |
516762306a36Sopenharmony_ci			cmd->cmnd[8];
516862306a36Sopenharmony_ci		break;
516962306a36Sopenharmony_ci	case WRITE_12:
517062306a36Sopenharmony_ci		is_write = 1;
517162306a36Sopenharmony_ci		fallthrough;
517262306a36Sopenharmony_ci	case READ_12:
517362306a36Sopenharmony_ci		first_block =
517462306a36Sopenharmony_ci			(((u64) cmd->cmnd[2]) << 24) |
517562306a36Sopenharmony_ci			(((u64) cmd->cmnd[3]) << 16) |
517662306a36Sopenharmony_ci			(((u64) cmd->cmnd[4]) << 8) |
517762306a36Sopenharmony_ci			cmd->cmnd[5];
517862306a36Sopenharmony_ci		block_cnt =
517962306a36Sopenharmony_ci			(((u32) cmd->cmnd[6]) << 24) |
518062306a36Sopenharmony_ci			(((u32) cmd->cmnd[7]) << 16) |
518162306a36Sopenharmony_ci			(((u32) cmd->cmnd[8]) << 8) |
518262306a36Sopenharmony_ci		cmd->cmnd[9];
518362306a36Sopenharmony_ci		break;
518462306a36Sopenharmony_ci	case WRITE_16:
518562306a36Sopenharmony_ci		is_write = 1;
518662306a36Sopenharmony_ci		fallthrough;
518762306a36Sopenharmony_ci	case READ_16:
518862306a36Sopenharmony_ci		first_block =
518962306a36Sopenharmony_ci			(((u64) cmd->cmnd[2]) << 56) |
519062306a36Sopenharmony_ci			(((u64) cmd->cmnd[3]) << 48) |
519162306a36Sopenharmony_ci			(((u64) cmd->cmnd[4]) << 40) |
519262306a36Sopenharmony_ci			(((u64) cmd->cmnd[5]) << 32) |
519362306a36Sopenharmony_ci			(((u64) cmd->cmnd[6]) << 24) |
519462306a36Sopenharmony_ci			(((u64) cmd->cmnd[7]) << 16) |
519562306a36Sopenharmony_ci			(((u64) cmd->cmnd[8]) << 8) |
519662306a36Sopenharmony_ci			cmd->cmnd[9];
519762306a36Sopenharmony_ci		block_cnt =
519862306a36Sopenharmony_ci			(((u32) cmd->cmnd[10]) << 24) |
519962306a36Sopenharmony_ci			(((u32) cmd->cmnd[11]) << 16) |
520062306a36Sopenharmony_ci			(((u32) cmd->cmnd[12]) << 8) |
520162306a36Sopenharmony_ci			cmd->cmnd[13];
520262306a36Sopenharmony_ci		break;
520362306a36Sopenharmony_ci	default:
520462306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE; /* process via normal I/O path */
520562306a36Sopenharmony_ci	}
520662306a36Sopenharmony_ci	last_block = first_block + block_cnt - 1;
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci	/* check for write to non-RAID-0 */
520962306a36Sopenharmony_ci	if (is_write && dev->raid_level != 0)
521062306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
521162306a36Sopenharmony_ci
521262306a36Sopenharmony_ci	/* check for invalid block or wraparound */
521362306a36Sopenharmony_ci	if (last_block >= le64_to_cpu(map->volume_blk_cnt) ||
521462306a36Sopenharmony_ci		last_block < first_block)
521562306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci	/* calculate stripe information for the request */
521862306a36Sopenharmony_ci	blocks_per_row = le16_to_cpu(map->data_disks_per_row) *
521962306a36Sopenharmony_ci				le16_to_cpu(map->strip_size);
522062306a36Sopenharmony_ci	strip_size = le16_to_cpu(map->strip_size);
522162306a36Sopenharmony_ci#if BITS_PER_LONG == 32
522262306a36Sopenharmony_ci	tmpdiv = first_block;
522362306a36Sopenharmony_ci	(void) do_div(tmpdiv, blocks_per_row);
522462306a36Sopenharmony_ci	first_row = tmpdiv;
522562306a36Sopenharmony_ci	tmpdiv = last_block;
522662306a36Sopenharmony_ci	(void) do_div(tmpdiv, blocks_per_row);
522762306a36Sopenharmony_ci	last_row = tmpdiv;
522862306a36Sopenharmony_ci	first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
522962306a36Sopenharmony_ci	last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
523062306a36Sopenharmony_ci	tmpdiv = first_row_offset;
523162306a36Sopenharmony_ci	(void) do_div(tmpdiv, strip_size);
523262306a36Sopenharmony_ci	first_column = tmpdiv;
523362306a36Sopenharmony_ci	tmpdiv = last_row_offset;
523462306a36Sopenharmony_ci	(void) do_div(tmpdiv, strip_size);
523562306a36Sopenharmony_ci	last_column = tmpdiv;
523662306a36Sopenharmony_ci#else
523762306a36Sopenharmony_ci	first_row = first_block / blocks_per_row;
523862306a36Sopenharmony_ci	last_row = last_block / blocks_per_row;
523962306a36Sopenharmony_ci	first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
524062306a36Sopenharmony_ci	last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
524162306a36Sopenharmony_ci	first_column = first_row_offset / strip_size;
524262306a36Sopenharmony_ci	last_column = last_row_offset / strip_size;
524362306a36Sopenharmony_ci#endif
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_ci	/* if this isn't a single row/column then give to the controller */
524662306a36Sopenharmony_ci	if ((first_row != last_row) || (first_column != last_column))
524762306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
524862306a36Sopenharmony_ci
524962306a36Sopenharmony_ci	/* proceeding with driver mapping */
525062306a36Sopenharmony_ci	total_disks_per_row = le16_to_cpu(map->data_disks_per_row) +
525162306a36Sopenharmony_ci				le16_to_cpu(map->metadata_disks_per_row);
525262306a36Sopenharmony_ci	map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
525362306a36Sopenharmony_ci				le16_to_cpu(map->row_cnt);
525462306a36Sopenharmony_ci	map_index = (map_row * total_disks_per_row) + first_column;
525562306a36Sopenharmony_ci
525662306a36Sopenharmony_ci	switch (dev->raid_level) {
525762306a36Sopenharmony_ci	case HPSA_RAID_0:
525862306a36Sopenharmony_ci		break; /* nothing special to do */
525962306a36Sopenharmony_ci	case HPSA_RAID_1:
526062306a36Sopenharmony_ci		/* Handles load balance across RAID 1 members.
526162306a36Sopenharmony_ci		 * (2-drive R1 and R10 with even # of drives.)
526262306a36Sopenharmony_ci		 * Appropriate for SSDs, not optimal for HDDs
526362306a36Sopenharmony_ci		 * Ensure we have the correct raid_map.
526462306a36Sopenharmony_ci		 */
526562306a36Sopenharmony_ci		if (le16_to_cpu(map->layout_map_count) != 2) {
526662306a36Sopenharmony_ci			hpsa_turn_off_ioaccel_for_device(dev);
526762306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
526862306a36Sopenharmony_ci		}
526962306a36Sopenharmony_ci		if (dev->offload_to_mirror)
527062306a36Sopenharmony_ci			map_index += le16_to_cpu(map->data_disks_per_row);
527162306a36Sopenharmony_ci		dev->offload_to_mirror = !dev->offload_to_mirror;
527262306a36Sopenharmony_ci		break;
527362306a36Sopenharmony_ci	case HPSA_RAID_ADM:
527462306a36Sopenharmony_ci		/* Handles N-way mirrors  (R1-ADM)
527562306a36Sopenharmony_ci		 * and R10 with # of drives divisible by 3.)
527662306a36Sopenharmony_ci		 * Ensure we have the correct raid_map.
527762306a36Sopenharmony_ci		 */
527862306a36Sopenharmony_ci		if (le16_to_cpu(map->layout_map_count) != 3) {
527962306a36Sopenharmony_ci			hpsa_turn_off_ioaccel_for_device(dev);
528062306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
528162306a36Sopenharmony_ci		}
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci		offload_to_mirror = dev->offload_to_mirror;
528462306a36Sopenharmony_ci		raid_map_helper(map, offload_to_mirror,
528562306a36Sopenharmony_ci				&map_index, &current_group);
528662306a36Sopenharmony_ci		/* set mirror group to use next time */
528762306a36Sopenharmony_ci		offload_to_mirror =
528862306a36Sopenharmony_ci			(offload_to_mirror >=
528962306a36Sopenharmony_ci			le16_to_cpu(map->layout_map_count) - 1)
529062306a36Sopenharmony_ci			? 0 : offload_to_mirror + 1;
529162306a36Sopenharmony_ci		dev->offload_to_mirror = offload_to_mirror;
529262306a36Sopenharmony_ci		/* Avoid direct use of dev->offload_to_mirror within this
529362306a36Sopenharmony_ci		 * function since multiple threads might simultaneously
529462306a36Sopenharmony_ci		 * increment it beyond the range of dev->layout_map_count -1.
529562306a36Sopenharmony_ci		 */
529662306a36Sopenharmony_ci		break;
529762306a36Sopenharmony_ci	case HPSA_RAID_5:
529862306a36Sopenharmony_ci	case HPSA_RAID_6:
529962306a36Sopenharmony_ci		if (le16_to_cpu(map->layout_map_count) <= 1)
530062306a36Sopenharmony_ci			break;
530162306a36Sopenharmony_ci
530262306a36Sopenharmony_ci		/* Verify first and last block are in same RAID group */
530362306a36Sopenharmony_ci		r5or6_blocks_per_row =
530462306a36Sopenharmony_ci			le16_to_cpu(map->strip_size) *
530562306a36Sopenharmony_ci			le16_to_cpu(map->data_disks_per_row);
530662306a36Sopenharmony_ci		if (r5or6_blocks_per_row == 0) {
530762306a36Sopenharmony_ci			hpsa_turn_off_ioaccel_for_device(dev);
530862306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
530962306a36Sopenharmony_ci		}
531062306a36Sopenharmony_ci		stripesize = r5or6_blocks_per_row *
531162306a36Sopenharmony_ci			le16_to_cpu(map->layout_map_count);
531262306a36Sopenharmony_ci#if BITS_PER_LONG == 32
531362306a36Sopenharmony_ci		tmpdiv = first_block;
531462306a36Sopenharmony_ci		first_group = do_div(tmpdiv, stripesize);
531562306a36Sopenharmony_ci		tmpdiv = first_group;
531662306a36Sopenharmony_ci		(void) do_div(tmpdiv, r5or6_blocks_per_row);
531762306a36Sopenharmony_ci		first_group = tmpdiv;
531862306a36Sopenharmony_ci		tmpdiv = last_block;
531962306a36Sopenharmony_ci		last_group = do_div(tmpdiv, stripesize);
532062306a36Sopenharmony_ci		tmpdiv = last_group;
532162306a36Sopenharmony_ci		(void) do_div(tmpdiv, r5or6_blocks_per_row);
532262306a36Sopenharmony_ci		last_group = tmpdiv;
532362306a36Sopenharmony_ci#else
532462306a36Sopenharmony_ci		first_group = (first_block % stripesize) / r5or6_blocks_per_row;
532562306a36Sopenharmony_ci		last_group = (last_block % stripesize) / r5or6_blocks_per_row;
532662306a36Sopenharmony_ci#endif
532762306a36Sopenharmony_ci		if (first_group != last_group)
532862306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci		/* Verify request is in a single row of RAID 5/6 */
533162306a36Sopenharmony_ci#if BITS_PER_LONG == 32
533262306a36Sopenharmony_ci		tmpdiv = first_block;
533362306a36Sopenharmony_ci		(void) do_div(tmpdiv, stripesize);
533462306a36Sopenharmony_ci		first_row = r5or6_first_row = r0_first_row = tmpdiv;
533562306a36Sopenharmony_ci		tmpdiv = last_block;
533662306a36Sopenharmony_ci		(void) do_div(tmpdiv, stripesize);
533762306a36Sopenharmony_ci		r5or6_last_row = r0_last_row = tmpdiv;
533862306a36Sopenharmony_ci#else
533962306a36Sopenharmony_ci		first_row = r5or6_first_row = r0_first_row =
534062306a36Sopenharmony_ci						first_block / stripesize;
534162306a36Sopenharmony_ci		r5or6_last_row = r0_last_row = last_block / stripesize;
534262306a36Sopenharmony_ci#endif
534362306a36Sopenharmony_ci		if (r5or6_first_row != r5or6_last_row)
534462306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
534562306a36Sopenharmony_ci
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci		/* Verify request is in a single column */
534862306a36Sopenharmony_ci#if BITS_PER_LONG == 32
534962306a36Sopenharmony_ci		tmpdiv = first_block;
535062306a36Sopenharmony_ci		first_row_offset = do_div(tmpdiv, stripesize);
535162306a36Sopenharmony_ci		tmpdiv = first_row_offset;
535262306a36Sopenharmony_ci		first_row_offset = (u32) do_div(tmpdiv, r5or6_blocks_per_row);
535362306a36Sopenharmony_ci		r5or6_first_row_offset = first_row_offset;
535462306a36Sopenharmony_ci		tmpdiv = last_block;
535562306a36Sopenharmony_ci		r5or6_last_row_offset = do_div(tmpdiv, stripesize);
535662306a36Sopenharmony_ci		tmpdiv = r5or6_last_row_offset;
535762306a36Sopenharmony_ci		r5or6_last_row_offset = do_div(tmpdiv, r5or6_blocks_per_row);
535862306a36Sopenharmony_ci		tmpdiv = r5or6_first_row_offset;
535962306a36Sopenharmony_ci		(void) do_div(tmpdiv, map->strip_size);
536062306a36Sopenharmony_ci		first_column = r5or6_first_column = tmpdiv;
536162306a36Sopenharmony_ci		tmpdiv = r5or6_last_row_offset;
536262306a36Sopenharmony_ci		(void) do_div(tmpdiv, map->strip_size);
536362306a36Sopenharmony_ci		r5or6_last_column = tmpdiv;
536462306a36Sopenharmony_ci#else
536562306a36Sopenharmony_ci		first_row_offset = r5or6_first_row_offset =
536662306a36Sopenharmony_ci			(u32)((first_block % stripesize) %
536762306a36Sopenharmony_ci						r5or6_blocks_per_row);
536862306a36Sopenharmony_ci
536962306a36Sopenharmony_ci		r5or6_last_row_offset =
537062306a36Sopenharmony_ci			(u32)((last_block % stripesize) %
537162306a36Sopenharmony_ci						r5or6_blocks_per_row);
537262306a36Sopenharmony_ci
537362306a36Sopenharmony_ci		first_column = r5or6_first_column =
537462306a36Sopenharmony_ci			r5or6_first_row_offset / le16_to_cpu(map->strip_size);
537562306a36Sopenharmony_ci		r5or6_last_column =
537662306a36Sopenharmony_ci			r5or6_last_row_offset / le16_to_cpu(map->strip_size);
537762306a36Sopenharmony_ci#endif
537862306a36Sopenharmony_ci		if (r5or6_first_column != r5or6_last_column)
537962306a36Sopenharmony_ci			return IO_ACCEL_INELIGIBLE;
538062306a36Sopenharmony_ci
538162306a36Sopenharmony_ci		/* Request is eligible */
538262306a36Sopenharmony_ci		map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
538362306a36Sopenharmony_ci			le16_to_cpu(map->row_cnt);
538462306a36Sopenharmony_ci
538562306a36Sopenharmony_ci		map_index = (first_group *
538662306a36Sopenharmony_ci			(le16_to_cpu(map->row_cnt) * total_disks_per_row)) +
538762306a36Sopenharmony_ci			(map_row * total_disks_per_row) + first_column;
538862306a36Sopenharmony_ci		break;
538962306a36Sopenharmony_ci	default:
539062306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
539162306a36Sopenharmony_ci	}
539262306a36Sopenharmony_ci
539362306a36Sopenharmony_ci	if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES))
539462306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
539562306a36Sopenharmony_ci
539662306a36Sopenharmony_ci	c->phys_disk = dev->phys_disk[map_index];
539762306a36Sopenharmony_ci	if (!c->phys_disk)
539862306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
539962306a36Sopenharmony_ci
540062306a36Sopenharmony_ci	disk_handle = dd[map_index].ioaccel_handle;
540162306a36Sopenharmony_ci	disk_block = le64_to_cpu(map->disk_starting_blk) +
540262306a36Sopenharmony_ci			first_row * le16_to_cpu(map->strip_size) +
540362306a36Sopenharmony_ci			(first_row_offset - first_column *
540462306a36Sopenharmony_ci			le16_to_cpu(map->strip_size));
540562306a36Sopenharmony_ci	disk_block_cnt = block_cnt;
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci	/* handle differing logical/physical block sizes */
540862306a36Sopenharmony_ci	if (map->phys_blk_shift) {
540962306a36Sopenharmony_ci		disk_block <<= map->phys_blk_shift;
541062306a36Sopenharmony_ci		disk_block_cnt <<= map->phys_blk_shift;
541162306a36Sopenharmony_ci	}
541262306a36Sopenharmony_ci	BUG_ON(disk_block_cnt > 0xffff);
541362306a36Sopenharmony_ci
541462306a36Sopenharmony_ci	/* build the new CDB for the physical disk I/O */
541562306a36Sopenharmony_ci	if (disk_block > 0xffffffff) {
541662306a36Sopenharmony_ci		cdb[0] = is_write ? WRITE_16 : READ_16;
541762306a36Sopenharmony_ci		cdb[1] = 0;
541862306a36Sopenharmony_ci		cdb[2] = (u8) (disk_block >> 56);
541962306a36Sopenharmony_ci		cdb[3] = (u8) (disk_block >> 48);
542062306a36Sopenharmony_ci		cdb[4] = (u8) (disk_block >> 40);
542162306a36Sopenharmony_ci		cdb[5] = (u8) (disk_block >> 32);
542262306a36Sopenharmony_ci		cdb[6] = (u8) (disk_block >> 24);
542362306a36Sopenharmony_ci		cdb[7] = (u8) (disk_block >> 16);
542462306a36Sopenharmony_ci		cdb[8] = (u8) (disk_block >> 8);
542562306a36Sopenharmony_ci		cdb[9] = (u8) (disk_block);
542662306a36Sopenharmony_ci		cdb[10] = (u8) (disk_block_cnt >> 24);
542762306a36Sopenharmony_ci		cdb[11] = (u8) (disk_block_cnt >> 16);
542862306a36Sopenharmony_ci		cdb[12] = (u8) (disk_block_cnt >> 8);
542962306a36Sopenharmony_ci		cdb[13] = (u8) (disk_block_cnt);
543062306a36Sopenharmony_ci		cdb[14] = 0;
543162306a36Sopenharmony_ci		cdb[15] = 0;
543262306a36Sopenharmony_ci		cdb_len = 16;
543362306a36Sopenharmony_ci	} else {
543462306a36Sopenharmony_ci		cdb[0] = is_write ? WRITE_10 : READ_10;
543562306a36Sopenharmony_ci		cdb[1] = 0;
543662306a36Sopenharmony_ci		cdb[2] = (u8) (disk_block >> 24);
543762306a36Sopenharmony_ci		cdb[3] = (u8) (disk_block >> 16);
543862306a36Sopenharmony_ci		cdb[4] = (u8) (disk_block >> 8);
543962306a36Sopenharmony_ci		cdb[5] = (u8) (disk_block);
544062306a36Sopenharmony_ci		cdb[6] = 0;
544162306a36Sopenharmony_ci		cdb[7] = (u8) (disk_block_cnt >> 8);
544262306a36Sopenharmony_ci		cdb[8] = (u8) (disk_block_cnt);
544362306a36Sopenharmony_ci		cdb[9] = 0;
544462306a36Sopenharmony_ci		cdb_len = 10;
544562306a36Sopenharmony_ci	}
544662306a36Sopenharmony_ci	return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len,
544762306a36Sopenharmony_ci						dev->scsi3addr,
544862306a36Sopenharmony_ci						dev->phys_disk[map_index]);
544962306a36Sopenharmony_ci}
545062306a36Sopenharmony_ci
545162306a36Sopenharmony_ci/*
545262306a36Sopenharmony_ci * Submit commands down the "normal" RAID stack path
545362306a36Sopenharmony_ci * All callers to hpsa_ciss_submit must check lockup_detected
545462306a36Sopenharmony_ci * beforehand, before (opt.) and after calling cmd_alloc
545562306a36Sopenharmony_ci */
545662306a36Sopenharmony_cistatic int hpsa_ciss_submit(struct ctlr_info *h,
545762306a36Sopenharmony_ci	struct CommandList *c, struct scsi_cmnd *cmd,
545862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev)
545962306a36Sopenharmony_ci{
546062306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *) c;
546162306a36Sopenharmony_ci	c->cmd_type = CMD_SCSI;
546262306a36Sopenharmony_ci	c->scsi_cmd = cmd;
546362306a36Sopenharmony_ci	c->Header.ReplyQueue = 0;  /* unused in simple mode */
546462306a36Sopenharmony_ci	memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8);
546562306a36Sopenharmony_ci	c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
546662306a36Sopenharmony_ci
546762306a36Sopenharmony_ci	/* Fill in the request block... */
546862306a36Sopenharmony_ci
546962306a36Sopenharmony_ci	c->Request.Timeout = 0;
547062306a36Sopenharmony_ci	BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB));
547162306a36Sopenharmony_ci	c->Request.CDBLen = cmd->cmd_len;
547262306a36Sopenharmony_ci	memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len);
547362306a36Sopenharmony_ci	switch (cmd->sc_data_direction) {
547462306a36Sopenharmony_ci	case DMA_TO_DEVICE:
547562306a36Sopenharmony_ci		c->Request.type_attr_dir =
547662306a36Sopenharmony_ci			TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_WRITE);
547762306a36Sopenharmony_ci		break;
547862306a36Sopenharmony_ci	case DMA_FROM_DEVICE:
547962306a36Sopenharmony_ci		c->Request.type_attr_dir =
548062306a36Sopenharmony_ci			TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_READ);
548162306a36Sopenharmony_ci		break;
548262306a36Sopenharmony_ci	case DMA_NONE:
548362306a36Sopenharmony_ci		c->Request.type_attr_dir =
548462306a36Sopenharmony_ci			TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_NONE);
548562306a36Sopenharmony_ci		break;
548662306a36Sopenharmony_ci	case DMA_BIDIRECTIONAL:
548762306a36Sopenharmony_ci		/* This can happen if a buggy application does a scsi passthru
548862306a36Sopenharmony_ci		 * and sets both inlen and outlen to non-zero. ( see
548962306a36Sopenharmony_ci		 * ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
549062306a36Sopenharmony_ci		 */
549162306a36Sopenharmony_ci
549262306a36Sopenharmony_ci		c->Request.type_attr_dir =
549362306a36Sopenharmony_ci			TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_RSVD);
549462306a36Sopenharmony_ci		/* This is technically wrong, and hpsa controllers should
549562306a36Sopenharmony_ci		 * reject it with CMD_INVALID, which is the most correct
549662306a36Sopenharmony_ci		 * response, but non-fibre backends appear to let it
549762306a36Sopenharmony_ci		 * slide by, and give the same results as if this field
549862306a36Sopenharmony_ci		 * were set correctly.  Either way is acceptable for
549962306a36Sopenharmony_ci		 * our purposes here.
550062306a36Sopenharmony_ci		 */
550162306a36Sopenharmony_ci
550262306a36Sopenharmony_ci		break;
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	default:
550562306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "unknown data direction: %d\n",
550662306a36Sopenharmony_ci			cmd->sc_data_direction);
550762306a36Sopenharmony_ci		BUG();
550862306a36Sopenharmony_ci		break;
550962306a36Sopenharmony_ci	}
551062306a36Sopenharmony_ci
551162306a36Sopenharmony_ci	if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */
551262306a36Sopenharmony_ci		hpsa_cmd_resolve_and_free(h, c);
551362306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
551462306a36Sopenharmony_ci	}
551562306a36Sopenharmony_ci
551662306a36Sopenharmony_ci	if (dev->in_reset) {
551762306a36Sopenharmony_ci		hpsa_cmd_resolve_and_free(h, c);
551862306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
551962306a36Sopenharmony_ci	}
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_ci	c->device = dev;
552262306a36Sopenharmony_ci
552362306a36Sopenharmony_ci	enqueue_cmd_and_start_io(h, c);
552462306a36Sopenharmony_ci	/* the cmd'll come back via intr handler in complete_scsi_command()  */
552562306a36Sopenharmony_ci	return 0;
552662306a36Sopenharmony_ci}
552762306a36Sopenharmony_ci
552862306a36Sopenharmony_cistatic void hpsa_cmd_init(struct ctlr_info *h, int index,
552962306a36Sopenharmony_ci				struct CommandList *c)
553062306a36Sopenharmony_ci{
553162306a36Sopenharmony_ci	dma_addr_t cmd_dma_handle, err_dma_handle;
553262306a36Sopenharmony_ci
553362306a36Sopenharmony_ci	/* Zero out all of commandlist except the last field, refcount */
553462306a36Sopenharmony_ci	memset(c, 0, offsetof(struct CommandList, refcount));
553562306a36Sopenharmony_ci	c->Header.tag = cpu_to_le64((u64) (index << DIRECT_LOOKUP_SHIFT));
553662306a36Sopenharmony_ci	cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c);
553762306a36Sopenharmony_ci	c->err_info = h->errinfo_pool + index;
553862306a36Sopenharmony_ci	memset(c->err_info, 0, sizeof(*c->err_info));
553962306a36Sopenharmony_ci	err_dma_handle = h->errinfo_pool_dhandle
554062306a36Sopenharmony_ci	    + index * sizeof(*c->err_info);
554162306a36Sopenharmony_ci	c->cmdindex = index;
554262306a36Sopenharmony_ci	c->busaddr = (u32) cmd_dma_handle;
554362306a36Sopenharmony_ci	c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle);
554462306a36Sopenharmony_ci	c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info));
554562306a36Sopenharmony_ci	c->h = h;
554662306a36Sopenharmony_ci	c->scsi_cmd = SCSI_CMD_IDLE;
554762306a36Sopenharmony_ci}
554862306a36Sopenharmony_ci
554962306a36Sopenharmony_cistatic void hpsa_preinitialize_commands(struct ctlr_info *h)
555062306a36Sopenharmony_ci{
555162306a36Sopenharmony_ci	int i;
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
555462306a36Sopenharmony_ci		struct CommandList *c = h->cmd_pool + i;
555562306a36Sopenharmony_ci
555662306a36Sopenharmony_ci		hpsa_cmd_init(h, i, c);
555762306a36Sopenharmony_ci		atomic_set(&c->refcount, 0);
555862306a36Sopenharmony_ci	}
555962306a36Sopenharmony_ci}
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_cistatic inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index,
556262306a36Sopenharmony_ci				struct CommandList *c)
556362306a36Sopenharmony_ci{
556462306a36Sopenharmony_ci	dma_addr_t cmd_dma_handle = h->cmd_pool_dhandle + index * sizeof(*c);
556562306a36Sopenharmony_ci
556662306a36Sopenharmony_ci	BUG_ON(c->cmdindex != index);
556762306a36Sopenharmony_ci
556862306a36Sopenharmony_ci	memset(c->Request.CDB, 0, sizeof(c->Request.CDB));
556962306a36Sopenharmony_ci	memset(c->err_info, 0, sizeof(*c->err_info));
557062306a36Sopenharmony_ci	c->busaddr = (u32) cmd_dma_handle;
557162306a36Sopenharmony_ci}
557262306a36Sopenharmony_ci
557362306a36Sopenharmony_cistatic int hpsa_ioaccel_submit(struct ctlr_info *h,
557462306a36Sopenharmony_ci		struct CommandList *c, struct scsi_cmnd *cmd,
557562306a36Sopenharmony_ci		bool retry)
557662306a36Sopenharmony_ci{
557762306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
557862306a36Sopenharmony_ci	int rc = IO_ACCEL_INELIGIBLE;
557962306a36Sopenharmony_ci
558062306a36Sopenharmony_ci	if (!dev)
558162306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	if (dev->in_reset)
558462306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
558562306a36Sopenharmony_ci
558662306a36Sopenharmony_ci	if (hpsa_simple_mode)
558762306a36Sopenharmony_ci		return IO_ACCEL_INELIGIBLE;
558862306a36Sopenharmony_ci
558962306a36Sopenharmony_ci	cmd->host_scribble = (unsigned char *) c;
559062306a36Sopenharmony_ci
559162306a36Sopenharmony_ci	if (dev->offload_enabled) {
559262306a36Sopenharmony_ci		hpsa_cmd_init(h, c->cmdindex, c); /* Zeroes out all fields */
559362306a36Sopenharmony_ci		c->cmd_type = CMD_SCSI;
559462306a36Sopenharmony_ci		c->scsi_cmd = cmd;
559562306a36Sopenharmony_ci		c->device = dev;
559662306a36Sopenharmony_ci		if (retry) /* Resubmit but do not increment device->commands_outstanding. */
559762306a36Sopenharmony_ci			c->retry_pending = true;
559862306a36Sopenharmony_ci		rc = hpsa_scsi_ioaccel_raid_map(h, c);
559962306a36Sopenharmony_ci		if (rc < 0)     /* scsi_dma_map failed. */
560062306a36Sopenharmony_ci			rc = SCSI_MLQUEUE_HOST_BUSY;
560162306a36Sopenharmony_ci	} else if (dev->hba_ioaccel_enabled) {
560262306a36Sopenharmony_ci		hpsa_cmd_init(h, c->cmdindex, c); /* Zeroes out all fields */
560362306a36Sopenharmony_ci		c->cmd_type = CMD_SCSI;
560462306a36Sopenharmony_ci		c->scsi_cmd = cmd;
560562306a36Sopenharmony_ci		c->device = dev;
560662306a36Sopenharmony_ci		if (retry) /* Resubmit but do not increment device->commands_outstanding. */
560762306a36Sopenharmony_ci			c->retry_pending = true;
560862306a36Sopenharmony_ci		rc = hpsa_scsi_ioaccel_direct_map(h, c);
560962306a36Sopenharmony_ci		if (rc < 0)     /* scsi_dma_map failed. */
561062306a36Sopenharmony_ci			rc = SCSI_MLQUEUE_HOST_BUSY;
561162306a36Sopenharmony_ci	}
561262306a36Sopenharmony_ci	return rc;
561362306a36Sopenharmony_ci}
561462306a36Sopenharmony_ci
561562306a36Sopenharmony_cistatic void hpsa_command_resubmit_worker(struct work_struct *work)
561662306a36Sopenharmony_ci{
561762306a36Sopenharmony_ci	struct scsi_cmnd *cmd;
561862306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev;
561962306a36Sopenharmony_ci	struct CommandList *c = container_of(work, struct CommandList, work);
562062306a36Sopenharmony_ci
562162306a36Sopenharmony_ci	cmd = c->scsi_cmd;
562262306a36Sopenharmony_ci	dev = cmd->device->hostdata;
562362306a36Sopenharmony_ci	if (!dev) {
562462306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
562562306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(c->h, c, cmd);
562662306a36Sopenharmony_ci	}
562762306a36Sopenharmony_ci
562862306a36Sopenharmony_ci	if (dev->in_reset) {
562962306a36Sopenharmony_ci		cmd->result = DID_RESET << 16;
563062306a36Sopenharmony_ci		return hpsa_cmd_free_and_done(c->h, c, cmd);
563162306a36Sopenharmony_ci	}
563262306a36Sopenharmony_ci
563362306a36Sopenharmony_ci	if (c->cmd_type == CMD_IOACCEL2) {
563462306a36Sopenharmony_ci		struct ctlr_info *h = c->h;
563562306a36Sopenharmony_ci		struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
563662306a36Sopenharmony_ci		int rc;
563762306a36Sopenharmony_ci
563862306a36Sopenharmony_ci		if (c2->error_data.serv_response ==
563962306a36Sopenharmony_ci				IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) {
564062306a36Sopenharmony_ci			/* Resubmit with the retry_pending flag set. */
564162306a36Sopenharmony_ci			rc = hpsa_ioaccel_submit(h, c, cmd, true);
564262306a36Sopenharmony_ci			if (rc == 0)
564362306a36Sopenharmony_ci				return;
564462306a36Sopenharmony_ci			if (rc == SCSI_MLQUEUE_HOST_BUSY) {
564562306a36Sopenharmony_ci				/*
564662306a36Sopenharmony_ci				 * If we get here, it means dma mapping failed.
564762306a36Sopenharmony_ci				 * Try again via scsi mid layer, which will
564862306a36Sopenharmony_ci				 * then get SCSI_MLQUEUE_HOST_BUSY.
564962306a36Sopenharmony_ci				 */
565062306a36Sopenharmony_ci				cmd->result = DID_IMM_RETRY << 16;
565162306a36Sopenharmony_ci				return hpsa_cmd_free_and_done(h, c, cmd);
565262306a36Sopenharmony_ci			}
565362306a36Sopenharmony_ci			/* else, fall thru and resubmit down CISS path */
565462306a36Sopenharmony_ci		}
565562306a36Sopenharmony_ci	}
565662306a36Sopenharmony_ci	hpsa_cmd_partial_init(c->h, c->cmdindex, c);
565762306a36Sopenharmony_ci	/*
565862306a36Sopenharmony_ci	 * Here we have not come in though queue_command, so we
565962306a36Sopenharmony_ci	 * can set the retry_pending flag to true for a driver initiated
566062306a36Sopenharmony_ci	 * retry attempt (I.E. not a SML retry).
566162306a36Sopenharmony_ci	 * I.E. We are submitting a driver initiated retry.
566262306a36Sopenharmony_ci	 * Note: hpsa_ciss_submit does not zero out the command fields like
566362306a36Sopenharmony_ci	 *       ioaccel submit does.
566462306a36Sopenharmony_ci	 */
566562306a36Sopenharmony_ci	c->retry_pending = true;
566662306a36Sopenharmony_ci	if (hpsa_ciss_submit(c->h, c, cmd, dev)) {
566762306a36Sopenharmony_ci		/*
566862306a36Sopenharmony_ci		 * If we get here, it means dma mapping failed. Try
566962306a36Sopenharmony_ci		 * again via scsi mid layer, which will then get
567062306a36Sopenharmony_ci		 * SCSI_MLQUEUE_HOST_BUSY.
567162306a36Sopenharmony_ci		 *
567262306a36Sopenharmony_ci		 * hpsa_ciss_submit will have already freed c
567362306a36Sopenharmony_ci		 * if it encountered a dma mapping failure.
567462306a36Sopenharmony_ci		 */
567562306a36Sopenharmony_ci		cmd->result = DID_IMM_RETRY << 16;
567662306a36Sopenharmony_ci		scsi_done(cmd);
567762306a36Sopenharmony_ci	}
567862306a36Sopenharmony_ci}
567962306a36Sopenharmony_ci
568062306a36Sopenharmony_ci/* Running in struct Scsi_Host->host_lock less mode */
568162306a36Sopenharmony_cistatic int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
568262306a36Sopenharmony_ci{
568362306a36Sopenharmony_ci	struct ctlr_info *h;
568462306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev;
568562306a36Sopenharmony_ci	struct CommandList *c;
568662306a36Sopenharmony_ci	int rc = 0;
568762306a36Sopenharmony_ci
568862306a36Sopenharmony_ci	/* Get the ptr to our adapter structure out of cmd->host. */
568962306a36Sopenharmony_ci	h = sdev_to_hba(cmd->device);
569062306a36Sopenharmony_ci
569162306a36Sopenharmony_ci	BUG_ON(scsi_cmd_to_rq(cmd)->tag < 0);
569262306a36Sopenharmony_ci
569362306a36Sopenharmony_ci	dev = cmd->device->hostdata;
569462306a36Sopenharmony_ci	if (!dev) {
569562306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
569662306a36Sopenharmony_ci		scsi_done(cmd);
569762306a36Sopenharmony_ci		return 0;
569862306a36Sopenharmony_ci	}
569962306a36Sopenharmony_ci
570062306a36Sopenharmony_ci	if (dev->removed) {
570162306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
570262306a36Sopenharmony_ci		scsi_done(cmd);
570362306a36Sopenharmony_ci		return 0;
570462306a36Sopenharmony_ci	}
570562306a36Sopenharmony_ci
570662306a36Sopenharmony_ci	if (unlikely(lockup_detected(h))) {
570762306a36Sopenharmony_ci		cmd->result = DID_NO_CONNECT << 16;
570862306a36Sopenharmony_ci		scsi_done(cmd);
570962306a36Sopenharmony_ci		return 0;
571062306a36Sopenharmony_ci	}
571162306a36Sopenharmony_ci
571262306a36Sopenharmony_ci	if (dev->in_reset)
571362306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
571462306a36Sopenharmony_ci
571562306a36Sopenharmony_ci	c = cmd_tagged_alloc(h, cmd);
571662306a36Sopenharmony_ci	if (c == NULL)
571762306a36Sopenharmony_ci		return SCSI_MLQUEUE_DEVICE_BUSY;
571862306a36Sopenharmony_ci
571962306a36Sopenharmony_ci	/*
572062306a36Sopenharmony_ci	 * This is necessary because the SML doesn't zero out this field during
572162306a36Sopenharmony_ci	 * error recovery.
572262306a36Sopenharmony_ci	 */
572362306a36Sopenharmony_ci	cmd->result = 0;
572462306a36Sopenharmony_ci
572562306a36Sopenharmony_ci	/*
572662306a36Sopenharmony_ci	 * Call alternate submit routine for I/O accelerated commands.
572762306a36Sopenharmony_ci	 * Retries always go down the normal I/O path.
572862306a36Sopenharmony_ci	 * Note: If cmd->retries is non-zero, then this is a SML
572962306a36Sopenharmony_ci	 *       initiated retry and not a driver initiated retry.
573062306a36Sopenharmony_ci	 *       This command has been obtained from cmd_tagged_alloc
573162306a36Sopenharmony_ci	 *       and is therefore a brand-new command.
573262306a36Sopenharmony_ci	 */
573362306a36Sopenharmony_ci	if (likely(cmd->retries == 0 &&
573462306a36Sopenharmony_ci			!blk_rq_is_passthrough(scsi_cmd_to_rq(cmd)) &&
573562306a36Sopenharmony_ci			h->acciopath_status)) {
573662306a36Sopenharmony_ci		/* Submit with the retry_pending flag unset. */
573762306a36Sopenharmony_ci		rc = hpsa_ioaccel_submit(h, c, cmd, false);
573862306a36Sopenharmony_ci		if (rc == 0)
573962306a36Sopenharmony_ci			return 0;
574062306a36Sopenharmony_ci		if (rc == SCSI_MLQUEUE_HOST_BUSY) {
574162306a36Sopenharmony_ci			hpsa_cmd_resolve_and_free(h, c);
574262306a36Sopenharmony_ci			return SCSI_MLQUEUE_HOST_BUSY;
574362306a36Sopenharmony_ci		}
574462306a36Sopenharmony_ci	}
574562306a36Sopenharmony_ci	return hpsa_ciss_submit(h, c, cmd, dev);
574662306a36Sopenharmony_ci}
574762306a36Sopenharmony_ci
574862306a36Sopenharmony_cistatic void hpsa_scan_complete(struct ctlr_info *h)
574962306a36Sopenharmony_ci{
575062306a36Sopenharmony_ci	unsigned long flags;
575162306a36Sopenharmony_ci
575262306a36Sopenharmony_ci	spin_lock_irqsave(&h->scan_lock, flags);
575362306a36Sopenharmony_ci	h->scan_finished = 1;
575462306a36Sopenharmony_ci	wake_up(&h->scan_wait_queue);
575562306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->scan_lock, flags);
575662306a36Sopenharmony_ci}
575762306a36Sopenharmony_ci
575862306a36Sopenharmony_cistatic void hpsa_scan_start(struct Scsi_Host *sh)
575962306a36Sopenharmony_ci{
576062306a36Sopenharmony_ci	struct ctlr_info *h = shost_to_hba(sh);
576162306a36Sopenharmony_ci	unsigned long flags;
576262306a36Sopenharmony_ci
576362306a36Sopenharmony_ci	/*
576462306a36Sopenharmony_ci	 * Don't let rescans be initiated on a controller known to be locked
576562306a36Sopenharmony_ci	 * up.  If the controller locks up *during* a rescan, that thread is
576662306a36Sopenharmony_ci	 * probably hosed, but at least we can prevent new rescan threads from
576762306a36Sopenharmony_ci	 * piling up on a locked up controller.
576862306a36Sopenharmony_ci	 */
576962306a36Sopenharmony_ci	if (unlikely(lockup_detected(h)))
577062306a36Sopenharmony_ci		return hpsa_scan_complete(h);
577162306a36Sopenharmony_ci
577262306a36Sopenharmony_ci	/*
577362306a36Sopenharmony_ci	 * If a scan is already waiting to run, no need to add another
577462306a36Sopenharmony_ci	 */
577562306a36Sopenharmony_ci	spin_lock_irqsave(&h->scan_lock, flags);
577662306a36Sopenharmony_ci	if (h->scan_waiting) {
577762306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->scan_lock, flags);
577862306a36Sopenharmony_ci		return;
577962306a36Sopenharmony_ci	}
578062306a36Sopenharmony_ci
578162306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->scan_lock, flags);
578262306a36Sopenharmony_ci
578362306a36Sopenharmony_ci	/* wait until any scan already in progress is finished. */
578462306a36Sopenharmony_ci	while (1) {
578562306a36Sopenharmony_ci		spin_lock_irqsave(&h->scan_lock, flags);
578662306a36Sopenharmony_ci		if (h->scan_finished)
578762306a36Sopenharmony_ci			break;
578862306a36Sopenharmony_ci		h->scan_waiting = 1;
578962306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->scan_lock, flags);
579062306a36Sopenharmony_ci		wait_event(h->scan_wait_queue, h->scan_finished);
579162306a36Sopenharmony_ci		/* Note: We don't need to worry about a race between this
579262306a36Sopenharmony_ci		 * thread and driver unload because the midlayer will
579362306a36Sopenharmony_ci		 * have incremented the reference count, so unload won't
579462306a36Sopenharmony_ci		 * happen if we're in here.
579562306a36Sopenharmony_ci		 */
579662306a36Sopenharmony_ci	}
579762306a36Sopenharmony_ci	h->scan_finished = 0; /* mark scan as in progress */
579862306a36Sopenharmony_ci	h->scan_waiting = 0;
579962306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->scan_lock, flags);
580062306a36Sopenharmony_ci
580162306a36Sopenharmony_ci	if (unlikely(lockup_detected(h)))
580262306a36Sopenharmony_ci		return hpsa_scan_complete(h);
580362306a36Sopenharmony_ci
580462306a36Sopenharmony_ci	/*
580562306a36Sopenharmony_ci	 * Do the scan after a reset completion
580662306a36Sopenharmony_ci	 */
580762306a36Sopenharmony_ci	spin_lock_irqsave(&h->reset_lock, flags);
580862306a36Sopenharmony_ci	if (h->reset_in_progress) {
580962306a36Sopenharmony_ci		h->drv_req_rescan = 1;
581062306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->reset_lock, flags);
581162306a36Sopenharmony_ci		hpsa_scan_complete(h);
581262306a36Sopenharmony_ci		return;
581362306a36Sopenharmony_ci	}
581462306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->reset_lock, flags);
581562306a36Sopenharmony_ci
581662306a36Sopenharmony_ci	hpsa_update_scsi_devices(h);
581762306a36Sopenharmony_ci
581862306a36Sopenharmony_ci	hpsa_scan_complete(h);
581962306a36Sopenharmony_ci}
582062306a36Sopenharmony_ci
582162306a36Sopenharmony_cistatic int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth)
582262306a36Sopenharmony_ci{
582362306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *logical_drive = sdev->hostdata;
582462306a36Sopenharmony_ci
582562306a36Sopenharmony_ci	if (!logical_drive)
582662306a36Sopenharmony_ci		return -ENODEV;
582762306a36Sopenharmony_ci
582862306a36Sopenharmony_ci	if (qdepth < 1)
582962306a36Sopenharmony_ci		qdepth = 1;
583062306a36Sopenharmony_ci	else if (qdepth > logical_drive->queue_depth)
583162306a36Sopenharmony_ci		qdepth = logical_drive->queue_depth;
583262306a36Sopenharmony_ci
583362306a36Sopenharmony_ci	return scsi_change_queue_depth(sdev, qdepth);
583462306a36Sopenharmony_ci}
583562306a36Sopenharmony_ci
583662306a36Sopenharmony_cistatic int hpsa_scan_finished(struct Scsi_Host *sh,
583762306a36Sopenharmony_ci	unsigned long elapsed_time)
583862306a36Sopenharmony_ci{
583962306a36Sopenharmony_ci	struct ctlr_info *h = shost_to_hba(sh);
584062306a36Sopenharmony_ci	unsigned long flags;
584162306a36Sopenharmony_ci	int finished;
584262306a36Sopenharmony_ci
584362306a36Sopenharmony_ci	spin_lock_irqsave(&h->scan_lock, flags);
584462306a36Sopenharmony_ci	finished = h->scan_finished;
584562306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->scan_lock, flags);
584662306a36Sopenharmony_ci	return finished;
584762306a36Sopenharmony_ci}
584862306a36Sopenharmony_ci
584962306a36Sopenharmony_cistatic int hpsa_scsi_host_alloc(struct ctlr_info *h)
585062306a36Sopenharmony_ci{
585162306a36Sopenharmony_ci	struct Scsi_Host *sh;
585262306a36Sopenharmony_ci
585362306a36Sopenharmony_ci	sh = scsi_host_alloc(&hpsa_driver_template, sizeof(struct ctlr_info));
585462306a36Sopenharmony_ci	if (sh == NULL) {
585562306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "scsi_host_alloc failed\n");
585662306a36Sopenharmony_ci		return -ENOMEM;
585762306a36Sopenharmony_ci	}
585862306a36Sopenharmony_ci
585962306a36Sopenharmony_ci	sh->io_port = 0;
586062306a36Sopenharmony_ci	sh->n_io_port = 0;
586162306a36Sopenharmony_ci	sh->this_id = -1;
586262306a36Sopenharmony_ci	sh->max_channel = 3;
586362306a36Sopenharmony_ci	sh->max_cmd_len = MAX_COMMAND_SIZE;
586462306a36Sopenharmony_ci	sh->max_lun = HPSA_MAX_LUN;
586562306a36Sopenharmony_ci	sh->max_id = HPSA_MAX_LUN;
586662306a36Sopenharmony_ci	sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS;
586762306a36Sopenharmony_ci	sh->cmd_per_lun = sh->can_queue;
586862306a36Sopenharmony_ci	sh->sg_tablesize = h->maxsgentries;
586962306a36Sopenharmony_ci	sh->transportt = hpsa_sas_transport_template;
587062306a36Sopenharmony_ci	sh->hostdata[0] = (unsigned long) h;
587162306a36Sopenharmony_ci	sh->irq = pci_irq_vector(h->pdev, 0);
587262306a36Sopenharmony_ci	sh->unique_id = sh->irq;
587362306a36Sopenharmony_ci
587462306a36Sopenharmony_ci	h->scsi_host = sh;
587562306a36Sopenharmony_ci	return 0;
587662306a36Sopenharmony_ci}
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_cistatic int hpsa_scsi_add_host(struct ctlr_info *h)
587962306a36Sopenharmony_ci{
588062306a36Sopenharmony_ci	int rv;
588162306a36Sopenharmony_ci
588262306a36Sopenharmony_ci	rv = scsi_add_host(h->scsi_host, &h->pdev->dev);
588362306a36Sopenharmony_ci	if (rv) {
588462306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "scsi_add_host failed\n");
588562306a36Sopenharmony_ci		return rv;
588662306a36Sopenharmony_ci	}
588762306a36Sopenharmony_ci	scsi_scan_host(h->scsi_host);
588862306a36Sopenharmony_ci	return 0;
588962306a36Sopenharmony_ci}
589062306a36Sopenharmony_ci
589162306a36Sopenharmony_ci/*
589262306a36Sopenharmony_ci * The block layer has already gone to the trouble of picking out a unique,
589362306a36Sopenharmony_ci * small-integer tag for this request.  We use an offset from that value as
589462306a36Sopenharmony_ci * an index to select our command block.  (The offset allows us to reserve the
589562306a36Sopenharmony_ci * low-numbered entries for our own uses.)
589662306a36Sopenharmony_ci */
589762306a36Sopenharmony_cistatic int hpsa_get_cmd_index(struct scsi_cmnd *scmd)
589862306a36Sopenharmony_ci{
589962306a36Sopenharmony_ci	int idx = scsi_cmd_to_rq(scmd)->tag;
590062306a36Sopenharmony_ci
590162306a36Sopenharmony_ci	if (idx < 0)
590262306a36Sopenharmony_ci		return idx;
590362306a36Sopenharmony_ci
590462306a36Sopenharmony_ci	/* Offset to leave space for internal cmds. */
590562306a36Sopenharmony_ci	return idx += HPSA_NRESERVED_CMDS;
590662306a36Sopenharmony_ci}
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci/*
590962306a36Sopenharmony_ci * Send a TEST_UNIT_READY command to the specified LUN using the specified
591062306a36Sopenharmony_ci * reply queue; returns zero if the unit is ready, and non-zero otherwise.
591162306a36Sopenharmony_ci */
591262306a36Sopenharmony_cistatic int hpsa_send_test_unit_ready(struct ctlr_info *h,
591362306a36Sopenharmony_ci				struct CommandList *c, unsigned char lunaddr[],
591462306a36Sopenharmony_ci				int reply_queue)
591562306a36Sopenharmony_ci{
591662306a36Sopenharmony_ci	int rc;
591762306a36Sopenharmony_ci
591862306a36Sopenharmony_ci	/* Send the Test Unit Ready, fill_cmd can't fail, no mapping */
591962306a36Sopenharmony_ci	(void) fill_cmd(c, TEST_UNIT_READY, h,
592062306a36Sopenharmony_ci			NULL, 0, 0, lunaddr, TYPE_CMD);
592162306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
592262306a36Sopenharmony_ci	if (rc)
592362306a36Sopenharmony_ci		return rc;
592462306a36Sopenharmony_ci	/* no unmap needed here because no data xfer. */
592562306a36Sopenharmony_ci
592662306a36Sopenharmony_ci	/* Check if the unit is already ready. */
592762306a36Sopenharmony_ci	if (c->err_info->CommandStatus == CMD_SUCCESS)
592862306a36Sopenharmony_ci		return 0;
592962306a36Sopenharmony_ci
593062306a36Sopenharmony_ci	/*
593162306a36Sopenharmony_ci	 * The first command sent after reset will receive "unit attention" to
593262306a36Sopenharmony_ci	 * indicate that the LUN has been reset...this is actually what we're
593362306a36Sopenharmony_ci	 * looking for (but, success is good too).
593462306a36Sopenharmony_ci	 */
593562306a36Sopenharmony_ci	if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
593662306a36Sopenharmony_ci		c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION &&
593762306a36Sopenharmony_ci			(c->err_info->SenseInfo[2] == NO_SENSE ||
593862306a36Sopenharmony_ci			 c->err_info->SenseInfo[2] == UNIT_ATTENTION))
593962306a36Sopenharmony_ci		return 0;
594062306a36Sopenharmony_ci
594162306a36Sopenharmony_ci	return 1;
594262306a36Sopenharmony_ci}
594362306a36Sopenharmony_ci
594462306a36Sopenharmony_ci/*
594562306a36Sopenharmony_ci * Wait for a TEST_UNIT_READY command to complete, retrying as necessary;
594662306a36Sopenharmony_ci * returns zero when the unit is ready, and non-zero when giving up.
594762306a36Sopenharmony_ci */
594862306a36Sopenharmony_cistatic int hpsa_wait_for_test_unit_ready(struct ctlr_info *h,
594962306a36Sopenharmony_ci				struct CommandList *c,
595062306a36Sopenharmony_ci				unsigned char lunaddr[], int reply_queue)
595162306a36Sopenharmony_ci{
595262306a36Sopenharmony_ci	int rc;
595362306a36Sopenharmony_ci	int count = 0;
595462306a36Sopenharmony_ci	int waittime = 1; /* seconds */
595562306a36Sopenharmony_ci
595662306a36Sopenharmony_ci	/* Send test unit ready until device ready, or give up. */
595762306a36Sopenharmony_ci	for (count = 0; count < HPSA_TUR_RETRY_LIMIT; count++) {
595862306a36Sopenharmony_ci
595962306a36Sopenharmony_ci		/*
596062306a36Sopenharmony_ci		 * Wait for a bit.  do this first, because if we send
596162306a36Sopenharmony_ci		 * the TUR right away, the reset will just abort it.
596262306a36Sopenharmony_ci		 */
596362306a36Sopenharmony_ci		msleep(1000 * waittime);
596462306a36Sopenharmony_ci
596562306a36Sopenharmony_ci		rc = hpsa_send_test_unit_ready(h, c, lunaddr, reply_queue);
596662306a36Sopenharmony_ci		if (!rc)
596762306a36Sopenharmony_ci			break;
596862306a36Sopenharmony_ci
596962306a36Sopenharmony_ci		/* Increase wait time with each try, up to a point. */
597062306a36Sopenharmony_ci		if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
597162306a36Sopenharmony_ci			waittime *= 2;
597262306a36Sopenharmony_ci
597362306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
597462306a36Sopenharmony_ci			 "waiting %d secs for device to become ready.\n",
597562306a36Sopenharmony_ci			 waittime);
597662306a36Sopenharmony_ci	}
597762306a36Sopenharmony_ci
597862306a36Sopenharmony_ci	return rc;
597962306a36Sopenharmony_ci}
598062306a36Sopenharmony_ci
598162306a36Sopenharmony_cistatic int wait_for_device_to_become_ready(struct ctlr_info *h,
598262306a36Sopenharmony_ci					   unsigned char lunaddr[],
598362306a36Sopenharmony_ci					   int reply_queue)
598462306a36Sopenharmony_ci{
598562306a36Sopenharmony_ci	int first_queue;
598662306a36Sopenharmony_ci	int last_queue;
598762306a36Sopenharmony_ci	int rq;
598862306a36Sopenharmony_ci	int rc = 0;
598962306a36Sopenharmony_ci	struct CommandList *c;
599062306a36Sopenharmony_ci
599162306a36Sopenharmony_ci	c = cmd_alloc(h);
599262306a36Sopenharmony_ci
599362306a36Sopenharmony_ci	/*
599462306a36Sopenharmony_ci	 * If no specific reply queue was requested, then send the TUR
599562306a36Sopenharmony_ci	 * repeatedly, requesting a reply on each reply queue; otherwise execute
599662306a36Sopenharmony_ci	 * the loop exactly once using only the specified queue.
599762306a36Sopenharmony_ci	 */
599862306a36Sopenharmony_ci	if (reply_queue == DEFAULT_REPLY_QUEUE) {
599962306a36Sopenharmony_ci		first_queue = 0;
600062306a36Sopenharmony_ci		last_queue = h->nreply_queues - 1;
600162306a36Sopenharmony_ci	} else {
600262306a36Sopenharmony_ci		first_queue = reply_queue;
600362306a36Sopenharmony_ci		last_queue = reply_queue;
600462306a36Sopenharmony_ci	}
600562306a36Sopenharmony_ci
600662306a36Sopenharmony_ci	for (rq = first_queue; rq <= last_queue; rq++) {
600762306a36Sopenharmony_ci		rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, rq);
600862306a36Sopenharmony_ci		if (rc)
600962306a36Sopenharmony_ci			break;
601062306a36Sopenharmony_ci	}
601162306a36Sopenharmony_ci
601262306a36Sopenharmony_ci	if (rc)
601362306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "giving up on device.\n");
601462306a36Sopenharmony_ci	else
601562306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "device is ready.\n");
601662306a36Sopenharmony_ci
601762306a36Sopenharmony_ci	cmd_free(h, c);
601862306a36Sopenharmony_ci	return rc;
601962306a36Sopenharmony_ci}
602062306a36Sopenharmony_ci
602162306a36Sopenharmony_ci/* Need at least one of these error handlers to keep ../scsi/hosts.c from
602262306a36Sopenharmony_ci * complaining.  Doing a host- or bus-reset can't do anything good here.
602362306a36Sopenharmony_ci */
602462306a36Sopenharmony_cistatic int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
602562306a36Sopenharmony_ci{
602662306a36Sopenharmony_ci	int rc = SUCCESS;
602762306a36Sopenharmony_ci	int i;
602862306a36Sopenharmony_ci	struct ctlr_info *h;
602962306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *dev = NULL;
603062306a36Sopenharmony_ci	u8 reset_type;
603162306a36Sopenharmony_ci	char msg[48];
603262306a36Sopenharmony_ci	unsigned long flags;
603362306a36Sopenharmony_ci
603462306a36Sopenharmony_ci	/* find the controller to which the command to be aborted was sent */
603562306a36Sopenharmony_ci	h = sdev_to_hba(scsicmd->device);
603662306a36Sopenharmony_ci	if (h == NULL) /* paranoia */
603762306a36Sopenharmony_ci		return FAILED;
603862306a36Sopenharmony_ci
603962306a36Sopenharmony_ci	spin_lock_irqsave(&h->reset_lock, flags);
604062306a36Sopenharmony_ci	h->reset_in_progress = 1;
604162306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->reset_lock, flags);
604262306a36Sopenharmony_ci
604362306a36Sopenharmony_ci	if (lockup_detected(h)) {
604462306a36Sopenharmony_ci		rc = FAILED;
604562306a36Sopenharmony_ci		goto return_reset_status;
604662306a36Sopenharmony_ci	}
604762306a36Sopenharmony_ci
604862306a36Sopenharmony_ci	dev = scsicmd->device->hostdata;
604962306a36Sopenharmony_ci	if (!dev) {
605062306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "%s: device lookup failed\n", __func__);
605162306a36Sopenharmony_ci		rc = FAILED;
605262306a36Sopenharmony_ci		goto return_reset_status;
605362306a36Sopenharmony_ci	}
605462306a36Sopenharmony_ci
605562306a36Sopenharmony_ci	if (dev->devtype == TYPE_ENCLOSURE) {
605662306a36Sopenharmony_ci		rc = SUCCESS;
605762306a36Sopenharmony_ci		goto return_reset_status;
605862306a36Sopenharmony_ci	}
605962306a36Sopenharmony_ci
606062306a36Sopenharmony_ci	/* if controller locked up, we can guarantee command won't complete */
606162306a36Sopenharmony_ci	if (lockup_detected(h)) {
606262306a36Sopenharmony_ci		snprintf(msg, sizeof(msg),
606362306a36Sopenharmony_ci			 "cmd %d RESET FAILED, lockup detected",
606462306a36Sopenharmony_ci			 hpsa_get_cmd_index(scsicmd));
606562306a36Sopenharmony_ci		hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
606662306a36Sopenharmony_ci		rc = FAILED;
606762306a36Sopenharmony_ci		goto return_reset_status;
606862306a36Sopenharmony_ci	}
606962306a36Sopenharmony_ci
607062306a36Sopenharmony_ci	/* this reset request might be the result of a lockup; check */
607162306a36Sopenharmony_ci	if (detect_controller_lockup(h)) {
607262306a36Sopenharmony_ci		snprintf(msg, sizeof(msg),
607362306a36Sopenharmony_ci			 "cmd %d RESET FAILED, new lockup detected",
607462306a36Sopenharmony_ci			 hpsa_get_cmd_index(scsicmd));
607562306a36Sopenharmony_ci		hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
607662306a36Sopenharmony_ci		rc = FAILED;
607762306a36Sopenharmony_ci		goto return_reset_status;
607862306a36Sopenharmony_ci	}
607962306a36Sopenharmony_ci
608062306a36Sopenharmony_ci	/* Do not attempt on controller */
608162306a36Sopenharmony_ci	if (is_hba_lunid(dev->scsi3addr)) {
608262306a36Sopenharmony_ci		rc = SUCCESS;
608362306a36Sopenharmony_ci		goto return_reset_status;
608462306a36Sopenharmony_ci	}
608562306a36Sopenharmony_ci
608662306a36Sopenharmony_ci	if (is_logical_dev_addr_mode(dev->scsi3addr))
608762306a36Sopenharmony_ci		reset_type = HPSA_DEVICE_RESET_MSG;
608862306a36Sopenharmony_ci	else
608962306a36Sopenharmony_ci		reset_type = HPSA_PHYS_TARGET_RESET;
609062306a36Sopenharmony_ci
609162306a36Sopenharmony_ci	sprintf(msg, "resetting %s",
609262306a36Sopenharmony_ci		reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
609362306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
609462306a36Sopenharmony_ci
609562306a36Sopenharmony_ci	/*
609662306a36Sopenharmony_ci	 * wait to see if any commands will complete before sending reset
609762306a36Sopenharmony_ci	 */
609862306a36Sopenharmony_ci	dev->in_reset = true; /* block any new cmds from OS for this device */
609962306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
610062306a36Sopenharmony_ci		if (atomic_read(&dev->commands_outstanding) > 0)
610162306a36Sopenharmony_ci			msleep(1000);
610262306a36Sopenharmony_ci		else
610362306a36Sopenharmony_ci			break;
610462306a36Sopenharmony_ci	}
610562306a36Sopenharmony_ci
610662306a36Sopenharmony_ci	/* send a reset to the SCSI LUN which the command was sent to */
610762306a36Sopenharmony_ci	rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE);
610862306a36Sopenharmony_ci	if (rc == 0)
610962306a36Sopenharmony_ci		rc = SUCCESS;
611062306a36Sopenharmony_ci	else
611162306a36Sopenharmony_ci		rc = FAILED;
611262306a36Sopenharmony_ci
611362306a36Sopenharmony_ci	sprintf(msg, "reset %s %s",
611462306a36Sopenharmony_ci		reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ",
611562306a36Sopenharmony_ci		rc == SUCCESS ? "completed successfully" : "failed");
611662306a36Sopenharmony_ci	hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
611762306a36Sopenharmony_ci
611862306a36Sopenharmony_cireturn_reset_status:
611962306a36Sopenharmony_ci	spin_lock_irqsave(&h->reset_lock, flags);
612062306a36Sopenharmony_ci	h->reset_in_progress = 0;
612162306a36Sopenharmony_ci	if (dev)
612262306a36Sopenharmony_ci		dev->in_reset = false;
612362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->reset_lock, flags);
612462306a36Sopenharmony_ci	return rc;
612562306a36Sopenharmony_ci}
612662306a36Sopenharmony_ci
612762306a36Sopenharmony_ci/*
612862306a36Sopenharmony_ci * For operations with an associated SCSI command, a command block is allocated
612962306a36Sopenharmony_ci * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the
613062306a36Sopenharmony_ci * block request tag as an index into a table of entries.  cmd_tagged_free() is
613162306a36Sopenharmony_ci * the complement, although cmd_free() may be called instead.
613262306a36Sopenharmony_ci * This function is only called for new requests from queue_command.
613362306a36Sopenharmony_ci */
613462306a36Sopenharmony_cistatic struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
613562306a36Sopenharmony_ci					    struct scsi_cmnd *scmd)
613662306a36Sopenharmony_ci{
613762306a36Sopenharmony_ci	int idx = hpsa_get_cmd_index(scmd);
613862306a36Sopenharmony_ci	struct CommandList *c = h->cmd_pool + idx;
613962306a36Sopenharmony_ci
614062306a36Sopenharmony_ci	if (idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds) {
614162306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "Bad block tag: %d not in [%d..%d]\n",
614262306a36Sopenharmony_ci			idx, HPSA_NRESERVED_CMDS, h->nr_cmds - 1);
614362306a36Sopenharmony_ci		/* The index value comes from the block layer, so if it's out of
614462306a36Sopenharmony_ci		 * bounds, it's probably not our bug.
614562306a36Sopenharmony_ci		 */
614662306a36Sopenharmony_ci		BUG();
614762306a36Sopenharmony_ci	}
614862306a36Sopenharmony_ci
614962306a36Sopenharmony_ci	if (unlikely(!hpsa_is_cmd_idle(c))) {
615062306a36Sopenharmony_ci		/*
615162306a36Sopenharmony_ci		 * We expect that the SCSI layer will hand us a unique tag
615262306a36Sopenharmony_ci		 * value.  Thus, there should never be a collision here between
615362306a36Sopenharmony_ci		 * two requests...because if the selected command isn't idle
615462306a36Sopenharmony_ci		 * then someone is going to be very disappointed.
615562306a36Sopenharmony_ci		 */
615662306a36Sopenharmony_ci		if (idx != h->last_collision_tag) { /* Print once per tag */
615762306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
615862306a36Sopenharmony_ci				"%s: tag collision (tag=%d)\n", __func__, idx);
615962306a36Sopenharmony_ci			if (scmd)
616062306a36Sopenharmony_ci				scsi_print_command(scmd);
616162306a36Sopenharmony_ci			h->last_collision_tag = idx;
616262306a36Sopenharmony_ci		}
616362306a36Sopenharmony_ci		return NULL;
616462306a36Sopenharmony_ci	}
616562306a36Sopenharmony_ci
616662306a36Sopenharmony_ci	atomic_inc(&c->refcount);
616762306a36Sopenharmony_ci	hpsa_cmd_partial_init(h, idx, c);
616862306a36Sopenharmony_ci
616962306a36Sopenharmony_ci	/*
617062306a36Sopenharmony_ci	 * This is a new command obtained from queue_command so
617162306a36Sopenharmony_ci	 * there have not been any driver initiated retry attempts.
617262306a36Sopenharmony_ci	 */
617362306a36Sopenharmony_ci	c->retry_pending = false;
617462306a36Sopenharmony_ci
617562306a36Sopenharmony_ci	return c;
617662306a36Sopenharmony_ci}
617762306a36Sopenharmony_ci
617862306a36Sopenharmony_cistatic void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c)
617962306a36Sopenharmony_ci{
618062306a36Sopenharmony_ci	/*
618162306a36Sopenharmony_ci	 * Release our reference to the block.  We don't need to do anything
618262306a36Sopenharmony_ci	 * else to free it, because it is accessed by index.
618362306a36Sopenharmony_ci	 */
618462306a36Sopenharmony_ci	(void)atomic_dec(&c->refcount);
618562306a36Sopenharmony_ci}
618662306a36Sopenharmony_ci
618762306a36Sopenharmony_ci/*
618862306a36Sopenharmony_ci * For operations that cannot sleep, a command block is allocated at init,
618962306a36Sopenharmony_ci * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
619062306a36Sopenharmony_ci * which ones are free or in use.  Lock must be held when calling this.
619162306a36Sopenharmony_ci * cmd_free() is the complement.
619262306a36Sopenharmony_ci * This function never gives up and returns NULL.  If it hangs,
619362306a36Sopenharmony_ci * another thread must call cmd_free() to free some tags.
619462306a36Sopenharmony_ci */
619562306a36Sopenharmony_ci
619662306a36Sopenharmony_cistatic struct CommandList *cmd_alloc(struct ctlr_info *h)
619762306a36Sopenharmony_ci{
619862306a36Sopenharmony_ci	struct CommandList *c;
619962306a36Sopenharmony_ci	int refcount, i;
620062306a36Sopenharmony_ci	int offset = 0;
620162306a36Sopenharmony_ci
620262306a36Sopenharmony_ci	/*
620362306a36Sopenharmony_ci	 * There is some *extremely* small but non-zero chance that that
620462306a36Sopenharmony_ci	 * multiple threads could get in here, and one thread could
620562306a36Sopenharmony_ci	 * be scanning through the list of bits looking for a free
620662306a36Sopenharmony_ci	 * one, but the free ones are always behind him, and other
620762306a36Sopenharmony_ci	 * threads sneak in behind him and eat them before he can
620862306a36Sopenharmony_ci	 * get to them, so that while there is always a free one, a
620962306a36Sopenharmony_ci	 * very unlucky thread might be starved anyway, never able to
621062306a36Sopenharmony_ci	 * beat the other threads.  In reality, this happens so
621162306a36Sopenharmony_ci	 * infrequently as to be indistinguishable from never.
621262306a36Sopenharmony_ci	 *
621362306a36Sopenharmony_ci	 * Note that we start allocating commands before the SCSI host structure
621462306a36Sopenharmony_ci	 * is initialized.  Since the search starts at bit zero, this
621562306a36Sopenharmony_ci	 * all works, since we have at least one command structure available;
621662306a36Sopenharmony_ci	 * however, it means that the structures with the low indexes have to be
621762306a36Sopenharmony_ci	 * reserved for driver-initiated requests, while requests from the block
621862306a36Sopenharmony_ci	 * layer will use the higher indexes.
621962306a36Sopenharmony_ci	 */
622062306a36Sopenharmony_ci
622162306a36Sopenharmony_ci	for (;;) {
622262306a36Sopenharmony_ci		i = find_next_zero_bit(h->cmd_pool_bits,
622362306a36Sopenharmony_ci					HPSA_NRESERVED_CMDS,
622462306a36Sopenharmony_ci					offset);
622562306a36Sopenharmony_ci		if (unlikely(i >= HPSA_NRESERVED_CMDS)) {
622662306a36Sopenharmony_ci			offset = 0;
622762306a36Sopenharmony_ci			continue;
622862306a36Sopenharmony_ci		}
622962306a36Sopenharmony_ci		c = h->cmd_pool + i;
623062306a36Sopenharmony_ci		refcount = atomic_inc_return(&c->refcount);
623162306a36Sopenharmony_ci		if (unlikely(refcount > 1)) {
623262306a36Sopenharmony_ci			cmd_free(h, c); /* already in use */
623362306a36Sopenharmony_ci			offset = (i + 1) % HPSA_NRESERVED_CMDS;
623462306a36Sopenharmony_ci			continue;
623562306a36Sopenharmony_ci		}
623662306a36Sopenharmony_ci		set_bit(i, h->cmd_pool_bits);
623762306a36Sopenharmony_ci		break; /* it's ours now. */
623862306a36Sopenharmony_ci	}
623962306a36Sopenharmony_ci	hpsa_cmd_partial_init(h, i, c);
624062306a36Sopenharmony_ci	c->device = NULL;
624162306a36Sopenharmony_ci
624262306a36Sopenharmony_ci	/*
624362306a36Sopenharmony_ci	 * cmd_alloc is for "internal" commands and they are never
624462306a36Sopenharmony_ci	 * retried.
624562306a36Sopenharmony_ci	 */
624662306a36Sopenharmony_ci	c->retry_pending = false;
624762306a36Sopenharmony_ci
624862306a36Sopenharmony_ci	return c;
624962306a36Sopenharmony_ci}
625062306a36Sopenharmony_ci
625162306a36Sopenharmony_ci/*
625262306a36Sopenharmony_ci * This is the complementary operation to cmd_alloc().  Note, however, in some
625362306a36Sopenharmony_ci * corner cases it may also be used to free blocks allocated by
625462306a36Sopenharmony_ci * cmd_tagged_alloc() in which case the ref-count decrement does the trick and
625562306a36Sopenharmony_ci * the clear-bit is harmless.
625662306a36Sopenharmony_ci */
625762306a36Sopenharmony_cistatic void cmd_free(struct ctlr_info *h, struct CommandList *c)
625862306a36Sopenharmony_ci{
625962306a36Sopenharmony_ci	if (atomic_dec_and_test(&c->refcount)) {
626062306a36Sopenharmony_ci		int i;
626162306a36Sopenharmony_ci
626262306a36Sopenharmony_ci		i = c - h->cmd_pool;
626362306a36Sopenharmony_ci		clear_bit(i, h->cmd_pool_bits);
626462306a36Sopenharmony_ci	}
626562306a36Sopenharmony_ci}
626662306a36Sopenharmony_ci
626762306a36Sopenharmony_ci#ifdef CONFIG_COMPAT
626862306a36Sopenharmony_ci
626962306a36Sopenharmony_cistatic int hpsa_ioctl32_passthru(struct scsi_device *dev, unsigned int cmd,
627062306a36Sopenharmony_ci	void __user *arg)
627162306a36Sopenharmony_ci{
627262306a36Sopenharmony_ci	struct ctlr_info *h = sdev_to_hba(dev);
627362306a36Sopenharmony_ci	IOCTL32_Command_struct __user *arg32 = arg;
627462306a36Sopenharmony_ci	IOCTL_Command_struct arg64;
627562306a36Sopenharmony_ci	int err;
627662306a36Sopenharmony_ci	u32 cp;
627762306a36Sopenharmony_ci
627862306a36Sopenharmony_ci	if (!arg)
627962306a36Sopenharmony_ci		return -EINVAL;
628062306a36Sopenharmony_ci
628162306a36Sopenharmony_ci	memset(&arg64, 0, sizeof(arg64));
628262306a36Sopenharmony_ci	if (copy_from_user(&arg64, arg32, offsetof(IOCTL_Command_struct, buf)))
628362306a36Sopenharmony_ci		return -EFAULT;
628462306a36Sopenharmony_ci	if (get_user(cp, &arg32->buf))
628562306a36Sopenharmony_ci		return -EFAULT;
628662306a36Sopenharmony_ci	arg64.buf = compat_ptr(cp);
628762306a36Sopenharmony_ci
628862306a36Sopenharmony_ci	if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
628962306a36Sopenharmony_ci		return -EAGAIN;
629062306a36Sopenharmony_ci	err = hpsa_passthru_ioctl(h, &arg64);
629162306a36Sopenharmony_ci	atomic_inc(&h->passthru_cmds_avail);
629262306a36Sopenharmony_ci	if (err)
629362306a36Sopenharmony_ci		return err;
629462306a36Sopenharmony_ci	if (copy_to_user(&arg32->error_info, &arg64.error_info,
629562306a36Sopenharmony_ci			 sizeof(arg32->error_info)))
629662306a36Sopenharmony_ci		return -EFAULT;
629762306a36Sopenharmony_ci	return 0;
629862306a36Sopenharmony_ci}
629962306a36Sopenharmony_ci
630062306a36Sopenharmony_cistatic int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
630162306a36Sopenharmony_ci	unsigned int cmd, void __user *arg)
630262306a36Sopenharmony_ci{
630362306a36Sopenharmony_ci	struct ctlr_info *h = sdev_to_hba(dev);
630462306a36Sopenharmony_ci	BIG_IOCTL32_Command_struct __user *arg32 = arg;
630562306a36Sopenharmony_ci	BIG_IOCTL_Command_struct arg64;
630662306a36Sopenharmony_ci	int err;
630762306a36Sopenharmony_ci	u32 cp;
630862306a36Sopenharmony_ci
630962306a36Sopenharmony_ci	if (!arg)
631062306a36Sopenharmony_ci		return -EINVAL;
631162306a36Sopenharmony_ci	memset(&arg64, 0, sizeof(arg64));
631262306a36Sopenharmony_ci	if (copy_from_user(&arg64, arg32,
631362306a36Sopenharmony_ci			   offsetof(BIG_IOCTL32_Command_struct, buf)))
631462306a36Sopenharmony_ci		return -EFAULT;
631562306a36Sopenharmony_ci	if (get_user(cp, &arg32->buf))
631662306a36Sopenharmony_ci		return -EFAULT;
631762306a36Sopenharmony_ci	arg64.buf = compat_ptr(cp);
631862306a36Sopenharmony_ci
631962306a36Sopenharmony_ci	if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
632062306a36Sopenharmony_ci		return -EAGAIN;
632162306a36Sopenharmony_ci	err = hpsa_big_passthru_ioctl(h, &arg64);
632262306a36Sopenharmony_ci	atomic_inc(&h->passthru_cmds_avail);
632362306a36Sopenharmony_ci	if (err)
632462306a36Sopenharmony_ci		return err;
632562306a36Sopenharmony_ci	if (copy_to_user(&arg32->error_info, &arg64.error_info,
632662306a36Sopenharmony_ci			 sizeof(arg32->error_info)))
632762306a36Sopenharmony_ci		return -EFAULT;
632862306a36Sopenharmony_ci	return 0;
632962306a36Sopenharmony_ci}
633062306a36Sopenharmony_ci
633162306a36Sopenharmony_cistatic int hpsa_compat_ioctl(struct scsi_device *dev, unsigned int cmd,
633262306a36Sopenharmony_ci			     void __user *arg)
633362306a36Sopenharmony_ci{
633462306a36Sopenharmony_ci	switch (cmd) {
633562306a36Sopenharmony_ci	case CCISS_GETPCIINFO:
633662306a36Sopenharmony_ci	case CCISS_GETINTINFO:
633762306a36Sopenharmony_ci	case CCISS_SETINTINFO:
633862306a36Sopenharmony_ci	case CCISS_GETNODENAME:
633962306a36Sopenharmony_ci	case CCISS_SETNODENAME:
634062306a36Sopenharmony_ci	case CCISS_GETHEARTBEAT:
634162306a36Sopenharmony_ci	case CCISS_GETBUSTYPES:
634262306a36Sopenharmony_ci	case CCISS_GETFIRMVER:
634362306a36Sopenharmony_ci	case CCISS_GETDRIVVER:
634462306a36Sopenharmony_ci	case CCISS_REVALIDVOLS:
634562306a36Sopenharmony_ci	case CCISS_DEREGDISK:
634662306a36Sopenharmony_ci	case CCISS_REGNEWDISK:
634762306a36Sopenharmony_ci	case CCISS_REGNEWD:
634862306a36Sopenharmony_ci	case CCISS_RESCANDISK:
634962306a36Sopenharmony_ci	case CCISS_GETLUNINFO:
635062306a36Sopenharmony_ci		return hpsa_ioctl(dev, cmd, arg);
635162306a36Sopenharmony_ci
635262306a36Sopenharmony_ci	case CCISS_PASSTHRU32:
635362306a36Sopenharmony_ci		return hpsa_ioctl32_passthru(dev, cmd, arg);
635462306a36Sopenharmony_ci	case CCISS_BIG_PASSTHRU32:
635562306a36Sopenharmony_ci		return hpsa_ioctl32_big_passthru(dev, cmd, arg);
635662306a36Sopenharmony_ci
635762306a36Sopenharmony_ci	default:
635862306a36Sopenharmony_ci		return -ENOIOCTLCMD;
635962306a36Sopenharmony_ci	}
636062306a36Sopenharmony_ci}
636162306a36Sopenharmony_ci#endif
636262306a36Sopenharmony_ci
636362306a36Sopenharmony_cistatic int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp)
636462306a36Sopenharmony_ci{
636562306a36Sopenharmony_ci	struct hpsa_pci_info pciinfo;
636662306a36Sopenharmony_ci
636762306a36Sopenharmony_ci	if (!argp)
636862306a36Sopenharmony_ci		return -EINVAL;
636962306a36Sopenharmony_ci	pciinfo.domain = pci_domain_nr(h->pdev->bus);
637062306a36Sopenharmony_ci	pciinfo.bus = h->pdev->bus->number;
637162306a36Sopenharmony_ci	pciinfo.dev_fn = h->pdev->devfn;
637262306a36Sopenharmony_ci	pciinfo.board_id = h->board_id;
637362306a36Sopenharmony_ci	if (copy_to_user(argp, &pciinfo, sizeof(pciinfo)))
637462306a36Sopenharmony_ci		return -EFAULT;
637562306a36Sopenharmony_ci	return 0;
637662306a36Sopenharmony_ci}
637762306a36Sopenharmony_ci
637862306a36Sopenharmony_cistatic int hpsa_getdrivver_ioctl(struct ctlr_info *h, void __user *argp)
637962306a36Sopenharmony_ci{
638062306a36Sopenharmony_ci	DriverVer_type DriverVer;
638162306a36Sopenharmony_ci	unsigned char vmaj, vmin, vsubmin;
638262306a36Sopenharmony_ci	int rc;
638362306a36Sopenharmony_ci
638462306a36Sopenharmony_ci	rc = sscanf(HPSA_DRIVER_VERSION, "%hhu.%hhu.%hhu",
638562306a36Sopenharmony_ci		&vmaj, &vmin, &vsubmin);
638662306a36Sopenharmony_ci	if (rc != 3) {
638762306a36Sopenharmony_ci		dev_info(&h->pdev->dev, "driver version string '%s' "
638862306a36Sopenharmony_ci			"unrecognized.", HPSA_DRIVER_VERSION);
638962306a36Sopenharmony_ci		vmaj = 0;
639062306a36Sopenharmony_ci		vmin = 0;
639162306a36Sopenharmony_ci		vsubmin = 0;
639262306a36Sopenharmony_ci	}
639362306a36Sopenharmony_ci	DriverVer = (vmaj << 16) | (vmin << 8) | vsubmin;
639462306a36Sopenharmony_ci	if (!argp)
639562306a36Sopenharmony_ci		return -EINVAL;
639662306a36Sopenharmony_ci	if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type)))
639762306a36Sopenharmony_ci		return -EFAULT;
639862306a36Sopenharmony_ci	return 0;
639962306a36Sopenharmony_ci}
640062306a36Sopenharmony_ci
640162306a36Sopenharmony_cistatic int hpsa_passthru_ioctl(struct ctlr_info *h,
640262306a36Sopenharmony_ci			       IOCTL_Command_struct *iocommand)
640362306a36Sopenharmony_ci{
640462306a36Sopenharmony_ci	struct CommandList *c;
640562306a36Sopenharmony_ci	char *buff = NULL;
640662306a36Sopenharmony_ci	u64 temp64;
640762306a36Sopenharmony_ci	int rc = 0;
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_ci	if (!capable(CAP_SYS_RAWIO))
641062306a36Sopenharmony_ci		return -EPERM;
641162306a36Sopenharmony_ci	if ((iocommand->buf_size < 1) &&
641262306a36Sopenharmony_ci	    (iocommand->Request.Type.Direction != XFER_NONE)) {
641362306a36Sopenharmony_ci		return -EINVAL;
641462306a36Sopenharmony_ci	}
641562306a36Sopenharmony_ci	if (iocommand->buf_size > 0) {
641662306a36Sopenharmony_ci		buff = kmalloc(iocommand->buf_size, GFP_KERNEL);
641762306a36Sopenharmony_ci		if (buff == NULL)
641862306a36Sopenharmony_ci			return -ENOMEM;
641962306a36Sopenharmony_ci		if (iocommand->Request.Type.Direction & XFER_WRITE) {
642062306a36Sopenharmony_ci			/* Copy the data into the buffer we created */
642162306a36Sopenharmony_ci			if (copy_from_user(buff, iocommand->buf,
642262306a36Sopenharmony_ci				iocommand->buf_size)) {
642362306a36Sopenharmony_ci				rc = -EFAULT;
642462306a36Sopenharmony_ci				goto out_kfree;
642562306a36Sopenharmony_ci			}
642662306a36Sopenharmony_ci		} else {
642762306a36Sopenharmony_ci			memset(buff, 0, iocommand->buf_size);
642862306a36Sopenharmony_ci		}
642962306a36Sopenharmony_ci	}
643062306a36Sopenharmony_ci	c = cmd_alloc(h);
643162306a36Sopenharmony_ci
643262306a36Sopenharmony_ci	/* Fill in the command type */
643362306a36Sopenharmony_ci	c->cmd_type = CMD_IOCTL_PEND;
643462306a36Sopenharmony_ci	c->scsi_cmd = SCSI_CMD_BUSY;
643562306a36Sopenharmony_ci	/* Fill in Command Header */
643662306a36Sopenharmony_ci	c->Header.ReplyQueue = 0; /* unused in simple mode */
643762306a36Sopenharmony_ci	if (iocommand->buf_size > 0) {	/* buffer to fill */
643862306a36Sopenharmony_ci		c->Header.SGList = 1;
643962306a36Sopenharmony_ci		c->Header.SGTotal = cpu_to_le16(1);
644062306a36Sopenharmony_ci	} else	{ /* no buffers to fill */
644162306a36Sopenharmony_ci		c->Header.SGList = 0;
644262306a36Sopenharmony_ci		c->Header.SGTotal = cpu_to_le16(0);
644362306a36Sopenharmony_ci	}
644462306a36Sopenharmony_ci	memcpy(&c->Header.LUN, &iocommand->LUN_info, sizeof(c->Header.LUN));
644562306a36Sopenharmony_ci
644662306a36Sopenharmony_ci	/* Fill in Request block */
644762306a36Sopenharmony_ci	memcpy(&c->Request, &iocommand->Request,
644862306a36Sopenharmony_ci		sizeof(c->Request));
644962306a36Sopenharmony_ci
645062306a36Sopenharmony_ci	/* Fill in the scatter gather information */
645162306a36Sopenharmony_ci	if (iocommand->buf_size > 0) {
645262306a36Sopenharmony_ci		temp64 = dma_map_single(&h->pdev->dev, buff,
645362306a36Sopenharmony_ci			iocommand->buf_size, DMA_BIDIRECTIONAL);
645462306a36Sopenharmony_ci		if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
645562306a36Sopenharmony_ci			c->SG[0].Addr = cpu_to_le64(0);
645662306a36Sopenharmony_ci			c->SG[0].Len = cpu_to_le32(0);
645762306a36Sopenharmony_ci			rc = -ENOMEM;
645862306a36Sopenharmony_ci			goto out;
645962306a36Sopenharmony_ci		}
646062306a36Sopenharmony_ci		c->SG[0].Addr = cpu_to_le64(temp64);
646162306a36Sopenharmony_ci		c->SG[0].Len = cpu_to_le32(iocommand->buf_size);
646262306a36Sopenharmony_ci		c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
646362306a36Sopenharmony_ci	}
646462306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
646562306a36Sopenharmony_ci					NO_TIMEOUT);
646662306a36Sopenharmony_ci	if (iocommand->buf_size > 0)
646762306a36Sopenharmony_ci		hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL);
646862306a36Sopenharmony_ci	check_ioctl_unit_attention(h, c);
646962306a36Sopenharmony_ci	if (rc) {
647062306a36Sopenharmony_ci		rc = -EIO;
647162306a36Sopenharmony_ci		goto out;
647262306a36Sopenharmony_ci	}
647362306a36Sopenharmony_ci
647462306a36Sopenharmony_ci	/* Copy the error information out */
647562306a36Sopenharmony_ci	memcpy(&iocommand->error_info, c->err_info,
647662306a36Sopenharmony_ci		sizeof(iocommand->error_info));
647762306a36Sopenharmony_ci	if ((iocommand->Request.Type.Direction & XFER_READ) &&
647862306a36Sopenharmony_ci		iocommand->buf_size > 0) {
647962306a36Sopenharmony_ci		/* Copy the data out of the buffer we created */
648062306a36Sopenharmony_ci		if (copy_to_user(iocommand->buf, buff, iocommand->buf_size)) {
648162306a36Sopenharmony_ci			rc = -EFAULT;
648262306a36Sopenharmony_ci			goto out;
648362306a36Sopenharmony_ci		}
648462306a36Sopenharmony_ci	}
648562306a36Sopenharmony_ciout:
648662306a36Sopenharmony_ci	cmd_free(h, c);
648762306a36Sopenharmony_ciout_kfree:
648862306a36Sopenharmony_ci	kfree(buff);
648962306a36Sopenharmony_ci	return rc;
649062306a36Sopenharmony_ci}
649162306a36Sopenharmony_ci
649262306a36Sopenharmony_cistatic int hpsa_big_passthru_ioctl(struct ctlr_info *h,
649362306a36Sopenharmony_ci				   BIG_IOCTL_Command_struct *ioc)
649462306a36Sopenharmony_ci{
649562306a36Sopenharmony_ci	struct CommandList *c;
649662306a36Sopenharmony_ci	unsigned char **buff = NULL;
649762306a36Sopenharmony_ci	int *buff_size = NULL;
649862306a36Sopenharmony_ci	u64 temp64;
649962306a36Sopenharmony_ci	BYTE sg_used = 0;
650062306a36Sopenharmony_ci	int status = 0;
650162306a36Sopenharmony_ci	u32 left;
650262306a36Sopenharmony_ci	u32 sz;
650362306a36Sopenharmony_ci	BYTE __user *data_ptr;
650462306a36Sopenharmony_ci
650562306a36Sopenharmony_ci	if (!capable(CAP_SYS_RAWIO))
650662306a36Sopenharmony_ci		return -EPERM;
650762306a36Sopenharmony_ci
650862306a36Sopenharmony_ci	if ((ioc->buf_size < 1) &&
650962306a36Sopenharmony_ci	    (ioc->Request.Type.Direction != XFER_NONE))
651062306a36Sopenharmony_ci		return -EINVAL;
651162306a36Sopenharmony_ci	/* Check kmalloc limits  using all SGs */
651262306a36Sopenharmony_ci	if (ioc->malloc_size > MAX_KMALLOC_SIZE)
651362306a36Sopenharmony_ci		return -EINVAL;
651462306a36Sopenharmony_ci	if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD)
651562306a36Sopenharmony_ci		return -EINVAL;
651662306a36Sopenharmony_ci	buff = kcalloc(SG_ENTRIES_IN_CMD, sizeof(char *), GFP_KERNEL);
651762306a36Sopenharmony_ci	if (!buff) {
651862306a36Sopenharmony_ci		status = -ENOMEM;
651962306a36Sopenharmony_ci		goto cleanup1;
652062306a36Sopenharmony_ci	}
652162306a36Sopenharmony_ci	buff_size = kmalloc_array(SG_ENTRIES_IN_CMD, sizeof(int), GFP_KERNEL);
652262306a36Sopenharmony_ci	if (!buff_size) {
652362306a36Sopenharmony_ci		status = -ENOMEM;
652462306a36Sopenharmony_ci		goto cleanup1;
652562306a36Sopenharmony_ci	}
652662306a36Sopenharmony_ci	left = ioc->buf_size;
652762306a36Sopenharmony_ci	data_ptr = ioc->buf;
652862306a36Sopenharmony_ci	while (left) {
652962306a36Sopenharmony_ci		sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
653062306a36Sopenharmony_ci		buff_size[sg_used] = sz;
653162306a36Sopenharmony_ci		buff[sg_used] = kmalloc(sz, GFP_KERNEL);
653262306a36Sopenharmony_ci		if (buff[sg_used] == NULL) {
653362306a36Sopenharmony_ci			status = -ENOMEM;
653462306a36Sopenharmony_ci			goto cleanup1;
653562306a36Sopenharmony_ci		}
653662306a36Sopenharmony_ci		if (ioc->Request.Type.Direction & XFER_WRITE) {
653762306a36Sopenharmony_ci			if (copy_from_user(buff[sg_used], data_ptr, sz)) {
653862306a36Sopenharmony_ci				status = -EFAULT;
653962306a36Sopenharmony_ci				goto cleanup1;
654062306a36Sopenharmony_ci			}
654162306a36Sopenharmony_ci		} else
654262306a36Sopenharmony_ci			memset(buff[sg_used], 0, sz);
654362306a36Sopenharmony_ci		left -= sz;
654462306a36Sopenharmony_ci		data_ptr += sz;
654562306a36Sopenharmony_ci		sg_used++;
654662306a36Sopenharmony_ci	}
654762306a36Sopenharmony_ci	c = cmd_alloc(h);
654862306a36Sopenharmony_ci
654962306a36Sopenharmony_ci	c->cmd_type = CMD_IOCTL_PEND;
655062306a36Sopenharmony_ci	c->scsi_cmd = SCSI_CMD_BUSY;
655162306a36Sopenharmony_ci	c->Header.ReplyQueue = 0;
655262306a36Sopenharmony_ci	c->Header.SGList = (u8) sg_used;
655362306a36Sopenharmony_ci	c->Header.SGTotal = cpu_to_le16(sg_used);
655462306a36Sopenharmony_ci	memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
655562306a36Sopenharmony_ci	memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
655662306a36Sopenharmony_ci	if (ioc->buf_size > 0) {
655762306a36Sopenharmony_ci		int i;
655862306a36Sopenharmony_ci		for (i = 0; i < sg_used; i++) {
655962306a36Sopenharmony_ci			temp64 = dma_map_single(&h->pdev->dev, buff[i],
656062306a36Sopenharmony_ci				    buff_size[i], DMA_BIDIRECTIONAL);
656162306a36Sopenharmony_ci			if (dma_mapping_error(&h->pdev->dev,
656262306a36Sopenharmony_ci							(dma_addr_t) temp64)) {
656362306a36Sopenharmony_ci				c->SG[i].Addr = cpu_to_le64(0);
656462306a36Sopenharmony_ci				c->SG[i].Len = cpu_to_le32(0);
656562306a36Sopenharmony_ci				hpsa_pci_unmap(h->pdev, c, i,
656662306a36Sopenharmony_ci					DMA_BIDIRECTIONAL);
656762306a36Sopenharmony_ci				status = -ENOMEM;
656862306a36Sopenharmony_ci				goto cleanup0;
656962306a36Sopenharmony_ci			}
657062306a36Sopenharmony_ci			c->SG[i].Addr = cpu_to_le64(temp64);
657162306a36Sopenharmony_ci			c->SG[i].Len = cpu_to_le32(buff_size[i]);
657262306a36Sopenharmony_ci			c->SG[i].Ext = cpu_to_le32(0);
657362306a36Sopenharmony_ci		}
657462306a36Sopenharmony_ci		c->SG[--i].Ext = cpu_to_le32(HPSA_SG_LAST);
657562306a36Sopenharmony_ci	}
657662306a36Sopenharmony_ci	status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
657762306a36Sopenharmony_ci						NO_TIMEOUT);
657862306a36Sopenharmony_ci	if (sg_used)
657962306a36Sopenharmony_ci		hpsa_pci_unmap(h->pdev, c, sg_used, DMA_BIDIRECTIONAL);
658062306a36Sopenharmony_ci	check_ioctl_unit_attention(h, c);
658162306a36Sopenharmony_ci	if (status) {
658262306a36Sopenharmony_ci		status = -EIO;
658362306a36Sopenharmony_ci		goto cleanup0;
658462306a36Sopenharmony_ci	}
658562306a36Sopenharmony_ci
658662306a36Sopenharmony_ci	/* Copy the error information out */
658762306a36Sopenharmony_ci	memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info));
658862306a36Sopenharmony_ci	if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) {
658962306a36Sopenharmony_ci		int i;
659062306a36Sopenharmony_ci
659162306a36Sopenharmony_ci		/* Copy the data out of the buffer we created */
659262306a36Sopenharmony_ci		BYTE __user *ptr = ioc->buf;
659362306a36Sopenharmony_ci		for (i = 0; i < sg_used; i++) {
659462306a36Sopenharmony_ci			if (copy_to_user(ptr, buff[i], buff_size[i])) {
659562306a36Sopenharmony_ci				status = -EFAULT;
659662306a36Sopenharmony_ci				goto cleanup0;
659762306a36Sopenharmony_ci			}
659862306a36Sopenharmony_ci			ptr += buff_size[i];
659962306a36Sopenharmony_ci		}
660062306a36Sopenharmony_ci	}
660162306a36Sopenharmony_ci	status = 0;
660262306a36Sopenharmony_cicleanup0:
660362306a36Sopenharmony_ci	cmd_free(h, c);
660462306a36Sopenharmony_cicleanup1:
660562306a36Sopenharmony_ci	if (buff) {
660662306a36Sopenharmony_ci		int i;
660762306a36Sopenharmony_ci
660862306a36Sopenharmony_ci		for (i = 0; i < sg_used; i++)
660962306a36Sopenharmony_ci			kfree(buff[i]);
661062306a36Sopenharmony_ci		kfree(buff);
661162306a36Sopenharmony_ci	}
661262306a36Sopenharmony_ci	kfree(buff_size);
661362306a36Sopenharmony_ci	return status;
661462306a36Sopenharmony_ci}
661562306a36Sopenharmony_ci
661662306a36Sopenharmony_cistatic void check_ioctl_unit_attention(struct ctlr_info *h,
661762306a36Sopenharmony_ci	struct CommandList *c)
661862306a36Sopenharmony_ci{
661962306a36Sopenharmony_ci	if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
662062306a36Sopenharmony_ci			c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
662162306a36Sopenharmony_ci		(void) check_for_unit_attention(h, c);
662262306a36Sopenharmony_ci}
662362306a36Sopenharmony_ci
662462306a36Sopenharmony_ci/*
662562306a36Sopenharmony_ci * ioctl
662662306a36Sopenharmony_ci */
662762306a36Sopenharmony_cistatic int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd,
662862306a36Sopenharmony_ci		      void __user *argp)
662962306a36Sopenharmony_ci{
663062306a36Sopenharmony_ci	struct ctlr_info *h = sdev_to_hba(dev);
663162306a36Sopenharmony_ci	int rc;
663262306a36Sopenharmony_ci
663362306a36Sopenharmony_ci	switch (cmd) {
663462306a36Sopenharmony_ci	case CCISS_DEREGDISK:
663562306a36Sopenharmony_ci	case CCISS_REGNEWDISK:
663662306a36Sopenharmony_ci	case CCISS_REGNEWD:
663762306a36Sopenharmony_ci		hpsa_scan_start(h->scsi_host);
663862306a36Sopenharmony_ci		return 0;
663962306a36Sopenharmony_ci	case CCISS_GETPCIINFO:
664062306a36Sopenharmony_ci		return hpsa_getpciinfo_ioctl(h, argp);
664162306a36Sopenharmony_ci	case CCISS_GETDRIVVER:
664262306a36Sopenharmony_ci		return hpsa_getdrivver_ioctl(h, argp);
664362306a36Sopenharmony_ci	case CCISS_PASSTHRU: {
664462306a36Sopenharmony_ci		IOCTL_Command_struct iocommand;
664562306a36Sopenharmony_ci
664662306a36Sopenharmony_ci		if (!argp)
664762306a36Sopenharmony_ci			return -EINVAL;
664862306a36Sopenharmony_ci		if (copy_from_user(&iocommand, argp, sizeof(iocommand)))
664962306a36Sopenharmony_ci			return -EFAULT;
665062306a36Sopenharmony_ci		if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
665162306a36Sopenharmony_ci			return -EAGAIN;
665262306a36Sopenharmony_ci		rc = hpsa_passthru_ioctl(h, &iocommand);
665362306a36Sopenharmony_ci		atomic_inc(&h->passthru_cmds_avail);
665462306a36Sopenharmony_ci		if (!rc && copy_to_user(argp, &iocommand, sizeof(iocommand)))
665562306a36Sopenharmony_ci			rc = -EFAULT;
665662306a36Sopenharmony_ci		return rc;
665762306a36Sopenharmony_ci	}
665862306a36Sopenharmony_ci	case CCISS_BIG_PASSTHRU: {
665962306a36Sopenharmony_ci		BIG_IOCTL_Command_struct ioc;
666062306a36Sopenharmony_ci		if (!argp)
666162306a36Sopenharmony_ci			return -EINVAL;
666262306a36Sopenharmony_ci		if (copy_from_user(&ioc, argp, sizeof(ioc)))
666362306a36Sopenharmony_ci			return -EFAULT;
666462306a36Sopenharmony_ci		if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
666562306a36Sopenharmony_ci			return -EAGAIN;
666662306a36Sopenharmony_ci		rc = hpsa_big_passthru_ioctl(h, &ioc);
666762306a36Sopenharmony_ci		atomic_inc(&h->passthru_cmds_avail);
666862306a36Sopenharmony_ci		if (!rc && copy_to_user(argp, &ioc, sizeof(ioc)))
666962306a36Sopenharmony_ci			rc = -EFAULT;
667062306a36Sopenharmony_ci		return rc;
667162306a36Sopenharmony_ci	}
667262306a36Sopenharmony_ci	default:
667362306a36Sopenharmony_ci		return -ENOTTY;
667462306a36Sopenharmony_ci	}
667562306a36Sopenharmony_ci}
667662306a36Sopenharmony_ci
667762306a36Sopenharmony_cistatic void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type)
667862306a36Sopenharmony_ci{
667962306a36Sopenharmony_ci	struct CommandList *c;
668062306a36Sopenharmony_ci
668162306a36Sopenharmony_ci	c = cmd_alloc(h);
668262306a36Sopenharmony_ci
668362306a36Sopenharmony_ci	/* fill_cmd can't fail here, no data buffer to map */
668462306a36Sopenharmony_ci	(void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
668562306a36Sopenharmony_ci		RAID_CTLR_LUNID, TYPE_MSG);
668662306a36Sopenharmony_ci	c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
668762306a36Sopenharmony_ci	c->waiting = NULL;
668862306a36Sopenharmony_ci	enqueue_cmd_and_start_io(h, c);
668962306a36Sopenharmony_ci	/* Don't wait for completion, the reset won't complete.  Don't free
669062306a36Sopenharmony_ci	 * the command either.  This is the last command we will send before
669162306a36Sopenharmony_ci	 * re-initializing everything, so it doesn't matter and won't leak.
669262306a36Sopenharmony_ci	 */
669362306a36Sopenharmony_ci	return;
669462306a36Sopenharmony_ci}
669562306a36Sopenharmony_ci
669662306a36Sopenharmony_cistatic int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
669762306a36Sopenharmony_ci	void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
669862306a36Sopenharmony_ci	int cmd_type)
669962306a36Sopenharmony_ci{
670062306a36Sopenharmony_ci	enum dma_data_direction dir = DMA_NONE;
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	c->cmd_type = CMD_IOCTL_PEND;
670362306a36Sopenharmony_ci	c->scsi_cmd = SCSI_CMD_BUSY;
670462306a36Sopenharmony_ci	c->Header.ReplyQueue = 0;
670562306a36Sopenharmony_ci	if (buff != NULL && size > 0) {
670662306a36Sopenharmony_ci		c->Header.SGList = 1;
670762306a36Sopenharmony_ci		c->Header.SGTotal = cpu_to_le16(1);
670862306a36Sopenharmony_ci	} else {
670962306a36Sopenharmony_ci		c->Header.SGList = 0;
671062306a36Sopenharmony_ci		c->Header.SGTotal = cpu_to_le16(0);
671162306a36Sopenharmony_ci	}
671262306a36Sopenharmony_ci	memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
671362306a36Sopenharmony_ci
671462306a36Sopenharmony_ci	if (cmd_type == TYPE_CMD) {
671562306a36Sopenharmony_ci		switch (cmd) {
671662306a36Sopenharmony_ci		case HPSA_INQUIRY:
671762306a36Sopenharmony_ci			/* are we trying to read a vital product page */
671862306a36Sopenharmony_ci			if (page_code & VPD_PAGE) {
671962306a36Sopenharmony_ci				c->Request.CDB[1] = 0x01;
672062306a36Sopenharmony_ci				c->Request.CDB[2] = (page_code & 0xff);
672162306a36Sopenharmony_ci			}
672262306a36Sopenharmony_ci			c->Request.CDBLen = 6;
672362306a36Sopenharmony_ci			c->Request.type_attr_dir =
672462306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
672562306a36Sopenharmony_ci			c->Request.Timeout = 0;
672662306a36Sopenharmony_ci			c->Request.CDB[0] = HPSA_INQUIRY;
672762306a36Sopenharmony_ci			c->Request.CDB[4] = size & 0xFF;
672862306a36Sopenharmony_ci			break;
672962306a36Sopenharmony_ci		case RECEIVE_DIAGNOSTIC:
673062306a36Sopenharmony_ci			c->Request.CDBLen = 6;
673162306a36Sopenharmony_ci			c->Request.type_attr_dir =
673262306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
673362306a36Sopenharmony_ci			c->Request.Timeout = 0;
673462306a36Sopenharmony_ci			c->Request.CDB[0] = cmd;
673562306a36Sopenharmony_ci			c->Request.CDB[1] = 1;
673662306a36Sopenharmony_ci			c->Request.CDB[2] = 1;
673762306a36Sopenharmony_ci			c->Request.CDB[3] = (size >> 8) & 0xFF;
673862306a36Sopenharmony_ci			c->Request.CDB[4] = size & 0xFF;
673962306a36Sopenharmony_ci			break;
674062306a36Sopenharmony_ci		case HPSA_REPORT_LOG:
674162306a36Sopenharmony_ci		case HPSA_REPORT_PHYS:
674262306a36Sopenharmony_ci			/* Talking to controller so It's a physical command
674362306a36Sopenharmony_ci			   mode = 00 target = 0.  Nothing to write.
674462306a36Sopenharmony_ci			 */
674562306a36Sopenharmony_ci			c->Request.CDBLen = 12;
674662306a36Sopenharmony_ci			c->Request.type_attr_dir =
674762306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
674862306a36Sopenharmony_ci			c->Request.Timeout = 0;
674962306a36Sopenharmony_ci			c->Request.CDB[0] = cmd;
675062306a36Sopenharmony_ci			c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
675162306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
675262306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0xFF;
675362306a36Sopenharmony_ci			c->Request.CDB[9] = size & 0xFF;
675462306a36Sopenharmony_ci			break;
675562306a36Sopenharmony_ci		case BMIC_SENSE_DIAG_OPTIONS:
675662306a36Sopenharmony_ci			c->Request.CDBLen = 16;
675762306a36Sopenharmony_ci			c->Request.type_attr_dir =
675862306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
675962306a36Sopenharmony_ci			c->Request.Timeout = 0;
676062306a36Sopenharmony_ci			/* Spec says this should be BMIC_WRITE */
676162306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
676262306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_SENSE_DIAG_OPTIONS;
676362306a36Sopenharmony_ci			break;
676462306a36Sopenharmony_ci		case BMIC_SET_DIAG_OPTIONS:
676562306a36Sopenharmony_ci			c->Request.CDBLen = 16;
676662306a36Sopenharmony_ci			c->Request.type_attr_dir =
676762306a36Sopenharmony_ci					TYPE_ATTR_DIR(cmd_type,
676862306a36Sopenharmony_ci						ATTR_SIMPLE, XFER_WRITE);
676962306a36Sopenharmony_ci			c->Request.Timeout = 0;
677062306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_WRITE;
677162306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_SET_DIAG_OPTIONS;
677262306a36Sopenharmony_ci			break;
677362306a36Sopenharmony_ci		case HPSA_CACHE_FLUSH:
677462306a36Sopenharmony_ci			c->Request.CDBLen = 12;
677562306a36Sopenharmony_ci			c->Request.type_attr_dir =
677662306a36Sopenharmony_ci					TYPE_ATTR_DIR(cmd_type,
677762306a36Sopenharmony_ci						ATTR_SIMPLE, XFER_WRITE);
677862306a36Sopenharmony_ci			c->Request.Timeout = 0;
677962306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_WRITE;
678062306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
678162306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 8) & 0xFF;
678262306a36Sopenharmony_ci			c->Request.CDB[8] = size & 0xFF;
678362306a36Sopenharmony_ci			break;
678462306a36Sopenharmony_ci		case TEST_UNIT_READY:
678562306a36Sopenharmony_ci			c->Request.CDBLen = 6;
678662306a36Sopenharmony_ci			c->Request.type_attr_dir =
678762306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
678862306a36Sopenharmony_ci			c->Request.Timeout = 0;
678962306a36Sopenharmony_ci			break;
679062306a36Sopenharmony_ci		case HPSA_GET_RAID_MAP:
679162306a36Sopenharmony_ci			c->Request.CDBLen = 12;
679262306a36Sopenharmony_ci			c->Request.type_attr_dir =
679362306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
679462306a36Sopenharmony_ci			c->Request.Timeout = 0;
679562306a36Sopenharmony_ci			c->Request.CDB[0] = HPSA_CISS_READ;
679662306a36Sopenharmony_ci			c->Request.CDB[1] = cmd;
679762306a36Sopenharmony_ci			c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
679862306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
679962306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0xFF;
680062306a36Sopenharmony_ci			c->Request.CDB[9] = size & 0xFF;
680162306a36Sopenharmony_ci			break;
680262306a36Sopenharmony_ci		case BMIC_SENSE_CONTROLLER_PARAMETERS:
680362306a36Sopenharmony_ci			c->Request.CDBLen = 10;
680462306a36Sopenharmony_ci			c->Request.type_attr_dir =
680562306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
680662306a36Sopenharmony_ci			c->Request.Timeout = 0;
680762306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
680862306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS;
680962306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
681062306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0xFF;
681162306a36Sopenharmony_ci			break;
681262306a36Sopenharmony_ci		case BMIC_IDENTIFY_PHYSICAL_DEVICE:
681362306a36Sopenharmony_ci			c->Request.CDBLen = 10;
681462306a36Sopenharmony_ci			c->Request.type_attr_dir =
681562306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
681662306a36Sopenharmony_ci			c->Request.Timeout = 0;
681762306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
681862306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_IDENTIFY_PHYSICAL_DEVICE;
681962306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
682062306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0XFF;
682162306a36Sopenharmony_ci			break;
682262306a36Sopenharmony_ci		case BMIC_SENSE_SUBSYSTEM_INFORMATION:
682362306a36Sopenharmony_ci			c->Request.CDBLen = 10;
682462306a36Sopenharmony_ci			c->Request.type_attr_dir =
682562306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
682662306a36Sopenharmony_ci			c->Request.Timeout = 0;
682762306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
682862306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION;
682962306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
683062306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0XFF;
683162306a36Sopenharmony_ci			break;
683262306a36Sopenharmony_ci		case BMIC_SENSE_STORAGE_BOX_PARAMS:
683362306a36Sopenharmony_ci			c->Request.CDBLen = 10;
683462306a36Sopenharmony_ci			c->Request.type_attr_dir =
683562306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
683662306a36Sopenharmony_ci			c->Request.Timeout = 0;
683762306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
683862306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_SENSE_STORAGE_BOX_PARAMS;
683962306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
684062306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0XFF;
684162306a36Sopenharmony_ci			break;
684262306a36Sopenharmony_ci		case BMIC_IDENTIFY_CONTROLLER:
684362306a36Sopenharmony_ci			c->Request.CDBLen = 10;
684462306a36Sopenharmony_ci			c->Request.type_attr_dir =
684562306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
684662306a36Sopenharmony_ci			c->Request.Timeout = 0;
684762306a36Sopenharmony_ci			c->Request.CDB[0] = BMIC_READ;
684862306a36Sopenharmony_ci			c->Request.CDB[1] = 0;
684962306a36Sopenharmony_ci			c->Request.CDB[2] = 0;
685062306a36Sopenharmony_ci			c->Request.CDB[3] = 0;
685162306a36Sopenharmony_ci			c->Request.CDB[4] = 0;
685262306a36Sopenharmony_ci			c->Request.CDB[5] = 0;
685362306a36Sopenharmony_ci			c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER;
685462306a36Sopenharmony_ci			c->Request.CDB[7] = (size >> 16) & 0xFF;
685562306a36Sopenharmony_ci			c->Request.CDB[8] = (size >> 8) & 0XFF;
685662306a36Sopenharmony_ci			c->Request.CDB[9] = 0;
685762306a36Sopenharmony_ci			break;
685862306a36Sopenharmony_ci		default:
685962306a36Sopenharmony_ci			dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
686062306a36Sopenharmony_ci			BUG();
686162306a36Sopenharmony_ci		}
686262306a36Sopenharmony_ci	} else if (cmd_type == TYPE_MSG) {
686362306a36Sopenharmony_ci		switch (cmd) {
686462306a36Sopenharmony_ci
686562306a36Sopenharmony_ci		case  HPSA_PHYS_TARGET_RESET:
686662306a36Sopenharmony_ci			c->Request.CDBLen = 16;
686762306a36Sopenharmony_ci			c->Request.type_attr_dir =
686862306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
686962306a36Sopenharmony_ci			c->Request.Timeout = 0; /* Don't time out */
687062306a36Sopenharmony_ci			memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
687162306a36Sopenharmony_ci			c->Request.CDB[0] = HPSA_RESET;
687262306a36Sopenharmony_ci			c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE;
687362306a36Sopenharmony_ci			/* Physical target reset needs no control bytes 4-7*/
687462306a36Sopenharmony_ci			c->Request.CDB[4] = 0x00;
687562306a36Sopenharmony_ci			c->Request.CDB[5] = 0x00;
687662306a36Sopenharmony_ci			c->Request.CDB[6] = 0x00;
687762306a36Sopenharmony_ci			c->Request.CDB[7] = 0x00;
687862306a36Sopenharmony_ci			break;
687962306a36Sopenharmony_ci		case  HPSA_DEVICE_RESET_MSG:
688062306a36Sopenharmony_ci			c->Request.CDBLen = 16;
688162306a36Sopenharmony_ci			c->Request.type_attr_dir =
688262306a36Sopenharmony_ci				TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
688362306a36Sopenharmony_ci			c->Request.Timeout = 0; /* Don't time out */
688462306a36Sopenharmony_ci			memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
688562306a36Sopenharmony_ci			c->Request.CDB[0] =  cmd;
688662306a36Sopenharmony_ci			c->Request.CDB[1] = HPSA_RESET_TYPE_LUN;
688762306a36Sopenharmony_ci			/* If bytes 4-7 are zero, it means reset the */
688862306a36Sopenharmony_ci			/* LunID device */
688962306a36Sopenharmony_ci			c->Request.CDB[4] = 0x00;
689062306a36Sopenharmony_ci			c->Request.CDB[5] = 0x00;
689162306a36Sopenharmony_ci			c->Request.CDB[6] = 0x00;
689262306a36Sopenharmony_ci			c->Request.CDB[7] = 0x00;
689362306a36Sopenharmony_ci			break;
689462306a36Sopenharmony_ci		default:
689562306a36Sopenharmony_ci			dev_warn(&h->pdev->dev, "unknown message type %d\n",
689662306a36Sopenharmony_ci				cmd);
689762306a36Sopenharmony_ci			BUG();
689862306a36Sopenharmony_ci		}
689962306a36Sopenharmony_ci	} else {
690062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "unknown command type %d\n", cmd_type);
690162306a36Sopenharmony_ci		BUG();
690262306a36Sopenharmony_ci	}
690362306a36Sopenharmony_ci
690462306a36Sopenharmony_ci	switch (GET_DIR(c->Request.type_attr_dir)) {
690562306a36Sopenharmony_ci	case XFER_READ:
690662306a36Sopenharmony_ci		dir = DMA_FROM_DEVICE;
690762306a36Sopenharmony_ci		break;
690862306a36Sopenharmony_ci	case XFER_WRITE:
690962306a36Sopenharmony_ci		dir = DMA_TO_DEVICE;
691062306a36Sopenharmony_ci		break;
691162306a36Sopenharmony_ci	case XFER_NONE:
691262306a36Sopenharmony_ci		dir = DMA_NONE;
691362306a36Sopenharmony_ci		break;
691462306a36Sopenharmony_ci	default:
691562306a36Sopenharmony_ci		dir = DMA_BIDIRECTIONAL;
691662306a36Sopenharmony_ci	}
691762306a36Sopenharmony_ci	if (hpsa_map_one(h->pdev, c, buff, size, dir))
691862306a36Sopenharmony_ci		return -1;
691962306a36Sopenharmony_ci	return 0;
692062306a36Sopenharmony_ci}
692162306a36Sopenharmony_ci
692262306a36Sopenharmony_ci/*
692362306a36Sopenharmony_ci * Map (physical) PCI mem into (virtual) kernel space
692462306a36Sopenharmony_ci */
692562306a36Sopenharmony_cistatic void __iomem *remap_pci_mem(ulong base, ulong size)
692662306a36Sopenharmony_ci{
692762306a36Sopenharmony_ci	ulong page_base = ((ulong) base) & PAGE_MASK;
692862306a36Sopenharmony_ci	ulong page_offs = ((ulong) base) - page_base;
692962306a36Sopenharmony_ci	void __iomem *page_remapped = ioremap(page_base,
693062306a36Sopenharmony_ci		page_offs + size);
693162306a36Sopenharmony_ci
693262306a36Sopenharmony_ci	return page_remapped ? (page_remapped + page_offs) : NULL;
693362306a36Sopenharmony_ci}
693462306a36Sopenharmony_ci
693562306a36Sopenharmony_cistatic inline unsigned long get_next_completion(struct ctlr_info *h, u8 q)
693662306a36Sopenharmony_ci{
693762306a36Sopenharmony_ci	return h->access.command_completed(h, q);
693862306a36Sopenharmony_ci}
693962306a36Sopenharmony_ci
694062306a36Sopenharmony_cistatic inline bool interrupt_pending(struct ctlr_info *h)
694162306a36Sopenharmony_ci{
694262306a36Sopenharmony_ci	return h->access.intr_pending(h);
694362306a36Sopenharmony_ci}
694462306a36Sopenharmony_ci
694562306a36Sopenharmony_cistatic inline long interrupt_not_for_us(struct ctlr_info *h)
694662306a36Sopenharmony_ci{
694762306a36Sopenharmony_ci	return (h->access.intr_pending(h) == 0) ||
694862306a36Sopenharmony_ci		(h->interrupts_enabled == 0);
694962306a36Sopenharmony_ci}
695062306a36Sopenharmony_ci
695162306a36Sopenharmony_cistatic inline int bad_tag(struct ctlr_info *h, u32 tag_index,
695262306a36Sopenharmony_ci	u32 raw_tag)
695362306a36Sopenharmony_ci{
695462306a36Sopenharmony_ci	if (unlikely(tag_index >= h->nr_cmds)) {
695562306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag);
695662306a36Sopenharmony_ci		return 1;
695762306a36Sopenharmony_ci	}
695862306a36Sopenharmony_ci	return 0;
695962306a36Sopenharmony_ci}
696062306a36Sopenharmony_ci
696162306a36Sopenharmony_cistatic inline void finish_cmd(struct CommandList *c)
696262306a36Sopenharmony_ci{
696362306a36Sopenharmony_ci	dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
696462306a36Sopenharmony_ci	if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI
696562306a36Sopenharmony_ci			|| c->cmd_type == CMD_IOACCEL2))
696662306a36Sopenharmony_ci		complete_scsi_command(c);
696762306a36Sopenharmony_ci	else if (c->cmd_type == CMD_IOCTL_PEND || c->cmd_type == IOACCEL2_TMF)
696862306a36Sopenharmony_ci		complete(c->waiting);
696962306a36Sopenharmony_ci}
697062306a36Sopenharmony_ci
697162306a36Sopenharmony_ci/* process completion of an indexed ("direct lookup") command */
697262306a36Sopenharmony_cistatic inline void process_indexed_cmd(struct ctlr_info *h,
697362306a36Sopenharmony_ci	u32 raw_tag)
697462306a36Sopenharmony_ci{
697562306a36Sopenharmony_ci	u32 tag_index;
697662306a36Sopenharmony_ci	struct CommandList *c;
697762306a36Sopenharmony_ci
697862306a36Sopenharmony_ci	tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT;
697962306a36Sopenharmony_ci	if (!bad_tag(h, tag_index, raw_tag)) {
698062306a36Sopenharmony_ci		c = h->cmd_pool + tag_index;
698162306a36Sopenharmony_ci		finish_cmd(c);
698262306a36Sopenharmony_ci	}
698362306a36Sopenharmony_ci}
698462306a36Sopenharmony_ci
698562306a36Sopenharmony_ci/* Some controllers, like p400, will give us one interrupt
698662306a36Sopenharmony_ci * after a soft reset, even if we turned interrupts off.
698762306a36Sopenharmony_ci * Only need to check for this in the hpsa_xxx_discard_completions
698862306a36Sopenharmony_ci * functions.
698962306a36Sopenharmony_ci */
699062306a36Sopenharmony_cistatic int ignore_bogus_interrupt(struct ctlr_info *h)
699162306a36Sopenharmony_ci{
699262306a36Sopenharmony_ci	if (likely(!reset_devices))
699362306a36Sopenharmony_ci		return 0;
699462306a36Sopenharmony_ci
699562306a36Sopenharmony_ci	if (likely(h->interrupts_enabled))
699662306a36Sopenharmony_ci		return 0;
699762306a36Sopenharmony_ci
699862306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
699962306a36Sopenharmony_ci		"(known firmware bug.)  Ignoring.\n");
700062306a36Sopenharmony_ci
700162306a36Sopenharmony_ci	return 1;
700262306a36Sopenharmony_ci}
700362306a36Sopenharmony_ci
700462306a36Sopenharmony_ci/*
700562306a36Sopenharmony_ci * Convert &h->q[x] (passed to interrupt handlers) back to h.
700662306a36Sopenharmony_ci * Relies on (h-q[x] == x) being true for x such that
700762306a36Sopenharmony_ci * 0 <= x < MAX_REPLY_QUEUES.
700862306a36Sopenharmony_ci */
700962306a36Sopenharmony_cistatic struct ctlr_info *queue_to_hba(u8 *queue)
701062306a36Sopenharmony_ci{
701162306a36Sopenharmony_ci	return container_of((queue - *queue), struct ctlr_info, q[0]);
701262306a36Sopenharmony_ci}
701362306a36Sopenharmony_ci
701462306a36Sopenharmony_cistatic irqreturn_t hpsa_intx_discard_completions(int irq, void *queue)
701562306a36Sopenharmony_ci{
701662306a36Sopenharmony_ci	struct ctlr_info *h = queue_to_hba(queue);
701762306a36Sopenharmony_ci	u8 q = *(u8 *) queue;
701862306a36Sopenharmony_ci	u32 raw_tag;
701962306a36Sopenharmony_ci
702062306a36Sopenharmony_ci	if (ignore_bogus_interrupt(h))
702162306a36Sopenharmony_ci		return IRQ_NONE;
702262306a36Sopenharmony_ci
702362306a36Sopenharmony_ci	if (interrupt_not_for_us(h))
702462306a36Sopenharmony_ci		return IRQ_NONE;
702562306a36Sopenharmony_ci	h->last_intr_timestamp = get_jiffies_64();
702662306a36Sopenharmony_ci	while (interrupt_pending(h)) {
702762306a36Sopenharmony_ci		raw_tag = get_next_completion(h, q);
702862306a36Sopenharmony_ci		while (raw_tag != FIFO_EMPTY)
702962306a36Sopenharmony_ci			raw_tag = next_command(h, q);
703062306a36Sopenharmony_ci	}
703162306a36Sopenharmony_ci	return IRQ_HANDLED;
703262306a36Sopenharmony_ci}
703362306a36Sopenharmony_ci
703462306a36Sopenharmony_cistatic irqreturn_t hpsa_msix_discard_completions(int irq, void *queue)
703562306a36Sopenharmony_ci{
703662306a36Sopenharmony_ci	struct ctlr_info *h = queue_to_hba(queue);
703762306a36Sopenharmony_ci	u32 raw_tag;
703862306a36Sopenharmony_ci	u8 q = *(u8 *) queue;
703962306a36Sopenharmony_ci
704062306a36Sopenharmony_ci	if (ignore_bogus_interrupt(h))
704162306a36Sopenharmony_ci		return IRQ_NONE;
704262306a36Sopenharmony_ci
704362306a36Sopenharmony_ci	h->last_intr_timestamp = get_jiffies_64();
704462306a36Sopenharmony_ci	raw_tag = get_next_completion(h, q);
704562306a36Sopenharmony_ci	while (raw_tag != FIFO_EMPTY)
704662306a36Sopenharmony_ci		raw_tag = next_command(h, q);
704762306a36Sopenharmony_ci	return IRQ_HANDLED;
704862306a36Sopenharmony_ci}
704962306a36Sopenharmony_ci
705062306a36Sopenharmony_cistatic irqreturn_t do_hpsa_intr_intx(int irq, void *queue)
705162306a36Sopenharmony_ci{
705262306a36Sopenharmony_ci	struct ctlr_info *h = queue_to_hba((u8 *) queue);
705362306a36Sopenharmony_ci	u32 raw_tag;
705462306a36Sopenharmony_ci	u8 q = *(u8 *) queue;
705562306a36Sopenharmony_ci
705662306a36Sopenharmony_ci	if (interrupt_not_for_us(h))
705762306a36Sopenharmony_ci		return IRQ_NONE;
705862306a36Sopenharmony_ci	h->last_intr_timestamp = get_jiffies_64();
705962306a36Sopenharmony_ci	while (interrupt_pending(h)) {
706062306a36Sopenharmony_ci		raw_tag = get_next_completion(h, q);
706162306a36Sopenharmony_ci		while (raw_tag != FIFO_EMPTY) {
706262306a36Sopenharmony_ci			process_indexed_cmd(h, raw_tag);
706362306a36Sopenharmony_ci			raw_tag = next_command(h, q);
706462306a36Sopenharmony_ci		}
706562306a36Sopenharmony_ci	}
706662306a36Sopenharmony_ci	return IRQ_HANDLED;
706762306a36Sopenharmony_ci}
706862306a36Sopenharmony_ci
706962306a36Sopenharmony_cistatic irqreturn_t do_hpsa_intr_msi(int irq, void *queue)
707062306a36Sopenharmony_ci{
707162306a36Sopenharmony_ci	struct ctlr_info *h = queue_to_hba(queue);
707262306a36Sopenharmony_ci	u32 raw_tag;
707362306a36Sopenharmony_ci	u8 q = *(u8 *) queue;
707462306a36Sopenharmony_ci
707562306a36Sopenharmony_ci	h->last_intr_timestamp = get_jiffies_64();
707662306a36Sopenharmony_ci	raw_tag = get_next_completion(h, q);
707762306a36Sopenharmony_ci	while (raw_tag != FIFO_EMPTY) {
707862306a36Sopenharmony_ci		process_indexed_cmd(h, raw_tag);
707962306a36Sopenharmony_ci		raw_tag = next_command(h, q);
708062306a36Sopenharmony_ci	}
708162306a36Sopenharmony_ci	return IRQ_HANDLED;
708262306a36Sopenharmony_ci}
708362306a36Sopenharmony_ci
708462306a36Sopenharmony_ci/* Send a message CDB to the firmware. Careful, this only works
708562306a36Sopenharmony_ci * in simple mode, not performant mode due to the tag lookup.
708662306a36Sopenharmony_ci * We only ever use this immediately after a controller reset.
708762306a36Sopenharmony_ci */
708862306a36Sopenharmony_cistatic int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
708962306a36Sopenharmony_ci			unsigned char type)
709062306a36Sopenharmony_ci{
709162306a36Sopenharmony_ci	struct Command {
709262306a36Sopenharmony_ci		struct CommandListHeader CommandHeader;
709362306a36Sopenharmony_ci		struct RequestBlock Request;
709462306a36Sopenharmony_ci		struct ErrDescriptor ErrorDescriptor;
709562306a36Sopenharmony_ci	};
709662306a36Sopenharmony_ci	struct Command *cmd;
709762306a36Sopenharmony_ci	static const size_t cmd_sz = sizeof(*cmd) +
709862306a36Sopenharmony_ci					sizeof(cmd->ErrorDescriptor);
709962306a36Sopenharmony_ci	dma_addr_t paddr64;
710062306a36Sopenharmony_ci	__le32 paddr32;
710162306a36Sopenharmony_ci	u32 tag;
710262306a36Sopenharmony_ci	void __iomem *vaddr;
710362306a36Sopenharmony_ci	int i, err;
710462306a36Sopenharmony_ci
710562306a36Sopenharmony_ci	vaddr = pci_ioremap_bar(pdev, 0);
710662306a36Sopenharmony_ci	if (vaddr == NULL)
710762306a36Sopenharmony_ci		return -ENOMEM;
710862306a36Sopenharmony_ci
710962306a36Sopenharmony_ci	/* The Inbound Post Queue only accepts 32-bit physical addresses for the
711062306a36Sopenharmony_ci	 * CCISS commands, so they must be allocated from the lower 4GiB of
711162306a36Sopenharmony_ci	 * memory.
711262306a36Sopenharmony_ci	 */
711362306a36Sopenharmony_ci	err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
711462306a36Sopenharmony_ci	if (err) {
711562306a36Sopenharmony_ci		iounmap(vaddr);
711662306a36Sopenharmony_ci		return err;
711762306a36Sopenharmony_ci	}
711862306a36Sopenharmony_ci
711962306a36Sopenharmony_ci	cmd = dma_alloc_coherent(&pdev->dev, cmd_sz, &paddr64, GFP_KERNEL);
712062306a36Sopenharmony_ci	if (cmd == NULL) {
712162306a36Sopenharmony_ci		iounmap(vaddr);
712262306a36Sopenharmony_ci		return -ENOMEM;
712362306a36Sopenharmony_ci	}
712462306a36Sopenharmony_ci
712562306a36Sopenharmony_ci	/* This must fit, because of the 32-bit consistent DMA mask.  Also,
712662306a36Sopenharmony_ci	 * although there's no guarantee, we assume that the address is at
712762306a36Sopenharmony_ci	 * least 4-byte aligned (most likely, it's page-aligned).
712862306a36Sopenharmony_ci	 */
712962306a36Sopenharmony_ci	paddr32 = cpu_to_le32(paddr64);
713062306a36Sopenharmony_ci
713162306a36Sopenharmony_ci	cmd->CommandHeader.ReplyQueue = 0;
713262306a36Sopenharmony_ci	cmd->CommandHeader.SGList = 0;
713362306a36Sopenharmony_ci	cmd->CommandHeader.SGTotal = cpu_to_le16(0);
713462306a36Sopenharmony_ci	cmd->CommandHeader.tag = cpu_to_le64(paddr64);
713562306a36Sopenharmony_ci	memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
713662306a36Sopenharmony_ci
713762306a36Sopenharmony_ci	cmd->Request.CDBLen = 16;
713862306a36Sopenharmony_ci	cmd->Request.type_attr_dir =
713962306a36Sopenharmony_ci			TYPE_ATTR_DIR(TYPE_MSG, ATTR_HEADOFQUEUE, XFER_NONE);
714062306a36Sopenharmony_ci	cmd->Request.Timeout = 0; /* Don't time out */
714162306a36Sopenharmony_ci	cmd->Request.CDB[0] = opcode;
714262306a36Sopenharmony_ci	cmd->Request.CDB[1] = type;
714362306a36Sopenharmony_ci	memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */
714462306a36Sopenharmony_ci	cmd->ErrorDescriptor.Addr =
714562306a36Sopenharmony_ci			cpu_to_le64((le32_to_cpu(paddr32) + sizeof(*cmd)));
714662306a36Sopenharmony_ci	cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo));
714762306a36Sopenharmony_ci
714862306a36Sopenharmony_ci	writel(le32_to_cpu(paddr32), vaddr + SA5_REQUEST_PORT_OFFSET);
714962306a36Sopenharmony_ci
715062306a36Sopenharmony_ci	for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
715162306a36Sopenharmony_ci		tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
715262306a36Sopenharmony_ci		if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr64)
715362306a36Sopenharmony_ci			break;
715462306a36Sopenharmony_ci		msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
715562306a36Sopenharmony_ci	}
715662306a36Sopenharmony_ci
715762306a36Sopenharmony_ci	iounmap(vaddr);
715862306a36Sopenharmony_ci
715962306a36Sopenharmony_ci	/* we leak the DMA buffer here ... no choice since the controller could
716062306a36Sopenharmony_ci	 *  still complete the command.
716162306a36Sopenharmony_ci	 */
716262306a36Sopenharmony_ci	if (i == HPSA_MSG_SEND_RETRY_LIMIT) {
716362306a36Sopenharmony_ci		dev_err(&pdev->dev, "controller message %02x:%02x timed out\n",
716462306a36Sopenharmony_ci			opcode, type);
716562306a36Sopenharmony_ci		return -ETIMEDOUT;
716662306a36Sopenharmony_ci	}
716762306a36Sopenharmony_ci
716862306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, cmd_sz, cmd, paddr64);
716962306a36Sopenharmony_ci
717062306a36Sopenharmony_ci	if (tag & HPSA_ERROR_BIT) {
717162306a36Sopenharmony_ci		dev_err(&pdev->dev, "controller message %02x:%02x failed\n",
717262306a36Sopenharmony_ci			opcode, type);
717362306a36Sopenharmony_ci		return -EIO;
717462306a36Sopenharmony_ci	}
717562306a36Sopenharmony_ci
717662306a36Sopenharmony_ci	dev_info(&pdev->dev, "controller message %02x:%02x succeeded\n",
717762306a36Sopenharmony_ci		opcode, type);
717862306a36Sopenharmony_ci	return 0;
717962306a36Sopenharmony_ci}
718062306a36Sopenharmony_ci
718162306a36Sopenharmony_ci#define hpsa_noop(p) hpsa_message(p, 3, 0)
718262306a36Sopenharmony_ci
718362306a36Sopenharmony_cistatic int hpsa_controller_hard_reset(struct pci_dev *pdev,
718462306a36Sopenharmony_ci	void __iomem *vaddr, u32 use_doorbell)
718562306a36Sopenharmony_ci{
718662306a36Sopenharmony_ci
718762306a36Sopenharmony_ci	if (use_doorbell) {
718862306a36Sopenharmony_ci		/* For everything after the P600, the PCI power state method
718962306a36Sopenharmony_ci		 * of resetting the controller doesn't work, so we have this
719062306a36Sopenharmony_ci		 * other way using the doorbell register.
719162306a36Sopenharmony_ci		 */
719262306a36Sopenharmony_ci		dev_info(&pdev->dev, "using doorbell to reset controller\n");
719362306a36Sopenharmony_ci		writel(use_doorbell, vaddr + SA5_DOORBELL);
719462306a36Sopenharmony_ci
719562306a36Sopenharmony_ci		/* PMC hardware guys tell us we need a 10 second delay after
719662306a36Sopenharmony_ci		 * doorbell reset and before any attempt to talk to the board
719762306a36Sopenharmony_ci		 * at all to ensure that this actually works and doesn't fall
719862306a36Sopenharmony_ci		 * over in some weird corner cases.
719962306a36Sopenharmony_ci		 */
720062306a36Sopenharmony_ci		msleep(10000);
720162306a36Sopenharmony_ci	} else { /* Try to do it the PCI power state way */
720262306a36Sopenharmony_ci
720362306a36Sopenharmony_ci		/* Quoting from the Open CISS Specification: "The Power
720462306a36Sopenharmony_ci		 * Management Control/Status Register (CSR) controls the power
720562306a36Sopenharmony_ci		 * state of the device.  The normal operating state is D0,
720662306a36Sopenharmony_ci		 * CSR=00h.  The software off state is D3, CSR=03h.  To reset
720762306a36Sopenharmony_ci		 * the controller, place the interface device in D3 then to D0,
720862306a36Sopenharmony_ci		 * this causes a secondary PCI reset which will reset the
720962306a36Sopenharmony_ci		 * controller." */
721062306a36Sopenharmony_ci
721162306a36Sopenharmony_ci		int rc = 0;
721262306a36Sopenharmony_ci
721362306a36Sopenharmony_ci		dev_info(&pdev->dev, "using PCI PM to reset controller\n");
721462306a36Sopenharmony_ci
721562306a36Sopenharmony_ci		/* enter the D3hot power management state */
721662306a36Sopenharmony_ci		rc = pci_set_power_state(pdev, PCI_D3hot);
721762306a36Sopenharmony_ci		if (rc)
721862306a36Sopenharmony_ci			return rc;
721962306a36Sopenharmony_ci
722062306a36Sopenharmony_ci		msleep(500);
722162306a36Sopenharmony_ci
722262306a36Sopenharmony_ci		/* enter the D0 power management state */
722362306a36Sopenharmony_ci		rc = pci_set_power_state(pdev, PCI_D0);
722462306a36Sopenharmony_ci		if (rc)
722562306a36Sopenharmony_ci			return rc;
722662306a36Sopenharmony_ci
722762306a36Sopenharmony_ci		/*
722862306a36Sopenharmony_ci		 * The P600 requires a small delay when changing states.
722962306a36Sopenharmony_ci		 * Otherwise we may think the board did not reset and we bail.
723062306a36Sopenharmony_ci		 * This for kdump only and is particular to the P600.
723162306a36Sopenharmony_ci		 */
723262306a36Sopenharmony_ci		msleep(500);
723362306a36Sopenharmony_ci	}
723462306a36Sopenharmony_ci	return 0;
723562306a36Sopenharmony_ci}
723662306a36Sopenharmony_ci
723762306a36Sopenharmony_cistatic void init_driver_version(char *driver_version, int len)
723862306a36Sopenharmony_ci{
723962306a36Sopenharmony_ci	memset(driver_version, 0, len);
724062306a36Sopenharmony_ci	strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1);
724162306a36Sopenharmony_ci}
724262306a36Sopenharmony_ci
724362306a36Sopenharmony_cistatic int write_driver_ver_to_cfgtable(struct CfgTable __iomem *cfgtable)
724462306a36Sopenharmony_ci{
724562306a36Sopenharmony_ci	char *driver_version;
724662306a36Sopenharmony_ci	int i, size = sizeof(cfgtable->driver_version);
724762306a36Sopenharmony_ci
724862306a36Sopenharmony_ci	driver_version = kmalloc(size, GFP_KERNEL);
724962306a36Sopenharmony_ci	if (!driver_version)
725062306a36Sopenharmony_ci		return -ENOMEM;
725162306a36Sopenharmony_ci
725262306a36Sopenharmony_ci	init_driver_version(driver_version, size);
725362306a36Sopenharmony_ci	for (i = 0; i < size; i++)
725462306a36Sopenharmony_ci		writeb(driver_version[i], &cfgtable->driver_version[i]);
725562306a36Sopenharmony_ci	kfree(driver_version);
725662306a36Sopenharmony_ci	return 0;
725762306a36Sopenharmony_ci}
725862306a36Sopenharmony_ci
725962306a36Sopenharmony_cistatic void read_driver_ver_from_cfgtable(struct CfgTable __iomem *cfgtable,
726062306a36Sopenharmony_ci					  unsigned char *driver_ver)
726162306a36Sopenharmony_ci{
726262306a36Sopenharmony_ci	int i;
726362306a36Sopenharmony_ci
726462306a36Sopenharmony_ci	for (i = 0; i < sizeof(cfgtable->driver_version); i++)
726562306a36Sopenharmony_ci		driver_ver[i] = readb(&cfgtable->driver_version[i]);
726662306a36Sopenharmony_ci}
726762306a36Sopenharmony_ci
726862306a36Sopenharmony_cistatic int controller_reset_failed(struct CfgTable __iomem *cfgtable)
726962306a36Sopenharmony_ci{
727062306a36Sopenharmony_ci
727162306a36Sopenharmony_ci	char *driver_ver, *old_driver_ver;
727262306a36Sopenharmony_ci	int rc, size = sizeof(cfgtable->driver_version);
727362306a36Sopenharmony_ci
727462306a36Sopenharmony_ci	old_driver_ver = kmalloc_array(2, size, GFP_KERNEL);
727562306a36Sopenharmony_ci	if (!old_driver_ver)
727662306a36Sopenharmony_ci		return -ENOMEM;
727762306a36Sopenharmony_ci	driver_ver = old_driver_ver + size;
727862306a36Sopenharmony_ci
727962306a36Sopenharmony_ci	/* After a reset, the 32 bytes of "driver version" in the cfgtable
728062306a36Sopenharmony_ci	 * should have been changed, otherwise we know the reset failed.
728162306a36Sopenharmony_ci	 */
728262306a36Sopenharmony_ci	init_driver_version(old_driver_ver, size);
728362306a36Sopenharmony_ci	read_driver_ver_from_cfgtable(cfgtable, driver_ver);
728462306a36Sopenharmony_ci	rc = !memcmp(driver_ver, old_driver_ver, size);
728562306a36Sopenharmony_ci	kfree(old_driver_ver);
728662306a36Sopenharmony_ci	return rc;
728762306a36Sopenharmony_ci}
728862306a36Sopenharmony_ci/* This does a hard reset of the controller using PCI power management
728962306a36Sopenharmony_ci * states or the using the doorbell register.
729062306a36Sopenharmony_ci */
729162306a36Sopenharmony_cistatic int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev, u32 board_id)
729262306a36Sopenharmony_ci{
729362306a36Sopenharmony_ci	u64 cfg_offset;
729462306a36Sopenharmony_ci	u32 cfg_base_addr;
729562306a36Sopenharmony_ci	u64 cfg_base_addr_index;
729662306a36Sopenharmony_ci	void __iomem *vaddr;
729762306a36Sopenharmony_ci	unsigned long paddr;
729862306a36Sopenharmony_ci	u32 misc_fw_support;
729962306a36Sopenharmony_ci	int rc;
730062306a36Sopenharmony_ci	struct CfgTable __iomem *cfgtable;
730162306a36Sopenharmony_ci	u32 use_doorbell;
730262306a36Sopenharmony_ci	u16 command_register;
730362306a36Sopenharmony_ci
730462306a36Sopenharmony_ci	/* For controllers as old as the P600, this is very nearly
730562306a36Sopenharmony_ci	 * the same thing as
730662306a36Sopenharmony_ci	 *
730762306a36Sopenharmony_ci	 * pci_save_state(pci_dev);
730862306a36Sopenharmony_ci	 * pci_set_power_state(pci_dev, PCI_D3hot);
730962306a36Sopenharmony_ci	 * pci_set_power_state(pci_dev, PCI_D0);
731062306a36Sopenharmony_ci	 * pci_restore_state(pci_dev);
731162306a36Sopenharmony_ci	 *
731262306a36Sopenharmony_ci	 * For controllers newer than the P600, the pci power state
731362306a36Sopenharmony_ci	 * method of resetting doesn't work so we have another way
731462306a36Sopenharmony_ci	 * using the doorbell register.
731562306a36Sopenharmony_ci	 */
731662306a36Sopenharmony_ci
731762306a36Sopenharmony_ci	if (!ctlr_is_resettable(board_id)) {
731862306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Controller not resettable\n");
731962306a36Sopenharmony_ci		return -ENODEV;
732062306a36Sopenharmony_ci	}
732162306a36Sopenharmony_ci
732262306a36Sopenharmony_ci	/* if controller is soft- but not hard resettable... */
732362306a36Sopenharmony_ci	if (!ctlr_is_hard_resettable(board_id))
732462306a36Sopenharmony_ci		return -ENOTSUPP; /* try soft reset later. */
732562306a36Sopenharmony_ci
732662306a36Sopenharmony_ci	/* Save the PCI command register */
732762306a36Sopenharmony_ci	pci_read_config_word(pdev, 4, &command_register);
732862306a36Sopenharmony_ci	pci_save_state(pdev);
732962306a36Sopenharmony_ci
733062306a36Sopenharmony_ci	/* find the first memory BAR, so we can find the cfg table */
733162306a36Sopenharmony_ci	rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
733262306a36Sopenharmony_ci	if (rc)
733362306a36Sopenharmony_ci		return rc;
733462306a36Sopenharmony_ci	vaddr = remap_pci_mem(paddr, 0x250);
733562306a36Sopenharmony_ci	if (!vaddr)
733662306a36Sopenharmony_ci		return -ENOMEM;
733762306a36Sopenharmony_ci
733862306a36Sopenharmony_ci	/* find cfgtable in order to check if reset via doorbell is supported */
733962306a36Sopenharmony_ci	rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
734062306a36Sopenharmony_ci					&cfg_base_addr_index, &cfg_offset);
734162306a36Sopenharmony_ci	if (rc)
734262306a36Sopenharmony_ci		goto unmap_vaddr;
734362306a36Sopenharmony_ci	cfgtable = remap_pci_mem(pci_resource_start(pdev,
734462306a36Sopenharmony_ci		       cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
734562306a36Sopenharmony_ci	if (!cfgtable) {
734662306a36Sopenharmony_ci		rc = -ENOMEM;
734762306a36Sopenharmony_ci		goto unmap_vaddr;
734862306a36Sopenharmony_ci	}
734962306a36Sopenharmony_ci	rc = write_driver_ver_to_cfgtable(cfgtable);
735062306a36Sopenharmony_ci	if (rc)
735162306a36Sopenharmony_ci		goto unmap_cfgtable;
735262306a36Sopenharmony_ci
735362306a36Sopenharmony_ci	/* If reset via doorbell register is supported, use that.
735462306a36Sopenharmony_ci	 * There are two such methods.  Favor the newest method.
735562306a36Sopenharmony_ci	 */
735662306a36Sopenharmony_ci	misc_fw_support = readl(&cfgtable->misc_fw_support);
735762306a36Sopenharmony_ci	use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
735862306a36Sopenharmony_ci	if (use_doorbell) {
735962306a36Sopenharmony_ci		use_doorbell = DOORBELL_CTLR_RESET2;
736062306a36Sopenharmony_ci	} else {
736162306a36Sopenharmony_ci		use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
736262306a36Sopenharmony_ci		if (use_doorbell) {
736362306a36Sopenharmony_ci			dev_warn(&pdev->dev,
736462306a36Sopenharmony_ci				"Soft reset not supported. Firmware update is required.\n");
736562306a36Sopenharmony_ci			rc = -ENOTSUPP; /* try soft reset */
736662306a36Sopenharmony_ci			goto unmap_cfgtable;
736762306a36Sopenharmony_ci		}
736862306a36Sopenharmony_ci	}
736962306a36Sopenharmony_ci
737062306a36Sopenharmony_ci	rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
737162306a36Sopenharmony_ci	if (rc)
737262306a36Sopenharmony_ci		goto unmap_cfgtable;
737362306a36Sopenharmony_ci
737462306a36Sopenharmony_ci	pci_restore_state(pdev);
737562306a36Sopenharmony_ci	pci_write_config_word(pdev, 4, command_register);
737662306a36Sopenharmony_ci
737762306a36Sopenharmony_ci	/* Some devices (notably the HP Smart Array 5i Controller)
737862306a36Sopenharmony_ci	   need a little pause here */
737962306a36Sopenharmony_ci	msleep(HPSA_POST_RESET_PAUSE_MSECS);
738062306a36Sopenharmony_ci
738162306a36Sopenharmony_ci	rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
738262306a36Sopenharmony_ci	if (rc) {
738362306a36Sopenharmony_ci		dev_warn(&pdev->dev,
738462306a36Sopenharmony_ci			"Failed waiting for board to become ready after hard reset\n");
738562306a36Sopenharmony_ci		goto unmap_cfgtable;
738662306a36Sopenharmony_ci	}
738762306a36Sopenharmony_ci
738862306a36Sopenharmony_ci	rc = controller_reset_failed(vaddr);
738962306a36Sopenharmony_ci	if (rc < 0)
739062306a36Sopenharmony_ci		goto unmap_cfgtable;
739162306a36Sopenharmony_ci	if (rc) {
739262306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Unable to successfully reset "
739362306a36Sopenharmony_ci			"controller. Will try soft reset.\n");
739462306a36Sopenharmony_ci		rc = -ENOTSUPP;
739562306a36Sopenharmony_ci	} else {
739662306a36Sopenharmony_ci		dev_info(&pdev->dev, "board ready after hard reset.\n");
739762306a36Sopenharmony_ci	}
739862306a36Sopenharmony_ci
739962306a36Sopenharmony_ciunmap_cfgtable:
740062306a36Sopenharmony_ci	iounmap(cfgtable);
740162306a36Sopenharmony_ci
740262306a36Sopenharmony_ciunmap_vaddr:
740362306a36Sopenharmony_ci	iounmap(vaddr);
740462306a36Sopenharmony_ci	return rc;
740562306a36Sopenharmony_ci}
740662306a36Sopenharmony_ci
740762306a36Sopenharmony_ci/*
740862306a36Sopenharmony_ci *  We cannot read the structure directly, for portability we must use
740962306a36Sopenharmony_ci *   the io functions.
741062306a36Sopenharmony_ci *   This is for debug only.
741162306a36Sopenharmony_ci */
741262306a36Sopenharmony_cistatic void print_cfg_table(struct device *dev, struct CfgTable __iomem *tb)
741362306a36Sopenharmony_ci{
741462306a36Sopenharmony_ci#ifdef HPSA_DEBUG
741562306a36Sopenharmony_ci	int i;
741662306a36Sopenharmony_ci	char temp_name[17];
741762306a36Sopenharmony_ci
741862306a36Sopenharmony_ci	dev_info(dev, "Controller Configuration information\n");
741962306a36Sopenharmony_ci	dev_info(dev, "------------------------------------\n");
742062306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
742162306a36Sopenharmony_ci		temp_name[i] = readb(&(tb->Signature[i]));
742262306a36Sopenharmony_ci	temp_name[4] = '\0';
742362306a36Sopenharmony_ci	dev_info(dev, "   Signature = %s\n", temp_name);
742462306a36Sopenharmony_ci	dev_info(dev, "   Spec Number = %d\n", readl(&(tb->SpecValence)));
742562306a36Sopenharmony_ci	dev_info(dev, "   Transport methods supported = 0x%x\n",
742662306a36Sopenharmony_ci	       readl(&(tb->TransportSupport)));
742762306a36Sopenharmony_ci	dev_info(dev, "   Transport methods active = 0x%x\n",
742862306a36Sopenharmony_ci	       readl(&(tb->TransportActive)));
742962306a36Sopenharmony_ci	dev_info(dev, "   Requested transport Method = 0x%x\n",
743062306a36Sopenharmony_ci	       readl(&(tb->HostWrite.TransportRequest)));
743162306a36Sopenharmony_ci	dev_info(dev, "   Coalesce Interrupt Delay = 0x%x\n",
743262306a36Sopenharmony_ci	       readl(&(tb->HostWrite.CoalIntDelay)));
743362306a36Sopenharmony_ci	dev_info(dev, "   Coalesce Interrupt Count = 0x%x\n",
743462306a36Sopenharmony_ci	       readl(&(tb->HostWrite.CoalIntCount)));
743562306a36Sopenharmony_ci	dev_info(dev, "   Max outstanding commands = %d\n",
743662306a36Sopenharmony_ci	       readl(&(tb->CmdsOutMax)));
743762306a36Sopenharmony_ci	dev_info(dev, "   Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
743862306a36Sopenharmony_ci	for (i = 0; i < 16; i++)
743962306a36Sopenharmony_ci		temp_name[i] = readb(&(tb->ServerName[i]));
744062306a36Sopenharmony_ci	temp_name[16] = '\0';
744162306a36Sopenharmony_ci	dev_info(dev, "   Server Name = %s\n", temp_name);
744262306a36Sopenharmony_ci	dev_info(dev, "   Heartbeat Counter = 0x%x\n\n\n",
744362306a36Sopenharmony_ci		readl(&(tb->HeartBeat)));
744462306a36Sopenharmony_ci#endif				/* HPSA_DEBUG */
744562306a36Sopenharmony_ci}
744662306a36Sopenharmony_ci
744762306a36Sopenharmony_cistatic int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
744862306a36Sopenharmony_ci{
744962306a36Sopenharmony_ci	int i, offset, mem_type, bar_type;
745062306a36Sopenharmony_ci
745162306a36Sopenharmony_ci	if (pci_bar_addr == PCI_BASE_ADDRESS_0)	/* looking for BAR zero? */
745262306a36Sopenharmony_ci		return 0;
745362306a36Sopenharmony_ci	offset = 0;
745462306a36Sopenharmony_ci	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
745562306a36Sopenharmony_ci		bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
745662306a36Sopenharmony_ci		if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
745762306a36Sopenharmony_ci			offset += 4;
745862306a36Sopenharmony_ci		else {
745962306a36Sopenharmony_ci			mem_type = pci_resource_flags(pdev, i) &
746062306a36Sopenharmony_ci			    PCI_BASE_ADDRESS_MEM_TYPE_MASK;
746162306a36Sopenharmony_ci			switch (mem_type) {
746262306a36Sopenharmony_ci			case PCI_BASE_ADDRESS_MEM_TYPE_32:
746362306a36Sopenharmony_ci			case PCI_BASE_ADDRESS_MEM_TYPE_1M:
746462306a36Sopenharmony_ci				offset += 4;	/* 32 bit */
746562306a36Sopenharmony_ci				break;
746662306a36Sopenharmony_ci			case PCI_BASE_ADDRESS_MEM_TYPE_64:
746762306a36Sopenharmony_ci				offset += 8;
746862306a36Sopenharmony_ci				break;
746962306a36Sopenharmony_ci			default:	/* reserved in PCI 2.2 */
747062306a36Sopenharmony_ci				dev_warn(&pdev->dev,
747162306a36Sopenharmony_ci				       "base address is invalid\n");
747262306a36Sopenharmony_ci				return -1;
747362306a36Sopenharmony_ci			}
747462306a36Sopenharmony_ci		}
747562306a36Sopenharmony_ci		if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
747662306a36Sopenharmony_ci			return i + 1;
747762306a36Sopenharmony_ci	}
747862306a36Sopenharmony_ci	return -1;
747962306a36Sopenharmony_ci}
748062306a36Sopenharmony_ci
748162306a36Sopenharmony_cistatic void hpsa_disable_interrupt_mode(struct ctlr_info *h)
748262306a36Sopenharmony_ci{
748362306a36Sopenharmony_ci	pci_free_irq_vectors(h->pdev);
748462306a36Sopenharmony_ci	h->msix_vectors = 0;
748562306a36Sopenharmony_ci}
748662306a36Sopenharmony_ci
748762306a36Sopenharmony_cistatic void hpsa_setup_reply_map(struct ctlr_info *h)
748862306a36Sopenharmony_ci{
748962306a36Sopenharmony_ci	const struct cpumask *mask;
749062306a36Sopenharmony_ci	unsigned int queue, cpu;
749162306a36Sopenharmony_ci
749262306a36Sopenharmony_ci	for (queue = 0; queue < h->msix_vectors; queue++) {
749362306a36Sopenharmony_ci		mask = pci_irq_get_affinity(h->pdev, queue);
749462306a36Sopenharmony_ci		if (!mask)
749562306a36Sopenharmony_ci			goto fallback;
749662306a36Sopenharmony_ci
749762306a36Sopenharmony_ci		for_each_cpu(cpu, mask)
749862306a36Sopenharmony_ci			h->reply_map[cpu] = queue;
749962306a36Sopenharmony_ci	}
750062306a36Sopenharmony_ci	return;
750162306a36Sopenharmony_ci
750262306a36Sopenharmony_cifallback:
750362306a36Sopenharmony_ci	for_each_possible_cpu(cpu)
750462306a36Sopenharmony_ci		h->reply_map[cpu] = 0;
750562306a36Sopenharmony_ci}
750662306a36Sopenharmony_ci
750762306a36Sopenharmony_ci/* If MSI/MSI-X is supported by the kernel we will try to enable it on
750862306a36Sopenharmony_ci * controllers that are capable. If not, we use legacy INTx mode.
750962306a36Sopenharmony_ci */
751062306a36Sopenharmony_cistatic int hpsa_interrupt_mode(struct ctlr_info *h)
751162306a36Sopenharmony_ci{
751262306a36Sopenharmony_ci	unsigned int flags = PCI_IRQ_LEGACY;
751362306a36Sopenharmony_ci	int ret;
751462306a36Sopenharmony_ci
751562306a36Sopenharmony_ci	/* Some boards advertise MSI but don't really support it */
751662306a36Sopenharmony_ci	switch (h->board_id) {
751762306a36Sopenharmony_ci	case 0x40700E11:
751862306a36Sopenharmony_ci	case 0x40800E11:
751962306a36Sopenharmony_ci	case 0x40820E11:
752062306a36Sopenharmony_ci	case 0x40830E11:
752162306a36Sopenharmony_ci		break;
752262306a36Sopenharmony_ci	default:
752362306a36Sopenharmony_ci		ret = pci_alloc_irq_vectors(h->pdev, 1, MAX_REPLY_QUEUES,
752462306a36Sopenharmony_ci				PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
752562306a36Sopenharmony_ci		if (ret > 0) {
752662306a36Sopenharmony_ci			h->msix_vectors = ret;
752762306a36Sopenharmony_ci			return 0;
752862306a36Sopenharmony_ci		}
752962306a36Sopenharmony_ci
753062306a36Sopenharmony_ci		flags |= PCI_IRQ_MSI;
753162306a36Sopenharmony_ci		break;
753262306a36Sopenharmony_ci	}
753362306a36Sopenharmony_ci
753462306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(h->pdev, 1, 1, flags);
753562306a36Sopenharmony_ci	if (ret < 0)
753662306a36Sopenharmony_ci		return ret;
753762306a36Sopenharmony_ci	return 0;
753862306a36Sopenharmony_ci}
753962306a36Sopenharmony_ci
754062306a36Sopenharmony_cistatic int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id,
754162306a36Sopenharmony_ci				bool *legacy_board)
754262306a36Sopenharmony_ci{
754362306a36Sopenharmony_ci	int i;
754462306a36Sopenharmony_ci	u32 subsystem_vendor_id, subsystem_device_id;
754562306a36Sopenharmony_ci
754662306a36Sopenharmony_ci	subsystem_vendor_id = pdev->subsystem_vendor;
754762306a36Sopenharmony_ci	subsystem_device_id = pdev->subsystem_device;
754862306a36Sopenharmony_ci	*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
754962306a36Sopenharmony_ci		    subsystem_vendor_id;
755062306a36Sopenharmony_ci
755162306a36Sopenharmony_ci	if (legacy_board)
755262306a36Sopenharmony_ci		*legacy_board = false;
755362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(products); i++)
755462306a36Sopenharmony_ci		if (*board_id == products[i].board_id) {
755562306a36Sopenharmony_ci			if (products[i].access != &SA5A_access &&
755662306a36Sopenharmony_ci			    products[i].access != &SA5B_access)
755762306a36Sopenharmony_ci				return i;
755862306a36Sopenharmony_ci			dev_warn(&pdev->dev,
755962306a36Sopenharmony_ci				 "legacy board ID: 0x%08x\n",
756062306a36Sopenharmony_ci				 *board_id);
756162306a36Sopenharmony_ci			if (legacy_board)
756262306a36Sopenharmony_ci			    *legacy_board = true;
756362306a36Sopenharmony_ci			return i;
756462306a36Sopenharmony_ci		}
756562306a36Sopenharmony_ci
756662306a36Sopenharmony_ci	dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x\n", *board_id);
756762306a36Sopenharmony_ci	if (legacy_board)
756862306a36Sopenharmony_ci		*legacy_board = true;
756962306a36Sopenharmony_ci	return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
757062306a36Sopenharmony_ci}
757162306a36Sopenharmony_ci
757262306a36Sopenharmony_cistatic int hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
757362306a36Sopenharmony_ci				    unsigned long *memory_bar)
757462306a36Sopenharmony_ci{
757562306a36Sopenharmony_ci	int i;
757662306a36Sopenharmony_ci
757762306a36Sopenharmony_ci	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
757862306a36Sopenharmony_ci		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
757962306a36Sopenharmony_ci			/* addressing mode bits already removed */
758062306a36Sopenharmony_ci			*memory_bar = pci_resource_start(pdev, i);
758162306a36Sopenharmony_ci			dev_dbg(&pdev->dev, "memory BAR = %lx\n",
758262306a36Sopenharmony_ci				*memory_bar);
758362306a36Sopenharmony_ci			return 0;
758462306a36Sopenharmony_ci		}
758562306a36Sopenharmony_ci	dev_warn(&pdev->dev, "no memory BAR found\n");
758662306a36Sopenharmony_ci	return -ENODEV;
758762306a36Sopenharmony_ci}
758862306a36Sopenharmony_ci
758962306a36Sopenharmony_cistatic int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
759062306a36Sopenharmony_ci				     int wait_for_ready)
759162306a36Sopenharmony_ci{
759262306a36Sopenharmony_ci	int i, iterations;
759362306a36Sopenharmony_ci	u32 scratchpad;
759462306a36Sopenharmony_ci	if (wait_for_ready)
759562306a36Sopenharmony_ci		iterations = HPSA_BOARD_READY_ITERATIONS;
759662306a36Sopenharmony_ci	else
759762306a36Sopenharmony_ci		iterations = HPSA_BOARD_NOT_READY_ITERATIONS;
759862306a36Sopenharmony_ci
759962306a36Sopenharmony_ci	for (i = 0; i < iterations; i++) {
760062306a36Sopenharmony_ci		scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
760162306a36Sopenharmony_ci		if (wait_for_ready) {
760262306a36Sopenharmony_ci			if (scratchpad == HPSA_FIRMWARE_READY)
760362306a36Sopenharmony_ci				return 0;
760462306a36Sopenharmony_ci		} else {
760562306a36Sopenharmony_ci			if (scratchpad != HPSA_FIRMWARE_READY)
760662306a36Sopenharmony_ci				return 0;
760762306a36Sopenharmony_ci		}
760862306a36Sopenharmony_ci		msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
760962306a36Sopenharmony_ci	}
761062306a36Sopenharmony_ci	dev_warn(&pdev->dev, "board not ready, timed out.\n");
761162306a36Sopenharmony_ci	return -ENODEV;
761262306a36Sopenharmony_ci}
761362306a36Sopenharmony_ci
761462306a36Sopenharmony_cistatic int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
761562306a36Sopenharmony_ci			       u32 *cfg_base_addr, u64 *cfg_base_addr_index,
761662306a36Sopenharmony_ci			       u64 *cfg_offset)
761762306a36Sopenharmony_ci{
761862306a36Sopenharmony_ci	*cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
761962306a36Sopenharmony_ci	*cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
762062306a36Sopenharmony_ci	*cfg_base_addr &= (u32) 0x0000ffff;
762162306a36Sopenharmony_ci	*cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
762262306a36Sopenharmony_ci	if (*cfg_base_addr_index == -1) {
762362306a36Sopenharmony_ci		dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
762462306a36Sopenharmony_ci		return -ENODEV;
762562306a36Sopenharmony_ci	}
762662306a36Sopenharmony_ci	return 0;
762762306a36Sopenharmony_ci}
762862306a36Sopenharmony_ci
762962306a36Sopenharmony_cistatic void hpsa_free_cfgtables(struct ctlr_info *h)
763062306a36Sopenharmony_ci{
763162306a36Sopenharmony_ci	if (h->transtable) {
763262306a36Sopenharmony_ci		iounmap(h->transtable);
763362306a36Sopenharmony_ci		h->transtable = NULL;
763462306a36Sopenharmony_ci	}
763562306a36Sopenharmony_ci	if (h->cfgtable) {
763662306a36Sopenharmony_ci		iounmap(h->cfgtable);
763762306a36Sopenharmony_ci		h->cfgtable = NULL;
763862306a36Sopenharmony_ci	}
763962306a36Sopenharmony_ci}
764062306a36Sopenharmony_ci
764162306a36Sopenharmony_ci/* Find and map CISS config table and transfer table
764262306a36Sopenharmony_ci+ * several items must be unmapped (freed) later
764362306a36Sopenharmony_ci+ * */
764462306a36Sopenharmony_cistatic int hpsa_find_cfgtables(struct ctlr_info *h)
764562306a36Sopenharmony_ci{
764662306a36Sopenharmony_ci	u64 cfg_offset;
764762306a36Sopenharmony_ci	u32 cfg_base_addr;
764862306a36Sopenharmony_ci	u64 cfg_base_addr_index;
764962306a36Sopenharmony_ci	u32 trans_offset;
765062306a36Sopenharmony_ci	int rc;
765162306a36Sopenharmony_ci
765262306a36Sopenharmony_ci	rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
765362306a36Sopenharmony_ci		&cfg_base_addr_index, &cfg_offset);
765462306a36Sopenharmony_ci	if (rc)
765562306a36Sopenharmony_ci		return rc;
765662306a36Sopenharmony_ci	h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
765762306a36Sopenharmony_ci		       cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
765862306a36Sopenharmony_ci	if (!h->cfgtable) {
765962306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "Failed mapping cfgtable\n");
766062306a36Sopenharmony_ci		return -ENOMEM;
766162306a36Sopenharmony_ci	}
766262306a36Sopenharmony_ci	rc = write_driver_ver_to_cfgtable(h->cfgtable);
766362306a36Sopenharmony_ci	if (rc)
766462306a36Sopenharmony_ci		return rc;
766562306a36Sopenharmony_ci	/* Find performant mode table. */
766662306a36Sopenharmony_ci	trans_offset = readl(&h->cfgtable->TransMethodOffset);
766762306a36Sopenharmony_ci	h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
766862306a36Sopenharmony_ci				cfg_base_addr_index)+cfg_offset+trans_offset,
766962306a36Sopenharmony_ci				sizeof(*h->transtable));
767062306a36Sopenharmony_ci	if (!h->transtable) {
767162306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "Failed mapping transfer table\n");
767262306a36Sopenharmony_ci		hpsa_free_cfgtables(h);
767362306a36Sopenharmony_ci		return -ENOMEM;
767462306a36Sopenharmony_ci	}
767562306a36Sopenharmony_ci	return 0;
767662306a36Sopenharmony_ci}
767762306a36Sopenharmony_ci
767862306a36Sopenharmony_cistatic void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
767962306a36Sopenharmony_ci{
768062306a36Sopenharmony_ci#define MIN_MAX_COMMANDS 16
768162306a36Sopenharmony_ci	BUILD_BUG_ON(MIN_MAX_COMMANDS <= HPSA_NRESERVED_CMDS);
768262306a36Sopenharmony_ci
768362306a36Sopenharmony_ci	h->max_commands = readl(&h->cfgtable->MaxPerformantModeCommands);
768462306a36Sopenharmony_ci
768562306a36Sopenharmony_ci	/* Limit commands in memory limited kdump scenario. */
768662306a36Sopenharmony_ci	if (reset_devices && h->max_commands > 32)
768762306a36Sopenharmony_ci		h->max_commands = 32;
768862306a36Sopenharmony_ci
768962306a36Sopenharmony_ci	if (h->max_commands < MIN_MAX_COMMANDS) {
769062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
769162306a36Sopenharmony_ci			"Controller reports max supported commands of %d Using %d instead. Ensure that firmware is up to date.\n",
769262306a36Sopenharmony_ci			h->max_commands,
769362306a36Sopenharmony_ci			MIN_MAX_COMMANDS);
769462306a36Sopenharmony_ci		h->max_commands = MIN_MAX_COMMANDS;
769562306a36Sopenharmony_ci	}
769662306a36Sopenharmony_ci}
769762306a36Sopenharmony_ci
769862306a36Sopenharmony_ci/* If the controller reports that the total max sg entries is greater than 512,
769962306a36Sopenharmony_ci * then we know that chained SG blocks work.  (Original smart arrays did not
770062306a36Sopenharmony_ci * support chained SG blocks and would return zero for max sg entries.)
770162306a36Sopenharmony_ci */
770262306a36Sopenharmony_cistatic int hpsa_supports_chained_sg_blocks(struct ctlr_info *h)
770362306a36Sopenharmony_ci{
770462306a36Sopenharmony_ci	return h->maxsgentries > 512;
770562306a36Sopenharmony_ci}
770662306a36Sopenharmony_ci
770762306a36Sopenharmony_ci/* Interrogate the hardware for some limits:
770862306a36Sopenharmony_ci * max commands, max SG elements without chaining, and with chaining,
770962306a36Sopenharmony_ci * SG chain block size, etc.
771062306a36Sopenharmony_ci */
771162306a36Sopenharmony_cistatic void hpsa_find_board_params(struct ctlr_info *h)
771262306a36Sopenharmony_ci{
771362306a36Sopenharmony_ci	hpsa_get_max_perf_mode_cmds(h);
771462306a36Sopenharmony_ci	h->nr_cmds = h->max_commands;
771562306a36Sopenharmony_ci	h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
771662306a36Sopenharmony_ci	h->fw_support = readl(&(h->cfgtable->misc_fw_support));
771762306a36Sopenharmony_ci	if (hpsa_supports_chained_sg_blocks(h)) {
771862306a36Sopenharmony_ci		/* Limit in-command s/g elements to 32 save dma'able memory. */
771962306a36Sopenharmony_ci		h->max_cmd_sg_entries = 32;
772062306a36Sopenharmony_ci		h->chainsize = h->maxsgentries - h->max_cmd_sg_entries;
772162306a36Sopenharmony_ci		h->maxsgentries--; /* save one for chain pointer */
772262306a36Sopenharmony_ci	} else {
772362306a36Sopenharmony_ci		/*
772462306a36Sopenharmony_ci		 * Original smart arrays supported at most 31 s/g entries
772562306a36Sopenharmony_ci		 * embedded inline in the command (trying to use more
772662306a36Sopenharmony_ci		 * would lock up the controller)
772762306a36Sopenharmony_ci		 */
772862306a36Sopenharmony_ci		h->max_cmd_sg_entries = 31;
772962306a36Sopenharmony_ci		h->maxsgentries = 31; /* default to traditional values */
773062306a36Sopenharmony_ci		h->chainsize = 0;
773162306a36Sopenharmony_ci	}
773262306a36Sopenharmony_ci
773362306a36Sopenharmony_ci	/* Find out what task management functions are supported and cache */
773462306a36Sopenharmony_ci	h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
773562306a36Sopenharmony_ci	if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags))
773662306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Physical aborts not supported\n");
773762306a36Sopenharmony_ci	if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
773862306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Logical aborts not supported\n");
773962306a36Sopenharmony_ci	if (!(HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags))
774062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "HP SSD Smart Path aborts not supported\n");
774162306a36Sopenharmony_ci}
774262306a36Sopenharmony_ci
774362306a36Sopenharmony_cistatic inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
774462306a36Sopenharmony_ci{
774562306a36Sopenharmony_ci	if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
774662306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "not a valid CISS config table\n");
774762306a36Sopenharmony_ci		return false;
774862306a36Sopenharmony_ci	}
774962306a36Sopenharmony_ci	return true;
775062306a36Sopenharmony_ci}
775162306a36Sopenharmony_ci
775262306a36Sopenharmony_cistatic inline void hpsa_set_driver_support_bits(struct ctlr_info *h)
775362306a36Sopenharmony_ci{
775462306a36Sopenharmony_ci	u32 driver_support;
775562306a36Sopenharmony_ci
775662306a36Sopenharmony_ci	driver_support = readl(&(h->cfgtable->driver_support));
775762306a36Sopenharmony_ci	/* Need to enable prefetch in the SCSI core for 6400 in x86 */
775862306a36Sopenharmony_ci#ifdef CONFIG_X86
775962306a36Sopenharmony_ci	driver_support |= ENABLE_SCSI_PREFETCH;
776062306a36Sopenharmony_ci#endif
776162306a36Sopenharmony_ci	driver_support |= ENABLE_UNIT_ATTN;
776262306a36Sopenharmony_ci	writel(driver_support, &(h->cfgtable->driver_support));
776362306a36Sopenharmony_ci}
776462306a36Sopenharmony_ci
776562306a36Sopenharmony_ci/* Disable DMA prefetch for the P600.  Otherwise an ASIC bug may result
776662306a36Sopenharmony_ci * in a prefetch beyond physical memory.
776762306a36Sopenharmony_ci */
776862306a36Sopenharmony_cistatic inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
776962306a36Sopenharmony_ci{
777062306a36Sopenharmony_ci	u32 dma_prefetch;
777162306a36Sopenharmony_ci
777262306a36Sopenharmony_ci	if (h->board_id != 0x3225103C)
777362306a36Sopenharmony_ci		return;
777462306a36Sopenharmony_ci	dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
777562306a36Sopenharmony_ci	dma_prefetch |= 0x8000;
777662306a36Sopenharmony_ci	writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
777762306a36Sopenharmony_ci}
777862306a36Sopenharmony_ci
777962306a36Sopenharmony_cistatic int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
778062306a36Sopenharmony_ci{
778162306a36Sopenharmony_ci	int i;
778262306a36Sopenharmony_ci	u32 doorbell_value;
778362306a36Sopenharmony_ci	unsigned long flags;
778462306a36Sopenharmony_ci	/* wait until the clear_event_notify bit 6 is cleared by controller. */
778562306a36Sopenharmony_ci	for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) {
778662306a36Sopenharmony_ci		spin_lock_irqsave(&h->lock, flags);
778762306a36Sopenharmony_ci		doorbell_value = readl(h->vaddr + SA5_DOORBELL);
778862306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
778962306a36Sopenharmony_ci		if (!(doorbell_value & DOORBELL_CLEAR_EVENTS))
779062306a36Sopenharmony_ci			goto done;
779162306a36Sopenharmony_ci		/* delay and try again */
779262306a36Sopenharmony_ci		msleep(CLEAR_EVENT_WAIT_INTERVAL);
779362306a36Sopenharmony_ci	}
779462306a36Sopenharmony_ci	return -ENODEV;
779562306a36Sopenharmony_cidone:
779662306a36Sopenharmony_ci	return 0;
779762306a36Sopenharmony_ci}
779862306a36Sopenharmony_ci
779962306a36Sopenharmony_cistatic int hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
780062306a36Sopenharmony_ci{
780162306a36Sopenharmony_ci	int i;
780262306a36Sopenharmony_ci	u32 doorbell_value;
780362306a36Sopenharmony_ci	unsigned long flags;
780462306a36Sopenharmony_ci
780562306a36Sopenharmony_ci	/* under certain very rare conditions, this can take awhile.
780662306a36Sopenharmony_ci	 * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
780762306a36Sopenharmony_ci	 * as we enter this code.)
780862306a36Sopenharmony_ci	 */
780962306a36Sopenharmony_ci	for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) {
781062306a36Sopenharmony_ci		if (h->remove_in_progress)
781162306a36Sopenharmony_ci			goto done;
781262306a36Sopenharmony_ci		spin_lock_irqsave(&h->lock, flags);
781362306a36Sopenharmony_ci		doorbell_value = readl(h->vaddr + SA5_DOORBELL);
781462306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
781562306a36Sopenharmony_ci		if (!(doorbell_value & CFGTBL_ChangeReq))
781662306a36Sopenharmony_ci			goto done;
781762306a36Sopenharmony_ci		/* delay and try again */
781862306a36Sopenharmony_ci		msleep(MODE_CHANGE_WAIT_INTERVAL);
781962306a36Sopenharmony_ci	}
782062306a36Sopenharmony_ci	return -ENODEV;
782162306a36Sopenharmony_cidone:
782262306a36Sopenharmony_ci	return 0;
782362306a36Sopenharmony_ci}
782462306a36Sopenharmony_ci
782562306a36Sopenharmony_ci/* return -ENODEV or other reason on error, 0 on success */
782662306a36Sopenharmony_cistatic int hpsa_enter_simple_mode(struct ctlr_info *h)
782762306a36Sopenharmony_ci{
782862306a36Sopenharmony_ci	u32 trans_support;
782962306a36Sopenharmony_ci
783062306a36Sopenharmony_ci	trans_support = readl(&(h->cfgtable->TransportSupport));
783162306a36Sopenharmony_ci	if (!(trans_support & SIMPLE_MODE))
783262306a36Sopenharmony_ci		return -ENOTSUPP;
783362306a36Sopenharmony_ci
783462306a36Sopenharmony_ci	h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
783562306a36Sopenharmony_ci
783662306a36Sopenharmony_ci	/* Update the field, and then ring the doorbell */
783762306a36Sopenharmony_ci	writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
783862306a36Sopenharmony_ci	writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
783962306a36Sopenharmony_ci	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
784062306a36Sopenharmony_ci	if (hpsa_wait_for_mode_change_ack(h))
784162306a36Sopenharmony_ci		goto error;
784262306a36Sopenharmony_ci	print_cfg_table(&h->pdev->dev, h->cfgtable);
784362306a36Sopenharmony_ci	if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
784462306a36Sopenharmony_ci		goto error;
784562306a36Sopenharmony_ci	h->transMethod = CFGTBL_Trans_Simple;
784662306a36Sopenharmony_ci	return 0;
784762306a36Sopenharmony_cierror:
784862306a36Sopenharmony_ci	dev_err(&h->pdev->dev, "failed to enter simple mode\n");
784962306a36Sopenharmony_ci	return -ENODEV;
785062306a36Sopenharmony_ci}
785162306a36Sopenharmony_ci
785262306a36Sopenharmony_ci/* free items allocated or mapped by hpsa_pci_init */
785362306a36Sopenharmony_cistatic void hpsa_free_pci_init(struct ctlr_info *h)
785462306a36Sopenharmony_ci{
785562306a36Sopenharmony_ci	hpsa_free_cfgtables(h);			/* pci_init 4 */
785662306a36Sopenharmony_ci	iounmap(h->vaddr);			/* pci_init 3 */
785762306a36Sopenharmony_ci	h->vaddr = NULL;
785862306a36Sopenharmony_ci	hpsa_disable_interrupt_mode(h);		/* pci_init 2 */
785962306a36Sopenharmony_ci	/*
786062306a36Sopenharmony_ci	 * call pci_disable_device before pci_release_regions per
786162306a36Sopenharmony_ci	 * Documentation/driver-api/pci/pci.rst
786262306a36Sopenharmony_ci	 */
786362306a36Sopenharmony_ci	pci_disable_device(h->pdev);		/* pci_init 1 */
786462306a36Sopenharmony_ci	pci_release_regions(h->pdev);		/* pci_init 2 */
786562306a36Sopenharmony_ci}
786662306a36Sopenharmony_ci
786762306a36Sopenharmony_ci/* several items must be freed later */
786862306a36Sopenharmony_cistatic int hpsa_pci_init(struct ctlr_info *h)
786962306a36Sopenharmony_ci{
787062306a36Sopenharmony_ci	int prod_index, err;
787162306a36Sopenharmony_ci	bool legacy_board;
787262306a36Sopenharmony_ci
787362306a36Sopenharmony_ci	prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id, &legacy_board);
787462306a36Sopenharmony_ci	if (prod_index < 0)
787562306a36Sopenharmony_ci		return prod_index;
787662306a36Sopenharmony_ci	h->product_name = products[prod_index].product_name;
787762306a36Sopenharmony_ci	h->access = *(products[prod_index].access);
787862306a36Sopenharmony_ci	h->legacy_board = legacy_board;
787962306a36Sopenharmony_ci	pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S |
788062306a36Sopenharmony_ci			       PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM);
788162306a36Sopenharmony_ci
788262306a36Sopenharmony_ci	err = pci_enable_device(h->pdev);
788362306a36Sopenharmony_ci	if (err) {
788462306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "failed to enable PCI device\n");
788562306a36Sopenharmony_ci		pci_disable_device(h->pdev);
788662306a36Sopenharmony_ci		return err;
788762306a36Sopenharmony_ci	}
788862306a36Sopenharmony_ci
788962306a36Sopenharmony_ci	err = pci_request_regions(h->pdev, HPSA);
789062306a36Sopenharmony_ci	if (err) {
789162306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
789262306a36Sopenharmony_ci			"failed to obtain PCI resources\n");
789362306a36Sopenharmony_ci		pci_disable_device(h->pdev);
789462306a36Sopenharmony_ci		return err;
789562306a36Sopenharmony_ci	}
789662306a36Sopenharmony_ci
789762306a36Sopenharmony_ci	pci_set_master(h->pdev);
789862306a36Sopenharmony_ci
789962306a36Sopenharmony_ci	err = hpsa_interrupt_mode(h);
790062306a36Sopenharmony_ci	if (err)
790162306a36Sopenharmony_ci		goto clean1;
790262306a36Sopenharmony_ci
790362306a36Sopenharmony_ci	/* setup mapping between CPU and reply queue */
790462306a36Sopenharmony_ci	hpsa_setup_reply_map(h);
790562306a36Sopenharmony_ci
790662306a36Sopenharmony_ci	err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
790762306a36Sopenharmony_ci	if (err)
790862306a36Sopenharmony_ci		goto clean2;	/* intmode+region, pci */
790962306a36Sopenharmony_ci	h->vaddr = remap_pci_mem(h->paddr, 0x250);
791062306a36Sopenharmony_ci	if (!h->vaddr) {
791162306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "failed to remap PCI mem\n");
791262306a36Sopenharmony_ci		err = -ENOMEM;
791362306a36Sopenharmony_ci		goto clean2;	/* intmode+region, pci */
791462306a36Sopenharmony_ci	}
791562306a36Sopenharmony_ci	err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
791662306a36Sopenharmony_ci	if (err)
791762306a36Sopenharmony_ci		goto clean3;	/* vaddr, intmode+region, pci */
791862306a36Sopenharmony_ci	err = hpsa_find_cfgtables(h);
791962306a36Sopenharmony_ci	if (err)
792062306a36Sopenharmony_ci		goto clean3;	/* vaddr, intmode+region, pci */
792162306a36Sopenharmony_ci	hpsa_find_board_params(h);
792262306a36Sopenharmony_ci
792362306a36Sopenharmony_ci	if (!hpsa_CISS_signature_present(h)) {
792462306a36Sopenharmony_ci		err = -ENODEV;
792562306a36Sopenharmony_ci		goto clean4;	/* cfgtables, vaddr, intmode+region, pci */
792662306a36Sopenharmony_ci	}
792762306a36Sopenharmony_ci	hpsa_set_driver_support_bits(h);
792862306a36Sopenharmony_ci	hpsa_p600_dma_prefetch_quirk(h);
792962306a36Sopenharmony_ci	err = hpsa_enter_simple_mode(h);
793062306a36Sopenharmony_ci	if (err)
793162306a36Sopenharmony_ci		goto clean4;	/* cfgtables, vaddr, intmode+region, pci */
793262306a36Sopenharmony_ci	return 0;
793362306a36Sopenharmony_ci
793462306a36Sopenharmony_ciclean4:	/* cfgtables, vaddr, intmode+region, pci */
793562306a36Sopenharmony_ci	hpsa_free_cfgtables(h);
793662306a36Sopenharmony_ciclean3:	/* vaddr, intmode+region, pci */
793762306a36Sopenharmony_ci	iounmap(h->vaddr);
793862306a36Sopenharmony_ci	h->vaddr = NULL;
793962306a36Sopenharmony_ciclean2:	/* intmode+region, pci */
794062306a36Sopenharmony_ci	hpsa_disable_interrupt_mode(h);
794162306a36Sopenharmony_ciclean1:
794262306a36Sopenharmony_ci	/*
794362306a36Sopenharmony_ci	 * call pci_disable_device before pci_release_regions per
794462306a36Sopenharmony_ci	 * Documentation/driver-api/pci/pci.rst
794562306a36Sopenharmony_ci	 */
794662306a36Sopenharmony_ci	pci_disable_device(h->pdev);
794762306a36Sopenharmony_ci	pci_release_regions(h->pdev);
794862306a36Sopenharmony_ci	return err;
794962306a36Sopenharmony_ci}
795062306a36Sopenharmony_ci
795162306a36Sopenharmony_cistatic void hpsa_hba_inquiry(struct ctlr_info *h)
795262306a36Sopenharmony_ci{
795362306a36Sopenharmony_ci	int rc;
795462306a36Sopenharmony_ci
795562306a36Sopenharmony_ci#define HBA_INQUIRY_BYTE_COUNT 64
795662306a36Sopenharmony_ci	h->hba_inquiry_data = kmalloc(HBA_INQUIRY_BYTE_COUNT, GFP_KERNEL);
795762306a36Sopenharmony_ci	if (!h->hba_inquiry_data)
795862306a36Sopenharmony_ci		return;
795962306a36Sopenharmony_ci	rc = hpsa_scsi_do_inquiry(h, RAID_CTLR_LUNID, 0,
796062306a36Sopenharmony_ci		h->hba_inquiry_data, HBA_INQUIRY_BYTE_COUNT);
796162306a36Sopenharmony_ci	if (rc != 0) {
796262306a36Sopenharmony_ci		kfree(h->hba_inquiry_data);
796362306a36Sopenharmony_ci		h->hba_inquiry_data = NULL;
796462306a36Sopenharmony_ci	}
796562306a36Sopenharmony_ci}
796662306a36Sopenharmony_ci
796762306a36Sopenharmony_cistatic int hpsa_init_reset_devices(struct pci_dev *pdev, u32 board_id)
796862306a36Sopenharmony_ci{
796962306a36Sopenharmony_ci	int rc, i;
797062306a36Sopenharmony_ci	void __iomem *vaddr;
797162306a36Sopenharmony_ci
797262306a36Sopenharmony_ci	if (!reset_devices)
797362306a36Sopenharmony_ci		return 0;
797462306a36Sopenharmony_ci
797562306a36Sopenharmony_ci	/* kdump kernel is loading, we don't know in which state is
797662306a36Sopenharmony_ci	 * the pci interface. The dev->enable_cnt is equal zero
797762306a36Sopenharmony_ci	 * so we call enable+disable, wait a while and switch it on.
797862306a36Sopenharmony_ci	 */
797962306a36Sopenharmony_ci	rc = pci_enable_device(pdev);
798062306a36Sopenharmony_ci	if (rc) {
798162306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to enable PCI device\n");
798262306a36Sopenharmony_ci		return -ENODEV;
798362306a36Sopenharmony_ci	}
798462306a36Sopenharmony_ci	pci_disable_device(pdev);
798562306a36Sopenharmony_ci	msleep(260);			/* a randomly chosen number */
798662306a36Sopenharmony_ci	rc = pci_enable_device(pdev);
798762306a36Sopenharmony_ci	if (rc) {
798862306a36Sopenharmony_ci		dev_warn(&pdev->dev, "failed to enable device.\n");
798962306a36Sopenharmony_ci		return -ENODEV;
799062306a36Sopenharmony_ci	}
799162306a36Sopenharmony_ci
799262306a36Sopenharmony_ci	pci_set_master(pdev);
799362306a36Sopenharmony_ci
799462306a36Sopenharmony_ci	vaddr = pci_ioremap_bar(pdev, 0);
799562306a36Sopenharmony_ci	if (vaddr == NULL) {
799662306a36Sopenharmony_ci		rc = -ENOMEM;
799762306a36Sopenharmony_ci		goto out_disable;
799862306a36Sopenharmony_ci	}
799962306a36Sopenharmony_ci	writel(SA5_INTR_OFF, vaddr + SA5_REPLY_INTR_MASK_OFFSET);
800062306a36Sopenharmony_ci	iounmap(vaddr);
800162306a36Sopenharmony_ci
800262306a36Sopenharmony_ci	/* Reset the controller with a PCI power-cycle or via doorbell */
800362306a36Sopenharmony_ci	rc = hpsa_kdump_hard_reset_controller(pdev, board_id);
800462306a36Sopenharmony_ci
800562306a36Sopenharmony_ci	/* -ENOTSUPP here means we cannot reset the controller
800662306a36Sopenharmony_ci	 * but it's already (and still) up and running in
800762306a36Sopenharmony_ci	 * "performant mode".  Or, it might be 640x, which can't reset
800862306a36Sopenharmony_ci	 * due to concerns about shared bbwc between 6402/6404 pair.
800962306a36Sopenharmony_ci	 */
801062306a36Sopenharmony_ci	if (rc)
801162306a36Sopenharmony_ci		goto out_disable;
801262306a36Sopenharmony_ci
801362306a36Sopenharmony_ci	/* Now try to get the controller to respond to a no-op */
801462306a36Sopenharmony_ci	dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n");
801562306a36Sopenharmony_ci	for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
801662306a36Sopenharmony_ci		if (hpsa_noop(pdev) == 0)
801762306a36Sopenharmony_ci			break;
801862306a36Sopenharmony_ci		else
801962306a36Sopenharmony_ci			dev_warn(&pdev->dev, "no-op failed%s\n",
802062306a36Sopenharmony_ci					(i < 11 ? "; re-trying" : ""));
802162306a36Sopenharmony_ci	}
802262306a36Sopenharmony_ci
802362306a36Sopenharmony_ciout_disable:
802462306a36Sopenharmony_ci
802562306a36Sopenharmony_ci	pci_disable_device(pdev);
802662306a36Sopenharmony_ci	return rc;
802762306a36Sopenharmony_ci}
802862306a36Sopenharmony_ci
802962306a36Sopenharmony_cistatic void hpsa_free_cmd_pool(struct ctlr_info *h)
803062306a36Sopenharmony_ci{
803162306a36Sopenharmony_ci	bitmap_free(h->cmd_pool_bits);
803262306a36Sopenharmony_ci	h->cmd_pool_bits = NULL;
803362306a36Sopenharmony_ci	if (h->cmd_pool) {
803462306a36Sopenharmony_ci		dma_free_coherent(&h->pdev->dev,
803562306a36Sopenharmony_ci				h->nr_cmds * sizeof(struct CommandList),
803662306a36Sopenharmony_ci				h->cmd_pool,
803762306a36Sopenharmony_ci				h->cmd_pool_dhandle);
803862306a36Sopenharmony_ci		h->cmd_pool = NULL;
803962306a36Sopenharmony_ci		h->cmd_pool_dhandle = 0;
804062306a36Sopenharmony_ci	}
804162306a36Sopenharmony_ci	if (h->errinfo_pool) {
804262306a36Sopenharmony_ci		dma_free_coherent(&h->pdev->dev,
804362306a36Sopenharmony_ci				h->nr_cmds * sizeof(struct ErrorInfo),
804462306a36Sopenharmony_ci				h->errinfo_pool,
804562306a36Sopenharmony_ci				h->errinfo_pool_dhandle);
804662306a36Sopenharmony_ci		h->errinfo_pool = NULL;
804762306a36Sopenharmony_ci		h->errinfo_pool_dhandle = 0;
804862306a36Sopenharmony_ci	}
804962306a36Sopenharmony_ci}
805062306a36Sopenharmony_ci
805162306a36Sopenharmony_cistatic int hpsa_alloc_cmd_pool(struct ctlr_info *h)
805262306a36Sopenharmony_ci{
805362306a36Sopenharmony_ci	h->cmd_pool_bits = bitmap_zalloc(h->nr_cmds, GFP_KERNEL);
805462306a36Sopenharmony_ci	h->cmd_pool = dma_alloc_coherent(&h->pdev->dev,
805562306a36Sopenharmony_ci		    h->nr_cmds * sizeof(*h->cmd_pool),
805662306a36Sopenharmony_ci		    &h->cmd_pool_dhandle, GFP_KERNEL);
805762306a36Sopenharmony_ci	h->errinfo_pool = dma_alloc_coherent(&h->pdev->dev,
805862306a36Sopenharmony_ci		    h->nr_cmds * sizeof(*h->errinfo_pool),
805962306a36Sopenharmony_ci		    &h->errinfo_pool_dhandle, GFP_KERNEL);
806062306a36Sopenharmony_ci	if ((h->cmd_pool_bits == NULL)
806162306a36Sopenharmony_ci	    || (h->cmd_pool == NULL)
806262306a36Sopenharmony_ci	    || (h->errinfo_pool == NULL)) {
806362306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "out of memory in %s", __func__);
806462306a36Sopenharmony_ci		goto clean_up;
806562306a36Sopenharmony_ci	}
806662306a36Sopenharmony_ci	hpsa_preinitialize_commands(h);
806762306a36Sopenharmony_ci	return 0;
806862306a36Sopenharmony_ciclean_up:
806962306a36Sopenharmony_ci	hpsa_free_cmd_pool(h);
807062306a36Sopenharmony_ci	return -ENOMEM;
807162306a36Sopenharmony_ci}
807262306a36Sopenharmony_ci
807362306a36Sopenharmony_ci/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */
807462306a36Sopenharmony_cistatic void hpsa_free_irqs(struct ctlr_info *h)
807562306a36Sopenharmony_ci{
807662306a36Sopenharmony_ci	int i;
807762306a36Sopenharmony_ci	int irq_vector = 0;
807862306a36Sopenharmony_ci
807962306a36Sopenharmony_ci	if (hpsa_simple_mode)
808062306a36Sopenharmony_ci		irq_vector = h->intr_mode;
808162306a36Sopenharmony_ci
808262306a36Sopenharmony_ci	if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) {
808362306a36Sopenharmony_ci		/* Single reply queue, only one irq to free */
808462306a36Sopenharmony_ci		free_irq(pci_irq_vector(h->pdev, irq_vector),
808562306a36Sopenharmony_ci				&h->q[h->intr_mode]);
808662306a36Sopenharmony_ci		h->q[h->intr_mode] = 0;
808762306a36Sopenharmony_ci		return;
808862306a36Sopenharmony_ci	}
808962306a36Sopenharmony_ci
809062306a36Sopenharmony_ci	for (i = 0; i < h->msix_vectors; i++) {
809162306a36Sopenharmony_ci		free_irq(pci_irq_vector(h->pdev, i), &h->q[i]);
809262306a36Sopenharmony_ci		h->q[i] = 0;
809362306a36Sopenharmony_ci	}
809462306a36Sopenharmony_ci	for (; i < MAX_REPLY_QUEUES; i++)
809562306a36Sopenharmony_ci		h->q[i] = 0;
809662306a36Sopenharmony_ci}
809762306a36Sopenharmony_ci
809862306a36Sopenharmony_ci/* returns 0 on success; cleans up and returns -Enn on error */
809962306a36Sopenharmony_cistatic int hpsa_request_irqs(struct ctlr_info *h,
810062306a36Sopenharmony_ci	irqreturn_t (*msixhandler)(int, void *),
810162306a36Sopenharmony_ci	irqreturn_t (*intxhandler)(int, void *))
810262306a36Sopenharmony_ci{
810362306a36Sopenharmony_ci	int rc, i;
810462306a36Sopenharmony_ci	int irq_vector = 0;
810562306a36Sopenharmony_ci
810662306a36Sopenharmony_ci	if (hpsa_simple_mode)
810762306a36Sopenharmony_ci		irq_vector = h->intr_mode;
810862306a36Sopenharmony_ci
810962306a36Sopenharmony_ci	/*
811062306a36Sopenharmony_ci	 * initialize h->q[x] = x so that interrupt handlers know which
811162306a36Sopenharmony_ci	 * queue to process.
811262306a36Sopenharmony_ci	 */
811362306a36Sopenharmony_ci	for (i = 0; i < MAX_REPLY_QUEUES; i++)
811462306a36Sopenharmony_ci		h->q[i] = (u8) i;
811562306a36Sopenharmony_ci
811662306a36Sopenharmony_ci	if (h->intr_mode == PERF_MODE_INT && h->msix_vectors > 0) {
811762306a36Sopenharmony_ci		/* If performant mode and MSI-X, use multiple reply queues */
811862306a36Sopenharmony_ci		for (i = 0; i < h->msix_vectors; i++) {
811962306a36Sopenharmony_ci			sprintf(h->intrname[i], "%s-msix%d", h->devname, i);
812062306a36Sopenharmony_ci			rc = request_irq(pci_irq_vector(h->pdev, i), msixhandler,
812162306a36Sopenharmony_ci					0, h->intrname[i],
812262306a36Sopenharmony_ci					&h->q[i]);
812362306a36Sopenharmony_ci			if (rc) {
812462306a36Sopenharmony_ci				int j;
812562306a36Sopenharmony_ci
812662306a36Sopenharmony_ci				dev_err(&h->pdev->dev,
812762306a36Sopenharmony_ci					"failed to get irq %d for %s\n",
812862306a36Sopenharmony_ci				       pci_irq_vector(h->pdev, i), h->devname);
812962306a36Sopenharmony_ci				for (j = 0; j < i; j++) {
813062306a36Sopenharmony_ci					free_irq(pci_irq_vector(h->pdev, j), &h->q[j]);
813162306a36Sopenharmony_ci					h->q[j] = 0;
813262306a36Sopenharmony_ci				}
813362306a36Sopenharmony_ci				for (; j < MAX_REPLY_QUEUES; j++)
813462306a36Sopenharmony_ci					h->q[j] = 0;
813562306a36Sopenharmony_ci				return rc;
813662306a36Sopenharmony_ci			}
813762306a36Sopenharmony_ci		}
813862306a36Sopenharmony_ci	} else {
813962306a36Sopenharmony_ci		/* Use single reply pool */
814062306a36Sopenharmony_ci		if (h->msix_vectors > 0 || h->pdev->msi_enabled) {
814162306a36Sopenharmony_ci			sprintf(h->intrname[0], "%s-msi%s", h->devname,
814262306a36Sopenharmony_ci				h->msix_vectors ? "x" : "");
814362306a36Sopenharmony_ci			rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
814462306a36Sopenharmony_ci				msixhandler, 0,
814562306a36Sopenharmony_ci				h->intrname[0],
814662306a36Sopenharmony_ci				&h->q[h->intr_mode]);
814762306a36Sopenharmony_ci		} else {
814862306a36Sopenharmony_ci			sprintf(h->intrname[h->intr_mode],
814962306a36Sopenharmony_ci				"%s-intx", h->devname);
815062306a36Sopenharmony_ci			rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
815162306a36Sopenharmony_ci				intxhandler, IRQF_SHARED,
815262306a36Sopenharmony_ci				h->intrname[0],
815362306a36Sopenharmony_ci				&h->q[h->intr_mode]);
815462306a36Sopenharmony_ci		}
815562306a36Sopenharmony_ci	}
815662306a36Sopenharmony_ci	if (rc) {
815762306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
815862306a36Sopenharmony_ci		       pci_irq_vector(h->pdev, irq_vector), h->devname);
815962306a36Sopenharmony_ci		hpsa_free_irqs(h);
816062306a36Sopenharmony_ci		return -ENODEV;
816162306a36Sopenharmony_ci	}
816262306a36Sopenharmony_ci	return 0;
816362306a36Sopenharmony_ci}
816462306a36Sopenharmony_ci
816562306a36Sopenharmony_cistatic int hpsa_kdump_soft_reset(struct ctlr_info *h)
816662306a36Sopenharmony_ci{
816762306a36Sopenharmony_ci	int rc;
816862306a36Sopenharmony_ci	hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER);
816962306a36Sopenharmony_ci
817062306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
817162306a36Sopenharmony_ci	rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY);
817262306a36Sopenharmony_ci	if (rc) {
817362306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Soft reset had no effect.\n");
817462306a36Sopenharmony_ci		return rc;
817562306a36Sopenharmony_ci	}
817662306a36Sopenharmony_ci
817762306a36Sopenharmony_ci	dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
817862306a36Sopenharmony_ci	rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
817962306a36Sopenharmony_ci	if (rc) {
818062306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Board failed to become ready "
818162306a36Sopenharmony_ci			"after soft reset.\n");
818262306a36Sopenharmony_ci		return rc;
818362306a36Sopenharmony_ci	}
818462306a36Sopenharmony_ci
818562306a36Sopenharmony_ci	return 0;
818662306a36Sopenharmony_ci}
818762306a36Sopenharmony_ci
818862306a36Sopenharmony_cistatic void hpsa_free_reply_queues(struct ctlr_info *h)
818962306a36Sopenharmony_ci{
819062306a36Sopenharmony_ci	int i;
819162306a36Sopenharmony_ci
819262306a36Sopenharmony_ci	for (i = 0; i < h->nreply_queues; i++) {
819362306a36Sopenharmony_ci		if (!h->reply_queue[i].head)
819462306a36Sopenharmony_ci			continue;
819562306a36Sopenharmony_ci		dma_free_coherent(&h->pdev->dev,
819662306a36Sopenharmony_ci					h->reply_queue_size,
819762306a36Sopenharmony_ci					h->reply_queue[i].head,
819862306a36Sopenharmony_ci					h->reply_queue[i].busaddr);
819962306a36Sopenharmony_ci		h->reply_queue[i].head = NULL;
820062306a36Sopenharmony_ci		h->reply_queue[i].busaddr = 0;
820162306a36Sopenharmony_ci	}
820262306a36Sopenharmony_ci	h->reply_queue_size = 0;
820362306a36Sopenharmony_ci}
820462306a36Sopenharmony_ci
820562306a36Sopenharmony_cistatic void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
820662306a36Sopenharmony_ci{
820762306a36Sopenharmony_ci	hpsa_free_performant_mode(h);		/* init_one 7 */
820862306a36Sopenharmony_ci	hpsa_free_sg_chain_blocks(h);		/* init_one 6 */
820962306a36Sopenharmony_ci	hpsa_free_cmd_pool(h);			/* init_one 5 */
821062306a36Sopenharmony_ci	hpsa_free_irqs(h);			/* init_one 4 */
821162306a36Sopenharmony_ci	scsi_host_put(h->scsi_host);		/* init_one 3 */
821262306a36Sopenharmony_ci	h->scsi_host = NULL;			/* init_one 3 */
821362306a36Sopenharmony_ci	hpsa_free_pci_init(h);			/* init_one 2_5 */
821462306a36Sopenharmony_ci	free_percpu(h->lockup_detected);	/* init_one 2 */
821562306a36Sopenharmony_ci	h->lockup_detected = NULL;		/* init_one 2 */
821662306a36Sopenharmony_ci	if (h->resubmit_wq) {
821762306a36Sopenharmony_ci		destroy_workqueue(h->resubmit_wq);	/* init_one 1 */
821862306a36Sopenharmony_ci		h->resubmit_wq = NULL;
821962306a36Sopenharmony_ci	}
822062306a36Sopenharmony_ci	if (h->rescan_ctlr_wq) {
822162306a36Sopenharmony_ci		destroy_workqueue(h->rescan_ctlr_wq);
822262306a36Sopenharmony_ci		h->rescan_ctlr_wq = NULL;
822362306a36Sopenharmony_ci	}
822462306a36Sopenharmony_ci	if (h->monitor_ctlr_wq) {
822562306a36Sopenharmony_ci		destroy_workqueue(h->monitor_ctlr_wq);
822662306a36Sopenharmony_ci		h->monitor_ctlr_wq = NULL;
822762306a36Sopenharmony_ci	}
822862306a36Sopenharmony_ci
822962306a36Sopenharmony_ci	kfree(h);				/* init_one 1 */
823062306a36Sopenharmony_ci}
823162306a36Sopenharmony_ci
823262306a36Sopenharmony_ci/* Called when controller lockup detected. */
823362306a36Sopenharmony_cistatic void fail_all_outstanding_cmds(struct ctlr_info *h)
823462306a36Sopenharmony_ci{
823562306a36Sopenharmony_ci	int i, refcount;
823662306a36Sopenharmony_ci	struct CommandList *c;
823762306a36Sopenharmony_ci	int failcount = 0;
823862306a36Sopenharmony_ci
823962306a36Sopenharmony_ci	flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */
824062306a36Sopenharmony_ci	for (i = 0; i < h->nr_cmds; i++) {
824162306a36Sopenharmony_ci		c = h->cmd_pool + i;
824262306a36Sopenharmony_ci		refcount = atomic_inc_return(&c->refcount);
824362306a36Sopenharmony_ci		if (refcount > 1) {
824462306a36Sopenharmony_ci			c->err_info->CommandStatus = CMD_CTLR_LOCKUP;
824562306a36Sopenharmony_ci			finish_cmd(c);
824662306a36Sopenharmony_ci			atomic_dec(&h->commands_outstanding);
824762306a36Sopenharmony_ci			failcount++;
824862306a36Sopenharmony_ci		}
824962306a36Sopenharmony_ci		cmd_free(h, c);
825062306a36Sopenharmony_ci	}
825162306a36Sopenharmony_ci	dev_warn(&h->pdev->dev,
825262306a36Sopenharmony_ci		"failed %d commands in fail_all\n", failcount);
825362306a36Sopenharmony_ci}
825462306a36Sopenharmony_ci
825562306a36Sopenharmony_cistatic void set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value)
825662306a36Sopenharmony_ci{
825762306a36Sopenharmony_ci	int cpu;
825862306a36Sopenharmony_ci
825962306a36Sopenharmony_ci	for_each_online_cpu(cpu) {
826062306a36Sopenharmony_ci		u32 *lockup_detected;
826162306a36Sopenharmony_ci		lockup_detected = per_cpu_ptr(h->lockup_detected, cpu);
826262306a36Sopenharmony_ci		*lockup_detected = value;
826362306a36Sopenharmony_ci	}
826462306a36Sopenharmony_ci	wmb(); /* be sure the per-cpu variables are out to memory */
826562306a36Sopenharmony_ci}
826662306a36Sopenharmony_ci
826762306a36Sopenharmony_cistatic void controller_lockup_detected(struct ctlr_info *h)
826862306a36Sopenharmony_ci{
826962306a36Sopenharmony_ci	unsigned long flags;
827062306a36Sopenharmony_ci	u32 lockup_detected;
827162306a36Sopenharmony_ci
827262306a36Sopenharmony_ci	h->access.set_intr_mask(h, HPSA_INTR_OFF);
827362306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
827462306a36Sopenharmony_ci	lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
827562306a36Sopenharmony_ci	if (!lockup_detected) {
827662306a36Sopenharmony_ci		/* no heartbeat, but controller gave us a zero. */
827762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
827862306a36Sopenharmony_ci			"lockup detected after %d but scratchpad register is zero\n",
827962306a36Sopenharmony_ci			h->heartbeat_sample_interval / HZ);
828062306a36Sopenharmony_ci		lockup_detected = 0xffffffff;
828162306a36Sopenharmony_ci	}
828262306a36Sopenharmony_ci	set_lockup_detected_for_all_cpus(h, lockup_detected);
828362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
828462306a36Sopenharmony_ci	dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x after %d\n",
828562306a36Sopenharmony_ci			lockup_detected, h->heartbeat_sample_interval / HZ);
828662306a36Sopenharmony_ci	if (lockup_detected == 0xffff0000) {
828762306a36Sopenharmony_ci		dev_warn(&h->pdev->dev, "Telling controller to do a CHKPT\n");
828862306a36Sopenharmony_ci		writel(DOORBELL_GENERATE_CHKPT, h->vaddr + SA5_DOORBELL);
828962306a36Sopenharmony_ci	}
829062306a36Sopenharmony_ci	pci_disable_device(h->pdev);
829162306a36Sopenharmony_ci	fail_all_outstanding_cmds(h);
829262306a36Sopenharmony_ci}
829362306a36Sopenharmony_ci
829462306a36Sopenharmony_cistatic int detect_controller_lockup(struct ctlr_info *h)
829562306a36Sopenharmony_ci{
829662306a36Sopenharmony_ci	u64 now;
829762306a36Sopenharmony_ci	u32 heartbeat;
829862306a36Sopenharmony_ci	unsigned long flags;
829962306a36Sopenharmony_ci
830062306a36Sopenharmony_ci	now = get_jiffies_64();
830162306a36Sopenharmony_ci	/* If we've received an interrupt recently, we're ok. */
830262306a36Sopenharmony_ci	if (time_after64(h->last_intr_timestamp +
830362306a36Sopenharmony_ci				(h->heartbeat_sample_interval), now))
830462306a36Sopenharmony_ci		return false;
830562306a36Sopenharmony_ci
830662306a36Sopenharmony_ci	/*
830762306a36Sopenharmony_ci	 * If we've already checked the heartbeat recently, we're ok.
830862306a36Sopenharmony_ci	 * This could happen if someone sends us a signal. We
830962306a36Sopenharmony_ci	 * otherwise don't care about signals in this thread.
831062306a36Sopenharmony_ci	 */
831162306a36Sopenharmony_ci	if (time_after64(h->last_heartbeat_timestamp +
831262306a36Sopenharmony_ci				(h->heartbeat_sample_interval), now))
831362306a36Sopenharmony_ci		return false;
831462306a36Sopenharmony_ci
831562306a36Sopenharmony_ci	/* If heartbeat has not changed since we last looked, we're not ok. */
831662306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
831762306a36Sopenharmony_ci	heartbeat = readl(&h->cfgtable->HeartBeat);
831862306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
831962306a36Sopenharmony_ci	if (h->last_heartbeat == heartbeat) {
832062306a36Sopenharmony_ci		controller_lockup_detected(h);
832162306a36Sopenharmony_ci		return true;
832262306a36Sopenharmony_ci	}
832362306a36Sopenharmony_ci
832462306a36Sopenharmony_ci	/* We're ok. */
832562306a36Sopenharmony_ci	h->last_heartbeat = heartbeat;
832662306a36Sopenharmony_ci	h->last_heartbeat_timestamp = now;
832762306a36Sopenharmony_ci	return false;
832862306a36Sopenharmony_ci}
832962306a36Sopenharmony_ci
833062306a36Sopenharmony_ci/*
833162306a36Sopenharmony_ci * Set ioaccel status for all ioaccel volumes.
833262306a36Sopenharmony_ci *
833362306a36Sopenharmony_ci * Called from monitor controller worker (hpsa_event_monitor_worker)
833462306a36Sopenharmony_ci *
833562306a36Sopenharmony_ci * A Volume (or Volumes that comprise an Array set) may be undergoing a
833662306a36Sopenharmony_ci * transformation, so we will be turning off ioaccel for all volumes that
833762306a36Sopenharmony_ci * make up the Array.
833862306a36Sopenharmony_ci */
833962306a36Sopenharmony_cistatic void hpsa_set_ioaccel_status(struct ctlr_info *h)
834062306a36Sopenharmony_ci{
834162306a36Sopenharmony_ci	int rc;
834262306a36Sopenharmony_ci	int i;
834362306a36Sopenharmony_ci	u8 ioaccel_status;
834462306a36Sopenharmony_ci	unsigned char *buf;
834562306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *device;
834662306a36Sopenharmony_ci
834762306a36Sopenharmony_ci	if (!h)
834862306a36Sopenharmony_ci		return;
834962306a36Sopenharmony_ci
835062306a36Sopenharmony_ci	buf = kmalloc(64, GFP_KERNEL);
835162306a36Sopenharmony_ci	if (!buf)
835262306a36Sopenharmony_ci		return;
835362306a36Sopenharmony_ci
835462306a36Sopenharmony_ci	/*
835562306a36Sopenharmony_ci	 * Run through current device list used during I/O requests.
835662306a36Sopenharmony_ci	 */
835762306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
835862306a36Sopenharmony_ci		int offload_to_be_enabled = 0;
835962306a36Sopenharmony_ci		int offload_config = 0;
836062306a36Sopenharmony_ci
836162306a36Sopenharmony_ci		device = h->dev[i];
836262306a36Sopenharmony_ci
836362306a36Sopenharmony_ci		if (!device)
836462306a36Sopenharmony_ci			continue;
836562306a36Sopenharmony_ci		if (!hpsa_vpd_page_supported(h, device->scsi3addr,
836662306a36Sopenharmony_ci						HPSA_VPD_LV_IOACCEL_STATUS))
836762306a36Sopenharmony_ci			continue;
836862306a36Sopenharmony_ci
836962306a36Sopenharmony_ci		memset(buf, 0, 64);
837062306a36Sopenharmony_ci
837162306a36Sopenharmony_ci		rc = hpsa_scsi_do_inquiry(h, device->scsi3addr,
837262306a36Sopenharmony_ci					VPD_PAGE | HPSA_VPD_LV_IOACCEL_STATUS,
837362306a36Sopenharmony_ci					buf, 64);
837462306a36Sopenharmony_ci		if (rc != 0)
837562306a36Sopenharmony_ci			continue;
837662306a36Sopenharmony_ci
837762306a36Sopenharmony_ci		ioaccel_status = buf[IOACCEL_STATUS_BYTE];
837862306a36Sopenharmony_ci
837962306a36Sopenharmony_ci		/*
838062306a36Sopenharmony_ci		 * Check if offload is still configured on
838162306a36Sopenharmony_ci		 */
838262306a36Sopenharmony_ci		offload_config =
838362306a36Sopenharmony_ci				!!(ioaccel_status & OFFLOAD_CONFIGURED_BIT);
838462306a36Sopenharmony_ci		/*
838562306a36Sopenharmony_ci		 * If offload is configured on, check to see if ioaccel
838662306a36Sopenharmony_ci		 * needs to be enabled.
838762306a36Sopenharmony_ci		 */
838862306a36Sopenharmony_ci		if (offload_config)
838962306a36Sopenharmony_ci			offload_to_be_enabled =
839062306a36Sopenharmony_ci				!!(ioaccel_status & OFFLOAD_ENABLED_BIT);
839162306a36Sopenharmony_ci
839262306a36Sopenharmony_ci		/*
839362306a36Sopenharmony_ci		 * If ioaccel is to be re-enabled, re-enable later during the
839462306a36Sopenharmony_ci		 * scan operation so the driver can get a fresh raidmap
839562306a36Sopenharmony_ci		 * before turning ioaccel back on.
839662306a36Sopenharmony_ci		 */
839762306a36Sopenharmony_ci		if (offload_to_be_enabled)
839862306a36Sopenharmony_ci			continue;
839962306a36Sopenharmony_ci
840062306a36Sopenharmony_ci		/*
840162306a36Sopenharmony_ci		 * Immediately turn off ioaccel for any volume the
840262306a36Sopenharmony_ci		 * controller tells us to. Some of the reasons could be:
840362306a36Sopenharmony_ci		 *    transformation - change to the LVs of an Array.
840462306a36Sopenharmony_ci		 *    degraded volume - component failure
840562306a36Sopenharmony_ci		 */
840662306a36Sopenharmony_ci		hpsa_turn_off_ioaccel_for_device(device);
840762306a36Sopenharmony_ci	}
840862306a36Sopenharmony_ci
840962306a36Sopenharmony_ci	kfree(buf);
841062306a36Sopenharmony_ci}
841162306a36Sopenharmony_ci
841262306a36Sopenharmony_cistatic void hpsa_ack_ctlr_events(struct ctlr_info *h)
841362306a36Sopenharmony_ci{
841462306a36Sopenharmony_ci	char *event_type;
841562306a36Sopenharmony_ci
841662306a36Sopenharmony_ci	if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
841762306a36Sopenharmony_ci		return;
841862306a36Sopenharmony_ci
841962306a36Sopenharmony_ci	/* Ask the controller to clear the events we're handling. */
842062306a36Sopenharmony_ci	if ((h->transMethod & (CFGTBL_Trans_io_accel1
842162306a36Sopenharmony_ci			| CFGTBL_Trans_io_accel2)) &&
842262306a36Sopenharmony_ci		(h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
842362306a36Sopenharmony_ci		 h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
842462306a36Sopenharmony_ci
842562306a36Sopenharmony_ci		if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
842662306a36Sopenharmony_ci			event_type = "state change";
842762306a36Sopenharmony_ci		if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
842862306a36Sopenharmony_ci			event_type = "configuration change";
842962306a36Sopenharmony_ci		/* Stop sending new RAID offload reqs via the IO accelerator */
843062306a36Sopenharmony_ci		scsi_block_requests(h->scsi_host);
843162306a36Sopenharmony_ci		hpsa_set_ioaccel_status(h);
843262306a36Sopenharmony_ci		hpsa_drain_accel_commands(h);
843362306a36Sopenharmony_ci		/* Set 'accelerator path config change' bit */
843462306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
843562306a36Sopenharmony_ci			"Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
843662306a36Sopenharmony_ci			h->events, event_type);
843762306a36Sopenharmony_ci		writel(h->events, &(h->cfgtable->clear_event_notify));
843862306a36Sopenharmony_ci		/* Set the "clear event notify field update" bit 6 */
843962306a36Sopenharmony_ci		writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
844062306a36Sopenharmony_ci		/* Wait until ctlr clears 'clear event notify field', bit 6 */
844162306a36Sopenharmony_ci		hpsa_wait_for_clear_event_notify_ack(h);
844262306a36Sopenharmony_ci		scsi_unblock_requests(h->scsi_host);
844362306a36Sopenharmony_ci	} else {
844462306a36Sopenharmony_ci		/* Acknowledge controller notification events. */
844562306a36Sopenharmony_ci		writel(h->events, &(h->cfgtable->clear_event_notify));
844662306a36Sopenharmony_ci		writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
844762306a36Sopenharmony_ci		hpsa_wait_for_clear_event_notify_ack(h);
844862306a36Sopenharmony_ci	}
844962306a36Sopenharmony_ci	return;
845062306a36Sopenharmony_ci}
845162306a36Sopenharmony_ci
845262306a36Sopenharmony_ci/* Check a register on the controller to see if there are configuration
845362306a36Sopenharmony_ci * changes (added/changed/removed logical drives, etc.) which mean that
845462306a36Sopenharmony_ci * we should rescan the controller for devices.
845562306a36Sopenharmony_ci * Also check flag for driver-initiated rescan.
845662306a36Sopenharmony_ci */
845762306a36Sopenharmony_cistatic int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
845862306a36Sopenharmony_ci{
845962306a36Sopenharmony_ci	if (h->drv_req_rescan) {
846062306a36Sopenharmony_ci		h->drv_req_rescan = 0;
846162306a36Sopenharmony_ci		return 1;
846262306a36Sopenharmony_ci	}
846362306a36Sopenharmony_ci
846462306a36Sopenharmony_ci	if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
846562306a36Sopenharmony_ci		return 0;
846662306a36Sopenharmony_ci
846762306a36Sopenharmony_ci	h->events = readl(&(h->cfgtable->event_notify));
846862306a36Sopenharmony_ci	return h->events & RESCAN_REQUIRED_EVENT_BITS;
846962306a36Sopenharmony_ci}
847062306a36Sopenharmony_ci
847162306a36Sopenharmony_ci/*
847262306a36Sopenharmony_ci * Check if any of the offline devices have become ready
847362306a36Sopenharmony_ci */
847462306a36Sopenharmony_cistatic int hpsa_offline_devices_ready(struct ctlr_info *h)
847562306a36Sopenharmony_ci{
847662306a36Sopenharmony_ci	unsigned long flags;
847762306a36Sopenharmony_ci	struct offline_device_entry *d;
847862306a36Sopenharmony_ci	struct list_head *this, *tmp;
847962306a36Sopenharmony_ci
848062306a36Sopenharmony_ci	spin_lock_irqsave(&h->offline_device_lock, flags);
848162306a36Sopenharmony_ci	list_for_each_safe(this, tmp, &h->offline_device_list) {
848262306a36Sopenharmony_ci		d = list_entry(this, struct offline_device_entry,
848362306a36Sopenharmony_ci				offline_list);
848462306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->offline_device_lock, flags);
848562306a36Sopenharmony_ci		if (!hpsa_volume_offline(h, d->scsi3addr)) {
848662306a36Sopenharmony_ci			spin_lock_irqsave(&h->offline_device_lock, flags);
848762306a36Sopenharmony_ci			list_del(&d->offline_list);
848862306a36Sopenharmony_ci			spin_unlock_irqrestore(&h->offline_device_lock, flags);
848962306a36Sopenharmony_ci			return 1;
849062306a36Sopenharmony_ci		}
849162306a36Sopenharmony_ci		spin_lock_irqsave(&h->offline_device_lock, flags);
849262306a36Sopenharmony_ci	}
849362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->offline_device_lock, flags);
849462306a36Sopenharmony_ci	return 0;
849562306a36Sopenharmony_ci}
849662306a36Sopenharmony_ci
849762306a36Sopenharmony_cistatic int hpsa_luns_changed(struct ctlr_info *h)
849862306a36Sopenharmony_ci{
849962306a36Sopenharmony_ci	int rc = 1; /* assume there are changes */
850062306a36Sopenharmony_ci	struct ReportLUNdata *logdev = NULL;
850162306a36Sopenharmony_ci
850262306a36Sopenharmony_ci	/* if we can't find out if lun data has changed,
850362306a36Sopenharmony_ci	 * assume that it has.
850462306a36Sopenharmony_ci	 */
850562306a36Sopenharmony_ci
850662306a36Sopenharmony_ci	if (!h->lastlogicals)
850762306a36Sopenharmony_ci		return rc;
850862306a36Sopenharmony_ci
850962306a36Sopenharmony_ci	logdev = kzalloc(sizeof(*logdev), GFP_KERNEL);
851062306a36Sopenharmony_ci	if (!logdev)
851162306a36Sopenharmony_ci		return rc;
851262306a36Sopenharmony_ci
851362306a36Sopenharmony_ci	if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) {
851462306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
851562306a36Sopenharmony_ci			"report luns failed, can't track lun changes.\n");
851662306a36Sopenharmony_ci		goto out;
851762306a36Sopenharmony_ci	}
851862306a36Sopenharmony_ci	if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) {
851962306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
852062306a36Sopenharmony_ci			"Lun changes detected.\n");
852162306a36Sopenharmony_ci		memcpy(h->lastlogicals, logdev, sizeof(*logdev));
852262306a36Sopenharmony_ci		goto out;
852362306a36Sopenharmony_ci	} else
852462306a36Sopenharmony_ci		rc = 0; /* no changes detected. */
852562306a36Sopenharmony_ciout:
852662306a36Sopenharmony_ci	kfree(logdev);
852762306a36Sopenharmony_ci	return rc;
852862306a36Sopenharmony_ci}
852962306a36Sopenharmony_ci
853062306a36Sopenharmony_cistatic void hpsa_perform_rescan(struct ctlr_info *h)
853162306a36Sopenharmony_ci{
853262306a36Sopenharmony_ci	struct Scsi_Host *sh = NULL;
853362306a36Sopenharmony_ci	unsigned long flags;
853462306a36Sopenharmony_ci
853562306a36Sopenharmony_ci	/*
853662306a36Sopenharmony_ci	 * Do the scan after the reset
853762306a36Sopenharmony_ci	 */
853862306a36Sopenharmony_ci	spin_lock_irqsave(&h->reset_lock, flags);
853962306a36Sopenharmony_ci	if (h->reset_in_progress) {
854062306a36Sopenharmony_ci		h->drv_req_rescan = 1;
854162306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->reset_lock, flags);
854262306a36Sopenharmony_ci		return;
854362306a36Sopenharmony_ci	}
854462306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->reset_lock, flags);
854562306a36Sopenharmony_ci
854662306a36Sopenharmony_ci	sh = scsi_host_get(h->scsi_host);
854762306a36Sopenharmony_ci	if (sh != NULL) {
854862306a36Sopenharmony_ci		hpsa_scan_start(sh);
854962306a36Sopenharmony_ci		scsi_host_put(sh);
855062306a36Sopenharmony_ci		h->drv_req_rescan = 0;
855162306a36Sopenharmony_ci	}
855262306a36Sopenharmony_ci}
855362306a36Sopenharmony_ci
855462306a36Sopenharmony_ci/*
855562306a36Sopenharmony_ci * watch for controller events
855662306a36Sopenharmony_ci */
855762306a36Sopenharmony_cistatic void hpsa_event_monitor_worker(struct work_struct *work)
855862306a36Sopenharmony_ci{
855962306a36Sopenharmony_ci	struct ctlr_info *h = container_of(to_delayed_work(work),
856062306a36Sopenharmony_ci					struct ctlr_info, event_monitor_work);
856162306a36Sopenharmony_ci	unsigned long flags;
856262306a36Sopenharmony_ci
856362306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
856462306a36Sopenharmony_ci	if (h->remove_in_progress) {
856562306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
856662306a36Sopenharmony_ci		return;
856762306a36Sopenharmony_ci	}
856862306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
856962306a36Sopenharmony_ci
857062306a36Sopenharmony_ci	if (hpsa_ctlr_needs_rescan(h)) {
857162306a36Sopenharmony_ci		hpsa_ack_ctlr_events(h);
857262306a36Sopenharmony_ci		hpsa_perform_rescan(h);
857362306a36Sopenharmony_ci	}
857462306a36Sopenharmony_ci
857562306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
857662306a36Sopenharmony_ci	if (!h->remove_in_progress)
857762306a36Sopenharmony_ci		queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work,
857862306a36Sopenharmony_ci				HPSA_EVENT_MONITOR_INTERVAL);
857962306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
858062306a36Sopenharmony_ci}
858162306a36Sopenharmony_ci
858262306a36Sopenharmony_cistatic void hpsa_rescan_ctlr_worker(struct work_struct *work)
858362306a36Sopenharmony_ci{
858462306a36Sopenharmony_ci	unsigned long flags;
858562306a36Sopenharmony_ci	struct ctlr_info *h = container_of(to_delayed_work(work),
858662306a36Sopenharmony_ci					struct ctlr_info, rescan_ctlr_work);
858762306a36Sopenharmony_ci
858862306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
858962306a36Sopenharmony_ci	if (h->remove_in_progress) {
859062306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
859162306a36Sopenharmony_ci		return;
859262306a36Sopenharmony_ci	}
859362306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
859462306a36Sopenharmony_ci
859562306a36Sopenharmony_ci	if (h->drv_req_rescan || hpsa_offline_devices_ready(h)) {
859662306a36Sopenharmony_ci		hpsa_perform_rescan(h);
859762306a36Sopenharmony_ci	} else if (h->discovery_polling) {
859862306a36Sopenharmony_ci		if (hpsa_luns_changed(h)) {
859962306a36Sopenharmony_ci			dev_info(&h->pdev->dev,
860062306a36Sopenharmony_ci				"driver discovery polling rescan.\n");
860162306a36Sopenharmony_ci			hpsa_perform_rescan(h);
860262306a36Sopenharmony_ci		}
860362306a36Sopenharmony_ci	}
860462306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
860562306a36Sopenharmony_ci	if (!h->remove_in_progress)
860662306a36Sopenharmony_ci		queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
860762306a36Sopenharmony_ci				h->heartbeat_sample_interval);
860862306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
860962306a36Sopenharmony_ci}
861062306a36Sopenharmony_ci
861162306a36Sopenharmony_cistatic void hpsa_monitor_ctlr_worker(struct work_struct *work)
861262306a36Sopenharmony_ci{
861362306a36Sopenharmony_ci	unsigned long flags;
861462306a36Sopenharmony_ci	struct ctlr_info *h = container_of(to_delayed_work(work),
861562306a36Sopenharmony_ci					struct ctlr_info, monitor_ctlr_work);
861662306a36Sopenharmony_ci
861762306a36Sopenharmony_ci	detect_controller_lockup(h);
861862306a36Sopenharmony_ci	if (lockup_detected(h))
861962306a36Sopenharmony_ci		return;
862062306a36Sopenharmony_ci
862162306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
862262306a36Sopenharmony_ci	if (!h->remove_in_progress)
862362306a36Sopenharmony_ci		queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work,
862462306a36Sopenharmony_ci				h->heartbeat_sample_interval);
862562306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
862662306a36Sopenharmony_ci}
862762306a36Sopenharmony_ci
862862306a36Sopenharmony_cistatic struct workqueue_struct *hpsa_create_controller_wq(struct ctlr_info *h,
862962306a36Sopenharmony_ci						char *name)
863062306a36Sopenharmony_ci{
863162306a36Sopenharmony_ci	struct workqueue_struct *wq = NULL;
863262306a36Sopenharmony_ci
863362306a36Sopenharmony_ci	wq = alloc_ordered_workqueue("%s_%d_hpsa", 0, name, h->ctlr);
863462306a36Sopenharmony_ci	if (!wq)
863562306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "failed to create %s workqueue\n", name);
863662306a36Sopenharmony_ci
863762306a36Sopenharmony_ci	return wq;
863862306a36Sopenharmony_ci}
863962306a36Sopenharmony_ci
864062306a36Sopenharmony_cistatic void hpda_free_ctlr_info(struct ctlr_info *h)
864162306a36Sopenharmony_ci{
864262306a36Sopenharmony_ci	kfree(h->reply_map);
864362306a36Sopenharmony_ci	kfree(h);
864462306a36Sopenharmony_ci}
864562306a36Sopenharmony_ci
864662306a36Sopenharmony_cistatic struct ctlr_info *hpda_alloc_ctlr_info(void)
864762306a36Sopenharmony_ci{
864862306a36Sopenharmony_ci	struct ctlr_info *h;
864962306a36Sopenharmony_ci
865062306a36Sopenharmony_ci	h = kzalloc(sizeof(*h), GFP_KERNEL);
865162306a36Sopenharmony_ci	if (!h)
865262306a36Sopenharmony_ci		return NULL;
865362306a36Sopenharmony_ci
865462306a36Sopenharmony_ci	h->reply_map = kcalloc(nr_cpu_ids, sizeof(*h->reply_map), GFP_KERNEL);
865562306a36Sopenharmony_ci	if (!h->reply_map) {
865662306a36Sopenharmony_ci		kfree(h);
865762306a36Sopenharmony_ci		return NULL;
865862306a36Sopenharmony_ci	}
865962306a36Sopenharmony_ci	return h;
866062306a36Sopenharmony_ci}
866162306a36Sopenharmony_ci
866262306a36Sopenharmony_cistatic int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
866362306a36Sopenharmony_ci{
866462306a36Sopenharmony_ci	int rc;
866562306a36Sopenharmony_ci	struct ctlr_info *h;
866662306a36Sopenharmony_ci	int try_soft_reset = 0;
866762306a36Sopenharmony_ci	unsigned long flags;
866862306a36Sopenharmony_ci	u32 board_id;
866962306a36Sopenharmony_ci
867062306a36Sopenharmony_ci	if (number_of_controllers == 0)
867162306a36Sopenharmony_ci		printk(KERN_INFO DRIVER_NAME "\n");
867262306a36Sopenharmony_ci
867362306a36Sopenharmony_ci	rc = hpsa_lookup_board_id(pdev, &board_id, NULL);
867462306a36Sopenharmony_ci	if (rc < 0) {
867562306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Board ID not found\n");
867662306a36Sopenharmony_ci		return rc;
867762306a36Sopenharmony_ci	}
867862306a36Sopenharmony_ci
867962306a36Sopenharmony_ci	rc = hpsa_init_reset_devices(pdev, board_id);
868062306a36Sopenharmony_ci	if (rc) {
868162306a36Sopenharmony_ci		if (rc != -ENOTSUPP)
868262306a36Sopenharmony_ci			return rc;
868362306a36Sopenharmony_ci		/* If the reset fails in a particular way (it has no way to do
868462306a36Sopenharmony_ci		 * a proper hard reset, so returns -ENOTSUPP) we can try to do
868562306a36Sopenharmony_ci		 * a soft reset once we get the controller configured up to the
868662306a36Sopenharmony_ci		 * point that it can accept a command.
868762306a36Sopenharmony_ci		 */
868862306a36Sopenharmony_ci		try_soft_reset = 1;
868962306a36Sopenharmony_ci		rc = 0;
869062306a36Sopenharmony_ci	}
869162306a36Sopenharmony_ci
869262306a36Sopenharmony_cireinit_after_soft_reset:
869362306a36Sopenharmony_ci
869462306a36Sopenharmony_ci	/* Command structures must be aligned on a 32-byte boundary because
869562306a36Sopenharmony_ci	 * the 5 lower bits of the address are used by the hardware. and by
869662306a36Sopenharmony_ci	 * the driver.  See comments in hpsa.h for more info.
869762306a36Sopenharmony_ci	 */
869862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
869962306a36Sopenharmony_ci	h = hpda_alloc_ctlr_info();
870062306a36Sopenharmony_ci	if (!h) {
870162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to allocate controller head\n");
870262306a36Sopenharmony_ci		return -ENOMEM;
870362306a36Sopenharmony_ci	}
870462306a36Sopenharmony_ci
870562306a36Sopenharmony_ci	h->pdev = pdev;
870662306a36Sopenharmony_ci
870762306a36Sopenharmony_ci	h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
870862306a36Sopenharmony_ci	INIT_LIST_HEAD(&h->offline_device_list);
870962306a36Sopenharmony_ci	spin_lock_init(&h->lock);
871062306a36Sopenharmony_ci	spin_lock_init(&h->offline_device_lock);
871162306a36Sopenharmony_ci	spin_lock_init(&h->scan_lock);
871262306a36Sopenharmony_ci	spin_lock_init(&h->reset_lock);
871362306a36Sopenharmony_ci	atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS);
871462306a36Sopenharmony_ci
871562306a36Sopenharmony_ci	/* Allocate and clear per-cpu variable lockup_detected */
871662306a36Sopenharmony_ci	h->lockup_detected = alloc_percpu(u32);
871762306a36Sopenharmony_ci	if (!h->lockup_detected) {
871862306a36Sopenharmony_ci		dev_err(&h->pdev->dev, "Failed to allocate lockup detector\n");
871962306a36Sopenharmony_ci		rc = -ENOMEM;
872062306a36Sopenharmony_ci		goto clean1;	/* aer/h */
872162306a36Sopenharmony_ci	}
872262306a36Sopenharmony_ci	set_lockup_detected_for_all_cpus(h, 0);
872362306a36Sopenharmony_ci
872462306a36Sopenharmony_ci	rc = hpsa_pci_init(h);
872562306a36Sopenharmony_ci	if (rc)
872662306a36Sopenharmony_ci		goto clean2;	/* lu, aer/h */
872762306a36Sopenharmony_ci
872862306a36Sopenharmony_ci	/* relies on h-> settings made by hpsa_pci_init, including
872962306a36Sopenharmony_ci	 * interrupt_mode h->intr */
873062306a36Sopenharmony_ci	rc = hpsa_scsi_host_alloc(h);
873162306a36Sopenharmony_ci	if (rc)
873262306a36Sopenharmony_ci		goto clean2_5;	/* pci, lu, aer/h */
873362306a36Sopenharmony_ci
873462306a36Sopenharmony_ci	sprintf(h->devname, HPSA "%d", h->scsi_host->host_no);
873562306a36Sopenharmony_ci	h->ctlr = number_of_controllers;
873662306a36Sopenharmony_ci	number_of_controllers++;
873762306a36Sopenharmony_ci
873862306a36Sopenharmony_ci	/* configure PCI DMA stuff */
873962306a36Sopenharmony_ci	rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
874062306a36Sopenharmony_ci	if (rc != 0) {
874162306a36Sopenharmony_ci		rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
874262306a36Sopenharmony_ci		if (rc != 0) {
874362306a36Sopenharmony_ci			dev_err(&pdev->dev, "no suitable DMA available\n");
874462306a36Sopenharmony_ci			goto clean3;	/* shost, pci, lu, aer/h */
874562306a36Sopenharmony_ci		}
874662306a36Sopenharmony_ci	}
874762306a36Sopenharmony_ci
874862306a36Sopenharmony_ci	/* make sure the board interrupts are off */
874962306a36Sopenharmony_ci	h->access.set_intr_mask(h, HPSA_INTR_OFF);
875062306a36Sopenharmony_ci
875162306a36Sopenharmony_ci	rc = hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx);
875262306a36Sopenharmony_ci	if (rc)
875362306a36Sopenharmony_ci		goto clean3;	/* shost, pci, lu, aer/h */
875462306a36Sopenharmony_ci	rc = hpsa_alloc_cmd_pool(h);
875562306a36Sopenharmony_ci	if (rc)
875662306a36Sopenharmony_ci		goto clean4;	/* irq, shost, pci, lu, aer/h */
875762306a36Sopenharmony_ci	rc = hpsa_alloc_sg_chain_blocks(h);
875862306a36Sopenharmony_ci	if (rc)
875962306a36Sopenharmony_ci		goto clean5;	/* cmd, irq, shost, pci, lu, aer/h */
876062306a36Sopenharmony_ci	init_waitqueue_head(&h->scan_wait_queue);
876162306a36Sopenharmony_ci	init_waitqueue_head(&h->event_sync_wait_queue);
876262306a36Sopenharmony_ci	mutex_init(&h->reset_mutex);
876362306a36Sopenharmony_ci	h->scan_finished = 1; /* no scan currently in progress */
876462306a36Sopenharmony_ci	h->scan_waiting = 0;
876562306a36Sopenharmony_ci
876662306a36Sopenharmony_ci	pci_set_drvdata(pdev, h);
876762306a36Sopenharmony_ci	h->ndevices = 0;
876862306a36Sopenharmony_ci
876962306a36Sopenharmony_ci	spin_lock_init(&h->devlock);
877062306a36Sopenharmony_ci	rc = hpsa_put_ctlr_into_performant_mode(h);
877162306a36Sopenharmony_ci	if (rc)
877262306a36Sopenharmony_ci		goto clean6; /* sg, cmd, irq, shost, pci, lu, aer/h */
877362306a36Sopenharmony_ci
877462306a36Sopenharmony_ci	/* create the resubmit workqueue */
877562306a36Sopenharmony_ci	h->rescan_ctlr_wq = hpsa_create_controller_wq(h, "rescan");
877662306a36Sopenharmony_ci	if (!h->rescan_ctlr_wq) {
877762306a36Sopenharmony_ci		rc = -ENOMEM;
877862306a36Sopenharmony_ci		goto clean7;
877962306a36Sopenharmony_ci	}
878062306a36Sopenharmony_ci
878162306a36Sopenharmony_ci	h->resubmit_wq = hpsa_create_controller_wq(h, "resubmit");
878262306a36Sopenharmony_ci	if (!h->resubmit_wq) {
878362306a36Sopenharmony_ci		rc = -ENOMEM;
878462306a36Sopenharmony_ci		goto clean7;	/* aer/h */
878562306a36Sopenharmony_ci	}
878662306a36Sopenharmony_ci
878762306a36Sopenharmony_ci	h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor");
878862306a36Sopenharmony_ci	if (!h->monitor_ctlr_wq) {
878962306a36Sopenharmony_ci		rc = -ENOMEM;
879062306a36Sopenharmony_ci		goto clean7;
879162306a36Sopenharmony_ci	}
879262306a36Sopenharmony_ci
879362306a36Sopenharmony_ci	/*
879462306a36Sopenharmony_ci	 * At this point, the controller is ready to take commands.
879562306a36Sopenharmony_ci	 * Now, if reset_devices and the hard reset didn't work, try
879662306a36Sopenharmony_ci	 * the soft reset and see if that works.
879762306a36Sopenharmony_ci	 */
879862306a36Sopenharmony_ci	if (try_soft_reset) {
879962306a36Sopenharmony_ci
880062306a36Sopenharmony_ci		/* This is kind of gross.  We may or may not get a completion
880162306a36Sopenharmony_ci		 * from the soft reset command, and if we do, then the value
880262306a36Sopenharmony_ci		 * from the fifo may or may not be valid.  So, we wait 10 secs
880362306a36Sopenharmony_ci		 * after the reset throwing away any completions we get during
880462306a36Sopenharmony_ci		 * that time.  Unregister the interrupt handler and register
880562306a36Sopenharmony_ci		 * fake ones to scoop up any residual completions.
880662306a36Sopenharmony_ci		 */
880762306a36Sopenharmony_ci		spin_lock_irqsave(&h->lock, flags);
880862306a36Sopenharmony_ci		h->access.set_intr_mask(h, HPSA_INTR_OFF);
880962306a36Sopenharmony_ci		spin_unlock_irqrestore(&h->lock, flags);
881062306a36Sopenharmony_ci		hpsa_free_irqs(h);
881162306a36Sopenharmony_ci		rc = hpsa_request_irqs(h, hpsa_msix_discard_completions,
881262306a36Sopenharmony_ci					hpsa_intx_discard_completions);
881362306a36Sopenharmony_ci		if (rc) {
881462306a36Sopenharmony_ci			dev_warn(&h->pdev->dev,
881562306a36Sopenharmony_ci				"Failed to request_irq after soft reset.\n");
881662306a36Sopenharmony_ci			/*
881762306a36Sopenharmony_ci			 * cannot goto clean7 or free_irqs will be called
881862306a36Sopenharmony_ci			 * again. Instead, do its work
881962306a36Sopenharmony_ci			 */
882062306a36Sopenharmony_ci			hpsa_free_performant_mode(h);	/* clean7 */
882162306a36Sopenharmony_ci			hpsa_free_sg_chain_blocks(h);	/* clean6 */
882262306a36Sopenharmony_ci			hpsa_free_cmd_pool(h);		/* clean5 */
882362306a36Sopenharmony_ci			/*
882462306a36Sopenharmony_ci			 * skip hpsa_free_irqs(h) clean4 since that
882562306a36Sopenharmony_ci			 * was just called before request_irqs failed
882662306a36Sopenharmony_ci			 */
882762306a36Sopenharmony_ci			goto clean3;
882862306a36Sopenharmony_ci		}
882962306a36Sopenharmony_ci
883062306a36Sopenharmony_ci		rc = hpsa_kdump_soft_reset(h);
883162306a36Sopenharmony_ci		if (rc)
883262306a36Sopenharmony_ci			/* Neither hard nor soft reset worked, we're hosed. */
883362306a36Sopenharmony_ci			goto clean7;
883462306a36Sopenharmony_ci
883562306a36Sopenharmony_ci		dev_info(&h->pdev->dev, "Board READY.\n");
883662306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
883762306a36Sopenharmony_ci			"Waiting for stale completions to drain.\n");
883862306a36Sopenharmony_ci		h->access.set_intr_mask(h, HPSA_INTR_ON);
883962306a36Sopenharmony_ci		msleep(10000);
884062306a36Sopenharmony_ci		h->access.set_intr_mask(h, HPSA_INTR_OFF);
884162306a36Sopenharmony_ci
884262306a36Sopenharmony_ci		rc = controller_reset_failed(h->cfgtable);
884362306a36Sopenharmony_ci		if (rc)
884462306a36Sopenharmony_ci			dev_info(&h->pdev->dev,
884562306a36Sopenharmony_ci				"Soft reset appears to have failed.\n");
884662306a36Sopenharmony_ci
884762306a36Sopenharmony_ci		/* since the controller's reset, we have to go back and re-init
884862306a36Sopenharmony_ci		 * everything.  Easiest to just forget what we've done and do it
884962306a36Sopenharmony_ci		 * all over again.
885062306a36Sopenharmony_ci		 */
885162306a36Sopenharmony_ci		hpsa_undo_allocations_after_kdump_soft_reset(h);
885262306a36Sopenharmony_ci		try_soft_reset = 0;
885362306a36Sopenharmony_ci		if (rc)
885462306a36Sopenharmony_ci			/* don't goto clean, we already unallocated */
885562306a36Sopenharmony_ci			return -ENODEV;
885662306a36Sopenharmony_ci
885762306a36Sopenharmony_ci		goto reinit_after_soft_reset;
885862306a36Sopenharmony_ci	}
885962306a36Sopenharmony_ci
886062306a36Sopenharmony_ci	/* Enable Accelerated IO path at driver layer */
886162306a36Sopenharmony_ci	h->acciopath_status = 1;
886262306a36Sopenharmony_ci	/* Disable discovery polling.*/
886362306a36Sopenharmony_ci	h->discovery_polling = 0;
886462306a36Sopenharmony_ci
886562306a36Sopenharmony_ci
886662306a36Sopenharmony_ci	/* Turn the interrupts on so we can service requests */
886762306a36Sopenharmony_ci	h->access.set_intr_mask(h, HPSA_INTR_ON);
886862306a36Sopenharmony_ci
886962306a36Sopenharmony_ci	hpsa_hba_inquiry(h);
887062306a36Sopenharmony_ci
887162306a36Sopenharmony_ci	h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL);
887262306a36Sopenharmony_ci	if (!h->lastlogicals)
887362306a36Sopenharmony_ci		dev_info(&h->pdev->dev,
887462306a36Sopenharmony_ci			"Can't track change to report lun data\n");
887562306a36Sopenharmony_ci
887662306a36Sopenharmony_ci	/* hook into SCSI subsystem */
887762306a36Sopenharmony_ci	rc = hpsa_scsi_add_host(h);
887862306a36Sopenharmony_ci	if (rc)
887962306a36Sopenharmony_ci		goto clean8; /* lastlogicals, perf, sg, cmd, irq, shost, pci, lu, aer/h */
888062306a36Sopenharmony_ci
888162306a36Sopenharmony_ci	/* Monitor the controller for firmware lockups */
888262306a36Sopenharmony_ci	h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
888362306a36Sopenharmony_ci	INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
888462306a36Sopenharmony_ci	schedule_delayed_work(&h->monitor_ctlr_work,
888562306a36Sopenharmony_ci				h->heartbeat_sample_interval);
888662306a36Sopenharmony_ci	INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker);
888762306a36Sopenharmony_ci	queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
888862306a36Sopenharmony_ci				h->heartbeat_sample_interval);
888962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&h->event_monitor_work, hpsa_event_monitor_worker);
889062306a36Sopenharmony_ci	schedule_delayed_work(&h->event_monitor_work,
889162306a36Sopenharmony_ci				HPSA_EVENT_MONITOR_INTERVAL);
889262306a36Sopenharmony_ci	return 0;
889362306a36Sopenharmony_ci
889462306a36Sopenharmony_ciclean8: /* lastlogicals, perf, sg, cmd, irq, shost, pci, lu, aer/h */
889562306a36Sopenharmony_ci	kfree(h->lastlogicals);
889662306a36Sopenharmony_ciclean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */
889762306a36Sopenharmony_ci	hpsa_free_performant_mode(h);
889862306a36Sopenharmony_ci	h->access.set_intr_mask(h, HPSA_INTR_OFF);
889962306a36Sopenharmony_ciclean6: /* sg, cmd, irq, pci, lockup, wq/aer/h */
890062306a36Sopenharmony_ci	hpsa_free_sg_chain_blocks(h);
890162306a36Sopenharmony_ciclean5: /* cmd, irq, shost, pci, lu, aer/h */
890262306a36Sopenharmony_ci	hpsa_free_cmd_pool(h);
890362306a36Sopenharmony_ciclean4: /* irq, shost, pci, lu, aer/h */
890462306a36Sopenharmony_ci	hpsa_free_irqs(h);
890562306a36Sopenharmony_ciclean3: /* shost, pci, lu, aer/h */
890662306a36Sopenharmony_ci	scsi_host_put(h->scsi_host);
890762306a36Sopenharmony_ci	h->scsi_host = NULL;
890862306a36Sopenharmony_ciclean2_5: /* pci, lu, aer/h */
890962306a36Sopenharmony_ci	hpsa_free_pci_init(h);
891062306a36Sopenharmony_ciclean2: /* lu, aer/h */
891162306a36Sopenharmony_ci	if (h->lockup_detected) {
891262306a36Sopenharmony_ci		free_percpu(h->lockup_detected);
891362306a36Sopenharmony_ci		h->lockup_detected = NULL;
891462306a36Sopenharmony_ci	}
891562306a36Sopenharmony_ciclean1:	/* wq/aer/h */
891662306a36Sopenharmony_ci	if (h->resubmit_wq) {
891762306a36Sopenharmony_ci		destroy_workqueue(h->resubmit_wq);
891862306a36Sopenharmony_ci		h->resubmit_wq = NULL;
891962306a36Sopenharmony_ci	}
892062306a36Sopenharmony_ci	if (h->rescan_ctlr_wq) {
892162306a36Sopenharmony_ci		destroy_workqueue(h->rescan_ctlr_wq);
892262306a36Sopenharmony_ci		h->rescan_ctlr_wq = NULL;
892362306a36Sopenharmony_ci	}
892462306a36Sopenharmony_ci	if (h->monitor_ctlr_wq) {
892562306a36Sopenharmony_ci		destroy_workqueue(h->monitor_ctlr_wq);
892662306a36Sopenharmony_ci		h->monitor_ctlr_wq = NULL;
892762306a36Sopenharmony_ci	}
892862306a36Sopenharmony_ci	hpda_free_ctlr_info(h);
892962306a36Sopenharmony_ci	return rc;
893062306a36Sopenharmony_ci}
893162306a36Sopenharmony_ci
893262306a36Sopenharmony_cistatic void hpsa_flush_cache(struct ctlr_info *h)
893362306a36Sopenharmony_ci{
893462306a36Sopenharmony_ci	char *flush_buf;
893562306a36Sopenharmony_ci	struct CommandList *c;
893662306a36Sopenharmony_ci	int rc;
893762306a36Sopenharmony_ci
893862306a36Sopenharmony_ci	if (unlikely(lockup_detected(h)))
893962306a36Sopenharmony_ci		return;
894062306a36Sopenharmony_ci	flush_buf = kzalloc(4, GFP_KERNEL);
894162306a36Sopenharmony_ci	if (!flush_buf)
894262306a36Sopenharmony_ci		return;
894362306a36Sopenharmony_ci
894462306a36Sopenharmony_ci	c = cmd_alloc(h);
894562306a36Sopenharmony_ci
894662306a36Sopenharmony_ci	if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
894762306a36Sopenharmony_ci		RAID_CTLR_LUNID, TYPE_CMD)) {
894862306a36Sopenharmony_ci		goto out;
894962306a36Sopenharmony_ci	}
895062306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE,
895162306a36Sopenharmony_ci			DEFAULT_TIMEOUT);
895262306a36Sopenharmony_ci	if (rc)
895362306a36Sopenharmony_ci		goto out;
895462306a36Sopenharmony_ci	if (c->err_info->CommandStatus != 0)
895562306a36Sopenharmony_ciout:
895662306a36Sopenharmony_ci		dev_warn(&h->pdev->dev,
895762306a36Sopenharmony_ci			"error flushing cache on controller\n");
895862306a36Sopenharmony_ci	cmd_free(h, c);
895962306a36Sopenharmony_ci	kfree(flush_buf);
896062306a36Sopenharmony_ci}
896162306a36Sopenharmony_ci
896262306a36Sopenharmony_ci/* Make controller gather fresh report lun data each time we
896362306a36Sopenharmony_ci * send down a report luns request
896462306a36Sopenharmony_ci */
896562306a36Sopenharmony_cistatic void hpsa_disable_rld_caching(struct ctlr_info *h)
896662306a36Sopenharmony_ci{
896762306a36Sopenharmony_ci	u32 *options;
896862306a36Sopenharmony_ci	struct CommandList *c;
896962306a36Sopenharmony_ci	int rc;
897062306a36Sopenharmony_ci
897162306a36Sopenharmony_ci	/* Don't bother trying to set diag options if locked up */
897262306a36Sopenharmony_ci	if (unlikely(h->lockup_detected))
897362306a36Sopenharmony_ci		return;
897462306a36Sopenharmony_ci
897562306a36Sopenharmony_ci	options = kzalloc(sizeof(*options), GFP_KERNEL);
897662306a36Sopenharmony_ci	if (!options)
897762306a36Sopenharmony_ci		return;
897862306a36Sopenharmony_ci
897962306a36Sopenharmony_ci	c = cmd_alloc(h);
898062306a36Sopenharmony_ci
898162306a36Sopenharmony_ci	/* first, get the current diag options settings */
898262306a36Sopenharmony_ci	if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
898362306a36Sopenharmony_ci		RAID_CTLR_LUNID, TYPE_CMD))
898462306a36Sopenharmony_ci		goto errout;
898562306a36Sopenharmony_ci
898662306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
898762306a36Sopenharmony_ci			NO_TIMEOUT);
898862306a36Sopenharmony_ci	if ((rc != 0) || (c->err_info->CommandStatus != 0))
898962306a36Sopenharmony_ci		goto errout;
899062306a36Sopenharmony_ci
899162306a36Sopenharmony_ci	/* Now, set the bit for disabling the RLD caching */
899262306a36Sopenharmony_ci	*options |= HPSA_DIAG_OPTS_DISABLE_RLD_CACHING;
899362306a36Sopenharmony_ci
899462306a36Sopenharmony_ci	if (fill_cmd(c, BMIC_SET_DIAG_OPTIONS, h, options, 4, 0,
899562306a36Sopenharmony_ci		RAID_CTLR_LUNID, TYPE_CMD))
899662306a36Sopenharmony_ci		goto errout;
899762306a36Sopenharmony_ci
899862306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE,
899962306a36Sopenharmony_ci			NO_TIMEOUT);
900062306a36Sopenharmony_ci	if ((rc != 0)  || (c->err_info->CommandStatus != 0))
900162306a36Sopenharmony_ci		goto errout;
900262306a36Sopenharmony_ci
900362306a36Sopenharmony_ci	/* Now verify that it got set: */
900462306a36Sopenharmony_ci	if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
900562306a36Sopenharmony_ci		RAID_CTLR_LUNID, TYPE_CMD))
900662306a36Sopenharmony_ci		goto errout;
900762306a36Sopenharmony_ci
900862306a36Sopenharmony_ci	rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_FROM_DEVICE,
900962306a36Sopenharmony_ci			NO_TIMEOUT);
901062306a36Sopenharmony_ci	if ((rc != 0)  || (c->err_info->CommandStatus != 0))
901162306a36Sopenharmony_ci		goto errout;
901262306a36Sopenharmony_ci
901362306a36Sopenharmony_ci	if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING)
901462306a36Sopenharmony_ci		goto out;
901562306a36Sopenharmony_ci
901662306a36Sopenharmony_cierrout:
901762306a36Sopenharmony_ci	dev_err(&h->pdev->dev,
901862306a36Sopenharmony_ci			"Error: failed to disable report lun data caching.\n");
901962306a36Sopenharmony_ciout:
902062306a36Sopenharmony_ci	cmd_free(h, c);
902162306a36Sopenharmony_ci	kfree(options);
902262306a36Sopenharmony_ci}
902362306a36Sopenharmony_ci
902462306a36Sopenharmony_cistatic void __hpsa_shutdown(struct pci_dev *pdev)
902562306a36Sopenharmony_ci{
902662306a36Sopenharmony_ci	struct ctlr_info *h;
902762306a36Sopenharmony_ci
902862306a36Sopenharmony_ci	h = pci_get_drvdata(pdev);
902962306a36Sopenharmony_ci	/* Turn board interrupts off  and send the flush cache command
903062306a36Sopenharmony_ci	 * sendcmd will turn off interrupt, and send the flush...
903162306a36Sopenharmony_ci	 * To write all data in the battery backed cache to disks
903262306a36Sopenharmony_ci	 */
903362306a36Sopenharmony_ci	hpsa_flush_cache(h);
903462306a36Sopenharmony_ci	h->access.set_intr_mask(h, HPSA_INTR_OFF);
903562306a36Sopenharmony_ci	hpsa_free_irqs(h);			/* init_one 4 */
903662306a36Sopenharmony_ci	hpsa_disable_interrupt_mode(h);		/* pci_init 2 */
903762306a36Sopenharmony_ci}
903862306a36Sopenharmony_ci
903962306a36Sopenharmony_cistatic void hpsa_shutdown(struct pci_dev *pdev)
904062306a36Sopenharmony_ci{
904162306a36Sopenharmony_ci	__hpsa_shutdown(pdev);
904262306a36Sopenharmony_ci	pci_disable_device(pdev);
904362306a36Sopenharmony_ci}
904462306a36Sopenharmony_ci
904562306a36Sopenharmony_cistatic void hpsa_free_device_info(struct ctlr_info *h)
904662306a36Sopenharmony_ci{
904762306a36Sopenharmony_ci	int i;
904862306a36Sopenharmony_ci
904962306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
905062306a36Sopenharmony_ci		kfree(h->dev[i]);
905162306a36Sopenharmony_ci		h->dev[i] = NULL;
905262306a36Sopenharmony_ci	}
905362306a36Sopenharmony_ci}
905462306a36Sopenharmony_ci
905562306a36Sopenharmony_cistatic void hpsa_remove_one(struct pci_dev *pdev)
905662306a36Sopenharmony_ci{
905762306a36Sopenharmony_ci	struct ctlr_info *h;
905862306a36Sopenharmony_ci	unsigned long flags;
905962306a36Sopenharmony_ci
906062306a36Sopenharmony_ci	if (pci_get_drvdata(pdev) == NULL) {
906162306a36Sopenharmony_ci		dev_err(&pdev->dev, "unable to remove device\n");
906262306a36Sopenharmony_ci		return;
906362306a36Sopenharmony_ci	}
906462306a36Sopenharmony_ci	h = pci_get_drvdata(pdev);
906562306a36Sopenharmony_ci
906662306a36Sopenharmony_ci	/* Get rid of any controller monitoring work items */
906762306a36Sopenharmony_ci	spin_lock_irqsave(&h->lock, flags);
906862306a36Sopenharmony_ci	h->remove_in_progress = 1;
906962306a36Sopenharmony_ci	spin_unlock_irqrestore(&h->lock, flags);
907062306a36Sopenharmony_ci	cancel_delayed_work_sync(&h->monitor_ctlr_work);
907162306a36Sopenharmony_ci	cancel_delayed_work_sync(&h->rescan_ctlr_work);
907262306a36Sopenharmony_ci	cancel_delayed_work_sync(&h->event_monitor_work);
907362306a36Sopenharmony_ci	destroy_workqueue(h->rescan_ctlr_wq);
907462306a36Sopenharmony_ci	destroy_workqueue(h->resubmit_wq);
907562306a36Sopenharmony_ci	destroy_workqueue(h->monitor_ctlr_wq);
907662306a36Sopenharmony_ci
907762306a36Sopenharmony_ci	hpsa_delete_sas_host(h);
907862306a36Sopenharmony_ci
907962306a36Sopenharmony_ci	/*
908062306a36Sopenharmony_ci	 * Call before disabling interrupts.
908162306a36Sopenharmony_ci	 * scsi_remove_host can trigger I/O operations especially
908262306a36Sopenharmony_ci	 * when multipath is enabled. There can be SYNCHRONIZE CACHE
908362306a36Sopenharmony_ci	 * operations which cannot complete and will hang the system.
908462306a36Sopenharmony_ci	 */
908562306a36Sopenharmony_ci	if (h->scsi_host)
908662306a36Sopenharmony_ci		scsi_remove_host(h->scsi_host);		/* init_one 8 */
908762306a36Sopenharmony_ci	/* includes hpsa_free_irqs - init_one 4 */
908862306a36Sopenharmony_ci	/* includes hpsa_disable_interrupt_mode - pci_init 2 */
908962306a36Sopenharmony_ci	__hpsa_shutdown(pdev);
909062306a36Sopenharmony_ci
909162306a36Sopenharmony_ci	hpsa_free_device_info(h);		/* scan */
909262306a36Sopenharmony_ci
909362306a36Sopenharmony_ci	kfree(h->hba_inquiry_data);			/* init_one 10 */
909462306a36Sopenharmony_ci	h->hba_inquiry_data = NULL;			/* init_one 10 */
909562306a36Sopenharmony_ci	hpsa_free_ioaccel2_sg_chain_blocks(h);
909662306a36Sopenharmony_ci	hpsa_free_performant_mode(h);			/* init_one 7 */
909762306a36Sopenharmony_ci	hpsa_free_sg_chain_blocks(h);			/* init_one 6 */
909862306a36Sopenharmony_ci	hpsa_free_cmd_pool(h);				/* init_one 5 */
909962306a36Sopenharmony_ci	kfree(h->lastlogicals);
910062306a36Sopenharmony_ci
910162306a36Sopenharmony_ci	/* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */
910262306a36Sopenharmony_ci
910362306a36Sopenharmony_ci	scsi_host_put(h->scsi_host);			/* init_one 3 */
910462306a36Sopenharmony_ci	h->scsi_host = NULL;				/* init_one 3 */
910562306a36Sopenharmony_ci
910662306a36Sopenharmony_ci	/* includes hpsa_disable_interrupt_mode - pci_init 2 */
910762306a36Sopenharmony_ci	hpsa_free_pci_init(h);				/* init_one 2.5 */
910862306a36Sopenharmony_ci
910962306a36Sopenharmony_ci	free_percpu(h->lockup_detected);		/* init_one 2 */
911062306a36Sopenharmony_ci	h->lockup_detected = NULL;			/* init_one 2 */
911162306a36Sopenharmony_ci
911262306a36Sopenharmony_ci	hpda_free_ctlr_info(h);				/* init_one 1 */
911362306a36Sopenharmony_ci}
911462306a36Sopenharmony_ci
911562306a36Sopenharmony_cistatic int __maybe_unused hpsa_suspend(
911662306a36Sopenharmony_ci	__attribute__((unused)) struct device *dev)
911762306a36Sopenharmony_ci{
911862306a36Sopenharmony_ci	return -ENOSYS;
911962306a36Sopenharmony_ci}
912062306a36Sopenharmony_ci
912162306a36Sopenharmony_cistatic int __maybe_unused hpsa_resume
912262306a36Sopenharmony_ci	(__attribute__((unused)) struct device *dev)
912362306a36Sopenharmony_ci{
912462306a36Sopenharmony_ci	return -ENOSYS;
912562306a36Sopenharmony_ci}
912662306a36Sopenharmony_ci
912762306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(hpsa_pm_ops, hpsa_suspend, hpsa_resume);
912862306a36Sopenharmony_ci
912962306a36Sopenharmony_cistatic struct pci_driver hpsa_pci_driver = {
913062306a36Sopenharmony_ci	.name = HPSA,
913162306a36Sopenharmony_ci	.probe = hpsa_init_one,
913262306a36Sopenharmony_ci	.remove = hpsa_remove_one,
913362306a36Sopenharmony_ci	.id_table = hpsa_pci_device_id,	/* id_table */
913462306a36Sopenharmony_ci	.shutdown = hpsa_shutdown,
913562306a36Sopenharmony_ci	.driver.pm = &hpsa_pm_ops,
913662306a36Sopenharmony_ci};
913762306a36Sopenharmony_ci
913862306a36Sopenharmony_ci/* Fill in bucket_map[], given nsgs (the max number of
913962306a36Sopenharmony_ci * scatter gather elements supported) and bucket[],
914062306a36Sopenharmony_ci * which is an array of 8 integers.  The bucket[] array
914162306a36Sopenharmony_ci * contains 8 different DMA transfer sizes (in 16
914262306a36Sopenharmony_ci * byte increments) which the controller uses to fetch
914362306a36Sopenharmony_ci * commands.  This function fills in bucket_map[], which
914462306a36Sopenharmony_ci * maps a given number of scatter gather elements to one of
914562306a36Sopenharmony_ci * the 8 DMA transfer sizes.  The point of it is to allow the
914662306a36Sopenharmony_ci * controller to only do as much DMA as needed to fetch the
914762306a36Sopenharmony_ci * command, with the DMA transfer size encoded in the lower
914862306a36Sopenharmony_ci * bits of the command address.
914962306a36Sopenharmony_ci */
915062306a36Sopenharmony_cistatic void  calc_bucket_map(int bucket[], int num_buckets,
915162306a36Sopenharmony_ci	int nsgs, int min_blocks, u32 *bucket_map)
915262306a36Sopenharmony_ci{
915362306a36Sopenharmony_ci	int i, j, b, size;
915462306a36Sopenharmony_ci
915562306a36Sopenharmony_ci	/* Note, bucket_map must have nsgs+1 entries. */
915662306a36Sopenharmony_ci	for (i = 0; i <= nsgs; i++) {
915762306a36Sopenharmony_ci		/* Compute size of a command with i SG entries */
915862306a36Sopenharmony_ci		size = i + min_blocks;
915962306a36Sopenharmony_ci		b = num_buckets; /* Assume the biggest bucket */
916062306a36Sopenharmony_ci		/* Find the bucket that is just big enough */
916162306a36Sopenharmony_ci		for (j = 0; j < num_buckets; j++) {
916262306a36Sopenharmony_ci			if (bucket[j] >= size) {
916362306a36Sopenharmony_ci				b = j;
916462306a36Sopenharmony_ci				break;
916562306a36Sopenharmony_ci			}
916662306a36Sopenharmony_ci		}
916762306a36Sopenharmony_ci		/* for a command with i SG entries, use bucket b. */
916862306a36Sopenharmony_ci		bucket_map[i] = b;
916962306a36Sopenharmony_ci	}
917062306a36Sopenharmony_ci}
917162306a36Sopenharmony_ci
917262306a36Sopenharmony_ci/*
917362306a36Sopenharmony_ci * return -ENODEV on err, 0 on success (or no action)
917462306a36Sopenharmony_ci * allocates numerous items that must be freed later
917562306a36Sopenharmony_ci */
917662306a36Sopenharmony_cistatic int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
917762306a36Sopenharmony_ci{
917862306a36Sopenharmony_ci	int i;
917962306a36Sopenharmony_ci	unsigned long register_value;
918062306a36Sopenharmony_ci	unsigned long transMethod = CFGTBL_Trans_Performant |
918162306a36Sopenharmony_ci			(trans_support & CFGTBL_Trans_use_short_tags) |
918262306a36Sopenharmony_ci				CFGTBL_Trans_enable_directed_msix |
918362306a36Sopenharmony_ci			(trans_support & (CFGTBL_Trans_io_accel1 |
918462306a36Sopenharmony_ci				CFGTBL_Trans_io_accel2));
918562306a36Sopenharmony_ci	struct access_method access = SA5_performant_access;
918662306a36Sopenharmony_ci
918762306a36Sopenharmony_ci	/* This is a bit complicated.  There are 8 registers on
918862306a36Sopenharmony_ci	 * the controller which we write to to tell it 8 different
918962306a36Sopenharmony_ci	 * sizes of commands which there may be.  It's a way of
919062306a36Sopenharmony_ci	 * reducing the DMA done to fetch each command.  Encoded into
919162306a36Sopenharmony_ci	 * each command's tag are 3 bits which communicate to the controller
919262306a36Sopenharmony_ci	 * which of the eight sizes that command fits within.  The size of
919362306a36Sopenharmony_ci	 * each command depends on how many scatter gather entries there are.
919462306a36Sopenharmony_ci	 * Each SG entry requires 16 bytes.  The eight registers are programmed
919562306a36Sopenharmony_ci	 * with the number of 16-byte blocks a command of that size requires.
919662306a36Sopenharmony_ci	 * The smallest command possible requires 5 such 16 byte blocks.
919762306a36Sopenharmony_ci	 * the largest command possible requires SG_ENTRIES_IN_CMD + 4 16-byte
919862306a36Sopenharmony_ci	 * blocks.  Note, this only extends to the SG entries contained
919962306a36Sopenharmony_ci	 * within the command block, and does not extend to chained blocks
920062306a36Sopenharmony_ci	 * of SG elements.   bft[] contains the eight values we write to
920162306a36Sopenharmony_ci	 * the registers.  They are not evenly distributed, but have more
920262306a36Sopenharmony_ci	 * sizes for small commands, and fewer sizes for larger commands.
920362306a36Sopenharmony_ci	 */
920462306a36Sopenharmony_ci	int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4};
920562306a36Sopenharmony_ci#define MIN_IOACCEL2_BFT_ENTRY 5
920662306a36Sopenharmony_ci#define HPSA_IOACCEL2_HEADER_SZ 4
920762306a36Sopenharmony_ci	int bft2[16] = {MIN_IOACCEL2_BFT_ENTRY, 6, 7, 8, 9, 10, 11, 12,
920862306a36Sopenharmony_ci			13, 14, 15, 16, 17, 18, 19,
920962306a36Sopenharmony_ci			HPSA_IOACCEL2_HEADER_SZ + IOACCEL2_MAXSGENTRIES};
921062306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(bft2) != 16);
921162306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(bft) != 8);
921262306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) >
921362306a36Sopenharmony_ci				 16 * MIN_IOACCEL2_BFT_ENTRY);
921462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct ioaccel2_sg_element) != 16);
921562306a36Sopenharmony_ci	BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4);
921662306a36Sopenharmony_ci	/*  5 = 1 s/g entry or 4k
921762306a36Sopenharmony_ci	 *  6 = 2 s/g entry or 8k
921862306a36Sopenharmony_ci	 *  8 = 4 s/g entry or 16k
921962306a36Sopenharmony_ci	 * 10 = 6 s/g entry or 24k
922062306a36Sopenharmony_ci	 */
922162306a36Sopenharmony_ci
922262306a36Sopenharmony_ci	/* If the controller supports either ioaccel method then
922362306a36Sopenharmony_ci	 * we can also use the RAID stack submit path that does not
922462306a36Sopenharmony_ci	 * perform the superfluous readl() after each command submission.
922562306a36Sopenharmony_ci	 */
922662306a36Sopenharmony_ci	if (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2))
922762306a36Sopenharmony_ci		access = SA5_performant_access_no_read;
922862306a36Sopenharmony_ci
922962306a36Sopenharmony_ci	/* Controller spec: zero out this buffer. */
923062306a36Sopenharmony_ci	for (i = 0; i < h->nreply_queues; i++)
923162306a36Sopenharmony_ci		memset(h->reply_queue[i].head, 0, h->reply_queue_size);
923262306a36Sopenharmony_ci
923362306a36Sopenharmony_ci	bft[7] = SG_ENTRIES_IN_CMD + 4;
923462306a36Sopenharmony_ci	calc_bucket_map(bft, ARRAY_SIZE(bft),
923562306a36Sopenharmony_ci				SG_ENTRIES_IN_CMD, 4, h->blockFetchTable);
923662306a36Sopenharmony_ci	for (i = 0; i < 8; i++)
923762306a36Sopenharmony_ci		writel(bft[i], &h->transtable->BlockFetch[i]);
923862306a36Sopenharmony_ci
923962306a36Sopenharmony_ci	/* size of controller ring buffer */
924062306a36Sopenharmony_ci	writel(h->max_commands, &h->transtable->RepQSize);
924162306a36Sopenharmony_ci	writel(h->nreply_queues, &h->transtable->RepQCount);
924262306a36Sopenharmony_ci	writel(0, &h->transtable->RepQCtrAddrLow32);
924362306a36Sopenharmony_ci	writel(0, &h->transtable->RepQCtrAddrHigh32);
924462306a36Sopenharmony_ci
924562306a36Sopenharmony_ci	for (i = 0; i < h->nreply_queues; i++) {
924662306a36Sopenharmony_ci		writel(0, &h->transtable->RepQAddr[i].upper);
924762306a36Sopenharmony_ci		writel(h->reply_queue[i].busaddr,
924862306a36Sopenharmony_ci			&h->transtable->RepQAddr[i].lower);
924962306a36Sopenharmony_ci	}
925062306a36Sopenharmony_ci
925162306a36Sopenharmony_ci	writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
925262306a36Sopenharmony_ci	writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest));
925362306a36Sopenharmony_ci	/*
925462306a36Sopenharmony_ci	 * enable outbound interrupt coalescing in accelerator mode;
925562306a36Sopenharmony_ci	 */
925662306a36Sopenharmony_ci	if (trans_support & CFGTBL_Trans_io_accel1) {
925762306a36Sopenharmony_ci		access = SA5_ioaccel_mode1_access;
925862306a36Sopenharmony_ci		writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
925962306a36Sopenharmony_ci		writel(4, &h->cfgtable->HostWrite.CoalIntCount);
926062306a36Sopenharmony_ci	} else
926162306a36Sopenharmony_ci		if (trans_support & CFGTBL_Trans_io_accel2)
926262306a36Sopenharmony_ci			access = SA5_ioaccel_mode2_access;
926362306a36Sopenharmony_ci	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
926462306a36Sopenharmony_ci	if (hpsa_wait_for_mode_change_ack(h)) {
926562306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
926662306a36Sopenharmony_ci			"performant mode problem - doorbell timeout\n");
926762306a36Sopenharmony_ci		return -ENODEV;
926862306a36Sopenharmony_ci	}
926962306a36Sopenharmony_ci	register_value = readl(&(h->cfgtable->TransportActive));
927062306a36Sopenharmony_ci	if (!(register_value & CFGTBL_Trans_Performant)) {
927162306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
927262306a36Sopenharmony_ci			"performant mode problem - transport not active\n");
927362306a36Sopenharmony_ci		return -ENODEV;
927462306a36Sopenharmony_ci	}
927562306a36Sopenharmony_ci	/* Change the access methods to the performant access methods */
927662306a36Sopenharmony_ci	h->access = access;
927762306a36Sopenharmony_ci	h->transMethod = transMethod;
927862306a36Sopenharmony_ci
927962306a36Sopenharmony_ci	if (!((trans_support & CFGTBL_Trans_io_accel1) ||
928062306a36Sopenharmony_ci		(trans_support & CFGTBL_Trans_io_accel2)))
928162306a36Sopenharmony_ci		return 0;
928262306a36Sopenharmony_ci
928362306a36Sopenharmony_ci	if (trans_support & CFGTBL_Trans_io_accel1) {
928462306a36Sopenharmony_ci		/* Set up I/O accelerator mode */
928562306a36Sopenharmony_ci		for (i = 0; i < h->nreply_queues; i++) {
928662306a36Sopenharmony_ci			writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
928762306a36Sopenharmony_ci			h->reply_queue[i].current_entry =
928862306a36Sopenharmony_ci				readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
928962306a36Sopenharmony_ci		}
929062306a36Sopenharmony_ci		bft[7] = h->ioaccel_maxsg + 8;
929162306a36Sopenharmony_ci		calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
929262306a36Sopenharmony_ci				h->ioaccel1_blockFetchTable);
929362306a36Sopenharmony_ci
929462306a36Sopenharmony_ci		/* initialize all reply queue entries to unused */
929562306a36Sopenharmony_ci		for (i = 0; i < h->nreply_queues; i++)
929662306a36Sopenharmony_ci			memset(h->reply_queue[i].head,
929762306a36Sopenharmony_ci				(u8) IOACCEL_MODE1_REPLY_UNUSED,
929862306a36Sopenharmony_ci				h->reply_queue_size);
929962306a36Sopenharmony_ci
930062306a36Sopenharmony_ci		/* set all the constant fields in the accelerator command
930162306a36Sopenharmony_ci		 * frames once at init time to save CPU cycles later.
930262306a36Sopenharmony_ci		 */
930362306a36Sopenharmony_ci		for (i = 0; i < h->nr_cmds; i++) {
930462306a36Sopenharmony_ci			struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
930562306a36Sopenharmony_ci
930662306a36Sopenharmony_ci			cp->function = IOACCEL1_FUNCTION_SCSIIO;
930762306a36Sopenharmony_ci			cp->err_info = (u32) (h->errinfo_pool_dhandle +
930862306a36Sopenharmony_ci					(i * sizeof(struct ErrorInfo)));
930962306a36Sopenharmony_ci			cp->err_info_len = sizeof(struct ErrorInfo);
931062306a36Sopenharmony_ci			cp->sgl_offset = IOACCEL1_SGLOFFSET;
931162306a36Sopenharmony_ci			cp->host_context_flags =
931262306a36Sopenharmony_ci				cpu_to_le16(IOACCEL1_HCFLAGS_CISS_FORMAT);
931362306a36Sopenharmony_ci			cp->timeout_sec = 0;
931462306a36Sopenharmony_ci			cp->ReplyQueue = 0;
931562306a36Sopenharmony_ci			cp->tag =
931662306a36Sopenharmony_ci				cpu_to_le64((i << DIRECT_LOOKUP_SHIFT));
931762306a36Sopenharmony_ci			cp->host_addr =
931862306a36Sopenharmony_ci				cpu_to_le64(h->ioaccel_cmd_pool_dhandle +
931962306a36Sopenharmony_ci					(i * sizeof(struct io_accel1_cmd)));
932062306a36Sopenharmony_ci		}
932162306a36Sopenharmony_ci	} else if (trans_support & CFGTBL_Trans_io_accel2) {
932262306a36Sopenharmony_ci		u64 cfg_offset, cfg_base_addr_index;
932362306a36Sopenharmony_ci		u32 bft2_offset, cfg_base_addr;
932462306a36Sopenharmony_ci
932562306a36Sopenharmony_ci		hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
932662306a36Sopenharmony_ci				    &cfg_base_addr_index, &cfg_offset);
932762306a36Sopenharmony_ci		BUILD_BUG_ON(offsetof(struct io_accel2_cmd, sg) != 64);
932862306a36Sopenharmony_ci		bft2[15] = h->ioaccel_maxsg + HPSA_IOACCEL2_HEADER_SZ;
932962306a36Sopenharmony_ci		calc_bucket_map(bft2, ARRAY_SIZE(bft2), h->ioaccel_maxsg,
933062306a36Sopenharmony_ci				4, h->ioaccel2_blockFetchTable);
933162306a36Sopenharmony_ci		bft2_offset = readl(&h->cfgtable->io_accel_request_size_offset);
933262306a36Sopenharmony_ci		BUILD_BUG_ON(offsetof(struct CfgTable,
933362306a36Sopenharmony_ci				io_accel_request_size_offset) != 0xb8);
933462306a36Sopenharmony_ci		h->ioaccel2_bft2_regs =
933562306a36Sopenharmony_ci			remap_pci_mem(pci_resource_start(h->pdev,
933662306a36Sopenharmony_ci					cfg_base_addr_index) +
933762306a36Sopenharmony_ci					cfg_offset + bft2_offset,
933862306a36Sopenharmony_ci					ARRAY_SIZE(bft2) *
933962306a36Sopenharmony_ci					sizeof(*h->ioaccel2_bft2_regs));
934062306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(bft2); i++)
934162306a36Sopenharmony_ci			writel(bft2[i], &h->ioaccel2_bft2_regs[i]);
934262306a36Sopenharmony_ci	}
934362306a36Sopenharmony_ci	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
934462306a36Sopenharmony_ci	if (hpsa_wait_for_mode_change_ack(h)) {
934562306a36Sopenharmony_ci		dev_err(&h->pdev->dev,
934662306a36Sopenharmony_ci			"performant mode problem - enabling ioaccel mode\n");
934762306a36Sopenharmony_ci		return -ENODEV;
934862306a36Sopenharmony_ci	}
934962306a36Sopenharmony_ci	return 0;
935062306a36Sopenharmony_ci}
935162306a36Sopenharmony_ci
935262306a36Sopenharmony_ci/* Free ioaccel1 mode command blocks and block fetch table */
935362306a36Sopenharmony_cistatic void hpsa_free_ioaccel1_cmd_and_bft(struct ctlr_info *h)
935462306a36Sopenharmony_ci{
935562306a36Sopenharmony_ci	if (h->ioaccel_cmd_pool) {
935662306a36Sopenharmony_ci		dma_free_coherent(&h->pdev->dev,
935762306a36Sopenharmony_ci				  h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
935862306a36Sopenharmony_ci				  h->ioaccel_cmd_pool,
935962306a36Sopenharmony_ci				  h->ioaccel_cmd_pool_dhandle);
936062306a36Sopenharmony_ci		h->ioaccel_cmd_pool = NULL;
936162306a36Sopenharmony_ci		h->ioaccel_cmd_pool_dhandle = 0;
936262306a36Sopenharmony_ci	}
936362306a36Sopenharmony_ci	kfree(h->ioaccel1_blockFetchTable);
936462306a36Sopenharmony_ci	h->ioaccel1_blockFetchTable = NULL;
936562306a36Sopenharmony_ci}
936662306a36Sopenharmony_ci
936762306a36Sopenharmony_ci/* Allocate ioaccel1 mode command blocks and block fetch table */
936862306a36Sopenharmony_cistatic int hpsa_alloc_ioaccel1_cmd_and_bft(struct ctlr_info *h)
936962306a36Sopenharmony_ci{
937062306a36Sopenharmony_ci	h->ioaccel_maxsg =
937162306a36Sopenharmony_ci		readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
937262306a36Sopenharmony_ci	if (h->ioaccel_maxsg > IOACCEL1_MAXSGENTRIES)
937362306a36Sopenharmony_ci		h->ioaccel_maxsg = IOACCEL1_MAXSGENTRIES;
937462306a36Sopenharmony_ci
937562306a36Sopenharmony_ci	/* Command structures must be aligned on a 128-byte boundary
937662306a36Sopenharmony_ci	 * because the 7 lower bits of the address are used by the
937762306a36Sopenharmony_ci	 * hardware.
937862306a36Sopenharmony_ci	 */
937962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct io_accel1_cmd) %
938062306a36Sopenharmony_ci			IOACCEL1_COMMANDLIST_ALIGNMENT);
938162306a36Sopenharmony_ci	h->ioaccel_cmd_pool =
938262306a36Sopenharmony_ci		dma_alloc_coherent(&h->pdev->dev,
938362306a36Sopenharmony_ci			h->nr_cmds * sizeof(*h->ioaccel_cmd_pool),
938462306a36Sopenharmony_ci			&h->ioaccel_cmd_pool_dhandle, GFP_KERNEL);
938562306a36Sopenharmony_ci
938662306a36Sopenharmony_ci	h->ioaccel1_blockFetchTable =
938762306a36Sopenharmony_ci		kmalloc(((h->ioaccel_maxsg + 1) *
938862306a36Sopenharmony_ci				sizeof(u32)), GFP_KERNEL);
938962306a36Sopenharmony_ci
939062306a36Sopenharmony_ci	if ((h->ioaccel_cmd_pool == NULL) ||
939162306a36Sopenharmony_ci		(h->ioaccel1_blockFetchTable == NULL))
939262306a36Sopenharmony_ci		goto clean_up;
939362306a36Sopenharmony_ci
939462306a36Sopenharmony_ci	memset(h->ioaccel_cmd_pool, 0,
939562306a36Sopenharmony_ci		h->nr_cmds * sizeof(*h->ioaccel_cmd_pool));
939662306a36Sopenharmony_ci	return 0;
939762306a36Sopenharmony_ci
939862306a36Sopenharmony_ciclean_up:
939962306a36Sopenharmony_ci	hpsa_free_ioaccel1_cmd_and_bft(h);
940062306a36Sopenharmony_ci	return -ENOMEM;
940162306a36Sopenharmony_ci}
940262306a36Sopenharmony_ci
940362306a36Sopenharmony_ci/* Free ioaccel2 mode command blocks and block fetch table */
940462306a36Sopenharmony_cistatic void hpsa_free_ioaccel2_cmd_and_bft(struct ctlr_info *h)
940562306a36Sopenharmony_ci{
940662306a36Sopenharmony_ci	hpsa_free_ioaccel2_sg_chain_blocks(h);
940762306a36Sopenharmony_ci
940862306a36Sopenharmony_ci	if (h->ioaccel2_cmd_pool) {
940962306a36Sopenharmony_ci		dma_free_coherent(&h->pdev->dev,
941062306a36Sopenharmony_ci				  h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
941162306a36Sopenharmony_ci				  h->ioaccel2_cmd_pool,
941262306a36Sopenharmony_ci				  h->ioaccel2_cmd_pool_dhandle);
941362306a36Sopenharmony_ci		h->ioaccel2_cmd_pool = NULL;
941462306a36Sopenharmony_ci		h->ioaccel2_cmd_pool_dhandle = 0;
941562306a36Sopenharmony_ci	}
941662306a36Sopenharmony_ci	kfree(h->ioaccel2_blockFetchTable);
941762306a36Sopenharmony_ci	h->ioaccel2_blockFetchTable = NULL;
941862306a36Sopenharmony_ci}
941962306a36Sopenharmony_ci
942062306a36Sopenharmony_ci/* Allocate ioaccel2 mode command blocks and block fetch table */
942162306a36Sopenharmony_cistatic int hpsa_alloc_ioaccel2_cmd_and_bft(struct ctlr_info *h)
942262306a36Sopenharmony_ci{
942362306a36Sopenharmony_ci	int rc;
942462306a36Sopenharmony_ci
942562306a36Sopenharmony_ci	/* Allocate ioaccel2 mode command blocks and block fetch table */
942662306a36Sopenharmony_ci
942762306a36Sopenharmony_ci	h->ioaccel_maxsg =
942862306a36Sopenharmony_ci		readl(&(h->cfgtable->io_accel_max_embedded_sg_count));
942962306a36Sopenharmony_ci	if (h->ioaccel_maxsg > IOACCEL2_MAXSGENTRIES)
943062306a36Sopenharmony_ci		h->ioaccel_maxsg = IOACCEL2_MAXSGENTRIES;
943162306a36Sopenharmony_ci
943262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct io_accel2_cmd) %
943362306a36Sopenharmony_ci			IOACCEL2_COMMANDLIST_ALIGNMENT);
943462306a36Sopenharmony_ci	h->ioaccel2_cmd_pool =
943562306a36Sopenharmony_ci		dma_alloc_coherent(&h->pdev->dev,
943662306a36Sopenharmony_ci			h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool),
943762306a36Sopenharmony_ci			&h->ioaccel2_cmd_pool_dhandle, GFP_KERNEL);
943862306a36Sopenharmony_ci
943962306a36Sopenharmony_ci	h->ioaccel2_blockFetchTable =
944062306a36Sopenharmony_ci		kmalloc(((h->ioaccel_maxsg + 1) *
944162306a36Sopenharmony_ci				sizeof(u32)), GFP_KERNEL);
944262306a36Sopenharmony_ci
944362306a36Sopenharmony_ci	if ((h->ioaccel2_cmd_pool == NULL) ||
944462306a36Sopenharmony_ci		(h->ioaccel2_blockFetchTable == NULL)) {
944562306a36Sopenharmony_ci		rc = -ENOMEM;
944662306a36Sopenharmony_ci		goto clean_up;
944762306a36Sopenharmony_ci	}
944862306a36Sopenharmony_ci
944962306a36Sopenharmony_ci	rc = hpsa_allocate_ioaccel2_sg_chain_blocks(h);
945062306a36Sopenharmony_ci	if (rc)
945162306a36Sopenharmony_ci		goto clean_up;
945262306a36Sopenharmony_ci
945362306a36Sopenharmony_ci	memset(h->ioaccel2_cmd_pool, 0,
945462306a36Sopenharmony_ci		h->nr_cmds * sizeof(*h->ioaccel2_cmd_pool));
945562306a36Sopenharmony_ci	return 0;
945662306a36Sopenharmony_ci
945762306a36Sopenharmony_ciclean_up:
945862306a36Sopenharmony_ci	hpsa_free_ioaccel2_cmd_and_bft(h);
945962306a36Sopenharmony_ci	return rc;
946062306a36Sopenharmony_ci}
946162306a36Sopenharmony_ci
946262306a36Sopenharmony_ci/* Free items allocated by hpsa_put_ctlr_into_performant_mode */
946362306a36Sopenharmony_cistatic void hpsa_free_performant_mode(struct ctlr_info *h)
946462306a36Sopenharmony_ci{
946562306a36Sopenharmony_ci	kfree(h->blockFetchTable);
946662306a36Sopenharmony_ci	h->blockFetchTable = NULL;
946762306a36Sopenharmony_ci	hpsa_free_reply_queues(h);
946862306a36Sopenharmony_ci	hpsa_free_ioaccel1_cmd_and_bft(h);
946962306a36Sopenharmony_ci	hpsa_free_ioaccel2_cmd_and_bft(h);
947062306a36Sopenharmony_ci}
947162306a36Sopenharmony_ci
947262306a36Sopenharmony_ci/* return -ENODEV on error, 0 on success (or no action)
947362306a36Sopenharmony_ci * allocates numerous items that must be freed later
947462306a36Sopenharmony_ci */
947562306a36Sopenharmony_cistatic int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
947662306a36Sopenharmony_ci{
947762306a36Sopenharmony_ci	u32 trans_support;
947862306a36Sopenharmony_ci	int i, rc;
947962306a36Sopenharmony_ci
948062306a36Sopenharmony_ci	if (hpsa_simple_mode)
948162306a36Sopenharmony_ci		return 0;
948262306a36Sopenharmony_ci
948362306a36Sopenharmony_ci	trans_support = readl(&(h->cfgtable->TransportSupport));
948462306a36Sopenharmony_ci	if (!(trans_support & PERFORMANT_MODE))
948562306a36Sopenharmony_ci		return 0;
948662306a36Sopenharmony_ci
948762306a36Sopenharmony_ci	/* Check for I/O accelerator mode support */
948862306a36Sopenharmony_ci	if (trans_support & CFGTBL_Trans_io_accel1) {
948962306a36Sopenharmony_ci		rc = hpsa_alloc_ioaccel1_cmd_and_bft(h);
949062306a36Sopenharmony_ci		if (rc)
949162306a36Sopenharmony_ci			return rc;
949262306a36Sopenharmony_ci	} else if (trans_support & CFGTBL_Trans_io_accel2) {
949362306a36Sopenharmony_ci		rc = hpsa_alloc_ioaccel2_cmd_and_bft(h);
949462306a36Sopenharmony_ci		if (rc)
949562306a36Sopenharmony_ci			return rc;
949662306a36Sopenharmony_ci	}
949762306a36Sopenharmony_ci
949862306a36Sopenharmony_ci	h->nreply_queues = h->msix_vectors > 0 ? h->msix_vectors : 1;
949962306a36Sopenharmony_ci	hpsa_get_max_perf_mode_cmds(h);
950062306a36Sopenharmony_ci	/* Performant mode ring buffer and supporting data structures */
950162306a36Sopenharmony_ci	h->reply_queue_size = h->max_commands * sizeof(u64);
950262306a36Sopenharmony_ci
950362306a36Sopenharmony_ci	for (i = 0; i < h->nreply_queues; i++) {
950462306a36Sopenharmony_ci		h->reply_queue[i].head = dma_alloc_coherent(&h->pdev->dev,
950562306a36Sopenharmony_ci						h->reply_queue_size,
950662306a36Sopenharmony_ci						&h->reply_queue[i].busaddr,
950762306a36Sopenharmony_ci						GFP_KERNEL);
950862306a36Sopenharmony_ci		if (!h->reply_queue[i].head) {
950962306a36Sopenharmony_ci			rc = -ENOMEM;
951062306a36Sopenharmony_ci			goto clean1;	/* rq, ioaccel */
951162306a36Sopenharmony_ci		}
951262306a36Sopenharmony_ci		h->reply_queue[i].size = h->max_commands;
951362306a36Sopenharmony_ci		h->reply_queue[i].wraparound = 1;  /* spec: init to 1 */
951462306a36Sopenharmony_ci		h->reply_queue[i].current_entry = 0;
951562306a36Sopenharmony_ci	}
951662306a36Sopenharmony_ci
951762306a36Sopenharmony_ci	/* Need a block fetch table for performant mode */
951862306a36Sopenharmony_ci	h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) *
951962306a36Sopenharmony_ci				sizeof(u32)), GFP_KERNEL);
952062306a36Sopenharmony_ci	if (!h->blockFetchTable) {
952162306a36Sopenharmony_ci		rc = -ENOMEM;
952262306a36Sopenharmony_ci		goto clean1;	/* rq, ioaccel */
952362306a36Sopenharmony_ci	}
952462306a36Sopenharmony_ci
952562306a36Sopenharmony_ci	rc = hpsa_enter_performant_mode(h, trans_support);
952662306a36Sopenharmony_ci	if (rc)
952762306a36Sopenharmony_ci		goto clean2;	/* bft, rq, ioaccel */
952862306a36Sopenharmony_ci	return 0;
952962306a36Sopenharmony_ci
953062306a36Sopenharmony_ciclean2:	/* bft, rq, ioaccel */
953162306a36Sopenharmony_ci	kfree(h->blockFetchTable);
953262306a36Sopenharmony_ci	h->blockFetchTable = NULL;
953362306a36Sopenharmony_ciclean1:	/* rq, ioaccel */
953462306a36Sopenharmony_ci	hpsa_free_reply_queues(h);
953562306a36Sopenharmony_ci	hpsa_free_ioaccel1_cmd_and_bft(h);
953662306a36Sopenharmony_ci	hpsa_free_ioaccel2_cmd_and_bft(h);
953762306a36Sopenharmony_ci	return rc;
953862306a36Sopenharmony_ci}
953962306a36Sopenharmony_ci
954062306a36Sopenharmony_cistatic int is_accelerated_cmd(struct CommandList *c)
954162306a36Sopenharmony_ci{
954262306a36Sopenharmony_ci	return c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_IOACCEL2;
954362306a36Sopenharmony_ci}
954462306a36Sopenharmony_ci
954562306a36Sopenharmony_cistatic void hpsa_drain_accel_commands(struct ctlr_info *h)
954662306a36Sopenharmony_ci{
954762306a36Sopenharmony_ci	struct CommandList *c = NULL;
954862306a36Sopenharmony_ci	int i, accel_cmds_out;
954962306a36Sopenharmony_ci	int refcount;
955062306a36Sopenharmony_ci
955162306a36Sopenharmony_ci	do { /* wait for all outstanding ioaccel commands to drain out */
955262306a36Sopenharmony_ci		accel_cmds_out = 0;
955362306a36Sopenharmony_ci		for (i = 0; i < h->nr_cmds; i++) {
955462306a36Sopenharmony_ci			c = h->cmd_pool + i;
955562306a36Sopenharmony_ci			refcount = atomic_inc_return(&c->refcount);
955662306a36Sopenharmony_ci			if (refcount > 1) /* Command is allocated */
955762306a36Sopenharmony_ci				accel_cmds_out += is_accelerated_cmd(c);
955862306a36Sopenharmony_ci			cmd_free(h, c);
955962306a36Sopenharmony_ci		}
956062306a36Sopenharmony_ci		if (accel_cmds_out <= 0)
956162306a36Sopenharmony_ci			break;
956262306a36Sopenharmony_ci		msleep(100);
956362306a36Sopenharmony_ci	} while (1);
956462306a36Sopenharmony_ci}
956562306a36Sopenharmony_ci
956662306a36Sopenharmony_cistatic struct hpsa_sas_phy *hpsa_alloc_sas_phy(
956762306a36Sopenharmony_ci				struct hpsa_sas_port *hpsa_sas_port)
956862306a36Sopenharmony_ci{
956962306a36Sopenharmony_ci	struct hpsa_sas_phy *hpsa_sas_phy;
957062306a36Sopenharmony_ci	struct sas_phy *phy;
957162306a36Sopenharmony_ci
957262306a36Sopenharmony_ci	hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL);
957362306a36Sopenharmony_ci	if (!hpsa_sas_phy)
957462306a36Sopenharmony_ci		return NULL;
957562306a36Sopenharmony_ci
957662306a36Sopenharmony_ci	phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev,
957762306a36Sopenharmony_ci		hpsa_sas_port->next_phy_index);
957862306a36Sopenharmony_ci	if (!phy) {
957962306a36Sopenharmony_ci		kfree(hpsa_sas_phy);
958062306a36Sopenharmony_ci		return NULL;
958162306a36Sopenharmony_ci	}
958262306a36Sopenharmony_ci
958362306a36Sopenharmony_ci	hpsa_sas_port->next_phy_index++;
958462306a36Sopenharmony_ci	hpsa_sas_phy->phy = phy;
958562306a36Sopenharmony_ci	hpsa_sas_phy->parent_port = hpsa_sas_port;
958662306a36Sopenharmony_ci
958762306a36Sopenharmony_ci	return hpsa_sas_phy;
958862306a36Sopenharmony_ci}
958962306a36Sopenharmony_ci
959062306a36Sopenharmony_cistatic void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy)
959162306a36Sopenharmony_ci{
959262306a36Sopenharmony_ci	struct sas_phy *phy = hpsa_sas_phy->phy;
959362306a36Sopenharmony_ci
959462306a36Sopenharmony_ci	sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy);
959562306a36Sopenharmony_ci	if (hpsa_sas_phy->added_to_port)
959662306a36Sopenharmony_ci		list_del(&hpsa_sas_phy->phy_list_entry);
959762306a36Sopenharmony_ci	sas_phy_delete(phy);
959862306a36Sopenharmony_ci	kfree(hpsa_sas_phy);
959962306a36Sopenharmony_ci}
960062306a36Sopenharmony_ci
960162306a36Sopenharmony_cistatic int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy)
960262306a36Sopenharmony_ci{
960362306a36Sopenharmony_ci	int rc;
960462306a36Sopenharmony_ci	struct hpsa_sas_port *hpsa_sas_port;
960562306a36Sopenharmony_ci	struct sas_phy *phy;
960662306a36Sopenharmony_ci	struct sas_identify *identify;
960762306a36Sopenharmony_ci
960862306a36Sopenharmony_ci	hpsa_sas_port = hpsa_sas_phy->parent_port;
960962306a36Sopenharmony_ci	phy = hpsa_sas_phy->phy;
961062306a36Sopenharmony_ci
961162306a36Sopenharmony_ci	identify = &phy->identify;
961262306a36Sopenharmony_ci	memset(identify, 0, sizeof(*identify));
961362306a36Sopenharmony_ci	identify->sas_address = hpsa_sas_port->sas_address;
961462306a36Sopenharmony_ci	identify->device_type = SAS_END_DEVICE;
961562306a36Sopenharmony_ci	identify->initiator_port_protocols = SAS_PROTOCOL_STP;
961662306a36Sopenharmony_ci	identify->target_port_protocols = SAS_PROTOCOL_STP;
961762306a36Sopenharmony_ci	phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
961862306a36Sopenharmony_ci	phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
961962306a36Sopenharmony_ci	phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
962062306a36Sopenharmony_ci	phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
962162306a36Sopenharmony_ci	phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
962262306a36Sopenharmony_ci
962362306a36Sopenharmony_ci	rc = sas_phy_add(hpsa_sas_phy->phy);
962462306a36Sopenharmony_ci	if (rc)
962562306a36Sopenharmony_ci		return rc;
962662306a36Sopenharmony_ci
962762306a36Sopenharmony_ci	sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy);
962862306a36Sopenharmony_ci	list_add_tail(&hpsa_sas_phy->phy_list_entry,
962962306a36Sopenharmony_ci			&hpsa_sas_port->phy_list_head);
963062306a36Sopenharmony_ci	hpsa_sas_phy->added_to_port = true;
963162306a36Sopenharmony_ci
963262306a36Sopenharmony_ci	return 0;
963362306a36Sopenharmony_ci}
963462306a36Sopenharmony_ci
963562306a36Sopenharmony_cistatic int
963662306a36Sopenharmony_ci	hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port,
963762306a36Sopenharmony_ci				struct sas_rphy *rphy)
963862306a36Sopenharmony_ci{
963962306a36Sopenharmony_ci	struct sas_identify *identify;
964062306a36Sopenharmony_ci
964162306a36Sopenharmony_ci	identify = &rphy->identify;
964262306a36Sopenharmony_ci	identify->sas_address = hpsa_sas_port->sas_address;
964362306a36Sopenharmony_ci	identify->initiator_port_protocols = SAS_PROTOCOL_STP;
964462306a36Sopenharmony_ci	identify->target_port_protocols = SAS_PROTOCOL_STP;
964562306a36Sopenharmony_ci
964662306a36Sopenharmony_ci	return sas_rphy_add(rphy);
964762306a36Sopenharmony_ci}
964862306a36Sopenharmony_ci
964962306a36Sopenharmony_cistatic struct hpsa_sas_port
965062306a36Sopenharmony_ci	*hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node,
965162306a36Sopenharmony_ci				u64 sas_address)
965262306a36Sopenharmony_ci{
965362306a36Sopenharmony_ci	int rc;
965462306a36Sopenharmony_ci	struct hpsa_sas_port *hpsa_sas_port;
965562306a36Sopenharmony_ci	struct sas_port *port;
965662306a36Sopenharmony_ci
965762306a36Sopenharmony_ci	hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL);
965862306a36Sopenharmony_ci	if (!hpsa_sas_port)
965962306a36Sopenharmony_ci		return NULL;
966062306a36Sopenharmony_ci
966162306a36Sopenharmony_ci	INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head);
966262306a36Sopenharmony_ci	hpsa_sas_port->parent_node = hpsa_sas_node;
966362306a36Sopenharmony_ci
966462306a36Sopenharmony_ci	port = sas_port_alloc_num(hpsa_sas_node->parent_dev);
966562306a36Sopenharmony_ci	if (!port)
966662306a36Sopenharmony_ci		goto free_hpsa_port;
966762306a36Sopenharmony_ci
966862306a36Sopenharmony_ci	rc = sas_port_add(port);
966962306a36Sopenharmony_ci	if (rc)
967062306a36Sopenharmony_ci		goto free_sas_port;
967162306a36Sopenharmony_ci
967262306a36Sopenharmony_ci	hpsa_sas_port->port = port;
967362306a36Sopenharmony_ci	hpsa_sas_port->sas_address = sas_address;
967462306a36Sopenharmony_ci	list_add_tail(&hpsa_sas_port->port_list_entry,
967562306a36Sopenharmony_ci			&hpsa_sas_node->port_list_head);
967662306a36Sopenharmony_ci
967762306a36Sopenharmony_ci	return hpsa_sas_port;
967862306a36Sopenharmony_ci
967962306a36Sopenharmony_cifree_sas_port:
968062306a36Sopenharmony_ci	sas_port_free(port);
968162306a36Sopenharmony_cifree_hpsa_port:
968262306a36Sopenharmony_ci	kfree(hpsa_sas_port);
968362306a36Sopenharmony_ci
968462306a36Sopenharmony_ci	return NULL;
968562306a36Sopenharmony_ci}
968662306a36Sopenharmony_ci
968762306a36Sopenharmony_cistatic void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port)
968862306a36Sopenharmony_ci{
968962306a36Sopenharmony_ci	struct hpsa_sas_phy *hpsa_sas_phy;
969062306a36Sopenharmony_ci	struct hpsa_sas_phy *next;
969162306a36Sopenharmony_ci
969262306a36Sopenharmony_ci	list_for_each_entry_safe(hpsa_sas_phy, next,
969362306a36Sopenharmony_ci			&hpsa_sas_port->phy_list_head, phy_list_entry)
969462306a36Sopenharmony_ci		hpsa_free_sas_phy(hpsa_sas_phy);
969562306a36Sopenharmony_ci
969662306a36Sopenharmony_ci	sas_port_delete(hpsa_sas_port->port);
969762306a36Sopenharmony_ci	list_del(&hpsa_sas_port->port_list_entry);
969862306a36Sopenharmony_ci	kfree(hpsa_sas_port);
969962306a36Sopenharmony_ci}
970062306a36Sopenharmony_ci
970162306a36Sopenharmony_cistatic struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev)
970262306a36Sopenharmony_ci{
970362306a36Sopenharmony_ci	struct hpsa_sas_node *hpsa_sas_node;
970462306a36Sopenharmony_ci
970562306a36Sopenharmony_ci	hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL);
970662306a36Sopenharmony_ci	if (hpsa_sas_node) {
970762306a36Sopenharmony_ci		hpsa_sas_node->parent_dev = parent_dev;
970862306a36Sopenharmony_ci		INIT_LIST_HEAD(&hpsa_sas_node->port_list_head);
970962306a36Sopenharmony_ci	}
971062306a36Sopenharmony_ci
971162306a36Sopenharmony_ci	return hpsa_sas_node;
971262306a36Sopenharmony_ci}
971362306a36Sopenharmony_ci
971462306a36Sopenharmony_cistatic void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node)
971562306a36Sopenharmony_ci{
971662306a36Sopenharmony_ci	struct hpsa_sas_port *hpsa_sas_port;
971762306a36Sopenharmony_ci	struct hpsa_sas_port *next;
971862306a36Sopenharmony_ci
971962306a36Sopenharmony_ci	if (!hpsa_sas_node)
972062306a36Sopenharmony_ci		return;
972162306a36Sopenharmony_ci
972262306a36Sopenharmony_ci	list_for_each_entry_safe(hpsa_sas_port, next,
972362306a36Sopenharmony_ci			&hpsa_sas_node->port_list_head, port_list_entry)
972462306a36Sopenharmony_ci		hpsa_free_sas_port(hpsa_sas_port);
972562306a36Sopenharmony_ci
972662306a36Sopenharmony_ci	kfree(hpsa_sas_node);
972762306a36Sopenharmony_ci}
972862306a36Sopenharmony_ci
972962306a36Sopenharmony_cistatic struct hpsa_scsi_dev_t
973062306a36Sopenharmony_ci	*hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
973162306a36Sopenharmony_ci					struct sas_rphy *rphy)
973262306a36Sopenharmony_ci{
973362306a36Sopenharmony_ci	int i;
973462306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *device;
973562306a36Sopenharmony_ci
973662306a36Sopenharmony_ci	for (i = 0; i < h->ndevices; i++) {
973762306a36Sopenharmony_ci		device = h->dev[i];
973862306a36Sopenharmony_ci		if (!device->sas_port)
973962306a36Sopenharmony_ci			continue;
974062306a36Sopenharmony_ci		if (device->sas_port->rphy == rphy)
974162306a36Sopenharmony_ci			return device;
974262306a36Sopenharmony_ci	}
974362306a36Sopenharmony_ci
974462306a36Sopenharmony_ci	return NULL;
974562306a36Sopenharmony_ci}
974662306a36Sopenharmony_ci
974762306a36Sopenharmony_cistatic int hpsa_add_sas_host(struct ctlr_info *h)
974862306a36Sopenharmony_ci{
974962306a36Sopenharmony_ci	int rc;
975062306a36Sopenharmony_ci	struct device *parent_dev;
975162306a36Sopenharmony_ci	struct hpsa_sas_node *hpsa_sas_node;
975262306a36Sopenharmony_ci	struct hpsa_sas_port *hpsa_sas_port;
975362306a36Sopenharmony_ci	struct hpsa_sas_phy *hpsa_sas_phy;
975462306a36Sopenharmony_ci
975562306a36Sopenharmony_ci	parent_dev = &h->scsi_host->shost_dev;
975662306a36Sopenharmony_ci
975762306a36Sopenharmony_ci	hpsa_sas_node = hpsa_alloc_sas_node(parent_dev);
975862306a36Sopenharmony_ci	if (!hpsa_sas_node)
975962306a36Sopenharmony_ci		return -ENOMEM;
976062306a36Sopenharmony_ci
976162306a36Sopenharmony_ci	hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address);
976262306a36Sopenharmony_ci	if (!hpsa_sas_port) {
976362306a36Sopenharmony_ci		rc = -ENODEV;
976462306a36Sopenharmony_ci		goto free_sas_node;
976562306a36Sopenharmony_ci	}
976662306a36Sopenharmony_ci
976762306a36Sopenharmony_ci	hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port);
976862306a36Sopenharmony_ci	if (!hpsa_sas_phy) {
976962306a36Sopenharmony_ci		rc = -ENODEV;
977062306a36Sopenharmony_ci		goto free_sas_port;
977162306a36Sopenharmony_ci	}
977262306a36Sopenharmony_ci
977362306a36Sopenharmony_ci	rc = hpsa_sas_port_add_phy(hpsa_sas_phy);
977462306a36Sopenharmony_ci	if (rc)
977562306a36Sopenharmony_ci		goto free_sas_phy;
977662306a36Sopenharmony_ci
977762306a36Sopenharmony_ci	h->sas_host = hpsa_sas_node;
977862306a36Sopenharmony_ci
977962306a36Sopenharmony_ci	return 0;
978062306a36Sopenharmony_ci
978162306a36Sopenharmony_cifree_sas_phy:
978262306a36Sopenharmony_ci	sas_phy_free(hpsa_sas_phy->phy);
978362306a36Sopenharmony_ci	kfree(hpsa_sas_phy);
978462306a36Sopenharmony_cifree_sas_port:
978562306a36Sopenharmony_ci	hpsa_free_sas_port(hpsa_sas_port);
978662306a36Sopenharmony_cifree_sas_node:
978762306a36Sopenharmony_ci	hpsa_free_sas_node(hpsa_sas_node);
978862306a36Sopenharmony_ci
978962306a36Sopenharmony_ci	return rc;
979062306a36Sopenharmony_ci}
979162306a36Sopenharmony_ci
979262306a36Sopenharmony_cistatic void hpsa_delete_sas_host(struct ctlr_info *h)
979362306a36Sopenharmony_ci{
979462306a36Sopenharmony_ci	hpsa_free_sas_node(h->sas_host);
979562306a36Sopenharmony_ci}
979662306a36Sopenharmony_ci
979762306a36Sopenharmony_cistatic int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
979862306a36Sopenharmony_ci				struct hpsa_scsi_dev_t *device)
979962306a36Sopenharmony_ci{
980062306a36Sopenharmony_ci	int rc;
980162306a36Sopenharmony_ci	struct hpsa_sas_port *hpsa_sas_port;
980262306a36Sopenharmony_ci	struct sas_rphy *rphy;
980362306a36Sopenharmony_ci
980462306a36Sopenharmony_ci	hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address);
980562306a36Sopenharmony_ci	if (!hpsa_sas_port)
980662306a36Sopenharmony_ci		return -ENOMEM;
980762306a36Sopenharmony_ci
980862306a36Sopenharmony_ci	rphy = sas_end_device_alloc(hpsa_sas_port->port);
980962306a36Sopenharmony_ci	if (!rphy) {
981062306a36Sopenharmony_ci		rc = -ENODEV;
981162306a36Sopenharmony_ci		goto free_sas_port;
981262306a36Sopenharmony_ci	}
981362306a36Sopenharmony_ci
981462306a36Sopenharmony_ci	hpsa_sas_port->rphy = rphy;
981562306a36Sopenharmony_ci	device->sas_port = hpsa_sas_port;
981662306a36Sopenharmony_ci
981762306a36Sopenharmony_ci	rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy);
981862306a36Sopenharmony_ci	if (rc)
981962306a36Sopenharmony_ci		goto free_sas_rphy;
982062306a36Sopenharmony_ci
982162306a36Sopenharmony_ci	return 0;
982262306a36Sopenharmony_ci
982362306a36Sopenharmony_cifree_sas_rphy:
982462306a36Sopenharmony_ci	sas_rphy_free(rphy);
982562306a36Sopenharmony_cifree_sas_port:
982662306a36Sopenharmony_ci	hpsa_free_sas_port(hpsa_sas_port);
982762306a36Sopenharmony_ci	device->sas_port = NULL;
982862306a36Sopenharmony_ci
982962306a36Sopenharmony_ci	return rc;
983062306a36Sopenharmony_ci}
983162306a36Sopenharmony_ci
983262306a36Sopenharmony_cistatic void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device)
983362306a36Sopenharmony_ci{
983462306a36Sopenharmony_ci	if (device->sas_port) {
983562306a36Sopenharmony_ci		hpsa_free_sas_port(device->sas_port);
983662306a36Sopenharmony_ci		device->sas_port = NULL;
983762306a36Sopenharmony_ci	}
983862306a36Sopenharmony_ci}
983962306a36Sopenharmony_ci
984062306a36Sopenharmony_cistatic int
984162306a36Sopenharmony_cihpsa_sas_get_linkerrors(struct sas_phy *phy)
984262306a36Sopenharmony_ci{
984362306a36Sopenharmony_ci	return 0;
984462306a36Sopenharmony_ci}
984562306a36Sopenharmony_ci
984662306a36Sopenharmony_cistatic int
984762306a36Sopenharmony_cihpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
984862306a36Sopenharmony_ci{
984962306a36Sopenharmony_ci	struct Scsi_Host *shost = phy_to_shost(rphy);
985062306a36Sopenharmony_ci	struct ctlr_info *h;
985162306a36Sopenharmony_ci	struct hpsa_scsi_dev_t *sd;
985262306a36Sopenharmony_ci
985362306a36Sopenharmony_ci	if (!shost)
985462306a36Sopenharmony_ci		return -ENXIO;
985562306a36Sopenharmony_ci
985662306a36Sopenharmony_ci	h = shost_to_hba(shost);
985762306a36Sopenharmony_ci
985862306a36Sopenharmony_ci	if (!h)
985962306a36Sopenharmony_ci		return -ENXIO;
986062306a36Sopenharmony_ci
986162306a36Sopenharmony_ci	sd = hpsa_find_device_by_sas_rphy(h, rphy);
986262306a36Sopenharmony_ci	if (!sd)
986362306a36Sopenharmony_ci		return -ENXIO;
986462306a36Sopenharmony_ci
986562306a36Sopenharmony_ci	*identifier = sd->eli;
986662306a36Sopenharmony_ci
986762306a36Sopenharmony_ci	return 0;
986862306a36Sopenharmony_ci}
986962306a36Sopenharmony_ci
987062306a36Sopenharmony_cistatic int
987162306a36Sopenharmony_cihpsa_sas_get_bay_identifier(struct sas_rphy *rphy)
987262306a36Sopenharmony_ci{
987362306a36Sopenharmony_ci	return -ENXIO;
987462306a36Sopenharmony_ci}
987562306a36Sopenharmony_ci
987662306a36Sopenharmony_cistatic int
987762306a36Sopenharmony_cihpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset)
987862306a36Sopenharmony_ci{
987962306a36Sopenharmony_ci	return 0;
988062306a36Sopenharmony_ci}
988162306a36Sopenharmony_ci
988262306a36Sopenharmony_cistatic int
988362306a36Sopenharmony_cihpsa_sas_phy_enable(struct sas_phy *phy, int enable)
988462306a36Sopenharmony_ci{
988562306a36Sopenharmony_ci	return 0;
988662306a36Sopenharmony_ci}
988762306a36Sopenharmony_ci
988862306a36Sopenharmony_cistatic int
988962306a36Sopenharmony_cihpsa_sas_phy_setup(struct sas_phy *phy)
989062306a36Sopenharmony_ci{
989162306a36Sopenharmony_ci	return 0;
989262306a36Sopenharmony_ci}
989362306a36Sopenharmony_ci
989462306a36Sopenharmony_cistatic void
989562306a36Sopenharmony_cihpsa_sas_phy_release(struct sas_phy *phy)
989662306a36Sopenharmony_ci{
989762306a36Sopenharmony_ci}
989862306a36Sopenharmony_ci
989962306a36Sopenharmony_cistatic int
990062306a36Sopenharmony_cihpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
990162306a36Sopenharmony_ci{
990262306a36Sopenharmony_ci	return -EINVAL;
990362306a36Sopenharmony_ci}
990462306a36Sopenharmony_ci
990562306a36Sopenharmony_cistatic struct sas_function_template hpsa_sas_transport_functions = {
990662306a36Sopenharmony_ci	.get_linkerrors = hpsa_sas_get_linkerrors,
990762306a36Sopenharmony_ci	.get_enclosure_identifier = hpsa_sas_get_enclosure_identifier,
990862306a36Sopenharmony_ci	.get_bay_identifier = hpsa_sas_get_bay_identifier,
990962306a36Sopenharmony_ci	.phy_reset = hpsa_sas_phy_reset,
991062306a36Sopenharmony_ci	.phy_enable = hpsa_sas_phy_enable,
991162306a36Sopenharmony_ci	.phy_setup = hpsa_sas_phy_setup,
991262306a36Sopenharmony_ci	.phy_release = hpsa_sas_phy_release,
991362306a36Sopenharmony_ci	.set_phy_speed = hpsa_sas_phy_speed,
991462306a36Sopenharmony_ci};
991562306a36Sopenharmony_ci
991662306a36Sopenharmony_ci/*
991762306a36Sopenharmony_ci *  This is it.  Register the PCI driver information for the cards we control
991862306a36Sopenharmony_ci *  the OS will call our registered routines when it finds one of our cards.
991962306a36Sopenharmony_ci */
992062306a36Sopenharmony_cistatic int __init hpsa_init(void)
992162306a36Sopenharmony_ci{
992262306a36Sopenharmony_ci	int rc;
992362306a36Sopenharmony_ci
992462306a36Sopenharmony_ci	hpsa_sas_transport_template =
992562306a36Sopenharmony_ci		sas_attach_transport(&hpsa_sas_transport_functions);
992662306a36Sopenharmony_ci	if (!hpsa_sas_transport_template)
992762306a36Sopenharmony_ci		return -ENODEV;
992862306a36Sopenharmony_ci
992962306a36Sopenharmony_ci	rc = pci_register_driver(&hpsa_pci_driver);
993062306a36Sopenharmony_ci
993162306a36Sopenharmony_ci	if (rc)
993262306a36Sopenharmony_ci		sas_release_transport(hpsa_sas_transport_template);
993362306a36Sopenharmony_ci
993462306a36Sopenharmony_ci	return rc;
993562306a36Sopenharmony_ci}
993662306a36Sopenharmony_ci
993762306a36Sopenharmony_cistatic void __exit hpsa_cleanup(void)
993862306a36Sopenharmony_ci{
993962306a36Sopenharmony_ci	pci_unregister_driver(&hpsa_pci_driver);
994062306a36Sopenharmony_ci	sas_release_transport(hpsa_sas_transport_template);
994162306a36Sopenharmony_ci}
994262306a36Sopenharmony_ci
994362306a36Sopenharmony_cistatic void __attribute__((unused)) verify_offsets(void)
994462306a36Sopenharmony_ci{
994562306a36Sopenharmony_ci#define VERIFY_OFFSET(member, offset) \
994662306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct raid_map_data, member) != offset)
994762306a36Sopenharmony_ci
994862306a36Sopenharmony_ci	VERIFY_OFFSET(structure_size, 0);
994962306a36Sopenharmony_ci	VERIFY_OFFSET(volume_blk_size, 4);
995062306a36Sopenharmony_ci	VERIFY_OFFSET(volume_blk_cnt, 8);
995162306a36Sopenharmony_ci	VERIFY_OFFSET(phys_blk_shift, 16);
995262306a36Sopenharmony_ci	VERIFY_OFFSET(parity_rotation_shift, 17);
995362306a36Sopenharmony_ci	VERIFY_OFFSET(strip_size, 18);
995462306a36Sopenharmony_ci	VERIFY_OFFSET(disk_starting_blk, 20);
995562306a36Sopenharmony_ci	VERIFY_OFFSET(disk_blk_cnt, 28);
995662306a36Sopenharmony_ci	VERIFY_OFFSET(data_disks_per_row, 36);
995762306a36Sopenharmony_ci	VERIFY_OFFSET(metadata_disks_per_row, 38);
995862306a36Sopenharmony_ci	VERIFY_OFFSET(row_cnt, 40);
995962306a36Sopenharmony_ci	VERIFY_OFFSET(layout_map_count, 42);
996062306a36Sopenharmony_ci	VERIFY_OFFSET(flags, 44);
996162306a36Sopenharmony_ci	VERIFY_OFFSET(dekindex, 46);
996262306a36Sopenharmony_ci	/* VERIFY_OFFSET(reserved, 48 */
996362306a36Sopenharmony_ci	VERIFY_OFFSET(data, 64);
996462306a36Sopenharmony_ci
996562306a36Sopenharmony_ci#undef VERIFY_OFFSET
996662306a36Sopenharmony_ci
996762306a36Sopenharmony_ci#define VERIFY_OFFSET(member, offset) \
996862306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct io_accel2_cmd, member) != offset)
996962306a36Sopenharmony_ci
997062306a36Sopenharmony_ci	VERIFY_OFFSET(IU_type, 0);
997162306a36Sopenharmony_ci	VERIFY_OFFSET(direction, 1);
997262306a36Sopenharmony_ci	VERIFY_OFFSET(reply_queue, 2);
997362306a36Sopenharmony_ci	/* VERIFY_OFFSET(reserved1, 3);  */
997462306a36Sopenharmony_ci	VERIFY_OFFSET(scsi_nexus, 4);
997562306a36Sopenharmony_ci	VERIFY_OFFSET(Tag, 8);
997662306a36Sopenharmony_ci	VERIFY_OFFSET(cdb, 16);
997762306a36Sopenharmony_ci	VERIFY_OFFSET(cciss_lun, 32);
997862306a36Sopenharmony_ci	VERIFY_OFFSET(data_len, 40);
997962306a36Sopenharmony_ci	VERIFY_OFFSET(cmd_priority_task_attr, 44);
998062306a36Sopenharmony_ci	VERIFY_OFFSET(sg_count, 45);
998162306a36Sopenharmony_ci	/* VERIFY_OFFSET(reserved3 */
998262306a36Sopenharmony_ci	VERIFY_OFFSET(err_ptr, 48);
998362306a36Sopenharmony_ci	VERIFY_OFFSET(err_len, 56);
998462306a36Sopenharmony_ci	/* VERIFY_OFFSET(reserved4  */
998562306a36Sopenharmony_ci	VERIFY_OFFSET(sg, 64);
998662306a36Sopenharmony_ci
998762306a36Sopenharmony_ci#undef VERIFY_OFFSET
998862306a36Sopenharmony_ci
998962306a36Sopenharmony_ci#define VERIFY_OFFSET(member, offset) \
999062306a36Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct io_accel1_cmd, member) != offset)
999162306a36Sopenharmony_ci
999262306a36Sopenharmony_ci	VERIFY_OFFSET(dev_handle, 0x00);
999362306a36Sopenharmony_ci	VERIFY_OFFSET(reserved1, 0x02);
999462306a36Sopenharmony_ci	VERIFY_OFFSET(function, 0x03);
999562306a36Sopenharmony_ci	VERIFY_OFFSET(reserved2, 0x04);
999662306a36Sopenharmony_ci	VERIFY_OFFSET(err_info, 0x0C);
999762306a36Sopenharmony_ci	VERIFY_OFFSET(reserved3, 0x10);
999862306a36Sopenharmony_ci	VERIFY_OFFSET(err_info_len, 0x12);
999962306a36Sopenharmony_ci	VERIFY_OFFSET(reserved4, 0x13);
1000062306a36Sopenharmony_ci	VERIFY_OFFSET(sgl_offset, 0x14);
1000162306a36Sopenharmony_ci	VERIFY_OFFSET(reserved5, 0x15);
1000262306a36Sopenharmony_ci	VERIFY_OFFSET(transfer_len, 0x1C);
1000362306a36Sopenharmony_ci	VERIFY_OFFSET(reserved6, 0x20);
1000462306a36Sopenharmony_ci	VERIFY_OFFSET(io_flags, 0x24);
1000562306a36Sopenharmony_ci	VERIFY_OFFSET(reserved7, 0x26);
1000662306a36Sopenharmony_ci	VERIFY_OFFSET(LUN, 0x34);
1000762306a36Sopenharmony_ci	VERIFY_OFFSET(control, 0x3C);
1000862306a36Sopenharmony_ci	VERIFY_OFFSET(CDB, 0x40);
1000962306a36Sopenharmony_ci	VERIFY_OFFSET(reserved8, 0x50);
1001062306a36Sopenharmony_ci	VERIFY_OFFSET(host_context_flags, 0x60);
1001162306a36Sopenharmony_ci	VERIFY_OFFSET(timeout_sec, 0x62);
1001262306a36Sopenharmony_ci	VERIFY_OFFSET(ReplyQueue, 0x64);
1001362306a36Sopenharmony_ci	VERIFY_OFFSET(reserved9, 0x65);
1001462306a36Sopenharmony_ci	VERIFY_OFFSET(tag, 0x68);
1001562306a36Sopenharmony_ci	VERIFY_OFFSET(host_addr, 0x70);
1001662306a36Sopenharmony_ci	VERIFY_OFFSET(CISS_LUN, 0x78);
1001762306a36Sopenharmony_ci	VERIFY_OFFSET(SG, 0x78 + 8);
1001862306a36Sopenharmony_ci#undef VERIFY_OFFSET
1001962306a36Sopenharmony_ci}
1002062306a36Sopenharmony_ci
1002162306a36Sopenharmony_cimodule_init(hpsa_init);
1002262306a36Sopenharmony_cimodule_exit(hpsa_cleanup);
10023