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, ¤t_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