diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/Kconfig | 29 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 37 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_osm.c | 39 | ||||
-rw-r--r-- | drivers/scsi/ide-scsi.c | 5 | ||||
-rw-r--r-- | drivers/scsi/ipr.c | 904 | ||||
-rw-r--r-- | drivers/scsi/ipr.h | 243 | ||||
-rw-r--r-- | drivers/scsi/ips.c | 138 | ||||
-rw-r--r-- | drivers/scsi/megaraid.c | 32 | ||||
-rw-r--r-- | drivers/scsi/megaraid.h | 10 | ||||
-rw-r--r-- | drivers/scsi/megaraid/mega_common.h | 2 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_mbox.c | 81 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 5 | ||||
-rw-r--r-- | drivers/scsi/qla1280.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qlogicisp.c | 1934 | ||||
-rw-r--r-- | drivers/scsi/qlogicisp_asm.c | 2034 | ||||
-rw-r--r-- | drivers/scsi/raid_class.c | 96 | ||||
-rw-r--r-- | drivers/scsi/scsi_error.c | 157 | ||||
-rw-r--r-- | drivers/scsi/scsi_lib.c | 49 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 1 | ||||
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 9 |
21 files changed, 1095 insertions, 4713 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index afeca325b4d..84c42c44e04 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1295,27 +1295,6 @@ config SCSI_QLOGIC_FAS To compile this driver as a module, choose M here: the module will be called qlogicfas. -config SCSI_QLOGIC_ISP - tristate "Qlogic ISP SCSI support (old driver)" - depends on PCI && SCSI && BROKEN - ---help--- - This driver works for all QLogic PCI SCSI host adapters (IQ-PCI, - IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter - card is supported by the "AM53/79C974 PCI SCSI" driver.) - - If you say Y here, make sure to choose "BIOS" at the question "PCI - access mode". - - Please read the file <file:Documentation/scsi/qlogicisp.txt>. You - should also read the SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called qlogicisp. - - These days the hardware is also supported by the more modern qla1280 - driver. In doubt use that one instead of qlogicisp. - config SCSI_QLOGIC_FC tristate "Qlogic ISP FC SCSI support" depends on PCI && SCSI @@ -1342,14 +1321,6 @@ config SCSI_QLOGIC_1280 To compile this driver as a module, choose M here: the module will be called qla1280. -config SCSI_QLOGIC_1280_1040 - bool "Qlogic QLA 1020/1040 SCSI support" - depends on SCSI_QLOGIC_1280 && SCSI_QLOGIC_ISP!=y - help - Say Y here if you have a QLogic ISP1020/1040 SCSI host adapter and - do not want to use the old driver. This option enables support in - the qla1280 driver for those host adapters. - config SCSI_QLOGICPTI tristate "PTI Qlogic, ISP Driver" depends on SBUS && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index b88b8c45559..f062ea0f813 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o -obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx/ diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index cfb46c241b3..31e9f40e79a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -436,29 +436,20 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) { struct ahd_softc *ahd; struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); + int rtn = SCSI_MLQUEUE_HOST_BUSY; + unsigned long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - /* - * Close the race of a command that was in the process of - * being queued to us just as our simq was frozen. Let - * DV commands through so long as we are only frozen to - * perform DV. - */ - if (ahd->platform_data->qfrozen != 0) { - printf("%s: queue frozen\n", ahd_name(ahd)); + ahd_lock(ahd, &flags); + if (ahd->platform_data->qfrozen == 0) { + cmd->scsi_done = scsi_done; + cmd->result = CAM_REQ_INPROG << 16; + rtn = ahd_linux_run_command(ahd, dev, cmd); - return SCSI_MLQUEUE_HOST_BUSY; } - - /* - * Save the callback on completion function. - */ - cmd->scsi_done = scsi_done; - - cmd->result = CAM_REQ_INPROG << 16; - - return ahd_linux_run_command(ahd, dev, cmd); + ahd_unlock(ahd, &flags); + return rtn; } static inline struct scsi_target ** @@ -1081,7 +1072,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa *((struct ahd_softc **)host->hostdata) = ahd; ahd_lock(ahd, &s); - scsi_assign_lock(host, &ahd->platform_data->spin_lock); ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; @@ -2062,6 +2052,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) int wait; int disconnected; ahd_mode_state saved_modes; + unsigned long flags; pending_scb = NULL; paused = FALSE; @@ -2077,7 +2068,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) printf(" 0x%x", cmd->cmnd[cdb_byte]); printf("\n"); - spin_lock_irq(&ahd->platform_data->spin_lock); + ahd_lock(ahd, &flags); /* * First determine if we currently own this command. @@ -2291,7 +2282,8 @@ done: int ret; ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; - spin_unlock_irq(&ahd->platform_data->spin_lock); + ahd_unlock(ahd, &flags); + init_timer(&timer); timer.data = (u_long)ahd; timer.expires = jiffies + (5 * HZ); @@ -2305,9 +2297,8 @@ done: printf("Timer Expired\n"); retval = FAILED; } - spin_lock_irq(&ahd->platform_data->spin_lock); } - spin_unlock_irq(&ahd->platform_data->spin_lock); + ahd_unlock(ahd, &flags); return (retval); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 1861407422e..7fc6454068e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -476,26 +476,20 @@ ahc_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) { struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); + int rtn = SCSI_MLQUEUE_HOST_BUSY; + unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - /* - * Save the callback on completion function. - */ - cmd->scsi_done = scsi_done; - - /* - * Close the race of a command that was in the process of - * being queued to us just as our simq was frozen. Let - * DV commands through so long as we are only frozen to - * perform DV. - */ - if (ahc->platform_data->qfrozen != 0) - return SCSI_MLQUEUE_HOST_BUSY; - - cmd->result = CAM_REQ_INPROG << 16; + ahc_lock(ahc, &flags); + if (ahc->platform_data->qfrozen == 0) { + cmd->scsi_done = scsi_done; + cmd->result = CAM_REQ_INPROG << 16; + rtn = ahc_linux_run_command(ahc, dev, cmd); + } + ahc_unlock(ahc, &flags); - return ahc_linux_run_command(ahc, dev, cmd); + return rtn; } static inline struct scsi_target ** @@ -1079,7 +1073,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa *((struct ahc_softc **)host->hostdata) = ahc; ahc_lock(ahc, &s); - scsi_assign_lock(host, &ahc->platform_data->spin_lock); ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; @@ -2111,6 +2104,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) int paused; int wait; int disconnected; + unsigned long flags; pending_scb = NULL; paused = FALSE; @@ -2125,7 +2119,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) printf(" 0x%x", cmd->cmnd[cdb_byte]); printf("\n"); - spin_lock_irq(&ahc->platform_data->spin_lock); + ahc_lock(ahc, &flags); /* * First determine if we currently own this command. @@ -2357,7 +2351,8 @@ done: int ret; ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE; - spin_unlock_irq(&ahc->platform_data->spin_lock); + ahc_unlock(ahc, &flags); + init_timer(&timer); timer.data = (u_long)ahc; timer.expires = jiffies + (5 * HZ); @@ -2371,10 +2366,8 @@ done: printf("Timer Expired\n"); retval = FAILED; } - spin_lock_irq(&ahc->platform_data->spin_lock); - } - - spin_unlock_irq(&ahc->platform_data->spin_lock); + } else + ahc_unlock(ahc, &flags); return (retval); } diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index c888af4a456..3553da0e1cd 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -395,6 +395,7 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); struct Scsi_Host *host; u8 *scsi_buf; + int errors = rq->errors; unsigned long flags; if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) { @@ -421,11 +422,11 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", drive->name, pc->scsi_cmd->serial_number); pc->scsi_cmd->result = DID_TIME_OUT << 16; - } else if (rq->errors >= ERROR_MAX) { + } else if (errors >= ERROR_MAX) { pc->scsi_cmd->result = DID_ERROR << 16; if (log) printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); - } else if (rq->errors) { + } else if (errors) { if (log) printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); if (!idescsi_check_condition(drive, rq)) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e0039dfae8e..fa2cb3582cf 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -91,11 +91,14 @@ static unsigned int ipr_max_speed = 1; static int ipr_testmode = 0; static unsigned int ipr_fastfail = 0; static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT; +static unsigned int ipr_enable_cache = 1; +static unsigned int ipr_debug = 0; +static int ipr_auto_create = 1; static DEFINE_SPINLOCK(ipr_driver_lock); /* This table describes the differences between DMA controller chips */ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { - { /* Gemstone and Citrine */ + { /* Gemstone, Citrine, and Obsidian */ .mailbox = 0x0042C, .cache_line_size = 0x20, { @@ -130,6 +133,8 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { static const struct ipr_chip_t ipr_chip[] = { { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, &ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] } }; @@ -150,6 +155,12 @@ module_param_named(fastfail, ipr_fastfail, int, 0); MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); module_param_named(transop_timeout, ipr_transop_timeout, int, 0); MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)"); +module_param_named(enable_cache, ipr_enable_cache, int, 0); +MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)"); +module_param_named(debug, ipr_debug, int, 0); +MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); +module_param_named(auto_create, ipr_auto_create, int, 0); +MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); @@ -285,12 +296,18 @@ struct ipr_error_table_t ipr_error_table[] = { "3110: Device bus error, message or command phase"}, {0x04670400, 0, 1, "9091: Incorrect hardware configuration change has been detected"}, + {0x04678000, 0, 1, + "9073: Invalid multi-adapter configuration"}, {0x046E0000, 0, 1, "FFF4: Command to logical unit failed"}, {0x05240000, 1, 0, "Illegal request, invalid request type or request packet"}, {0x05250000, 0, 0, "Illegal request, invalid resource handle"}, + {0x05258000, 0, 0, + "Illegal request, commands not allowed to this device"}, + {0x05258100, 0, 0, + "Illegal request, command not allowed to a secondary adapter"}, {0x05260000, 0, 0, "Illegal request, invalid field in parameter list"}, {0x05260100, 0, 0, @@ -299,6 +316,8 @@ struct ipr_error_table_t ipr_error_table[] = { "Illegal request, parameter value invalid"}, {0x052C0000, 0, 0, "Illegal request, command sequence error"}, + {0x052C8000, 1, 0, + "Illegal request, dual adapter support not enabled"}, {0x06040500, 0, 1, "9031: Array protection temporarily suspended, protection resuming"}, {0x06040600, 0, 1, @@ -315,18 +334,26 @@ struct ipr_error_table_t ipr_error_table[] = { "3029: A device replacement has occurred"}, {0x064C8000, 0, 1, "9051: IOA cache data exists for a missing or failed device"}, + {0x064C8100, 0, 1, + "9055: Auxiliary cache IOA contains cache data needed by the primary IOA"}, {0x06670100, 0, 1, "9025: Disk unit is not supported at its physical location"}, {0x06670600, 0, 1, "3020: IOA detected a SCSI bus configuration error"}, {0x06678000, 0, 1, "3150: SCSI bus configuration error"}, + {0x06678100, 0, 1, + "9074: Asymmetric advanced function disk configuration"}, {0x06690200, 0, 1, "9041: Array protection temporarily suspended"}, {0x06698200, 0, 1, "9042: Corrupt array parity detected on specified device"}, {0x066B0200, 0, 1, "9030: Array no longer protected due to missing or failed disk unit"}, + {0x066B8000, 0, 1, + "9071: Link operational transition"}, + {0x066B8100, 0, 1, + "9072: Link not operational transition"}, {0x066B8200, 0, 1, "9032: Array exposed but still protected"}, {0x07270000, 0, 0, @@ -789,7 +816,7 @@ static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, **/ static void ipr_init_res_entry(struct ipr_resource_entry *res) { - res->needs_sync_complete = 1; + res->needs_sync_complete = 0; res->in_erp = 0; res->add_to_ml = 0; res->del_from_ml = 0; @@ -889,29 +916,74 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) /** * ipr_log_vpd - Log the passed VPD to the error log. - * @vpids: vendor/product id struct - * @serial_num: serial number string + * @vpd: vendor/product id/sn struct * * Return value: * none **/ -static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num) +static void ipr_log_vpd(struct ipr_vpd *vpd) { char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN]; - memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN); - memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id, + memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); + memcpy(buffer + IPR_VENDOR_ID_LEN, vpd->vpids.product_id, IPR_PROD_ID_LEN); buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0'; ipr_err("Vendor/Product ID: %s\n", buffer); - memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN); + memcpy(buffer, vpd->sn, IPR_SERIAL_NUM_LEN); buffer[IPR_SERIAL_NUM_LEN] = '\0'; ipr_err(" Serial Number: %s\n", buffer); } /** + * ipr_log_ext_vpd - Log the passed extended VPD to the error log. + * @vpd: vendor/product id/sn/wwn struct + * + * Return value: + * none + **/ +static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd) +{ + ipr_log_vpd(&vpd->vpd); + ipr_err(" WWN: %08X%08X\n", be32_to_cpu(vpd->wwid[0]), + be32_to_cpu(vpd->wwid[1])); +} + +/** + * ipr_log_enhanced_cache_error - Log a cache error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_12_error *error = + &hostrcb->hcam.u.error.u.type_12_error; + + ipr_err("-----Current Configuration-----\n"); + ipr_err("Cache Directory Card Information:\n"); + ipr_log_ext_vpd(&error->ioa_vpd); + ipr_err("Adapter Card Information:\n"); + ipr_log_ext_vpd(&error->cfc_vpd); + + ipr_err("-----Expected Configuration-----\n"); + ipr_err("Cache Directory Card Information:\n"); + ipr_log_ext_vpd(&error->ioa_last_attached_to_cfc_vpd); + ipr_err("Adapter Card Information:\n"); + ipr_log_ext_vpd(&error->cfc_last_attached_to_ioa_vpd); + + ipr_err("Additional IOA Data: %08X %08X %08X\n", + be32_to_cpu(error->ioa_data[0]), + be32_to_cpu(error->ioa_data[1]), + be32_to_cpu(error->ioa_data[2])); +} + +/** * ipr_log_cache_error - Log a cache error. * @ioa_cfg: ioa config struct * @hostrcb: hostrcb struct @@ -927,17 +999,15 @@ static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("-----Current Configuration-----\n"); ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&error->ioa_vpids, error->ioa_sn); + ipr_log_vpd(&error->ioa_vpd); ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&error->cfc_vpids, error->cfc_sn); + ipr_log_vpd(&error->cfc_vpd); ipr_err("-----Expected Configuration-----\n"); ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpids, - error->ioa_last_attached_to_cfc_sn); + ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpd); ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpids, - error->cfc_last_attached_to_ioa_sn); + ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpd); ipr_err("Additional IOA Data: %08X %08X %08X\n", be32_to_cpu(error->ioa_data[0]), @@ -946,6 +1016,46 @@ static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg, } /** + * ipr_log_enhanced_config_error - Log a configuration error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + int errors_logged, i; + struct ipr_hostrcb_device_data_entry_enhanced *dev_entry; + struct ipr_hostrcb_type_13_error *error; + + error = &hostrcb->hcam.u.error.u.type_13_error; + errors_logged = be32_to_cpu(error->errors_logged); + + ipr_err("Device Errors Detected/Logged: %d/%d\n", + be32_to_cpu(error->errors_detected), errors_logged); + + dev_entry = error->dev; + + for (i = 0; i < errors_logged; i++, dev_entry++) { + ipr_err_separator; + + ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); + ipr_log_ext_vpd(&dev_entry->vpd); + + ipr_err("-----New Device Information-----\n"); + ipr_log_ext_vpd(&dev_entry->new_vpd); + + ipr_err("Cache Directory Card Information:\n"); + ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd); + + ipr_err("Adapter Card Information:\n"); + ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd); + } +} + +/** * ipr_log_config_error - Log a configuration error. * @ioa_cfg: ioa config struct * @hostrcb: hostrcb struct @@ -966,30 +1076,22 @@ static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg, ipr_err("Device Errors Detected/Logged: %d/%d\n", be32_to_cpu(error->errors_detected), errors_logged); - dev_entry = error->dev_entry; + dev_entry = error->dev; for (i = 0; i < errors_logged; i++, dev_entry++) { ipr_err_separator; - if (dev_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { - ipr_err("Device %d: missing\n", i + 1); - } else { - ipr_err("Device %d: %d:%d:%d:%d\n", i + 1, - ioa_cfg->host->host_no, dev_entry->dev_res_addr.bus, - dev_entry->dev_res_addr.target, dev_entry->dev_res_addr.lun); - } - ipr_log_vpd(&dev_entry->dev_vpids, dev_entry->dev_sn); + ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); + ipr_log_vpd(&dev_entry->vpd); ipr_err("-----New Device Information-----\n"); - ipr_log_vpd(&dev_entry->new_dev_vpids, dev_entry->new_dev_sn); + ipr_log_vpd(&dev_entry->new_vpd); ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpids, - dev_entry->ioa_last_with_dev_sn); + ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpd); ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpids, - dev_entry->cfc_last_with_dev_sn); + ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpd); ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n", be32_to_cpu(dev_entry->ioa_data[0]), @@ -1001,6 +1103,57 @@ static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg, } /** + * ipr_log_enhanced_array_error - Log an array configuration error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_enhanced_array_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + int i, num_entries; + struct ipr_hostrcb_type_14_error *error; + struct ipr_hostrcb_array_data_entry_enhanced *array_entry; + const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; + + error = &hostrcb->hcam.u.error.u.type_14_error; + + ipr_err_separator; + + ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", + error->protection_level, + ioa_cfg->host->host_no, + error->last_func_vset_res_addr.bus, + error->last_func_vset_res_addr.target, + error->last_func_vset_res_addr.lun); + + ipr_err_separator; + + array_entry = error->array_member; + num_entries = min_t(u32, be32_to_cpu(error->num_entries), + sizeof(error->array_member)); + + for (i = 0; i < num_entries; i++, array_entry++) { + if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) + continue; + + if (be32_to_cpu(error->exposed_mode_adn) == i) + ipr_err("Exposed Array Member %d:\n", i); + else + ipr_err("Array Member %d:\n", i); + + ipr_log_ext_vpd(&array_entry->vpd); + ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); + ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, + "Expected Location"); + + ipr_err_separator; + } +} + +/** * ipr_log_array_error - Log an array configuration error. * @ioa_cfg: ioa config struct * @hostrcb: hostrcb struct @@ -1032,36 +1185,19 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, array_entry = error->array_member; for (i = 0; i < 18; i++) { - if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN)) + if (!memcmp(array_entry->vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) continue; - if (be32_to_cpu(error->exposed_mode_adn) == i) { + if (be32_to_cpu(error->exposed_mode_adn) == i) ipr_err("Exposed Array Member %d:\n", i); - } else { + else ipr_err("Array Member %d:\n", i); - } - ipr_log_vpd(&array_entry->vpids, array_entry->serial_num); - - if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { - ipr_err("Current Location: unknown\n"); - } else { - ipr_err("Current Location: %d:%d:%d:%d\n", - ioa_cfg->host->host_no, - array_entry->dev_res_addr.bus, - array_entry->dev_res_addr.target, - array_entry->dev_res_addr.lun); - } + ipr_log_vpd(&array_entry->vpd); - if (array_entry->expected_dev_res_addr.bus >= IPR_MAX_NUM_BUSES) { - ipr_err("Expected Location: unknown\n"); - } else { - ipr_err("Expected Location: %d:%d:%d:%d\n", - ioa_cfg->host->host_no, - array_entry->expected_dev_res_addr.bus, - array_entry->expected_dev_res_addr.target, - array_entry->expected_dev_res_addr.lun); - } + ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); + ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, + "Expected Location"); ipr_err_separator; @@ -1073,35 +1209,95 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, } /** - * ipr_log_generic_error - Log an adapter error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct + * ipr_log_hex_data - Log additional hex IOA error data. + * @data: IOA error data + * @len: data length * * Return value: * none **/ -static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) +static void ipr_log_hex_data(u32 *data, int len) { int i; - int ioa_data_len = be32_to_cpu(hostrcb->hcam.length); - if (ioa_data_len == 0) + if (len == 0) return; - ipr_err("IOA Error Data:\n"); - ipr_err("Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); - - for (i = 0; i < ioa_data_len / 4; i += 4) { + for (i = 0; i < len / 4; i += 4) { ipr_err("%08X: %08X %08X %08X %08X\n", i*4, - be32_to_cpu(hostrcb->hcam.u.raw.data[i]), - be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]), - be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]), - be32_to_cpu(hostrcb->hcam.u.raw.data[i+3])); + be32_to_cpu(data[i]), + be32_to_cpu(data[i+1]), + be32_to_cpu(data[i+2]), + be32_to_cpu(data[i+3])); } } /** + * ipr_log_enhanced_dual_ioa_error - Log an enhanced dual adapter error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_17_error *error; + + error = &hostrcb->hcam.u.error.u.type_17_error; + error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + + ipr_err("%s\n", error->failure_reason); + ipr_err("Remote Adapter VPD:\n"); + ipr_log_ext_vpd(&error->vpd); + ipr_log_hex_data(error->data, + be32_to_cpu(hostrcb->hcam.length) - + (offsetof(struct ipr_hostrcb_error, u) + + offsetof(struct ipr_hostrcb_type_17_error, data))); +} + +/** + * ipr_log_dual_ioa_error - Log a dual adapter error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_07_error *error; + + error = &hostrcb->hcam.u.error.u.type_07_error; + error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + + ipr_err("%s\n", error->failure_reason); + ipr_err("Remote Adapter VPD:\n"); + ipr_log_vpd(&error->vpd); + ipr_log_hex_data(error->data, + be32_to_cpu(hostrcb->hcam.length) - + (offsetof(struct ipr_hostrcb_error, u) + + offsetof(struct ipr_hostrcb_type_07_error, data))); +} + +/** + * ipr_log_generic_error - Log an adapter error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + ipr_log_hex_data(hostrcb->hcam.u.raw.data, + be32_to_cpu(hostrcb->hcam.length)); +} + +/** * ipr_get_error - Find the specfied IOASC in the ipr_error_table. * @ioasc: IOASC * @@ -1172,11 +1368,10 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) return; + if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw)) + hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw)); switch (hostrcb->hcam.overlay_id) { - case IPR_HOST_RCB_OVERLAY_ID_1: - ipr_log_generic_error(ioa_cfg, hostrcb); - break; case IPR_HOST_RCB_OVERLAY_ID_2: ipr_log_cache_error(ioa_cfg, hostrcb); break; @@ -1187,13 +1382,26 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, case IPR_HOST_RCB_OVERLAY_ID_6: ipr_log_array_error(ioa_cfg, hostrcb); break; - case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: - ipr_log_generic_error(ioa_cfg, hostrcb); + case IPR_HOST_RCB_OVERLAY_ID_7: + ipr_log_dual_ioa_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_12: + ipr_log_enhanced_cache_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_13: + ipr_log_enhanced_config_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_14: + case IPR_HOST_RCB_OVERLAY_ID_16: + ipr_log_enhanced_array_error(ioa_cfg, hostrcb); break; + case IPR_HOST_RCB_OVERLAY_ID_17: + ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); + break; + case IPR_HOST_RCB_OVERLAY_ID_1: + case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: default: - dev_err(&ioa_cfg->pdev->dev, - "Unknown error received. Overlay ID: %d\n", - hostrcb->hcam.overlay_id); + ipr_log_generic_error(ioa_cfg, hostrcb); break; } } @@ -1972,6 +2180,103 @@ static struct bin_attribute ipr_trace_attr = { }; #endif +static const struct { + enum ipr_cache_state state; + char *name; +} cache_state [] = { + { CACHE_NONE, "none" }, + { CACHE_DISABLED, "disabled" }, + { CACHE_ENABLED, "enabled" } +}; + +/** + * ipr_show_write_caching - Show the write caching attribute + * @class_dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_write_caching(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int i, len = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + for (i = 0; i < ARRAY_SIZE(cache_state); i++) { + if (cache_state[i].state == ioa_cfg->cache_state) { + len = snprintf(buf, PAGE_SIZE, "%s\n", cache_state[i].name); + break; + } + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + + +/** + * ipr_store_write_caching - Enable/disable adapter write cache + * @class_dev: class_device struct + * @buf: buffer + * @count: buffer size + * + * This function will enable/disable adapter write cache. + * + * Return value: + * count on success / other on failure + **/ +static ssize_t ipr_store_write_caching(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + enum ipr_cache_state new_state = CACHE_INVALID; + int i; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (ioa_cfg->cache_state == CACHE_NONE) + return -EINVAL; + |