X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fipr.c;h=de5ae6a65029ffbd1efc31911ecf3d660e5f2320;hb=6fe07aaffbf086a0ce9134ef27ce4a8921ff5947;hp=cca4972735be724c2da8a8fc4cf18c70506d9a8c;hpb=ee0f05b863df0a623792eaa46703019c100be2de;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index cca4972..de5ae6a 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -54,7 +54,6 @@ * */ -#include #include #include #include @@ -71,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -79,26 +79,25 @@ #include #include #include -#include #include "ipr.h" /* * Global Data */ -static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head); +static LIST_HEAD(ipr_ioa_head); static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; 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_transop_timeout = 0; static unsigned int ipr_enable_cache = 1; static unsigned int ipr_debug = 0; -static int ipr_auto_create = 1; +static unsigned int ipr_dual_ioa_raid = 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, Obsidian, and Obsidian-E */ .mailbox = 0x0042C, .cache_line_size = 0x20, { @@ -133,6 +132,9 @@ 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_OBSIDIAN_E, &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] } }; @@ -157,38 +159,15 @@ 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_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0); +MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); -static const char *ipr_gpdd_dev_end_states[] = { - "Command complete", - "Terminated by host", - "Terminated by device reset", - "Terminated by bus reset", - "Unknown", - "Command not started" -}; - -static const char *ipr_gpdd_dev_bus_phases[] = { - "Bus free", - "Arbitration", - "Selection", - "Message out", - "Command", - "Message in", - "Data out", - "Data in", - "Status", - "Reselection", - "Unknown" -}; - /* A constant array of IOASCs/URCs/Error Messages */ static const struct ipr_error_table_t ipr_error_table[] = { - {0x00000000, 1, 1, + {0x00000000, 1, IPR_DEFAULT_LOG_LEVEL, "8155: An unknown error was received"}, {0x00330000, 0, 0, "Soft underlength error"}, @@ -196,107 +175,127 @@ struct ipr_error_table_t ipr_error_table[] = { "Command to be cancelled not found"}, {0x00808000, 0, 0, "Qualified success"}, - {0x01080000, 1, 1, + {0x01080000, 1, IPR_DEFAULT_LOG_LEVEL, "FFFE: Soft device bus error recovered by the IOA"}, - {0x01170600, 0, 1, + {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL, + "4101: Soft device bus fabric error"}, + {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL, "FFF9: Device sector reassign successful"}, - {0x01170900, 0, 1, + {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL, "FFF7: Media error recovered by device rewrite procedures"}, - {0x01180200, 0, 1, + {0x01180200, 0, IPR_DEFAULT_LOG_LEVEL, "7001: IOA sector reassignment successful"}, - {0x01180500, 0, 1, + {0x01180500, 0, IPR_DEFAULT_LOG_LEVEL, "FFF9: Soft media error. Sector reassignment recommended"}, - {0x01180600, 0, 1, + {0x01180600, 0, IPR_DEFAULT_LOG_LEVEL, "FFF7: Media error recovered by IOA rewrite procedures"}, - {0x01418000, 0, 1, + {0x01418000, 0, IPR_DEFAULT_LOG_LEVEL, "FF3D: Soft PCI bus error recovered by the IOA"}, - {0x01440000, 1, 1, + {0x01440000, 1, IPR_DEFAULT_LOG_LEVEL, "FFF6: Device hardware error recovered by the IOA"}, - {0x01448100, 0, 1, + {0x01448100, 0, IPR_DEFAULT_LOG_LEVEL, "FFF6: Device hardware error recovered by the device"}, - {0x01448200, 1, 1, + {0x01448200, 1, IPR_DEFAULT_LOG_LEVEL, "FF3D: Soft IOA error recovered by the IOA"}, - {0x01448300, 0, 1, + {0x01448300, 0, IPR_DEFAULT_LOG_LEVEL, "FFFA: Undefined device response recovered by the IOA"}, - {0x014A0000, 1, 1, + {0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL, "FFF6: Device bus error, message or command phase"}, - {0x015D0000, 0, 1, + {0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL, + "FFFE: Task Management Function failed"}, + {0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL, "FFF6: Failure prediction threshold exceeded"}, - {0x015D9200, 0, 1, + {0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL, "8009: Impending cache battery pack failure"}, {0x02040400, 0, 0, "34FF: Disk device format in progress"}, + {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL, + "9070: IOA requested reset"}, {0x023F0000, 0, 0, "Synchronization required"}, {0x024E0000, 0, 0, "No ready, IOA shutdown"}, {0x025A0000, 0, 0, "Not ready, IOA has been shutdown"}, - {0x02670100, 0, 1, + {0x02670100, 0, IPR_DEFAULT_LOG_LEVEL, "3020: Storage subsystem configuration error"}, {0x03110B00, 0, 0, "FFF5: Medium error, data unreadable, recommend reassign"}, {0x03110C00, 0, 0, "7000: Medium error, data unreadable, do not reassign"}, - {0x03310000, 0, 1, + {0x03310000, 0, IPR_DEFAULT_LOG_LEVEL, "FFF3: Disk media format bad"}, - {0x04050000, 0, 1, + {0x04050000, 0, IPR_DEFAULT_LOG_LEVEL, "3002: Addressed device failed to respond to selection"}, - {0x04080000, 1, 1, + {0x04080000, 1, IPR_DEFAULT_LOG_LEVEL, "3100: Device bus error"}, - {0x04080100, 0, 1, + {0x04080100, 0, IPR_DEFAULT_LOG_LEVEL, "3109: IOA timed out a device command"}, {0x04088000, 0, 0, "3120: SCSI bus is not operational"}, - {0x04118000, 0, 1, + {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL, + "4100: Hard device bus fabric error"}, + {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL, "9000: IOA reserved area data check"}, - {0x04118100, 0, 1, + {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL, "9001: IOA reserved area invalid data pattern"}, - {0x04118200, 0, 1, + {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL, "9002: IOA reserved area LRC error"}, - {0x04320000, 0, 1, + {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL, "102E: Out of alternate sectors for disk storage"}, - {0x04330000, 1, 1, + {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL, "FFF4: Data transfer underlength error"}, - {0x04338000, 1, 1, + {0x04338000, 1, IPR_DEFAULT_LOG_LEVEL, "FFF4: Data transfer overlength error"}, - {0x043E0100, 0, 1, + {0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL, "3400: Logical unit failure"}, - {0x04408500, 0, 1, + {0x04408500, 0, IPR_DEFAULT_LOG_LEVEL, "FFF4: Device microcode is corrupt"}, - {0x04418000, 1, 1, + {0x04418000, 1, IPR_DEFAULT_LOG_LEVEL, "8150: PCI bus error"}, {0x04430000, 1, 0, "Unsupported device bus message received"}, - {0x04440000, 1, 1, + {0x04440000, 1, IPR_DEFAULT_LOG_LEVEL, "FFF4: Disk device problem"}, - {0x04448200, 1, 1, + {0x04448200, 1, IPR_DEFAULT_LOG_LEVEL, "8150: Permanent IOA failure"}, - {0x04448300, 0, 1, + {0x04448300, 0, IPR_DEFAULT_LOG_LEVEL, "3010: Disk device returned wrong response to IOA"}, - {0x04448400, 0, 1, + {0x04448400, 0, IPR_DEFAULT_LOG_LEVEL, "8151: IOA microcode error"}, {0x04448500, 0, 0, "Device bus status error"}, - {0x04448600, 0, 1, + {0x04448600, 0, IPR_DEFAULT_LOG_LEVEL, "8157: IOA error requiring IOA reset to recover"}, + {0x04448700, 0, 0, + "ATA device status error"}, {0x04490000, 0, 0, "Message reject received from the device"}, - {0x04449200, 0, 1, + {0x04449200, 0, IPR_DEFAULT_LOG_LEVEL, "8008: A permanent cache battery pack failure occurred"}, - {0x0444A000, 0, 1, + {0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL, "9090: Disk unit has been modified after the last known status"}, - {0x0444A200, 0, 1, + {0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL, "9081: IOA detected device error"}, - {0x0444A300, 0, 1, + {0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL, "9082: IOA detected device error"}, - {0x044A0000, 1, 1, + {0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL, "3110: Device bus error, message or command phase"}, - {0x04670400, 0, 1, + {0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL, + "3110: SAS Command / Task Management Function failed"}, + {0x04670400, 0, IPR_DEFAULT_LOG_LEVEL, "9091: Incorrect hardware configuration change has been detected"}, - {0x04678000, 0, 1, + {0x04678000, 0, IPR_DEFAULT_LOG_LEVEL, "9073: Invalid multi-adapter configuration"}, - {0x046E0000, 0, 1, + {0x04678100, 0, IPR_DEFAULT_LOG_LEVEL, + "4010: Incorrect connection between cascaded expanders"}, + {0x04678200, 0, IPR_DEFAULT_LOG_LEVEL, + "4020: Connections exceed IOA design limits"}, + {0x04678300, 0, IPR_DEFAULT_LOG_LEVEL, + "4030: Incorrect multipath connection"}, + {0x04679000, 0, IPR_DEFAULT_LOG_LEVEL, + "4110: Unsupported enclosure function"}, + {0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL, "FFF4: Command to logical unit failed"}, {0x05240000, 1, 0, "Illegal request, invalid request type or request packet"}, @@ -316,85 +315,103 @@ struct ipr_error_table_t ipr_error_table[] = { "Illegal request, command sequence error"}, {0x052C8000, 1, 0, "Illegal request, dual adapter support not enabled"}, - {0x06040500, 0, 1, + {0x06040500, 0, IPR_DEFAULT_LOG_LEVEL, "9031: Array protection temporarily suspended, protection resuming"}, - {0x06040600, 0, 1, + {0x06040600, 0, IPR_DEFAULT_LOG_LEVEL, "9040: Array protection temporarily suspended, protection resuming"}, - {0x06290000, 0, 1, + {0x06288000, 0, IPR_DEFAULT_LOG_LEVEL, + "3140: Device bus not ready to ready transition"}, + {0x06290000, 0, IPR_DEFAULT_LOG_LEVEL, "FFFB: SCSI bus was reset"}, {0x06290500, 0, 0, "FFFE: SCSI bus transition to single ended"}, {0x06290600, 0, 0, "FFFE: SCSI bus transition to LVD"}, - {0x06298000, 0, 1, + {0x06298000, 0, IPR_DEFAULT_LOG_LEVEL, "FFFB: SCSI bus was reset by another initiator"}, - {0x063F0300, 0, 1, + {0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL, "3029: A device replacement has occurred"}, - {0x064C8000, 0, 1, + {0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL, "9051: IOA cache data exists for a missing or failed device"}, - {0x064C8100, 0, 1, + {0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL, "9055: Auxiliary cache IOA contains cache data needed by the primary IOA"}, - {0x06670100, 0, 1, + {0x06670100, 0, IPR_DEFAULT_LOG_LEVEL, "9025: Disk unit is not supported at its physical location"}, - {0x06670600, 0, 1, + {0x06670600, 0, IPR_DEFAULT_LOG_LEVEL, "3020: IOA detected a SCSI bus configuration error"}, - {0x06678000, 0, 1, + {0x06678000, 0, IPR_DEFAULT_LOG_LEVEL, "3150: SCSI bus configuration error"}, - {0x06678100, 0, 1, + {0x06678100, 0, IPR_DEFAULT_LOG_LEVEL, "9074: Asymmetric advanced function disk configuration"}, - {0x06690200, 0, 1, + {0x06678300, 0, IPR_DEFAULT_LOG_LEVEL, + "4040: Incomplete multipath connection between IOA and enclosure"}, + {0x06678400, 0, IPR_DEFAULT_LOG_LEVEL, + "4041: Incomplete multipath connection between enclosure and device"}, + {0x06678500, 0, IPR_DEFAULT_LOG_LEVEL, + "9075: Incomplete multipath connection between IOA and remote IOA"}, + {0x06678600, 0, IPR_DEFAULT_LOG_LEVEL, + "9076: Configuration error, missing remote IOA"}, + {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL, + "4050: Enclosure does not support a required multipath function"}, + {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL, "9041: Array protection temporarily suspended"}, - {0x06698200, 0, 1, + {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL, "9042: Corrupt array parity detected on specified device"}, - {0x066B0200, 0, 1, + {0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL, "9030: Array no longer protected due to missing or failed disk unit"}, - {0x066B8000, 0, 1, + {0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL, "9071: Link operational transition"}, - {0x066B8100, 0, 1, + {0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL, "9072: Link not operational transition"}, - {0x066B8200, 0, 1, + {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL, "9032: Array exposed but still protected"}, + {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1, + "70DD: Device forced failed by disrupt device command"}, + {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL, + "4061: Multipath redundancy level got better"}, + {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL, + "4060: Multipath redundancy level got worse"}, {0x07270000, 0, 0, "Failure due to other device"}, - {0x07278000, 0, 1, + {0x07278000, 0, IPR_DEFAULT_LOG_LEVEL, "9008: IOA does not support functions expected by devices"}, - {0x07278100, 0, 1, + {0x07278100, 0, IPR_DEFAULT_LOG_LEVEL, "9010: Cache data associated with attached devices cannot be found"}, - {0x07278200, 0, 1, + {0x07278200, 0, IPR_DEFAULT_LOG_LEVEL, "9011: Cache data belongs to devices other than those attached"}, - {0x07278400, 0, 1, + {0x07278400, 0, IPR_DEFAULT_LOG_LEVEL, "9020: Array missing 2 or more devices with only 1 device present"}, - {0x07278500, 0, 1, + {0x07278500, 0, IPR_DEFAULT_LOG_LEVEL, "9021: Array missing 2 or more devices with 2 or more devices present"}, - {0x07278600, 0, 1, + {0x07278600, 0, IPR_DEFAULT_LOG_LEVEL, "9022: Exposed array is missing a required device"}, - {0x07278700, 0, 1, + {0x07278700, 0, IPR_DEFAULT_LOG_LEVEL, "9023: Array member(s) not at required physical locations"}, - {0x07278800, 0, 1, + {0x07278800, 0, IPR_DEFAULT_LOG_LEVEL, "9024: Array not functional due to present hardware configuration"}, - {0x07278900, 0, 1, + {0x07278900, 0, IPR_DEFAULT_LOG_LEVEL, "9026: Array not functional due to present hardware configuration"}, - {0x07278A00, 0, 1, + {0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL, "9027: Array is missing a device and parity is out of sync"}, - {0x07278B00, 0, 1, + {0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL, "9028: Maximum number of arrays already exist"}, - {0x07278C00, 0, 1, + {0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL, "9050: Required cache data cannot be located for a disk unit"}, - {0x07278D00, 0, 1, + {0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL, "9052: Cache data exists for a device that has been modified"}, - {0x07278F00, 0, 1, + {0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL, "9054: IOA resources not available due to previous problems"}, - {0x07279100, 0, 1, + {0x07279100, 0, IPR_DEFAULT_LOG_LEVEL, "9092: Disk unit requires initialization before use"}, - {0x07279200, 0, 1, + {0x07279200, 0, IPR_DEFAULT_LOG_LEVEL, "9029: Incorrect hardware configuration change has been detected"}, - {0x07279600, 0, 1, + {0x07279600, 0, IPR_DEFAULT_LOG_LEVEL, "9060: One or more disk pairs are missing from an array"}, - {0x07279700, 0, 1, + {0x07279700, 0, IPR_DEFAULT_LOG_LEVEL, "9061: One or more disks are missing from an array"}, - {0x07279800, 0, 1, + {0x07279800, 0, IPR_DEFAULT_LOG_LEVEL, "9062: One or more disks are missing from an array"}, - {0x07279900, 0, 1, + {0x07279900, 0, IPR_DEFAULT_LOG_LEVEL, "9063: Maximum number of functional arrays has been exceeded"}, {0x0B260000, 0, 0, "Aborted command, invalid descriptor"}, @@ -448,7 +465,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, trace_entry->time = jiffies; trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; trace_entry->type = type; - trace_entry->cmd_index = ipr_cmd->cmd_index; + trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command; + trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; trace_entry->u.add_data = add_data; } @@ -467,16 +485,22 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) { struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr); memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); ioarcb->write_data_transfer_length = 0; ioarcb->read_data_transfer_length = 0; ioarcb->write_ioadl_len = 0; ioarcb->read_ioadl_len = 0; + ioarcb->write_ioadl_addr = + cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); + ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; ioasa->ioasc = 0; ioasa->residual_data_len = 0; + ioasa->u.gata.status = 0; ipr_cmd->scsi_cmd = NULL; + ipr_cmd->qc = NULL; ipr_cmd->sense_buffer[0] = 0; ipr_cmd->dma_use_sg = 0; } @@ -516,32 +540,6 @@ struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg) } /** - * ipr_unmap_sglist - Unmap scatterlist if mapped - * @ioa_cfg: ioa config struct - * @ipr_cmd: ipr command struct - * - * Return value: - * nothing - **/ -static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) -{ - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - - if (ipr_cmd->dma_use_sg) { - if (scsi_cmd->use_sg > 0) { - pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer, - scsi_cmd->use_sg, - scsi_cmd->sc_data_direction); - } else { - pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle, - scsi_cmd->request_bufflen, - scsi_cmd->sc_data_direction); - } - } -} - -/** * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts * @ioa_cfg: ioa config struct * @clr_ints: interrupts to clear @@ -579,10 +577,8 @@ static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) { int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); - if (pcix_cmd_reg == 0) { - dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); - return -EIO; - } + if (pcix_cmd_reg == 0) + return 0; if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { @@ -611,16 +607,34 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); return -EIO; } - } else { - dev_err(&ioa_cfg->pdev->dev, - "Failed to setup PCI-X command register\n"); - return -EIO; } return 0; } /** + * ipr_sata_eh_done - done function for aborted SATA commands + * @ipr_cmd: ipr command struct + * + * This function is invoked for ops generated to SATA + * devices which are being aborted. + * + * Return value: + * none + **/ +static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ata_queued_cmd *qc = ipr_cmd->qc; + struct ipr_sata_port *sata_port = qc->ap->private_data; + + qc->err_mask |= AC_ERR_OTHER; + sata_port->ioasa.status |= ATA_BUSY; + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + ata_qc_complete(qc); +} + +/** * ipr_scsi_eh_done - mid-layer done function for aborted ops * @ipr_cmd: ipr command struct * @@ -637,7 +651,7 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) scsi_cmd->result |= (DID_ERROR << 16); - ipr_unmap_sglist(ioa_cfg, ipr_cmd); + scsi_dma_unmap(ipr_cmd->scsi_cmd); scsi_cmd->scsi_done(scsi_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); } @@ -664,6 +678,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; + else if (ipr_cmd->qc) + ipr_cmd->done = ipr_sata_eh_done; ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); del_timer(&ipr_cmd->timer); @@ -814,12 +830,13 @@ 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; res->resetting_device = 0; res->sdev = NULL; + res->sata_port = NULL; } /** @@ -867,8 +884,8 @@ static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { if (res->sdev) { - res->sdev->hostdata = NULL; res->del_from_ml = 1; + res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; if (ioa_cfg->allow_ml_add_del) schedule_work(&ioa_cfg->work_q); } else @@ -913,6 +930,53 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) } /** + * strip_and_pad_whitespace - Strip and pad trailing whitespace. + * @i: index into buffer + * @buf: string to modify + * + * This function will strip all trailing whitespace, pad the end + * of the string with a single space, and NULL terminate the string. + * + * Return value: + * new length of string + **/ +static int strip_and_pad_whitespace(int i, char *buf) +{ + while (i && buf[i] == ' ') + i--; + buf[i+1] = ' '; + buf[i+2] = '\0'; + return i + 2; +} + +/** + * ipr_log_vpd_compact - Log the passed extended VPD compactly. + * @prefix: string to print at start of printk + * @hostrcb: hostrcb pointer + * @vpd: vendor/product id/sn struct + * + * Return value: + * none + **/ +static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, + struct ipr_vpd *vpd) +{ + char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3]; + int i = 0; + + memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); + i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer); + + memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN); + i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer); + + memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN); + buffer[IPR_SERIAL_NUM_LEN + i] = '\0'; + + ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer); +} + +/** * ipr_log_vpd - Log the passed VPD to the error log. * @vpd: vendor/product id/sn struct * @@ -936,6 +1000,23 @@ static void ipr_log_vpd(struct ipr_vpd *vpd) } /** + * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly. + * @prefix: string to print at start of printk + * @hostrcb: hostrcb pointer + * @vpd: vendor/product id/sn/wwn struct + * + * Return value: + * none + **/ +static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, + struct ipr_ext_vpd *vpd) +{ + ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd); + ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix, + be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1])); +} + +/** * ipr_log_ext_vpd - Log the passed extended VPD to the error log. * @vpd: vendor/product id/sn/wwn struct * @@ -1208,19 +1289,23 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_log_hex_data - Log additional hex IOA error data. + * @ioa_cfg: ioa config struct * @data: IOA error data * @len: data length * * Return value: * none **/ -static void ipr_log_hex_data(u32 *data, int len) +static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len) { int i; if (len == 0) return; + if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL) + len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP); + for (i = 0; i < len / 4; i += 4) { ipr_err("%08X: %08X %08X %08X %08X\n", i*4, be32_to_cpu(data[i]), @@ -1245,11 +1330,12 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, error = &hostrcb->hcam.u.error.u.type_17_error; error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + strstrip(error->failure_reason); - 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, + ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, + be32_to_cpu(hostrcb->hcam.u.error.prc)); + ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd); + ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + offsetof(struct ipr_hostrcb_type_17_error, data))); @@ -1270,16 +1356,230 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, error = &hostrcb->hcam.u.error.u.type_07_error; error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + strstrip(error->failure_reason); - ipr_err("%s\n", error->failure_reason); - ipr_err("Remote Adapter VPD:\n"); - ipr_log_vpd(&error->vpd); - ipr_log_hex_data(error->data, + ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, + be32_to_cpu(hostrcb->hcam.u.error.prc)); + ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd); + ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + offsetof(struct ipr_hostrcb_type_07_error, data))); } +static const struct { + u8 active; + char *desc; +} path_active_desc[] = { + { IPR_PATH_NO_INFO, "Path" }, + { IPR_PATH_ACTIVE, "Active path" }, + { IPR_PATH_NOT_ACTIVE, "Inactive path" } +}; + +static const struct { + u8 state; + char *desc; +} path_state_desc[] = { + { IPR_PATH_STATE_NO_INFO, "has no path state information available" }, + { IPR_PATH_HEALTHY, "is healthy" }, + { IPR_PATH_DEGRADED, "is degraded" }, + { IPR_PATH_FAILED, "is failed" } +}; + +/** + * ipr_log_fabric_path - Log a fabric path error + * @hostrcb: hostrcb struct + * @fabric: fabric descriptor + * + * Return value: + * none + **/ +static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb, + struct ipr_hostrcb_fabric_desc *fabric) +{ + int i, j; + u8 path_state = fabric->path_state; + u8 active = path_state & IPR_PATH_ACTIVE_MASK; + u8 state = path_state & IPR_PATH_STATE_MASK; + + for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { + if (path_active_desc[i].active != active) + continue; + + for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { + if (path_state_desc[j].state != state) + continue; + + if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port); + } else if (fabric->cascaded_expander == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->phy); + } else if (fabric->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->cascaded_expander); + } else { + ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n", + path_active_desc[i].desc, path_state_desc[j].desc, + fabric->ioa_port, fabric->cascaded_expander, fabric->phy); + } + return; + } + } + + ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state, + fabric->ioa_port, fabric->cascaded_expander, fabric->phy); +} + +static const struct { + u8 type; + char *desc; +} path_type_desc[] = { + { IPR_PATH_CFG_IOA_PORT, "IOA port" }, + { IPR_PATH_CFG_EXP_PORT, "Expander port" }, + { IPR_PATH_CFG_DEVICE_PORT, "Device port" }, + { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" } +}; + +static const struct { + u8 status; + char *desc; +} path_status_desc[] = { + { IPR_PATH_CFG_NO_PROB, "Functional" }, + { IPR_PATH_CFG_DEGRADED, "Degraded" }, + { IPR_PATH_CFG_FAILED, "Failed" }, + { IPR_PATH_CFG_SUSPECT, "Suspect" }, + { IPR_PATH_NOT_DETECTED, "Missing" }, + { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" } +}; + +static const char *link_rate[] = { + "unknown", + "disabled", + "phy reset problem", + "spinup hold", + "port selector", + "unknown", + "unknown", + "unknown", + "1.5Gbps", + "3.0Gbps", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown", + "unknown" +}; + +/** + * ipr_log_path_elem - Log a fabric path element. + * @hostrcb: hostrcb struct + * @cfg: fabric path element struct + * + * Return value: + * none + **/ +static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb, + struct ipr_hostrcb_config_element *cfg) +{ + int i, j; + u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; + u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; + + if (type == IPR_PATH_CFG_NOT_EXIST) + return; + + for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { + if (path_type_desc[i].type != type) + continue; + + for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { + if (path_status_desc[j].status != status) + continue; + + if (type == IPR_PATH_CFG_IOA_PORT) { + ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n", + path_status_desc[j].desc, path_type_desc[i].desc, + cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else { + if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n", + path_status_desc[j].desc, path_type_desc[i].desc, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else if (cfg->cascaded_expander == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else if (cfg->phy == 0xff) { + ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->cascaded_expander, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } else { + ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s " + "WWN=%08X%08X\n", path_status_desc[j].desc, + path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); + } + } + return; + } + } + + ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s " + "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy, + link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], + be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); +} + +/** + * ipr_log_fabric_error - Log a fabric error. + * @ioa_cfg: ioa config struct + * @hostrcb: hostrcb struct + * + * Return value: + * none + **/ +static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_hostrcb *hostrcb) +{ + struct ipr_hostrcb_type_20_error *error; + struct ipr_hostrcb_fabric_desc *fabric; + struct ipr_hostrcb_config_element *cfg; + int i, add_len; + + error = &hostrcb->hcam.u.error.u.type_20_error; + error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); + + add_len = be32_to_cpu(hostrcb->hcam.length) - + (offsetof(struct ipr_hostrcb_error, u) + + offsetof(struct ipr_hostrcb_type_20_error, desc)); + + for (i = 0, fabric = error->desc; i < error->num_entries; i++) { + ipr_log_fabric_path(hostrcb, fabric); + for_each_fabric_cfg(fabric, cfg) + ipr_log_path_elem(hostrcb, cfg); + + add_len -= be16_to_cpu(fabric->length); + fabric = (struct ipr_hostrcb_fabric_desc *) + ((unsigned long)fabric + be16_to_cpu(fabric->length)); + } + + ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); +} + /** * ipr_log_generic_error - Log an adapter error. * @ioa_cfg: ioa config struct @@ -1291,7 +1591,7 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, 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, + ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data, be32_to_cpu(hostrcb->hcam.length)); } @@ -1311,7 +1611,7 @@ static u32 ipr_get_error(u32 ioasc) int i; for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++) - if (ipr_error_table[i].ioasc == ioasc) + if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK)) return i; return 0; @@ -1353,18 +1653,12 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, if (!ipr_error_table[error_index].log_hcam) return; - if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { - ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, - "%s\n", ipr_error_table[error_index].error); - } else { - dev_err(&ioa_cfg->pdev->dev, "%s\n", - ipr_error_table[error_index].error); - } + ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error); /* Set indication we have logged an error */ ioa_cfg->errors_logged++; - if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) + if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam) return; if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw)) hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw)); @@ -1396,6 +1690,9 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, case IPR_HOST_RCB_OVERLAY_ID_17: ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); break; + case IPR_HOST_RCB_OVERLAY_ID_20: + ipr_log_fabric_error(ioa_cfg, hostrcb); + break; case IPR_HOST_RCB_OVERLAY_ID_1: case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: default: @@ -1420,12 +1717,15 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); list_del(&hostrcb->queue); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); if (!ioasc) { ipr_handle_log_data(ioa_cfg, hostrcb); + if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV); } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) { dev_err(&ioa_cfg->pdev->dev, "Host RCB failed with IOASC: 0x%08X\n", ioasc); @@ -2052,7 +2352,7 @@ static void ipr_release_dump(struct kref *kref) /** * ipr_worker_thread - Worker thread - * @data: ioa config struct + * @work: ioa config struct * * Called at task level from a work thread. This function takes care * of adding and removing device from the mid-layer as configuration @@ -2061,13 +2361,14 @@ static void ipr_release_dump(struct kref *kref) * Return value: * nothing **/ -static void ipr_worker_thread(void *data) +static void ipr_worker_thread(struct work_struct *work) { unsigned long lock_flags; struct ipr_resource_entry *res; struct scsi_device *sdev; struct ipr_dump *dump; - struct ipr_ioa_cfg *ioa_cfg = data; + struct ipr_ioa_cfg *ioa_cfg = + container_of(work, struct ipr_ioa_cfg, work_q); u8 bus, target, lun; int did_work; @@ -2105,7 +2406,6 @@ restart: did_work = 1; sdev = res->sdev; if (!scsi_device_get(sdev)) { - res->sdev = NULL; list_move_tail(&res->queue, &ioa_cfg->free_res_q); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); scsi_remove_device(sdev); @@ -2122,6 +2422,7 @@ restart: bus = res->cfgte.res_addr.bus; target = res->cfgte.res_addr.target; lun = res->cfgte.res_addr.lun; + res->add_to_ml = 0; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); scsi_add_device(ioa_cfg->host, bus, target, lun); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -2130,7 +2431,7 @@ restart: } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - kobject_uevent(&ioa_cfg->host->shost_classdev.kobj, KOBJ_CHANGE, NULL); + kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE); LEAVE; } @@ -2138,6 +2439,7 @@ restart: /** * ipr_read_trace - Dump the adapter trace * @kobj: kobject struct + * @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size @@ -2145,11 +2447,12 @@ restart: * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_read_trace(struct kobject *kobj, char *buf, - loff_t off, size_t count) +static ssize_t ipr_read_trace(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { - struct class_device *cdev = container_of(kobj,struct class_device,kobj); - struct Scsi_Host *shost = class_to_shost(cdev); + struct device *dev = container_of(kobj, struct device, kobj); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; int size = IPR_TRACE_SIZE; @@ -2189,15 +2492,16 @@ static const struct { /** * ipr_show_write_caching - Show the write caching attribute - * @class_dev: class device struct - * @buf: buffer + * @dev: 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) +static ssize_t ipr_show_write_caching(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; int i, len = 0; @@ -2216,19 +2520,20 @@ static ssize_t ipr_show_write_caching(struct class_device *class_dev, char *buf) /** * ipr_store_write_caching - Enable/disable adapter write cache - * @class_dev: class_device struct - * @buf: buffer - * @count: buffer size + * @dev: 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) +static ssize_t ipr_store_write_caching(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(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; @@ -2266,7 +2571,7 @@ static ssize_t ipr_store_write_caching(struct class_device *class_dev, return count; } -static struct class_device_attribute ipr_ioa_cache_attr = { +static struct device_attribute ipr_ioa_cache_attr = { .attr = { .name = "write_cache", .mode = S_IRUGO | S_IWUSR, @@ -2277,15 +2582,16 @@ static struct class_device_attribute ipr_ioa_cache_attr = { /** * ipr_show_fw_version - Show the firmware version - * @class_dev: class device struct - * @buf: buffer + * @dev: class device struct + * @buf: buffer * * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf) +static ssize_t ipr_show_fw_version(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; unsigned long lock_flags = 0; @@ -2300,7 +2606,7 @@ static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf) return len; } -static struct class_device_attribute ipr_fw_version_attr = { +static struct device_attribute ipr_fw_version_attr = { .attr = { .name = "fw_version", .mode = S_IRUGO, @@ -2310,15 +2616,16 @@ static struct class_device_attribute ipr_fw_version_attr = { /** * ipr_show_log_level - Show the adapter's error logging level - * @class_dev: class device struct - * @buf: buffer + * @dev: class device struct + * @buf: buffer * * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf) +static ssize_t ipr_show_log_level(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; int len; @@ -2331,16 +2638,17 @@ static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf) /** * ipr_store_log_level - Change the adapter's error logging level - * @class_dev: class device struct - * @buf: buffer + * @dev: class device struct + * @buf: buffer * * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_store_log_level(struct class_device *class_dev, +static ssize_t ipr_store_log_level(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; @@ -2350,7 +2658,7 @@ static ssize_t ipr_store_log_level(struct class_device *class_dev, return strlen(buf); } -static struct class_device_attribute ipr_log_level_attr = { +static struct device_attribute ipr_log_level_attr = { .attr = { .name = "log_level", .mode = S_IRUGO | S_IWUSR, @@ -2361,9 +2669,9 @@ static struct class_device_attribute ipr_log_level_attr = { /** * ipr_store_diagnostics - IOA Diagnostics interface - * @class_dev: class_device struct - * @buf: buffer - * @count: buffer size + * @dev: device struct + * @buf: buffer + * @count: buffer size * * This function will reset the adapter and wait a reasonable * amount of time for any errors that the adapter might log. @@ -2371,10 +2679,11 @@ static struct class_device_attribute ipr_log_level_attr = { * Return value: * count on success / other on failure **/ -static ssize_t ipr_store_diagnostics(struct class_device *class_dev, +static ssize_t ipr_store_diagnostics(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; int rc = count; @@ -2382,8 +2691,13 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + ioa_cfg->errors_logged = 0; ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); @@ -2406,7 +2720,7 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev, return rc; } -static struct class_device_attribute ipr_diagnostics_attr = { +static struct device_attribute ipr_diagnostics_attr = { .attr = { .name = "run_diagnostics", .mode = S_IWUSR, @@ -2416,15 +2730,16 @@ static struct class_device_attribute ipr_diagnostics_attr = { /** * ipr_show_adapter_state - Show the adapter's state - * @class_dev: class device struct - * @buf: buffer + * @class_dev: device struct + * @buf: buffer * * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_show_adapter_state(struct class_device *class_dev, char *buf) +static ssize_t ipr_show_adapter_state(struct device *dev, + struct device_attribute *attr, char *buf) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags = 0; int len; @@ -2440,19 +2755,20 @@ static ssize_t ipr_show_adapter_state(struct class_device *class_dev, char *buf) /** * ipr_store_adapter_state - Change adapter state - * @class_dev: class_device struct - * @buf: buffer - * @count: buffer size + * @dev: device struct + * @buf: buffer + * @count: buffer size * * This function will change the adapter's state. * * Return value: * count on success / other on failure **/ -static ssize_t ipr_store_adapter_state(struct class_device *class_dev, +static ssize_t ipr_store_adapter_state(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags; int result = count; @@ -2473,7 +2789,7 @@ static ssize_t ipr_store_adapter_state(struct class_device *class_dev, return result; } -static struct class_device_attribute ipr_ioa_state_attr = { +static struct device_attribute ipr_ioa_state_attr = { .attr = { .name = "state", .mode = S_IRUGO | S_IWUSR, @@ -2484,19 +2800,20 @@ static struct class_device_attribute ipr_ioa_state_attr = { /** * ipr_store_reset_adapter - Reset the adapter - * @class_dev: class_device struct - * @buf: buffer - * @count: buffer size + * @dev: device struct + * @buf: buffer + * @count: buffer size * * This function will reset the adapter. * * Return value: * count on success / other on failure **/ -static ssize_t ipr_store_reset_adapter(struct class_device *class_dev, +static ssize_t ipr_store_reset_adapter(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; unsigned long lock_flags; int result = count; @@ -2513,7 +2830,7 @@ static ssize_t ipr_store_reset_adapter(struct class_device *class_dev, return result; } -static struct class_device_attribute ipr_ioa_reset_attr = { +static struct device_attribute ipr_ioa_reset_attr = { .attr = { .name = "reset_host", .mode = S_IWUSR, @@ -2564,6 +2881,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) } scatterlist = sglist->scatterlist; + sg_init_table(scatterlist, num_elem); sglist->order = order; sglist->num_sg = num_elem; @@ -2576,12 +2894,12 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) /* Free up what we already allocated */ for (j = i - 1; j >= 0; j--) - __free_pages(scatterlist[j].page, order); + __free_pages(sg_page(&scatterlist[j]), order); kfree(sglist); return NULL; } - scatterlist[i].page = page; + sg_set_page(&scatterlist[i], page, 0, 0); } return sglist; @@ -2602,7 +2920,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) int i; for (i = 0; i < sglist->num_sg; i++) - __free_pages(sglist->scatterlist[i].page, sglist->order); + __free_pages(sg_page(&sglist->scatterlist[i]), sglist->order); kfree(sglist); } @@ -2632,9 +2950,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, scatterlist = sglist->scatterlist; for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - kaddr = kmap(scatterlist[i].page); + struct page *page = sg_page(&scatterlist[i]); + + kaddr = kmap(page); memcpy(kaddr, buffer, bsize_elem); - kunmap(scatterlist[i].page); + kunmap(page); scatterlist[i].length = bsize_elem; @@ -2645,9 +2965,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, } if (len % bsize_elem) { - kaddr = kmap(scatterlist[i].page); + struct page *page = sg_page(&scatterlist[i]); + + kaddr = kmap(page); memcpy(kaddr, buffer, len % bsize_elem); - kunmap(scatterlist[i].page); + kunmap(page); scatterlist[i].length = len % bsize_elem; } @@ -2705,6 +3027,11 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, unsigned long lock_flags; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } if (ioa_cfg->ucode_sglist) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); @@ -2736,19 +3063,20 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, /** * ipr_store_update_fw - Update the firmware on the adapter - * @class_dev: class_device struct - * @buf: buffer - * @count: buffer size + * @class_dev: device struct + * @buf: buffer + * @count: buffer size * * This function will update the firmware on the adapter. * * Return value: * count on success / other on failure **/ -static ssize_t ipr_store_update_fw(struct class_device *class_dev, - const char *buf, size_t count) +static ssize_t ipr_store_update_fw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(class_dev); + struct Scsi_Host *shost = class_to_shost(dev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; struct ipr_ucode_image_header *image_hdr; const struct firmware *fw_entry; @@ -2806,7 +3134,7 @@ out: return result; } -static struct class_device_attribute ipr_update_fw_attr = { +static struct device_attribute ipr_update_fw_attr = { .attr = { .name = "update_fw", .mode = S_IWUSR, @@ -2814,7 +3142,7 @@ static struct class_device_attribute ipr_update_fw_attr = { .store = ipr_store_update_fw }; -static struct class_device_attribute *ipr_ioa_attrs[] = { +static struct device_attribute *ipr_ioa_attrs[] = { &ipr_fw_version_attr, &ipr_log_level_attr, &ipr_diagnostics_attr, @@ -2829,6 +3157,7 @@ static struct class_device_attribute *ipr_ioa_attrs[] = { /** * ipr_read_dump - Dump the adapter * @kobj: kobject struct + * @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size @@ -2836,10 +3165,11 @@ static struct class_device_attribute *ipr_ioa_attrs[] = { * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_read_dump(struct kobject *kobj, char *buf, - loff_t off, size_t count) +static ssize_t ipr_read_dump(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { - struct class_device *cdev = container_of(kobj,struct class_device,kobj); + struct device *cdev = container_of(kobj, struct device, kobj); struct Scsi_Host *shost = class_to_shost(cdev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; struct ipr_dump *dump; @@ -2928,7 +3258,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) struct ipr_dump *dump; unsigned long lock_flags = 0; - ENTER; dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); if (!dump) { @@ -2955,7 +3284,6 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; return 0; } @@ -2992,6 +3320,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) /** * ipr_write_dump - Setup dump state of adapter * @kobj: kobject struct + * @bin_attr: bin_attribute struct * @buf: buffer * @off: offset * @count: buffer size @@ -2999,10 +3328,11 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) * Return value: * number of bytes printed to buffer **/ -static ssize_t ipr_write_dump(struct kobject *kobj, char *buf, - loff_t off, size_t count) +static ssize_t ipr_write_dump(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) { - struct class_device *cdev = container_of(kobj,struct class_device,kobj); + struct device *cdev = container_of(kobj, struct device, kobj); struct Scsi_Host *shost = class_to_shost(cdev); struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; int rc; @@ -3046,6 +3376,17 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; **/ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth) { + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + + if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN) + qdepth = IPR_MAX_CMD_PER_ATA_LUN; + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); return sdev->queue_depth; } @@ -3161,67 +3502,218 @@ static int ipr_biosparam(struct scsi_device *sdev, } /** - * ipr_slave_destroy - Unconfigure a SCSI device - * @sdev: scsi device struct + * ipr_find_starget - Find target based on bus/target. + * @starget: scsi target struct * * Return value: - * nothing + * resource entry pointer if found / NULL if not found **/ -static void ipr_slave_destroy(struct scsi_device *sdev) +static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget) { + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; struct ipr_resource_entry *res; - struct ipr_ioa_cfg *ioa_cfg; - unsigned long lock_flags = 0; - - ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *) sdev->hostdata; - if (res) { - sdev->hostdata = NULL; - res->sdev = NULL; + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if ((res->cfgte.res_addr.bus == starget->channel) && + (res->cfgte.res_addr.target == starget->id) && + (res->cfgte.res_addr.lun == 0)) { + return res; + } } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + + return NULL; } +static struct ata_port_info sata_port_info; + /** - * ipr_slave_configure - Configure a SCSI device - * @sdev: scsi device struct + * ipr_target_alloc - Prepare for commands to a SCSI target + * @starget: scsi target struct * - * This function configures the specified scsi device. + * If the device is a SATA device, this function allocates an + * ATA port with libata, else it does nothing. * * Return value: - * 0 on success + * 0 on success / non-0 on failure **/ -static int ipr_slave_configure(struct scsi_device *sdev) +static int ipr_target_alloc(struct scsi_target *starget) { - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct Scsi_Host *shost = dev_to_shost(&starget->dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; + struct ipr_sata_port *sata_port; + struct ata_port *ap; struct ipr_resource_entry *res; - unsigned long lock_flags = 0; + unsigned long lock_flags; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = sdev->hostdata; - if (res) { - if (ipr_is_af_dasd_device(res)) - sdev->type = TYPE_RAID; - if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) { - sdev->scsi_level = 4; - sdev->no_uld_attach = 1; - } - if (ipr_is_vset_device(res)) { - sdev->timeout = IPR_VSET_RW_TIMEOUT; - blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); + res = ipr_find_starget(starget); + starget->hostdata = NULL; + + if (res && ipr_is_gata(res)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); + if (!sata_port) + return -ENOMEM; + + ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost); + if (ap) { + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + sata_port->ioa_cfg = ioa_cfg; + sata_port->ap = ap; + sata_port->res = res; + + res->sata_port = sata_port; + ap->private_data = sata_port; + starget->hostdata = sata_port; + } else { + kfree(sata_port); + return -ENOMEM; } - if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) - sdev->allow_restart = 1; - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; } /** - * ipr_slave_alloc - Prepare for commands to a device. + * ipr_target_destroy - Destroy a SCSI target + * @starget: scsi target struct + * + * If the device was a SATA device, this function frees the libata + * ATA port, else it does nothing. + * + **/ +static void ipr_target_destroy(struct scsi_target *starget) +{ + struct ipr_sata_port *sata_port = starget->hostdata; + + if (sata_port) { + starget->hostdata = NULL; + ata_sas_port_destroy(sata_port->ap); + kfree(sata_port); + } +} + +/** + * ipr_find_sdev - Find device based on bus/target/lun. + * @sdev: scsi device struct + * + * Return value: + * resource entry pointer if found / NULL if not found + **/ +static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; + + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { + if ((res->cfgte.res_addr.bus == sdev->channel) && + (res->cfgte.res_addr.target == sdev->id) && + (res->cfgte.res_addr.lun == sdev->lun)) + return res; + } + + return NULL; +} + +/** + * ipr_slave_destroy - Unconfigure a SCSI device + * @sdev: scsi device struct + * + * Return value: + * nothing + **/ +static void ipr_slave_destroy(struct scsi_device *sdev) +{ + struct ipr_resource_entry *res; + struct ipr_ioa_cfg *ioa_cfg; + unsigned long lock_flags = 0; + + ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *) sdev->hostdata; + if (res) { + if (res->sata_port) + ata_port_disable(res->sata_port->ap); + sdev->hostdata = NULL; + res->sdev = NULL; + res->sata_port = NULL; + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); +} + +/** + * ipr_slave_configure - Configure a SCSI device + * @sdev: scsi device struct + * + * This function configures the specified scsi device. + * + * Return value: + * 0 on success + **/ +static int ipr_slave_configure(struct scsi_device *sdev) +{ + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = sdev->hostdata; + if (res) { + if (ipr_is_af_dasd_device(res)) + sdev->type = TYPE_RAID; + if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) { + sdev->scsi_level = 4; + sdev->no_uld_attach = 1; + } + if (ipr_is_vset_device(res)) { + sdev->timeout = IPR_VSET_RW_TIMEOUT; + blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); + } + if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) + sdev->allow_restart = 1; + if (ipr_is_gata(res) && res->sata_port) { + scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); + ata_sas_slave_configure(sdev, res->sata_port->ap); + } else { + scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + } + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return 0; +} + +/** + * ipr_ata_slave_alloc - Prepare for commands to a SATA device + * @sdev: scsi device struct + * + * This function initializes an ATA port so that future commands + * sent through queuecommand will work. + * + * Return value: + * 0 on success + **/ +static int ipr_ata_slave_alloc(struct scsi_device *sdev) +{ + struct ipr_sata_port *sata_port = NULL; + int rc = -ENXIO; + + ENTER; + if (sdev->sdev_target) + sata_port = sdev->sdev_target->hostdata; + if (sata_port) + rc = ata_sas_port_init(sata_port->ap); + if (rc) + ipr_slave_destroy(sdev); + + LEAVE; + return rc; +} + +/** + * ipr_slave_alloc - Prepare for commands to a device. * @sdev: scsi device struct * * This function saves a pointer to the resource entry @@ -3243,17 +3735,18 @@ static int ipr_slave_alloc(struct scsi_device *sdev) spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if ((res->cfgte.res_addr.bus == sdev->channel) && - (res->cfgte.res_addr.target == sdev->id) && - (res->cfgte.res_addr.lun == sdev->lun)) { - res->sdev = sdev; - res->add_to_ml = 0; - res->in_erp = 0; - sdev->hostdata = res; + res = ipr_find_sdev(sdev); + if (res) { + res->sdev = sdev; + res->add_to_ml = 0; + res->in_erp = 0; + sdev->hostdata = res; + if (!ipr_is_naca_model(res)) res->needs_sync_complete = 1; - rc = 0; - break; + rc = 0; + if (ipr_is_gata(res)) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return ipr_ata_slave_alloc(sdev); } } @@ -3301,6 +3794,105 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd) } /** + * ipr_device_reset - Reset the device + * @ioa_cfg: ioa config struct + * @res: resource entry struct + * + * This function issues a device reset to the affected device. + * If the device is a SCSI device, a LUN reset will be sent + * to the device first. If that does not work, a target reset + * will be sent. If the device is a SATA device, a PHY reset will + * be sent. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_resource_entry *res) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + struct ipr_cmd_pkt *cmd_pkt; + struct ipr_ioarcb_ata_regs *regs; + u32 ioasc; + + ENTER; + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioarcb = &ipr_cmd->ioarcb; + cmd_pkt = &ioarcb->cmd_pkt; + regs = &ioarcb->add_data.u.regs; + + ioarcb->res_handle = res->cfgte.res_handle; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_RESET_DEVICE; + if (ipr_is_gata(res)) { + cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET; + ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags)); + regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; + } + + ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) + memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata, + sizeof(struct ipr_ioasa_gata)); + + LEAVE; + return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); +} + +/** + * ipr_sata_reset - Reset the SATA port + * @link: SATA link to reset + * @classes: class of the attached device + * + * This function issues a SATA phy reset to the affected ATA link. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) +{ + struct ipr_sata_port *sata_port = link->ap->private_data; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + int rc = -ENXIO; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + + res = sata_port->res; + if (res) { + rc = ipr_device_reset(ioa_cfg, res); + switch(res->cfgte.proto) { + case IPR_PROTO_SATA: + case IPR_PROTO_SAS_STP: + *classes = ATA_DEV_ATA; + break; + case IPR_PROTO_SATA_ATAPI: + case IPR_PROTO_SAS_STP_ATAPI: + *classes = ATA_DEV_ATAPI; + break; + default: + *classes = ATA_DEV_UNKNOWN; + break; + }; + } + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + LEAVE; + return rc; +} + +/** * ipr_eh_dev_reset - Reset the device * @scsi_cmd: scsi command struct * @@ -3316,14 +3908,14 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) struct ipr_cmnd *ipr_cmd; struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; - struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc; + struct ata_port *ap; + int rc = 0; ENTER; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; res = scsi_cmd->device->hostdata; - if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res))) + if (!res) return FAILED; /* @@ -3340,29 +3932,36 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { if (ipr_cmd->scsi_cmd) ipr_cmd->done = ipr_scsi_eh_done; + if (ipr_cmd->qc) + ipr_cmd->done = ipr_sata_eh_done; + if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { + ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; + ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; + } } } res->resetting_device = 1; + scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - - ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; - cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_RESET_DEVICE; - - ipr_sdev_err(scsi_cmd->device, "Resetting device\n"); - ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); - - ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + if (ipr_is_gata(res) && res->sata_port) { + ap = res->sata_port->ap; + spin_unlock_irq(scsi_cmd->device->host->host_lock); + ata_std_error_handler(ap); + spin_lock_irq(scsi_cmd->device->host->host_lock); + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { + rc = -EIO; + break; + } + } + } else + rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - LEAVE; - return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); + return (rc ? FAILED : SUCCESS); } static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) @@ -3437,7 +4036,7 @@ static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) return; } - ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n"); + sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n"); reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ipr_cmd->sibling = reset_cmd; reset_cmd->sibling = ipr_cmd; @@ -3480,7 +4079,7 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) */ if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead) return FAILED; - if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res))) + if (!res || !ipr_is_gscsi(res)) return FAILED; list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { @@ -3501,7 +4100,8 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; ipr_cmd->u.sdev = scsi_cmd->device; - ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); + scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n", + scsi_cmd->cmnd[0]); ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); @@ -3515,7 +4115,8 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) } list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - res->needs_sync_complete = 1; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; LEAVE; return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); @@ -3588,12 +4189,11 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, * ipr_isr - Interrupt service routine * @irq: irq number * @devp: pointer to ioa config struct - * @regs: pt_regs struct * * Return value: * IRQ_NONE / IRQ_HANDLED **/ -static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs) +static irqreturn_t ipr_isr(int irq, void *devp) { struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; unsigned long lock_flags = 0; @@ -3687,80 +4287,55 @@ static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs) static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, struct ipr_cmnd *ipr_cmd) { - int i; - struct scatterlist *sglist; + int i, nseg; + struct scatterlist *sg; u32 length; u32 ioadl_flags = 0; struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; - length = scsi_cmd->request_bufflen; - - if (length == 0) + length = scsi_bufflen(scsi_cmd); + if (!length) return 0; - if (scsi_cmd->use_sg) { - ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, - scsi_cmd->request_buffer, - scsi_cmd->use_sg, - scsi_cmd->sc_data_direction); - - if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->write_data_transfer_length = cpu_to_be32(length); - ioarcb->write_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_READ; - ioarcb->read_data_transfer_length = cpu_to_be32(length); - ioarcb->read_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } - - sglist = scsi_cmd->request_buffer; + nseg = scsi_dma_map(scsi_cmd); + if (nseg < 0) { + dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); + return -1; + } - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { - ioadl[i].flags_and_data_len = - cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i])); - ioadl[i].address = - cpu_to_be32(sg_dma_address(&sglist[i])); - } + ipr_cmd->dma_use_sg = nseg; - if (likely(ipr_cmd->dma_use_sg)) { - ioadl[i-1].flags_and_data_len |= - cpu_to_be32(IPR_IOADL_FLAGS_LAST); - return 0; - } else - dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); - } else { - if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->write_data_transfer_length = cpu_to_be32(length); - ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); - } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_READ; - ioarcb->read_data_transfer_length = cpu_to_be32(length); - ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc)); - } - - ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev, - scsi_cmd->request_buffer, length, - scsi_cmd->sc_data_direction); + if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_WRITE; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(length); + ioarcb->write_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_READ; + ioarcb->read_data_transfer_length = cpu_to_be32(length); + ioarcb->read_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } + + if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) { + ioadl = ioarcb->add_data.u.ioadl; + ioarcb->write_ioadl_addr = + cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) + + offsetof(struct ipr_ioarcb, add_data)); + ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; + } - if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) { - ipr_cmd->dma_use_sg = 1; - ioadl[0].flags_and_data_len = - cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST); - ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle); - return 0; - } else - dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n"); + scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) { + ioadl[i].flags_and_data_len = + cpu_to_be32(ioadl_flags | sg_dma_len(sg)); + ioadl[i].address = cpu_to_be32(sg_dma_address(sg)); } - return -1; + ioadl[i-1].flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); + return 0; } /** @@ -3811,18 +4386,19 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { scsi_cmd->result |= (DID_ERROR << 16); - ipr_sdev_err(scsi_cmd->device, - "Request Sense failed with IOASC: 0x%08X\n", ioasc); + scmd_printk(KERN_ERR, scsi_cmd, + "Request Sense failed with IOASC: 0x%08X\n", ioasc); } else { memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); } if (res) { - res->needs_sync_complete = 1; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; res->in_erp = 0; } - ipr_unmap_sglist(ioa_cfg, ipr_cmd); + scsi_dma_unmap(ipr_cmd->scsi_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); scsi_cmd->scsi_done(scsi_cmd); } @@ -3836,11 +4412,9 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) **/ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) { - struct ipr_ioarcb *ioarcb; - struct ipr_ioasa *ioasa; - - ioarcb = &ipr_cmd->ioarcb; - ioasa = &ipr_cmd->ioasa; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr); memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); ioarcb->write_data_transfer_length = 0; @@ -3849,6 +4423,9 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) ioarcb->read_ioadl_len = 0; ioasa->ioasc = 0; ioasa->residual_data_len = 0; + ioarcb->write_ioadl_addr = + cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl)); + ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; } /** @@ -3933,6 +4510,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) * ipr_dump_ioasa - Dump contents of IOASA * @ioa_cfg: ioa config struct * @ipr_cmd: ipr command struct + * @res: resource entry struct * * This function is invoked by the interrupt handler when ops * fail. It will log the IOASA if appropriate. Only called @@ -3942,16 +4520,17 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) * none **/ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) + struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res) { int i; u16 data_len; - u32 ioasc; + u32 ioasc, fd_ioasc; struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; __be32 *ioasa_data = (__be32 *)ioasa; int error_index; ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK; + fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK; if (0 == ioasc) return; @@ -3959,27 +4538,24 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) return; - error_index = ipr_get_error(ioasc); + if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc) + error_index = ipr_get_error(fd_ioasc); + else + error_index = ipr_get_error(ioasc); if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) { /* Don't log an error if the IOA already logged one */ if (ioasa->ilid != 0) return; + if (!ipr_is_gscsi(res)) + return; + if (ipr_error_table[error_index].log_ioasa == 0) return; } - ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n", - ipr_error_table[error_index].error); - - if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) && - (ioasa->u.gpdd.bus_phase <= ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) { - ipr_sdev_err(ipr_cmd->scsi_cmd->device, - "Device End state: %s Phase: %s\n", - ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state], - ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]); - } + ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error); if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len)) data_len = sizeof(struct ipr_ioasa); @@ -4089,6 +4665,29 @@ static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd) } /** + * ipr_get_autosense - Copy autosense data to sense buffer + * @ipr_cmd: ipr command struct + * + * This function copies the autosense buffer to the buffer + * in the scsi_cmd, if there is autosense available. + * + * Return value: + * 1 if autosense was available / 0 if not + **/ +static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioasa *ioasa = &ipr_cmd->ioasa; + + if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0) + return 0; + + memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data, + min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len), + SCSI_SENSE_BUFFERSIZE)); + return 1; +} + +/** * ipr_erp_start - Process an error response for a SCSI op * @ioa_cfg: ioa config struct * @ipr_cmd: ipr command struct @@ -4105,20 +4704,24 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; struct ipr_resource_entry *res = scsi_cmd->device->hostdata; u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK; if (!res) { ipr_scsi_eh_done(ipr_cmd); return; } - if (ipr_is_gscsi(res)) - ipr_dump_ioasa(ioa_cfg, ipr_cmd); - else + if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS) ipr_gen_sense(ipr_cmd); - switch (ioasc & IPR_IOASC_IOASC_MASK) { + ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); + + switch (masked_ioasc) { case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: - scsi_cmd->result |= (DID_IMM_RETRY << 16); + if (ipr_is_naca_model(res)) + scsi_cmd->result |= (DID_ABORT << 16); + else + scsi_cmd->result |= (DID_IMM_RETRY << 16); break; case IPR_IOASC_IR_RESOURCE_HANDLE: case IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA: @@ -4126,7 +4729,8 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, break; case IPR_IOASC_HW_SEL_TIMEOUT: scsi_cmd->result |= (DID_NO_CONNECT << 16); - res->needs_sync_complete = 1; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; break; case IPR_IOASC_SYNC_REQUIRED: if (!res->in_erp) @@ -4146,26 +4750,33 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, if (!res->resetting_device) scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel); scsi_cmd->result |= (DID_ERROR << 16); - res->needs_sync_complete = 1; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; break; case IPR_IOASC_HW_DEV_BUS_STATUS: scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc); if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) { - ipr_erp_cancel_all(ipr_cmd); - return; + if (!ipr_get_autosense(ipr_cmd)) { + if (!ipr_is_naca_model(res)) { + ipr_erp_cancel_all(ipr_cmd); + return; + } + } } - res->needs_sync_complete = 1; + if (!ipr_is_naca_model(res)) + res->needs_sync_complete = 1; break; case IPR_IOASC_NR_INIT_CMD_REQUIRED: break; default: - scsi_cmd->result |= (DID_ERROR << 16); - if (!ipr_is_vset_device(res)) + if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) + scsi_cmd->result |= (DID_ERROR << 16); + if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res)) res->needs_sync_complete = 1; break; } - ipr_unmap_sglist(ioa_cfg, ipr_cmd); + scsi_dma_unmap(ipr_cmd->scsi_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); scsi_cmd->scsi_done(scsi_cmd); } @@ -4186,10 +4797,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); - scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len); + scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->ioasa.residual_data_len)); if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) { - ipr_unmap_sglist(ioa_cfg, ipr_cmd); + scsi_dma_unmap(ipr_cmd->scsi_cmd); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); scsi_cmd->scsi_done(scsi_cmd); } else @@ -4197,35 +4808,6 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) } /** - * ipr_save_ioafp_mode_select - Save adapters mode select data - * @ioa_cfg: ioa config struct - * @scsi_cmd: scsi command struct - * - * This function saves mode select data for the adapter to - * use following an adapter reset. - * - * Return value: - * 0 on success / SCSI_MLQUEUE_HOST_BUSY on failure - **/ -static int ipr_save_ioafp_mode_select(struct ipr_ioa_cfg *ioa_cfg, - struct scsi_cmnd *scsi_cmd) -{ - if (!ioa_cfg->saved_mode_pages) { - ioa_cfg->saved_mode_pages = kmalloc(sizeof(struct ipr_mode_pages), - GFP_ATOMIC); - if (!ioa_cfg->saved_mode_pages) { - dev_err(&ioa_cfg->pdev->dev, - "IOA mode select buffer allocation failed\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - } - - memcpy(ioa_cfg->saved_mode_pages, scsi_cmd->buffer, scsi_cmd->cmnd[4]); - ioa_cfg->saved_mode_page_len = scsi_cmd->cmnd[4]; - return 0; -} - -/** * ipr_queuecommand - Queue a mid-layer request * @scsi_cmd: scsi command struct * @done: done function @@ -4270,6 +4852,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, return 0; } + if (ipr_is_gata(res) && res->sata_port) + return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap); + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ioarcb = &ipr_cmd->ioarcb; list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); @@ -4299,9 +4884,6 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE)) ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - if (ipr_is_ioa_resource(res) && scsi_cmd->cmnd[0] == MODE_SELECT) - rc = ipr_save_ioafp_mode_select(ioa_cfg, scsi_cmd); - if (likely(rc == 0)) rc = ipr_build_ioadl(ioa_cfg, ipr_cmd); @@ -4318,6 +4900,26 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd, } /** + * ipr_ioctl - IOCTL handler + * @sdev: scsi device struct + * @cmd: IOCTL cmd + * @arg: IOCTL arg + * + * Return value: + * 0 on success / other on failure + **/ +static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +{ + struct ipr_resource_entry *res; + + res = (struct ipr_resource_entry *)sdev->hostdata; + if (res && ipr_is_gata(res)) + return ata_scsi_ioctl(sdev, cmd, arg); + + return -EINVAL; +} + +/** * ipr_info - Get information about the card/driver * @scsi_host: scsi host struct * @@ -4343,6 +4945,7 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = "IPR", .info = ipr_ioa_info, + .ioctl = ipr_ioctl, .queuecommand = ipr_queuecommand, .eh_abort_handler = ipr_eh_abort, .eh_device_reset_handler = ipr_eh_dev_reset, @@ -4350,6 +4953,8 @@ static struct scsi_host_template driver_template = { .slave_alloc = ipr_slave_alloc, .slave_configure = ipr_slave_configure, .slave_destroy = ipr_slave_destroy, + .target_alloc = ipr_target_alloc, + .target_destroy = ipr_target_destroy, .change_queue_depth = ipr_change_queue_depth, .change_queue_type = ipr_change_queue_type, .bios_param = ipr_biosparam, @@ -4364,6 +4969,313 @@ static struct scsi_host_template driver_template = { .proc_name = IPR_NAME }; +/** + * ipr_ata_phy_reset - libata phy_reset handler + * @ap: ata port to reset + * + **/ +static void ipr_ata_phy_reset(struct ata_port *ap) +{ + unsigned long flags; + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + int rc; + + ENTER; + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + } + + if (!ioa_cfg->allow_cmds) + goto out_unlock; + + rc = ipr_device_reset(ioa_cfg, res); + + if (rc) { + ata_port_disable(ap); + goto out_unlock; + } + + switch(res->cfgte.proto) { + case IPR_PROTO_SATA: + case IPR_PROTO_SAS_STP: + ap->link.device[0].class = ATA_DEV_ATA; + break; + case IPR_PROTO_SATA_ATAPI: + case IPR_PROTO_SAS_STP_ATAPI: + ap->link.device[0].class = ATA_DEV_ATAPI; + break; + default: + ap->link.device[0].class = ATA_DEV_UNKNOWN; + ata_port_disable(ap); + break; + }; + +out_unlock: + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + LEAVE; +} + +/** + * ipr_ata_post_internal - Cleanup after an internal command + * @qc: ATA queued command + * + * Return value: + * none + **/ +static void ipr_ata_post_internal(struct ata_queued_cmd *qc) +{ + struct ipr_sata_port *sata_port = qc->ap->private_data; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_cmnd *ipr_cmd; + unsigned long flags; + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + } + + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->qc == qc) { + ipr_device_reset(ioa_cfg, sata_port->res); + break; + } + } + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); +} + +/** + * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure + * @regs: destination + * @tf: source ATA taskfile + * + * Return value: + * none + **/ +static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs, + struct ata_taskfile *tf) +{ + regs->feature = tf->feature; + regs->nsect = tf->nsect; + regs->lbal = tf->lbal; + regs->lbam = tf->lbam; + regs->lbah = tf->lbah; + regs->device = tf->device; + regs->command = tf->command; + regs->hob_feature = tf->hob_feature; + regs->hob_nsect = tf->hob_nsect; + regs->hob_lbal = tf->hob_lbal; + regs->hob_lbam = tf->hob_lbam; + regs->hob_lbah = tf->hob_lbah; + regs->ctl = tf->ctl; +} + +/** + * ipr_sata_done - done function for SATA commands + * @ipr_cmd: ipr command struct + * + * This function is invoked by the interrupt handler for + * ops generated by the SCSI mid-layer to SATA devices + * + * Return value: + * none + **/ +static void ipr_sata_done(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ata_queued_cmd *qc = ipr_cmd->qc; + struct ipr_sata_port *sata_port = qc->ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata, + sizeof(struct ipr_ioasa_gata)); + ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); + + if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET) + scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus, + res->cfgte.res_addr.target); + + if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) + qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status); + else + qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + ata_qc_complete(qc); +} + +/** + * ipr_build_ata_ioadl - Build an ATA scatter/gather list + * @ipr_cmd: ipr command struct + * @qc: ATA queued command + * + **/ +static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, + struct ata_queued_cmd *qc) +{ + u32 ioadl_flags = 0; + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; + struct ipr_ioadl_desc *last_ioadl = NULL; + int len = qc->nbytes; + struct scatterlist *sg; + unsigned int si; + + if (len == 0) + return; + + if (qc->dma_dir == DMA_TO_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_WRITE; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; + ioarcb->write_data_transfer_length = cpu_to_be32(len); + ioarcb->write_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } else if (qc->dma_dir == DMA_FROM_DEVICE) { + ioadl_flags = IPR_IOADL_FLAGS_READ; + ioarcb->read_data_transfer_length = cpu_to_be32(len); + ioarcb->read_ioadl_len = + cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); + } + + for_each_sg(qc->sg, sg, qc->n_elem, si) { + ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); + ioadl->address = cpu_to_be32(sg_dma_address(sg)); + + last_ioadl = ioadl; + ioadl++; + } + + if (likely(last_ioadl)) + last_ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); +} + +/** + * ipr_qc_issue - Issue a SATA qc to a device + * @qc: queued command + * + * Return value: + * 0 if success + **/ +static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ipr_sata_port *sata_port = ap->private_data; + struct ipr_resource_entry *res = sata_port->res; + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + struct ipr_ioarcb_ata_regs *regs; + + if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) + return AC_ERR_SYSTEM; + + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioarcb = &ipr_cmd->ioarcb; + regs = &ioarcb->add_data.u.regs; + + memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data)); + ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs)); + + list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); + ipr_cmd->qc = qc; + ipr_cmd->done = ipr_sata_done; + ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; + ipr_cmd->dma_use_sg = qc->n_elem; + + ipr_build_ata_ioadl(ipr_cmd, qc); + regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; + ipr_copy_sata_tf(regs, &qc->tf); + memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN); + ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr)); + + switch (qc->tf.protocol) { + case ATA_PROT_NODATA: + case ATA_PROT_PIO: + break; + + case ATA_PROT_DMA: + regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; + break; + + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + regs->flags |= IPR_ATA_FLAG_PACKET_CMD; + break; + + case ATAPI_PROT_DMA: + regs->flags |= IPR_ATA_FLAG_PACKET_CMD; + regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; + break; + + default: + WARN_ON(1); + return AC_ERR_INVALID; + } + + mb(); + writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr), + ioa_cfg->regs.ioarrin_reg); + return 0; +} + +/** + * ipr_qc_fill_rtf - Read result TF + * @qc: ATA queued command + * + * Return value: + * true + **/ +static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) +{ + struct ipr_sata_port *sata_port = qc->ap->private_data; + struct ipr_ioasa_gata *g = &sata_port->ioasa; + struct ata_taskfile *tf = &qc->result_tf; + + tf->feature = g->error; + tf->nsect = g->nsect; + tf->lbal = g->lbal; + tf->lbam = g->lbam; + tf->lbah = g->lbah; + tf->device = g->device; + tf->command = g->status; + tf->hob_nsect = g->hob_nsect; + tf->hob_lbal = g->hob_lbal; + tf->hob_lbam = g->hob_lbam; + tf->hob_lbah = g->hob_lbah; + tf->ctl = g->alt_status; + + return true; +} + +static struct ata_port_operations ipr_sata_ops = { + .phy_reset = ipr_ata_phy_reset, + .hardreset = ipr_sata_reset, + .post_internal_cmd = ipr_ata_post_internal, + .qc_prep = ata_noop_qc_prep, + .qc_issue = ipr_qc_issue, + .qc_fill_rtf = ipr_qc_fill_rtf, + .port_start = ata_sas_port_start, + .port_stop = ata_sas_port_stop +}; + +static struct ata_port_info sata_port_info = { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | + ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, + .pio_mask = 0x10, /* pio4 */ + .mwdma_mask = 0x07, + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &ipr_sata_ops +}; + #ifdef CONFIG_PPC_PSERIES static const u16 ipr_blocked_processors[] = { PV_NORTHSTAR, @@ -4389,18 +5301,12 @@ static const u16 ipr_blocked_processors[] = { **/ static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) { - u8 rev_id; int i; - if (ioa_cfg->type == 0x5702) { - if (pci_read_config_byte(ioa_cfg->pdev, PCI_REVISION_ID, - &rev_id) == PCIBIOS_SUCCESSFUL) { - if (rev_id < 4) { - for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ - if (__is_processor(ipr_blocked_processors[i])) - return 1; - } - } + if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { + for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ + if (__is_processor(ipr_blocked_processors[i])) + return 1; } } return 0; @@ -4477,6 +5383,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); } + scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS); dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n"); ioa_cfg->reset_retries = 0; @@ -4533,7 +5440,7 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd) ipr_cmd->job_step = ipr_ioa_reset_done; list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { - if (!IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) + if (!ipr_is_scsi_disk(res)) continue; ipr_cmd->u.res = res; @@ -4790,17 +5697,11 @@ static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd) int length; ENTER; - if (ioa_cfg->saved_mode_pages) { - memcpy(mode_pages, ioa_cfg->saved_mode_pages, - ioa_cfg->saved_mode_page_len); - length = ioa_cfg->saved_mode_page_len; - } else { - ipr_scsi_bus_speed_limit(ioa_cfg); - ipr_check_term_power(ioa_cfg, mode_pages); - ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages); - length = mode_pages->hdr.length + 1; - mode_pages->hdr.length = 0; - } + ipr_scsi_bus_speed_limit(ioa_cfg); + ipr_check_term_power(ioa_cfg, mode_pages); + ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages); + length = mode_pages->hdr.length + 1; + mode_pages->hdr.length = 0; ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), @@ -4845,6 +5746,51 @@ static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd, } /** + * ipr_reset_cmd_failed - Handle failure of IOA reset command + * @ipr_cmd: ipr command struct + * + * This function handles the failure of an IOA bringup command. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + dev_err(&ioa_cfg->pdev->dev, + "0x%02X failed with IOASC: 0x%08X\n", + ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc); + + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_mode_sense_failed - Handle failure of IOAFP mode sense + * @ipr_cmd: ipr command struct + * + * This function handles the failure of a Mode Sense to the IOAFP. + * Some adapters do not handle all mode pages. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd) +{ + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { + ipr_cmd->job_step = ipr_setup_write_cache; + return IPR_RC_JOB_CONTINUE; + } + + return ipr_reset_cmd_failed(ipr_cmd); +} + +/** * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA * @ipr_cmd: ipr command struct * @@ -4865,6 +5811,95 @@ static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd) sizeof(struct ipr_mode_pages)); ipr_cmd->job_step = ipr_ioafp_mode_select_page28; + ipr_cmd->job_step_failed = ipr_reset_mode_sense_failed; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA + * @ipr_cmd: ipr command struct + * + * This function enables dual IOA RAID support if possible. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; + struct ipr_mode_page24 *mode_page; + int length; + + ENTER; + mode_page = ipr_get_mode_page(mode_pages, 0x24, + sizeof(struct ipr_mode_page24)); + + if (mode_page) + mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF; + + length = mode_pages->hdr.length + 1; + mode_pages->hdr.length = 0; + + ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), + length); + + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense + * @ipr_cmd: ipr command struct + * + * This function handles the failure of a Mode Sense to the IOAFP. + * Some adapters do not handle all mode pages. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd) +{ + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + return IPR_RC_JOB_CONTINUE; + } + + return ipr_reset_cmd_failed(ipr_cmd); +} + +/** + * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA + * @ipr_cmd: ipr command struct + * + * This function send a mode sense to the IOA to retrieve + * the IOA Advanced Function Control mode page. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), + 0x24, ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, mode_pages), + sizeof(struct ipr_mode_pages)); + + ipr_cmd->job_step = ipr_ioafp_mode_select_page24; + ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed; ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); @@ -4933,14 +5968,17 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) list_for_each_entry_safe(res, temp, &old_res, queue) { if (res->sdev) { res->del_from_ml = 1; - res->sdev->hostdata = NULL; + res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; list_move_tail(&res->queue, &ioa_cfg->used_res_q); } else { list_move_tail(&res->queue, &ioa_cfg->free_res_q); } } - ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) + ipr_cmd->job_step = ipr_ioafp_mode_sense_page24; + else + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; LEAVE; return IPR_RC_JOB_CONTINUE; @@ -4962,8 +6000,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; + struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; ENTER; + if (cap->cap & IPR_CAP_DUAL_IOA_RAID) + ioa_cfg->dual_raid = 1; dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n", ucode_vpd->major_release, ucode_vpd->card_type, ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]); @@ -5047,6 +6088,37 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) } /** + * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Page 0xD0 inquiry to the adapter + * to retrieve adapter capabilities. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; + struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + memset(cap, 0, sizeof(*cap)); + + if (ipr_inquiry_page_supported(page0, 0xD0)) { + ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap), + sizeof(struct ipr_inquiry_cap)); + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter. * @ipr_cmd: ipr command struct * @@ -5066,7 +6138,7 @@ static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd) if (!ipr_inquiry_page_supported(page0, 1)) ioa_cfg->cache_state = CACHE_NONE; - ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + ipr_cmd->job_step = ipr_ioafp_cap_inquiry; ipr_ioafp_inquiry(ipr_cmd, 1, 3, ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data), @@ -5288,7 +6360,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n"); ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ); + ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ); ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout; ipr_cmd->done = ipr_reset_ioa_job; add_timer(&ipr_cmd->timer); @@ -5352,6 +6424,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) struct ipr_hostrcb *hostrcb; struct ipr_uc_sdt sdt; int rc, length; + u32 ioasc; mailbox = readl(ioa_cfg->ioa_mailbox); @@ -5384,9 +6457,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) (__be32 *)&hostrcb->hcam, min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); - if (!rc) + if (!rc) { ipr_handle_log_data(ioa_cfg, hostrcb); - else + ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); + if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED && + ioa_cfg->sdt_state == GET_DUMP) + ioa_cfg->sdt_state = WAIT_FOR_DUMP; + } else ipr_unit_check_no_data(ioa_cfg); list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); @@ -5409,7 +6486,6 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) int rc; ENTER; - pci_unblock_user_cfg_access(ioa_cfg->pdev); rc = pci_restore_state(ioa_cfg->pdev); if (rc != PCIBIOS_SUCCESSFUL) { @@ -5450,6 +6526,24 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) } /** + * ipr_reset_bist_done - BIST has completed on the adapter. + * @ipr_cmd: ipr command struct + * + * Description: Unblock config space and resume the reset process. + * + * Return value: + * IPR_RC_JOB_CONTINUE + **/ +static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) +{ + ENTER; + pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + ipr_cmd->job_step = ipr_reset_restore_cfg_space; + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_reset_start_bist - Run BIST on the adapter. * @ipr_cmd: ipr command struct * @@ -5468,10 +6562,11 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); if (rc != PCIBIOS_SUCCESSFUL) { + pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); rc = IPR_RC_JOB_CONTINUE; } else { - ipr_cmd->job_step = ipr_reset_restore_cfg_space; + ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; } @@ -5481,6 +6576,48 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) } /** + * ipr_reset_slot_reset_done - Clear PCI reset to the adapter + * @ipr_cmd: ipr command struct + * + * Description: This clears PCI reset to the adapter and delays two seconds. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd) +{ + ENTER; + pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset); + ipr_cmd->job_step = ipr_reset_bist_done; + ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_slot_reset - Reset the PCI slot of the adapter. + * @ipr_cmd: ipr command struct + * + * Description: This asserts PCI reset to the adapter. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct pci_dev *pdev = ioa_cfg->pdev; + + ENTER; + pci_block_user_cfg_access(pdev); + pci_set_pcie_reset_state(pdev, pcie_warm_reset); + ipr_cmd->job_step = ipr_reset_slot_reset_done; + ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** * ipr_reset_allowed - Query whether or not IOA can be reset * @ioa_cfg: ioa config struct * @@ -5519,7 +6656,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); } else { - ipr_cmd->job_step = ipr_reset_start_bist; + ipr_cmd->job_step = ioa_cfg->reset; rc = IPR_RC_JOB_CONTINUE; } @@ -5552,7 +6689,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg); ipr_cmd->job_step = ipr_reset_wait_to_start_bist; } else { - ipr_cmd->job_step = ipr_reset_start_bist; + ipr_cmd->job_step = ioa_cfg->reset; } ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; @@ -5647,12 +6784,14 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type; - if (shutdown_type == IPR_SHUTDOWN_ABBREV) - timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; + if (shutdown_type == IPR_SHUTDOWN_NORMAL) + timeout = IPR_SHUTDOWN_TIMEOUT; else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL) timeout = IPR_INTERNAL_TIMEOUT; + else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) + timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO; else - timeout = IPR_SHUTDOWN_TIMEOUT; + timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout); @@ -5677,7 +6816,6 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) { u32 rc, ioasc; - unsigned long scratch = ipr_cmd->u.scratch; struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; do { @@ -5693,17 +6831,13 @@ static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) } if (IPR_IOASC_SENSE_KEY(ioasc)) { - dev_err(&ioa_cfg->pdev->dev, - "0x%02X failed with IOASC: 0x%08X\n", - ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc); - - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - return; + rc = ipr_cmd->job_step_failed(ipr_cmd); + if (rc == IPR_RC_JOB_RETURN) + return; } ipr_reinit_ipr_cmnd(ipr_cmd); - ipr_cmd->u.scratch = scratch; + ipr_cmd->job_step_failed = ipr_reset_cmd_failed; rc = ipr_cmd->job_step(ipr_cmd); } while(rc == IPR_RC_JOB_CONTINUE); } @@ -5789,6 +6923,112 @@ static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, } /** + * ipr_reset_freeze - Hold off all I/O activity + * @ipr_cmd: ipr command struct + * + * Description: If the PCI slot is frozen, hold off all I/O + * activity; then, as soon as the slot is available again, + * initiate an adapter reset. + */ +static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd) +{ + /* Disallow new interrupts, avoid loop */ + ipr_cmd->ioa_cfg->allow_interrupts = 0; + list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); + ipr_cmd->done = ipr_reset_ioa_job; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_pci_frozen - Called when slot has experienced a PCI bus error. + * @pdev: PCI device struct + * + * Description: This routine is called to tell us that the PCI bus + * is down. Can't do anything here, except put the device driver + * into a holding pattern, waiting for the PCI bus to come back. + */ +static void ipr_pci_frozen(struct pci_dev *pdev) +{ + unsigned long flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); +} + +/** + * ipr_pci_slot_reset - Called when PCI slot has been reset. + * @pdev: PCI device struct + * + * Description: This routine is called by the pci error recovery + * code after the PCI slot has been reset, just before we + * should resume normal operations. + */ +static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev) +{ + unsigned long flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + if (ioa_cfg->needs_warm_reset) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + else + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, + IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * ipr_pci_perm_failure - Called when PCI slot is dead for good. + * @pdev: PCI device struct + * + * Description: This routine is called when the PCI bus has + * permanently failed. + */ +static void ipr_pci_perm_failure(struct pci_dev *pdev) +{ + unsigned long flags = 0; + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + + spin_lock_irqsave(ioa_cfg->host->host_lock, flags); + if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) + ioa_cfg->sdt_state = ABORT_DUMP; + ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES; + ioa_cfg->in_ioa_bringdown = 1; + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); +} + +/** + * ipr_pci_error_detected - Called when a PCI error is detected. + * @pdev: PCI device struct + * @state: PCI channel state + * + * Description: Called when a PCI error is detected. + * + * Return value: + * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + switch (state) { + case pci_channel_io_frozen: + ipr_pci_frozen(pdev); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + ipr_pci_perm_failure(pdev); + return PCI_ERS_RESULT_DISCONNECT; + break; + default: + break; + } + return PCI_ERS_RESULT_NEED_RESET; +} + +/** * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) * @ioa_cfg: ioa cfg struct * @@ -5797,7 +7037,7 @@ static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, * where it can accept new commands. * Return value: - * 0 on sucess / -EIO on failure + * 0 on success / -EIO on failure **/ static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg) { @@ -5807,7 +7047,12 @@ static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg) ENTER; spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg); - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, IPR_SHUTDOWN_NONE); + if (ioa_cfg->needs_hard_reset) { + ioa_cfg->needs_hard_reset = 0; + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + } else + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, + IPR_SHUTDOWN_NONE); spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); @@ -5884,7 +7129,6 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) } ipr_free_dump(ioa_cfg); - kfree(ioa_cfg->saved_mode_pages); kfree(ioa_cfg->trace); } @@ -5933,7 +7177,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) return -ENOMEM; for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { - ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, SLAB_KERNEL, &dma_addr); + ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); if (!ipr_cmd) { ipr_free_cmd_blks(ioa_cfg); @@ -6020,6 +7264,7 @@ static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) ioa_cfg->hostrcb[i]->hostrcb_dma = ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); + ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg; list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); } @@ -6097,8 +7342,6 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, ioa_cfg->pdev = pdev; ioa_cfg->log_level = ipr_log_level; ioa_cfg->doorbell = IPR_DOORBELL; - if (!ipr_auto_create) - ioa_cfg->doorbell |= IPR_RUNTIME_RESET; sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER); sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL); sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL); @@ -6114,7 +7357,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); INIT_LIST_HEAD(&ioa_cfg->free_res_q); INIT_LIST_HEAD(&ioa_cfg->used_res_q); - INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg); + INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); init_waitqueue_head(&ioa_cfg->reset_wait_q); ioa_cfg->sdt_state = INACTIVE; if (ipr_enable_cache) @@ -6158,9 +7401,6 @@ ipr_get_chip_cfg(const struct pci_device_id *dev_id) { int i; - if (dev_id->driver_data) - return (const struct ipr_chip_cfg_t *)dev_id->driver_data; - for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) if (ipr_chip[i].vendor == dev_id->vendor && ipr_chip[i].device == dev_id->device) @@ -6183,7 +7423,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, struct Scsi_Host *host; unsigned long ipr_regs_pci; void __iomem *ipr_regs; - u32 rc = PCIBIOS_SUCCESSFUL; + int rc = PCIBIOS_SUCCESSFUL; + volatile u32 mask, uproc, interrupts; ENTER; @@ -6204,6 +7445,8 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); + ata_host_init(&ioa_cfg->ata_host, &pdev->dev, + sata_port_info.flags, &ipr_sata_ops); ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id); @@ -6213,6 +7456,15 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto out_scsi_host_put; } + if (ipr_transop_timeout) + ioa_cfg->transop_timeout = ipr_transop_timeout; + else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) + ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT; + else + ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT; + + ioa_cfg->revid = pdev->revision; + ipr_regs_pci = pci_resource_start(pdev, 0); rc = pci_request_regions(pdev, IPR_NAME); @@ -6276,8 +7528,22 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto cleanup_nomem; } + /* + * If HRRQ updated interrupt is not masked, or reset alert is set, + * the card is in an unknown state and needs a hard reset + */ + mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + interrupts = readl(ioa_cfg->regs.sense_interrupt_reg); + uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg); + if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT)) + ioa_cfg->needs_hard_reset = 1; + if (interrupts & IPR_PCII_ERROR_INTERRUPTS) + ioa_cfg->needs_hard_reset = 1; + if (interrupts & IPR_PCII_IOA_UNIT_CHECKED) + ioa_cfg->ioa_unit_checked = 1; + ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); - rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg); + rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); if (rc) { dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", @@ -6285,6 +7551,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto cleanup_nolog; } + if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) || + (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) { + ioa_cfg->needs_warm_reset = 1; + ioa_cfg->reset = ipr_reset_slot_reset; + } else + ioa_cfg->reset = ipr_reset_start_bist; + spin_lock(&ipr_driver_lock); list_add_tail(&ioa_cfg->queue, &ipr_ioa_head); spin_unlock(&ipr_driver_lock); @@ -6367,6 +7640,12 @@ static void __ipr_remove(struct pci_dev *pdev) ENTER; spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + } + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); @@ -6402,9 +7681,9 @@ static void ipr_remove(struct pci_dev *pdev) ENTER; - ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, + ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, &ipr_trace_attr); - ipr_remove_dump_file(&ioa_cfg->host->shost_classdev.kobj, + ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj, &ipr_dump_attr); scsi_remove_host(ioa_cfg->host); @@ -6445,7 +7724,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev, return rc; } - rc = ipr_create_trace_file(&ioa_cfg->host->shost_classdev.kobj, + rc = ipr_create_trace_file(&ioa_cfg->host->shost_dev.kobj, &ipr_trace_attr); if (rc) { @@ -6454,11 +7733,11 @@ static int __devinit ipr_probe(struct pci_dev *pdev, return rc; } - rc = ipr_create_dump_file(&ioa_cfg->host->shost_classdev.kobj, + rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj, &ipr_dump_attr); if (rc) { - ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj, + ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, &ipr_trace_attr); scsi_remove_host(ioa_cfg->host); __ipr_remove(pdev); @@ -6490,6 +7769,12 @@ static void ipr_shutdown(struct pci_dev *pdev) unsigned long lock_flags = 0; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); @@ -6497,42 +7782,79 @@ static void ipr_shutdown(struct pci_dev *pdev) static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, 0 }, { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT}, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, { } }; MODULE_DEVICE_TABLE(pci, ipr_pci_table); +static struct pci_error_handlers ipr_err_handler = { + .error_detected = ipr_pci_error_detected, + .slot_reset = ipr_pci_slot_reset, +}; + static struct pci_driver ipr_driver = { .name = IPR_NAME, .id_table = ipr_pci_table, .probe = ipr_probe, .remove = ipr_remove, .shutdown = ipr_shutdown, + .err_handler = &ipr_err_handler, + .dynids.use_driver_data = 1 }; /** @@ -6546,7 +7868,7 @@ static int __init ipr_init(void) ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); - return pci_module_init(&ipr_driver); + return pci_register_driver(&ipr_driver); } /**