/drivers/scsi/hpsa.c
C | 1567 lines | 1246 code | 143 blank | 178 comment | 185 complexity | fa2a3175bf00c09a473541e03ff8cffb MD5 | raw file
- /*
- * Disk Array driver for HP Smart Array SAS controllers
- * Copyright 2016 Microsemi Corporation
- * Copyright 2014-2015 PMC-Sierra, Inc.
- * Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
- *
- * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
- *
- */
- #include <linux/module.h>
- #include <linux/interrupt.h>
- #include <linux/types.h>
- #include <linux/pci.h>
- #include <linux/pci-aspm.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/fs.h>
- #include <linux/timer.h>
- #include <linux/init.h>
- #include <linux/spinlock.h>
- #include <linux/compat.h>
- #include <linux/blktrace_api.h>
- #include <linux/uaccess.h>
- #include <linux/io.h>
- #include <linux/dma-mapping.h>
- #include <linux/completion.h>
- #include <linux/moduleparam.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_tcq.h>
- #include <scsi/scsi_eh.h>
- #include <scsi/scsi_transport_sas.h>
- #include <scsi/scsi_dbg.h>
- #include <linux/cciss_ioctl.h>
- #include <linux/string.h>
- #include <linux/bitmap.h>
- #include <linux/atomic.h>
- #include <linux/jiffies.h>
- #include <linux/percpu-defs.h>
- #include <linux/percpu.h>
- #include <asm/unaligned.h>
- #include <asm/div64.h>
- #include "hpsa_cmd.h"
- #include "hpsa.h"
- /*
- * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
- * with an optional trailing '-' followed by a byte value (0-255).
- */
- #define HPSA_DRIVER_VERSION "3.4.16-0"
- #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
- #define HPSA "hpsa"
- /* How long to wait for CISS doorbell communication */
- #define CLEAR_EVENT_WAIT_INTERVAL 20 /* ms for each msleep() call */
- #define MODE_CHANGE_WAIT_INTERVAL 10 /* ms for each msleep() call */
- #define MAX_CLEAR_EVENT_WAIT 30000 /* times 20 ms = 600 s */
- #define MAX_MODE_CHANGE_WAIT 2000 /* times 10 ms = 20 s */
- #define MAX_IOCTL_CONFIG_WAIT 1000
- /*define how many times we will try a command because of bus resets */
- #define MAX_CMD_RETRIES 3
- /* Embedded module documentation macros - see modules.h */
- MODULE_AUTHOR("Hewlett-Packard Company");
- MODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \
- HPSA_DRIVER_VERSION);
- MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
- MODULE_VERSION(HPSA_DRIVER_VERSION);
- MODULE_LICENSE("GPL");
- static int hpsa_allow_any;
- module_param(hpsa_allow_any, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(hpsa_allow_any,
- "Allow hpsa driver to access unknown HP Smart Array hardware");
- static int hpsa_simple_mode;
- module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(hpsa_simple_mode,
- "Use 'simple mode' rather than 'performant mode'");
- /* define the PCI info for the cards we can control */
- static const struct pci_device_id hpsa_pci_device_id[] = {
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3356},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1921},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1929},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21BD},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21BE},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21BF},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C0},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C1},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C2},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C3},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C4},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C5},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C6},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C7},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C8},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21C9},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CA},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CB},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CC},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CD},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CE},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0580},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0581},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0582},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0583},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0584},
- {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0585},
- {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076},
- {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087},
- {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D},
- {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0088},
- {PCI_VENDOR_ID_HP, 0x333f, 0x103c, 0x333f},
- {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
- {0,}
- };
- MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id);
- /* board_id = Subsystem Device ID & Vendor ID
- * product = Marketing Name for the board
- * access = Address of the struct of function pointers
- */
- static struct board_type products[] = {
- {0x3241103C, "Smart Array P212", &SA5_access},
- {0x3243103C, "Smart Array P410", &SA5_access},
- {0x3245103C, "Smart Array P410i", &SA5_access},
- {0x3247103C, "Smart Array P411", &SA5_access},
- {0x3249103C, "Smart Array P812", &SA5_access},
- {0x324A103C, "Smart Array P712m", &SA5_access},
- {0x324B103C, "Smart Array P711m", &SA5_access},
- {0x3233103C, "HP StorageWorks 1210m", &SA5_access}, /* alias of 333f */
- {0x3350103C, "Smart Array P222", &SA5_access},
- {0x3351103C, "Smart Array P420", &SA5_access},
- {0x3352103C, "Smart Array P421", &SA5_access},
- {0x3353103C, "Smart Array P822", &SA5_access},
- {0x3354103C, "Smart Array P420i", &SA5_access},
- {0x3355103C, "Smart Array P220i", &SA5_access},
- {0x3356103C, "Smart Array P721m", &SA5_access},
- {0x1921103C, "Smart Array P830i", &SA5_access},
- {0x1922103C, "Smart Array P430", &SA5_access},
- {0x1923103C, "Smart Array P431", &SA5_access},
- {0x1924103C, "Smart Array P830", &SA5_access},
- {0x1926103C, "Smart Array P731m", &SA5_access},
- {0x1928103C, "Smart Array P230i", &SA5_access},
- {0x1929103C, "Smart Array P530", &SA5_access},
- {0x21BD103C, "Smart Array P244br", &SA5_access},
- {0x21BE103C, "Smart Array P741m", &SA5_access},
- {0x21BF103C, "Smart HBA H240ar", &SA5_access},
- {0x21C0103C, "Smart Array P440ar", &SA5_access},
- {0x21C1103C, "Smart Array P840ar", &SA5_access},
- {0x21C2103C, "Smart Array P440", &SA5_access},
- {0x21C3103C, "Smart Array P441", &SA5_access},
- {0x21C4103C, "Smart Array", &SA5_access},
- {0x21C5103C, "Smart Array P841", &SA5_access},
- {0x21C6103C, "Smart HBA H244br", &SA5_access},
- {0x21C7103C, "Smart HBA H240", &SA5_access},
- {0x21C8103C, "Smart HBA H241", &SA5_access},
- {0x21C9103C, "Smart Array", &SA5_access},
- {0x21CA103C, "Smart Array P246br", &SA5_access},
- {0x21CB103C, "Smart Array P840", &SA5_access},
- {0x21CC103C, "Smart Array", &SA5_access},
- {0x21CD103C, "Smart Array", &SA5_access},
- {0x21CE103C, "Smart HBA", &SA5_access},
- {0x05809005, "SmartHBA-SA", &SA5_access},
- {0x05819005, "SmartHBA-SA 8i", &SA5_access},
- {0x05829005, "SmartHBA-SA 8i8e", &SA5_access},
- {0x05839005, "SmartHBA-SA 8e", &SA5_access},
- {0x05849005, "SmartHBA-SA 16i", &SA5_access},
- {0x05859005, "SmartHBA-SA 4i4e", &SA5_access},
- {0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
- {0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
- {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
- {0x00881590, "HP Storage P1228e Array Controller", &SA5_access},
- {0x333f103c, "HP StorageWorks 1210m Array Controller", &SA5_access},
- {0xFFFF103C, "Unknown Smart Array", &SA5_access},
- };
- static struct scsi_transport_template *hpsa_sas_transport_template;
- static int hpsa_add_sas_host(struct ctlr_info *h);
- static void hpsa_delete_sas_host(struct ctlr_info *h);
- static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
- struct hpsa_scsi_dev_t *device);
- static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device);
- static struct hpsa_scsi_dev_t
- *hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
- struct sas_rphy *rphy);
- #define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy)
- static const struct scsi_cmnd hpsa_cmd_busy;
- #define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle)
- static const struct scsi_cmnd hpsa_cmd_idle;
- static int number_of_controllers;
- static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
- static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
- static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
- #ifdef CONFIG_COMPAT
- static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd,
- void __user *arg);
- #endif
- static void cmd_free(struct ctlr_info *h, struct CommandList *c);
- static struct CommandList *cmd_alloc(struct ctlr_info *h);
- static void cmd_tagged_free(struct ctlr_info *h, struct CommandList *c);
- static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
- struct scsi_cmnd *scmd);
- static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
- void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
- int cmd_type);
- static void hpsa_free_cmd_pool(struct ctlr_info *h);
- #define VPD_PAGE (1 << 8)
- #define HPSA_SIMPLE_ERROR_BITS 0x03
- static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
- static void hpsa_scan_start(struct Scsi_Host *);
- static int hpsa_scan_finished(struct Scsi_Host *sh,
- unsigned long elapsed_time);
- static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth);
- static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
- static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
- static int hpsa_slave_alloc(struct scsi_device *sdev);
- static int hpsa_slave_configure(struct scsi_device *sdev);
- static void hpsa_slave_destroy(struct scsi_device *sdev);
- static void hpsa_update_scsi_devices(struct ctlr_info *h);
- static int check_for_unit_attention(struct ctlr_info *h,
- struct CommandList *c);
- static void check_ioctl_unit_attention(struct ctlr_info *h,
- struct CommandList *c);
- /* performant mode helper functions */
- static void calc_bucket_map(int *bucket, int num_buckets,
- int nsgs, int min_blocks, u32 *bucket_map);
- static void hpsa_free_performant_mode(struct ctlr_info *h);
- static int hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
- static inline u32 next_command(struct ctlr_info *h, u8 q);
- static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
- u32 *cfg_base_addr, u64 *cfg_base_addr_index,
- u64 *cfg_offset);
- static int hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
- unsigned long *memory_bar);
- static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
- static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
- int wait_for_ready);
- static inline void finish_cmd(struct CommandList *c);
- static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
- #define BOARD_NOT_READY 0
- #define BOARD_READY 1
- static void hpsa_drain_accel_commands(struct ctlr_info *h);
- static void hpsa_flush_cache(struct ctlr_info *h);
- static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
- struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
- u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk);
- static void hpsa_command_resubmit_worker(struct work_struct *work);
- static u32 lockup_detected(struct ctlr_info *h);
- static int detect_controller_lockup(struct ctlr_info *h);
- static void hpsa_disable_rld_caching(struct ctlr_info *h);
- static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
- struct ReportExtendedLUNdata *buf, int bufsize);
- static int hpsa_luns_changed(struct ctlr_info *h);
- static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
- struct hpsa_scsi_dev_t *dev,
- unsigned char *scsi3addr);
- static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
- {
- unsigned long *priv = shost_priv(sdev->host);
- return (struct ctlr_info *) *priv;
- }
- static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
- {
- unsigned long *priv = shost_priv(sh);
- return (struct ctlr_info *) *priv;
- }
- static inline bool hpsa_is_cmd_idle(struct CommandList *c)
- {
- return c->scsi_cmd == SCSI_CMD_IDLE;
- }
- static inline bool hpsa_is_pending_event(struct CommandList *c)
- {
- return c->abort_pending || c->reset_pending;
- }
- /* extract sense key, asc, and ascq from sense data. -1 means invalid. */
- static void decode_sense_data(const u8 *sense_data, int sense_data_len,
- u8 *sense_key, u8 *asc, u8 *ascq)
- {
- struct scsi_sense_hdr sshdr;
- bool rc;
- *sense_key = -1;
- *asc = -1;
- *ascq = -1;
- if (sense_data_len < 1)
- return;
- rc = scsi_normalize_sense(sense_data, sense_data_len, &sshdr);
- if (rc) {
- *sense_key = sshdr.sense_key;
- *asc = sshdr.asc;
- *ascq = sshdr.ascq;
- }
- }
- static int check_for_unit_attention(struct ctlr_info *h,
- struct CommandList *c)
- {
- u8 sense_key, asc, ascq;
- int sense_len;
- if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
- sense_len = sizeof(c->err_info->SenseInfo);
- else
- sense_len = c->err_info->SenseLen;
- decode_sense_data(c->err_info->SenseInfo, sense_len,
- &sense_key, &asc, &ascq);
- if (sense_key != UNIT_ATTENTION || asc == 0xff)
- return 0;
- switch (asc) {
- case STATE_CHANGED:
- dev_warn(&h->pdev->dev,
- "%s: a state change detected, command retried\n",
- h->devname);
- break;
- case LUN_FAILED:
- dev_warn(&h->pdev->dev,
- "%s: LUN failure detected\n", h->devname);
- break;
- case REPORT_LUNS_CHANGED:
- dev_warn(&h->pdev->dev,
- "%s: report LUN data changed\n", h->devname);
- /*
- * Note: this REPORT_LUNS_CHANGED condition only occurs on the external
- * target (array) devices.
- */
- break;
- case POWER_OR_RESET:
- dev_warn(&h->pdev->dev,
- "%s: a power on or device reset detected\n",
- h->devname);
- break;
- case UNIT_ATTENTION_CLEARED:
- dev_warn(&h->pdev->dev,
- "%s: unit attention cleared by another initiator\n",
- h->devname);
- break;
- default:
- dev_warn(&h->pdev->dev,
- "%s: unknown unit attention detected\n",
- h->devname);
- break;
- }
- return 1;
- }
- static int check_for_busy(struct ctlr_info *h, struct CommandList *c)
- {
- if (c->err_info->CommandStatus != CMD_TARGET_STATUS ||
- (c->err_info->ScsiStatus != SAM_STAT_BUSY &&
- c->err_info->ScsiStatus != SAM_STAT_TASK_SET_FULL))
- return 0;
- dev_warn(&h->pdev->dev, HPSA "device busy");
- return 1;
- }
- static u32 lockup_detected(struct ctlr_info *h);
- static ssize_t host_show_lockup_detected(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- int ld;
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- h = shost_to_hba(shost);
- ld = lockup_detected(h);
- return sprintf(buf, "ld=%d\n", ld);
- }
- static ssize_t host_store_hp_ssd_smart_path_status(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- int status, len;
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- char tmpbuf[10];
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
- strncpy(tmpbuf, buf, len);
- tmpbuf[len] = '\0';
- if (sscanf(tmpbuf, "%d", &status) != 1)
- return -EINVAL;
- h = shost_to_hba(shost);
- h->acciopath_status = !!status;
- dev_warn(&h->pdev->dev,
- "hpsa: HP SSD Smart Path %s via sysfs update.\n",
- h->acciopath_status ? "enabled" : "disabled");
- return count;
- }
- static ssize_t host_store_raid_offload_debug(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- int debug_level, len;
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- char tmpbuf[10];
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- len = count > sizeof(tmpbuf) - 1 ? sizeof(tmpbuf) - 1 : count;
- strncpy(tmpbuf, buf, len);
- tmpbuf[len] = '\0';
- if (sscanf(tmpbuf, "%d", &debug_level) != 1)
- return -EINVAL;
- if (debug_level < 0)
- debug_level = 0;
- h = shost_to_hba(shost);
- h->raid_offload_debug = debug_level;
- dev_warn(&h->pdev->dev, "hpsa: Set raid_offload_debug level = %d\n",
- h->raid_offload_debug);
- return count;
- }
- static ssize_t host_store_rescan(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- h = shost_to_hba(shost);
- hpsa_scan_start(h->scsi_host);
- return count;
- }
- static ssize_t host_show_firmware_revision(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- unsigned char *fwrev;
- h = shost_to_hba(shost);
- if (!h->hba_inquiry_data)
- return 0;
- fwrev = &h->hba_inquiry_data[32];
- return snprintf(buf, 20, "%c%c%c%c\n",
- fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
- }
- static ssize_t host_show_commands_outstanding(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct Scsi_Host *shost = class_to_shost(dev);
- struct ctlr_info *h = shost_to_hba(shost);
- return snprintf(buf, 20, "%d\n",
- atomic_read(&h->commands_outstanding));
- }
- static ssize_t host_show_transport_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- h = shost_to_hba(shost);
- return snprintf(buf, 20, "%s\n",
- h->transMethod & CFGTBL_Trans_Performant ?
- "performant" : "simple");
- }
- static ssize_t host_show_hp_ssd_smart_path_status(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- h = shost_to_hba(shost);
- return snprintf(buf, 30, "HP SSD Smart Path %s\n",
- (h->acciopath_status == 1) ? "enabled" : "disabled");
- }
- /* List of controllers which cannot be hard reset on kexec with reset_devices */
- static u32 unresettable_controller[] = {
- 0x324a103C, /* Smart Array P712m */
- 0x324b103C, /* Smart Array P711m */
- 0x3223103C, /* Smart Array P800 */
- 0x3234103C, /* Smart Array P400 */
- 0x3235103C, /* Smart Array P400i */
- 0x3211103C, /* Smart Array E200i */
- 0x3212103C, /* Smart Array E200 */
- 0x3213103C, /* Smart Array E200i */
- 0x3214103C, /* Smart Array E200i */
- 0x3215103C, /* Smart Array E200i */
- 0x3237103C, /* Smart Array E500 */
- 0x323D103C, /* Smart Array P700m */
- 0x40800E11, /* Smart Array 5i */
- 0x409C0E11, /* Smart Array 6400 */
- 0x409D0E11, /* Smart Array 6400 EM */
- 0x40700E11, /* Smart Array 5300 */
- 0x40820E11, /* Smart Array 532 */
- 0x40830E11, /* Smart Array 5312 */
- 0x409A0E11, /* Smart Array 641 */
- 0x409B0E11, /* Smart Array 642 */
- 0x40910E11, /* Smart Array 6i */
- };
- /* List of controllers which cannot even be soft reset */
- static u32 soft_unresettable_controller[] = {
- 0x40800E11, /* Smart Array 5i */
- 0x40700E11, /* Smart Array 5300 */
- 0x40820E11, /* Smart Array 532 */
- 0x40830E11, /* Smart Array 5312 */
- 0x409A0E11, /* Smart Array 641 */
- 0x409B0E11, /* Smart Array 642 */
- 0x40910E11, /* Smart Array 6i */
- /* Exclude 640x boards. These are two pci devices in one slot
- * which share a battery backed cache module. One controls the
- * cache, the other accesses the cache through the one that controls
- * it. If we reset the one controlling the cache, the other will
- * likely not be happy. Just forbid resetting this conjoined mess.
- * The 640x isn't really supported by hpsa anyway.
- */
- 0x409C0E11, /* Smart Array 6400 */
- 0x409D0E11, /* Smart Array 6400 EM */
- };
- static u32 needs_abort_tags_swizzled[] = {
- 0x323D103C, /* Smart Array P700m */
- 0x324a103C, /* Smart Array P712m */
- 0x324b103C, /* SmartArray P711m */
- };
- static int board_id_in_array(u32 a[], int nelems, u32 board_id)
- {
- int i;
- for (i = 0; i < nelems; i++)
- if (a[i] == board_id)
- return 1;
- return 0;
- }
- static int ctlr_is_hard_resettable(u32 board_id)
- {
- return !board_id_in_array(unresettable_controller,
- ARRAY_SIZE(unresettable_controller), board_id);
- }
- static int ctlr_is_soft_resettable(u32 board_id)
- {
- return !board_id_in_array(soft_unresettable_controller,
- ARRAY_SIZE(soft_unresettable_controller), board_id);
- }
- static int ctlr_is_resettable(u32 board_id)
- {
- return ctlr_is_hard_resettable(board_id) ||
- ctlr_is_soft_resettable(board_id);
- }
- static int ctlr_needs_abort_tags_swizzled(u32 board_id)
- {
- return board_id_in_array(needs_abort_tags_swizzled,
- ARRAY_SIZE(needs_abort_tags_swizzled), board_id);
- }
- static ssize_t host_show_resettable(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct Scsi_Host *shost = class_to_shost(dev);
- h = shost_to_hba(shost);
- return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
- }
- static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
- {
- return (scsi3addr[3] & 0xC0) == 0x40;
- }
- static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
- "1(+0)ADM", "UNKNOWN", "PHYS DRV"
- };
- #define HPSA_RAID_0 0
- #define HPSA_RAID_4 1
- #define HPSA_RAID_1 2 /* also used for RAID 10 */
- #define HPSA_RAID_5 3 /* also used for RAID 50 */
- #define HPSA_RAID_51 4
- #define HPSA_RAID_6 5 /* also used for RAID 60 */
- #define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
- #define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2)
- #define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1)
- static inline bool is_logical_device(struct hpsa_scsi_dev_t *device)
- {
- return !device->physical_device;
- }
- static ssize_t raid_level_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- ssize_t l = 0;
- unsigned char rlevel;
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->lock, flags);
- hdev = sdev->hostdata;
- if (!hdev) {
- spin_unlock_irqrestore(&h->lock, flags);
- return -ENODEV;
- }
- /* Is this even a logical drive? */
- if (!is_logical_device(hdev)) {
- spin_unlock_irqrestore(&h->lock, flags);
- l = snprintf(buf, PAGE_SIZE, "N/A\n");
- return l;
- }
- rlevel = hdev->raid_level;
- spin_unlock_irqrestore(&h->lock, flags);
- if (rlevel > RAID_UNKNOWN)
- rlevel = RAID_UNKNOWN;
- l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]);
- return l;
- }
- static ssize_t lunid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- unsigned char lunid[8];
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->lock, flags);
- hdev = sdev->hostdata;
- if (!hdev) {
- spin_unlock_irqrestore(&h->lock, flags);
- return -ENODEV;
- }
- memcpy(lunid, hdev->scsi3addr, sizeof(lunid));
- spin_unlock_irqrestore(&h->lock, flags);
- return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- lunid[0], lunid[1], lunid[2], lunid[3],
- lunid[4], lunid[5], lunid[6], lunid[7]);
- }
- static ssize_t unique_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- unsigned char sn[16];
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->lock, flags);
- hdev = sdev->hostdata;
- if (!hdev) {
- spin_unlock_irqrestore(&h->lock, flags);
- return -ENODEV;
- }
- memcpy(sn, hdev->device_id, sizeof(sn));
- spin_unlock_irqrestore(&h->lock, flags);
- return snprintf(buf, 16 * 2 + 2,
- "%02X%02X%02X%02X%02X%02X%02X%02X"
- "%02X%02X%02X%02X%02X%02X%02X%02X\n",
- sn[0], sn[1], sn[2], sn[3],
- sn[4], sn[5], sn[6], sn[7],
- sn[8], sn[9], sn[10], sn[11],
- sn[12], sn[13], sn[14], sn[15]);
- }
- static ssize_t sas_address_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- u64 sas_address;
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->lock, flags);
- hdev = sdev->hostdata;
- if (!hdev || is_logical_device(hdev) || !hdev->expose_device) {
- spin_unlock_irqrestore(&h->lock, flags);
- return -ENODEV;
- }
- sas_address = hdev->sas_address;
- spin_unlock_irqrestore(&h->lock, flags);
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n", sas_address);
- }
- static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- int offload_enabled;
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->lock, flags);
- hdev = sdev->hostdata;
- if (!hdev) {
- spin_unlock_irqrestore(&h->lock, flags);
- return -ENODEV;
- }
- offload_enabled = hdev->offload_enabled;
- spin_unlock_irqrestore(&h->lock, flags);
- return snprintf(buf, 20, "%d\n", offload_enabled);
- }
- #define MAX_PATHS 8
- static ssize_t path_info_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ctlr_info *h;
- struct scsi_device *sdev;
- struct hpsa_scsi_dev_t *hdev;
- unsigned long flags;
- int i;
- int output_len = 0;
- u8 box;
- u8 bay;
- u8 path_map_index = 0;
- char *active;
- unsigned char phys_connector[2];
- sdev = to_scsi_device(dev);
- h = sdev_to_hba(sdev);
- spin_lock_irqsave(&h->devlock, flags);
- hdev = sdev->hostdata;
- if (!hdev) {
- spin_unlock_irqrestore(&h->devlock, flags);
- return -ENODEV;
- }
- bay = hdev->bay;
- for (i = 0; i < MAX_PATHS; i++) {
- path_map_index = 1<<i;
- if (i == hdev->active_path_index)
- active = "Active";
- else if (hdev->path_map & path_map_index)
- active = "Inactive";
- else
- continue;
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len,
- "[%d:%d:%d:%d] %20.20s ",
- h->scsi_host->host_no,
- hdev->bus, hdev->target, hdev->lun,
- scsi_device_type(hdev->devtype));
- if (hdev->devtype == TYPE_RAID || is_logical_device(hdev)) {
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len,
- "%s\n", active);
- continue;
- }
- box = hdev->box[i];
- memcpy(&phys_connector, &hdev->phys_connector[i],
- sizeof(phys_connector));
- if (phys_connector[0] < '0')
- phys_connector[0] = '0';
- if (phys_connector[1] < '0')
- phys_connector[1] = '0';
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len,
- "PORT: %.2s ",
- phys_connector);
- if ((hdev->devtype == TYPE_DISK || hdev->devtype == TYPE_ZBC) &&
- hdev->expose_device) {
- if (box == 0 || box == 0xFF) {
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len,
- "BAY: %hhu %s\n",
- bay, active);
- } else {
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len,
- "BOX: %hhu BAY: %hhu %s\n",
- box, bay, active);
- }
- } else if (box != 0 && box != 0xFF) {
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len, "BOX: %hhu %s\n",
- box, active);
- } else
- output_len += scnprintf(buf + output_len,
- PAGE_SIZE - output_len, "%s\n", active);
- }
- spin_unlock_irqrestore(&h->devlock, flags);
- return output_len;
- }
- static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
- static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
- static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
- static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
- static DEVICE_ATTR(sas_address, S_IRUGO, sas_address_show, NULL);
- static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO,
- host_show_hp_ssd_smart_path_enabled, NULL);
- static DEVICE_ATTR(path_info, S_IRUGO, path_info_show, NULL);
- static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH,
- host_show_hp_ssd_smart_path_status,
- host_store_hp_ssd_smart_path_status);
- static DEVICE_ATTR(raid_offload_debug, S_IWUSR, NULL,
- host_store_raid_offload_debug);
- static DEVICE_ATTR(firmware_revision, S_IRUGO,
- host_show_firmware_revision, NULL);
- static DEVICE_ATTR(commands_outstanding, S_IRUGO,
- host_show_commands_outstanding, NULL);
- static DEVICE_ATTR(transport_mode, S_IRUGO,
- host_show_transport_mode, NULL);
- static DEVICE_ATTR(resettable, S_IRUGO,
- host_show_resettable, NULL);
- static DEVICE_ATTR(lockup_detected, S_IRUGO,
- host_show_lockup_detected, NULL);
- static struct device_attribute *hpsa_sdev_attrs[] = {
- &dev_attr_raid_level,
- &dev_attr_lunid,
- &dev_attr_unique_id,
- &dev_attr_hp_ssd_smart_path_enabled,
- &dev_attr_path_info,
- &dev_attr_sas_address,
- NULL,
- };
- static struct device_attribute *hpsa_shost_attrs[] = {
- &dev_attr_rescan,
- &dev_attr_firmware_revision,
- &dev_attr_commands_outstanding,
- &dev_attr_transport_mode,
- &dev_attr_resettable,
- &dev_attr_hp_ssd_smart_path_status,
- &dev_attr_raid_offload_debug,
- &dev_attr_lockup_detected,
- NULL,
- };
- #define HPSA_NRESERVED_CMDS (HPSA_CMDS_RESERVED_FOR_ABORTS + \
- HPSA_CMDS_RESERVED_FOR_DRIVER + HPSA_MAX_CONCURRENT_PASSTHRUS)
- static struct scsi_host_template hpsa_driver_template = {
- .module = THIS_MODULE,
- .name = HPSA,
- .proc_name = HPSA,
- .queuecommand = hpsa_scsi_queue_command,
- .scan_start = hpsa_scan_start,
- .scan_finished = hpsa_scan_finished,
- .change_queue_depth = hpsa_change_queue_depth,
- .this_id = -1,
- .use_clustering = ENABLE_CLUSTERING,
- .eh_abort_handler = hpsa_eh_abort_handler,
- .eh_device_reset_handler = hpsa_eh_device_reset_handler,
- .ioctl = hpsa_ioctl,
- .slave_alloc = hpsa_slave_alloc,
- .slave_configure = hpsa_slave_configure,
- .slave_destroy = hpsa_slave_destroy,
- #ifdef CONFIG_COMPAT
- .compat_ioctl = hpsa_compat_ioctl,
- #endif
- .sdev_attrs = hpsa_sdev_attrs,
- .shost_attrs = hpsa_shost_attrs,
- .max_sectors = 8192,
- .no_write_same = 1,
- };
- static inline u32 next_command(struct ctlr_info *h, u8 q)
- {
- u32 a;
- struct reply_queue_buffer *rq = &h->reply_queue[q];
- if (h->transMethod & CFGTBL_Trans_io_accel1)
- return h->access.command_completed(h, q);
- if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
- return h->access.command_completed(h, q);
- if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
- a = rq->head[rq->current_entry];
- rq->current_entry++;
- atomic_dec(&h->commands_outstanding);
- } else {
- a = FIFO_EMPTY;
- }
- /* Check for wraparound */
- if (rq->current_entry == h->max_commands) {
- rq->current_entry = 0;
- rq->wraparound ^= 1;
- }
- return a;
- }
- /*
- * There are some special bits in the bus address of the
- * command that we have to set for the controller to know
- * how to process the command:
- *
- * Normal performant mode:
- * bit 0: 1 means performant mode, 0 means simple mode.
- * bits 1-3 = block fetch table entry
- * bits 4-6 = command type (== 0)
- *
- * ioaccel1 mode:
- * bit 0 = "performant mode" bit.
- * bits 1-3 = block fetch table entry
- * bits 4-6 = command type (== 110)
- * (command type is needed because ioaccel1 mode
- * commands are submitted through the same register as normal
- * mode commands, so this is how the controller knows whether
- * the command is normal mode or ioaccel1 mode.)
- *
- * ioaccel2 mode:
- * bit 0 = "performant mode" bit.
- * bits 1-4 = block fetch table entry (note extra bit)
- * bits 4-6 = not needed, because ioaccel2 mode has
- * a separate special register for submitting commands.
- */
- /*
- * set_performant_mode: Modify the tag for cciss performant
- * set bit 0 for pull model, bits 3-1 for block fetch
- * register number
- */
- #define DEFAULT_REPLY_QUEUE (-1)
- static void set_performant_mode(struct ctlr_info *h, struct CommandList *c,
- int reply_queue)
- {
- if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
- c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
- if (unlikely(!h->msix_vector))
- return;
- if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
- c->Header.ReplyQueue =
- raw_smp_processor_id() % h->nreply_queues;
- else
- c->Header.ReplyQueue = reply_queue % h->nreply_queues;
- }
- }
- static void set_ioaccel1_performant_mode(struct ctlr_info *h,
- struct CommandList *c,
- int reply_queue)
- {
- struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
- /*
- * Tell the controller to post the reply to the queue for this
- * processor. This seems to give the best I/O throughput.
- */
- if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
- cp->ReplyQueue = smp_processor_id() % h->nreply_queues;
- else
- cp->ReplyQueue = reply_queue % h->nreply_queues;
- /*
- * Set the bits in the address sent down to include:
- * - performant mode bit (bit 0)
- * - pull count (bits 1-3)
- * - command type (bits 4-6)
- */
- c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
- IOACCEL1_BUSADDR_CMDTYPE;
- }
- static void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h,
- struct CommandList *c,
- int reply_queue)
- {
- struct hpsa_tmf_struct *cp = (struct hpsa_tmf_struct *)
- &h->ioaccel2_cmd_pool[c->cmdindex];
- /* Tell the controller to post the reply to the queue for this
- * processor. This seems to give the best I/O throughput.
- */
- if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
- cp->reply_queue = smp_processor_id() % h->nreply_queues;
- else
- cp->reply_queue = reply_queue % h->nreply_queues;
- /* Set the bits in the address sent down to include:
- * - performant mode bit not used in ioaccel mode 2
- * - pull count (bits 0-3)
- * - command type isn't needed for ioaccel2
- */
- c->busaddr |= h->ioaccel2_blockFetchTable[0];
- }
- static void set_ioaccel2_performant_mode(struct ctlr_info *h,
- struct CommandList *c,
- int reply_queue)
- {
- struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
- /*
- * Tell the controller to post the reply to the queue for this
- * processor. This seems to give the best I/O throughput.
- */
- if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
- cp->reply_queue = smp_processor_id() % h->nreply_queues;
- else
- cp->reply_queue = reply_queue % h->nreply_queues;
- /*
- * Set the bits in the address sent down to include:
- * - performant mode bit not used in ioaccel mode 2
- * - pull count (bits 0-3)
- * - command type isn't needed for ioaccel2
- */
- c->busaddr |= (h->ioaccel2_blockFetchTable[cp->sg_count]);
- }
- static int is_firmware_flash_cmd(u8 *cdb)
- {
- return cdb[0] == BMIC_WRITE && cdb[6] == BMIC_FLASH_FIRMWARE;
- }
- /*
- * During firmware flash, the heartbeat register may not update as frequently
- * as it should. So we dial down lockup detection during firmware flash. and
- * dial it back up when firmware flash completes.
- */
- #define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ)
- #define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ)
- static void dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h,
- struct CommandList *c)
- {
- if (!is_firmware_flash_cmd(c->Request.CDB))
- return;
- atomic_inc(&h->firmware_flash_in_progress);
- h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
- }
- static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
- struct CommandList *c)
- {
- if (is_firmware_flash_cmd(c->Request.CDB) &&
- atomic_dec_and_test(&h->firmware_flash_in_progress))
- h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
- }
- static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
- struct CommandList *c, int reply_queue)
- {
- dial_down_lockup_detection_during_fw_flash(h, c);
- atomic_inc(&h->commands_outstanding);
- switch (c->cmd_type) {
- case CMD_IOACCEL1:
- set_ioaccel1_performant_mode(h, c, reply_queue);
- writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
- break;
- case CMD_IOACCEL2:
- set_ioaccel2_performant_mode(h, c, reply_queue);
- writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
- break;
- case IOACCEL2_TMF:
- set_ioaccel2_tmf_performant_mode(h, c, reply_queue);
- writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
- break;
- default:
- set_performant_mode(h, c, reply_queue);
- h->access.submit_command(h, c);
- }
- }
- static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c)
- {
- if (unlikely(hpsa_is_pending_event(c)))
- return finish_cmd(c);
- __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE);
- }
- static inline int is_hba_lunid(unsigned char scsi3addr[])
- {
- return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0;
- }
- static inline int is_scsi_rev_5(struct ctlr_info *h)
- {
- if (!h->hba_inquiry_data)
- return 0;
- if ((h->hba_inquiry_data[2] & 0x07) == 5)
- return 1;
- return 0;
- }
- static int hpsa_find_target_lun(struct ctlr_info *h,
- unsigned char scsi3addr[], int bus, int *target, int *lun)
- {
- /* finds an unused bus, target, lun for a new physical device
- * assumes h->devlock is held
- */
- int i, found = 0;
- DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES);
- bitmap_zero(lun_taken, HPSA_MAX_DEVICES);
- for (i = 0; i < h->ndevices; i++) {
- if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
- __set_bit(h->dev[i]->target, lun_taken);
- }
- i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES);
- if (i < HPSA_MAX_DEVICES) {
- /* *bus = 1; */
- *target = i;
- *lun = 0;
- found = 1;
- }
- return !found;
- }
- static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
- struct hpsa_scsi_dev_t *dev, char *description)
- {
- #define LABEL_SIZE 25
- char label[LABEL_SIZE];
- if (h == NULL || h->pdev == NULL || h->scsi_host == NULL)
- return;
- switch (dev->devtype) {
- case TYPE_RAID:
- snprintf(label, LABEL_SIZE, "controller");
- break;
- case TYPE_ENCLOSURE:
- snprintf(label, LABEL_SIZE, "enclosure");
- break;
- case TYPE_DISK:
- case TYPE_ZBC:
- if (dev->external)
- snprintf(label, LABEL_SIZE, "external");
- else if (!is_logical_dev_addr_mode(dev->scsi3addr))
- snprintf(label, LABEL_SIZE, "%s",
- raid_label[PHYSICAL_DRIVE]);
- else
- snprintf(label, LABEL_SIZE, "RAID-%s",
- dev->raid_level > RAID_UNKNOWN ? "?" :
- raid_label[dev->raid_level]);
- break;
- case TYPE_ROM:
- snprintf(label, LABEL_SIZE, "rom");
- break;
- case TYPE_TAPE:
- snprintf(label, LABEL_SIZE, "tape");
- break;
- case TYPE_MEDIUM_CHANGER:
- snprintf(label, LABEL_SIZE, "changer");
- break;
- default:
- snprintf(label, LABEL_SIZE, "UNKNOWN");
- break;
- }
- dev_printk(level, &h->pdev->dev,
- "scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n",
- h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
- description,
- scsi_device_type(dev->devtype),
- dev->vendor,
- dev->model,
- label,
- dev->offload_config ? '+' : '-',
- dev->offload_enabled ? '+' : '-',
- dev->expose_device);
- }
- /* Add an entry into h->dev[] array. */
- static int hpsa_scsi_add_entry(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *device,
- struct hpsa_scsi_dev_t *added[], int *nadded)
- {
- /* assumes h->devlock is held */
- int n = h->ndevices;
- int i;
- unsigned char addr1[8], addr2[8];
- struct hpsa_scsi_dev_t *sd;
- if (n >= HPSA_MAX_DEVICES) {
- dev_err(&h->pdev->dev, "too many devices, some will be "
- "inaccessible.\n");
- return -1;
- }
- /* physical devices do not have lun or target assigned until now. */
- if (device->lun != -1)
- /* Logical device, lun is already assigned. */
- goto lun_assigned;
- /* If this device a non-zero lun of a multi-lun device
- * byte 4 of the 8-byte LUN addr will contain the logical
- * unit no, zero otherwise.
- */
- if (device->scsi3addr[4] == 0) {
- /* This is not a non-zero lun of a multi-lun device */
- if (hpsa_find_target_lun(h, device->scsi3addr,
- device->bus, &device->target, &device->lun) != 0)
- return -1;
- goto lun_assigned;
- }
- /* This is a non-zero lun of a multi-lun device.
- * Search through our list and find the device which
- * has the same 8 byte LUN address, excepting byte 4 and 5.
- * Assign the same bus and target for this new LUN.
- * Use the logical unit number from the firmware.
- */
- memcpy(addr1, device->scsi3addr, 8);
- addr1[4] = 0;
- addr1[5] = 0;
- for (i = 0; i < n; i++) {
- sd = h->dev[i];
- memcpy(addr2, sd->scsi3addr, 8);
- addr2[4] = 0;
- addr2[5] = 0;
- /* differ only in byte 4 and 5? */
- if (memcmp(addr1, addr2, 8) == 0) {
- device->bus = sd->bus;
- device->target = sd->target;
- device->lun = device->scsi3addr[4];
- break;
- }
- }
- if (device->lun == -1) {
- dev_warn(&h->pdev->dev, "physical device with no LUN=0,"
- " suspect firmware bug or unsupported hardware "
- "configuration.\n");
- return -1;
- }
- lun_assigned:
- h->dev[n] = device;
- h->ndevices++;
- added[*nadded] = device;
- (*nadded)++;
- hpsa_show_dev_msg(KERN_INFO, h, device,
- device->expose_device ? "added" : "masked");
- device->offload_to_be_enabled = device->offload_enabled;
- device->offload_enabled = 0;
- return 0;
- }
- /* Update an entry in h->dev[] array. */
- static void hpsa_scsi_update_entry(struct ctlr_info *h,
- int entry, struct hpsa_scsi_dev_t *new_entry)
- {
- int offload_enabled;
- /* assumes h->devlock is held */
- BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
- /* Raid level changed. */
- h->dev[entry]->raid_level = new_entry->raid_level;
- /* Raid offload parameters changed. Careful about the ordering. */
- if (new_entry->offload_config && new_entry->offload_enabled) {
- /*
- * if drive is newly offload_enabled, we want to copy the
- * raid map data first. If previously offload_enabled and
- * offload_config were set, raid map data had better be
- * the same as it was before. if raid map data is changed
- * then it had better be the case that
- * h->dev[entry]->offload_enabled is currently 0.
- */
- h->dev[entry]->raid_map = new_entry->raid_map;
- h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
- }
- if (new_entry->hba_ioaccel_enabled) {
- h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
- wmb(); /* set ioaccel_handle *before* hba_ioaccel_enabled */
- }
- h->dev[entry]->hba_ioaccel_enabled = new_entry->hba_ioaccel_enabled;
- h->dev[entry]->offload_config = new_entry->offload_config;
- h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
- h->dev[entry]->queue_depth = new_entry->queue_depth;
- /*
- * We can turn off ioaccel offload now, but need to delay turning
- * it on until we can update h->dev[entry]->phys_disk[], but we
- * can't do that until all the devices are updated.
- */
- h->dev[entry]->offload_to_be_enabled = new_entry->offload_enabled;
- if (!new_entry->offload_enabled)
- h->dev[entry]->offload_enabled = 0;
- offload_enabled = h->dev[entry]->offload_enabled;
- h->dev[entry]->offload_enabled = h->dev[entry]->offload_to_be_enabled;
- hpsa_show_dev_msg(KERN_INFO, h, h->dev[entry], "updated");
- h->dev[entry]->offload_enabled = offload_enabled;
- }
- /* Replace an entry from h->dev[] array. */
- static void hpsa_scsi_replace_entry(struct ctlr_info *h,
- int entry, struct hpsa_scsi_dev_t *new_entry,
- struct hpsa_scsi_dev_t *added[], int *nadded,
- struct hpsa_scsi_dev_t *removed[], int *nremoved)
- {
- /* assumes h->devlock is held */
- BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
- removed[*nremoved] = h->dev[entry];
- (*nremoved)++;
- /*
- * New physical devices won't have target/lun assigned yet
- * so we need to preserve the values in the slot we are replacing.
- */
- if (new_entry->target == -1) {
- new_entry->target = h->dev[entry]->target;
- new_entry->lun = h->dev[entry]->lun;
- }
- h->dev[entry] = new_entry;
- added[*nadded] = new_entry;
- (*nadded)++;
- hpsa_show_dev_msg(KERN_INFO, h, new_entry, "replaced");
- new_entry->offload_to_be_enabled = new_entry->offload_enabled;
- new_entry->offload_enabled = 0;
- }
- /* Remove an entry from h->dev[] array. */
- static void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry,
- struct hpsa_scsi_dev_t *removed[], int *nremoved)
- {
- /* assumes h->devlock is held */
- int i;
- struct hpsa_scsi_dev_t *sd;
- BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
- sd = h->dev[entry];
- removed[*nremoved] = h->dev[entry];
- (*nremoved)++;
- for (i = entry; i < h->ndevices-1; i++)
- h->dev[i] = h->dev[i+1];
- h->ndevices--;
- hpsa_show_dev_msg(KERN_INFO, h, sd, "removed");
- }
- #define SCSI3ADDR_EQ(a, b) ( \
- (a)[7] == (b)[7] && \
- (a)[6] == (b)[6] && \
- (a)[5] == (b)[5] && \
- (a)[4] == (b)[4] && \
- (a)[3] == (b)[3] && \
- (a)[2] == (b)[2] && \
- (a)[1] == (b)[1] && \
- (a)[0] == (b)[0])
- static void fixup_botched_add(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *added)
- {
- /* called when scsi_add_device fails in order to re-adjust
- * h->dev[] to match the mid layer's view.
- */
- unsigned long flags;
- int i, j;
- spin_lock_irqsave(&h->lock, flags);
- for (i = 0; i < h->ndevices; i++) {
- if (h->dev[i] == added) {
- for (j = i; j < h->ndevices-1; j++)
- h->dev[j] = h->dev[j+1];
- h->ndevices--;
- break;
- }
- }
- spin_unlock_irqrestore(&h->lock, flags);
- kfree(added);
- }
- static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
- struct hpsa_scsi_dev_t *dev2)
- {
- /* we compare everything except lun and target as these
- * are not yet assigned. Compare parts likely
- * to differ first
- */
- if (memcmp(dev1->scsi3addr, dev2->scsi3addr,
- sizeof(dev1->scsi3addr)) != 0)
- return 0;
- if (memcmp(dev1->device_id, dev2->device_id,
- sizeof(dev1->device_id)) != 0)
- return 0;
- if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0)
- return 0;
- if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0)
- return 0;
- if (dev1->devtype != dev2->devtype)
- return 0;
- if (dev1->bus != dev2->bus)
- return 0;
- return 1;
- }
- static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
- struct hpsa_scsi_dev_t *dev2)
- {
- /* Device attributes that can change, but don't mean
- * that the device is a different device, nor that the OS
- * needs to be told anything about the change.
- */
- if (dev1->raid_level != dev2->raid_level)
- return 1;
- if (dev1->offload_config != dev2->offload_config)
- return 1;
- if (dev1->offload_enabled != dev2->offload_enabled)
- return 1;
- if (!is_logical_dev_addr_mode(dev1->scsi3addr))
- if (dev1->queue_depth != dev2->queue_depth)
- return 1;
- return 0;
- }
- /* Find needle in haystack. If exact match found, return DEVICE_SAME,
- * and return needle location in *index. If scsi3addr matches, but not
- * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
- * location in *index.
- * In the case of a minor device attribute change, such as RAID level, just
- * return DEVICE_UPDATED, along with the updated device's location in index.
- * If needle not found, return DEVICE_NOT_FOUND.
- */
- static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
- struct hpsa_scsi_dev_t *haystack[], int haystack_size,
- int *index)
- {
- int i;
- #define DEVICE_NOT_FOUND 0
- #define DEVICE_CHANGED 1
- #define DEVICE_SAME 2
- #define DEVICE_UPDATED 3
- if (needle == NULL)
- return DEVICE_NOT_FOUND;
- for (i = 0; i < haystack_size; i++) {
- if (haystack[i] == NULL) /* previously removed. */
- continue;
- if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
- *index = i;
- if (device_is_the_same(needle, haystack[i])) {
- if (device_updated(needle, haystack[i]))
- return DEVICE_UPDATED;
- return DEVICE_SAME;
- } else {
- /* Keep offline devices offline */
- if (needle->volume_offline)
- return DEVICE_NOT_FOUND;
- return DEVICE_CHANGED;
- }
- }
- }
- *index = -1;
- return DEVICE_NOT_FOUND;
- }
- static void hpsa_monitor_offline_device(struct ctlr_info *h,
- unsigned char scsi3addr[])
- {
- struct offline_device_entry *device;
- unsigned long flags;
- /* Check to see if device is already on the list */
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_for_each_entry(device, &h->offline_device_list, offline_list) {
- if (memcmp(device->scsi3addr, scsi3addr,
- sizeof(device->scsi3addr)) == 0) {
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- return;
- }
- }
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- /* Device is not on the list, add it. */
- device = kmalloc(sizeof(*device), GFP_KERNEL);
- if (!device) {
- dev_warn(&h->pdev->dev, "out of memory in %s\n", __func__);
- return;
- }
- memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr));
- spin_lock_irqsave(&h->offline_device_lock, flags);
- list_add_tail(&device->offline_list, &h->offline_device_list);
- spin_unlock_irqrestore(&h->offline_device_lock, flags);
- }
- /* Print a message explaining various offline volume states */
- static void hpsa_show_volume_status(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *sd)
- {
- if (sd->volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED)
- dev_info(&h->pdev->dev,
- "C%d:B%d:T%d:L%d Volume status is not available through vital product data pages.\n",
- h->scsi_host->host_no,
- sd->bus, sd->target, sd->lun);
- switch (sd->volume_offline) {
- case HPSA_LV_OK:
- break;
- case HPSA_LV_UNDERGOING_ERASE:
- dev_inf