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[] = {
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
return;
if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
- ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
- "%s\n", ipr_error_table[error_index].error);
+ 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);
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);
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);
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))
+ 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);
}
return rc;
}
-/**
- * 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.
- *
- * 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;
- u32 ioasc;
-
- ENTER;
- ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
- ioarcb = &ipr_cmd->ioarcb;
- cmd_pkt = &ioarcb->cmd_pkt;
-
- ioarcb->res_handle = res->cfgte.res_handle;
- cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
- cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
-
- 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);
-
- LEAVE;
- return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
-}
-
/**
* ipr_eh_dev_reset - Reset the device
* @scsi_cmd: scsi command struct
struct ipr_cmnd *ipr_cmd;
struct ipr_ioa_cfg *ioa_cfg;
struct ipr_resource_entry *res;
- int rc;
+ struct ipr_cmd_pkt *cmd_pkt;
+ u32 ioasc;
ENTER;
ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
}
res->resetting_device = 1;
- scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
- rc = ipr_device_reset(ioa_cfg, res);
+
+ 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);
+
res->resetting_device = 0;
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+
LEAVE;
- return (rc ? FAILED : SUCCESS);
+ return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
}
static int ipr_eh_dev_reset(struct scsi_cmnd * cmd)
return;
}
- sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n");
+ ipr_sdev_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;
cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS;
ipr_cmd->u.sdev = scsi_cmd->device;
- scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n",
- scsi_cmd->cmnd[0]);
+ ipr_sdev_err(scsi_cmd->device, "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);
if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
scsi_cmd->result |= (DID_ERROR << 16);
- scmd_printk(KERN_ERR, scsi_cmd,
- "Request Sense failed with IOASC: 0x%08X\n", ioasc);
+ ipr_sdev_err(scsi_cmd->device,
+ "Request Sense failed with IOASC: 0x%08X\n", ioasc);
} else {
memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE);
* 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
* none
**/
static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
- struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res)
+ struct ipr_cmnd *ipr_cmd)
{
int i;
u16 data_len;
return;
}
- ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error);
+ 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]);
+ }
if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len))
data_len = sizeof(struct ipr_ioasa);
}
if (ipr_is_gscsi(res))
- ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+ ipr_dump_ioasa(ioa_cfg, ipr_cmd);
else
ipr_gen_sense(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_scsi_disk(res))
+ if (!IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))
continue;
ipr_cmd->u.res = res;
list_for_each_entry_safe(res, temp, &old_res, queue) {
if (res->sdev) {
res->del_from_ml = 1;
- res->cfgte.res_handle = IPR_INVALID_RES_HANDLE;
+ res->sdev->hostdata = NULL;
list_move_tail(&res->queue, &ioa_cfg->used_res_q);
} else {
list_move_tail(&res->queue, &ioa_cfg->free_res_q);
shutdown_type);
}
-/**
- * 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);
- _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
};
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,
};
/**