Brian King <brk...@linux.vnet.ibm.com> writes: > Converts ipr to use the new EH API of libata, removing the > last user of this API, allowing for its ultimate removal from > the kernel. > > Sending this out only as an RFC for now. The patch will need > significantly more testing, but I can now detect and initialize > a SATA device and the main functional path appears to be working.
Hi Brian, I took a quick look, didn't take the time to run it yet. small comment below > > Signed-off-by: Brian King <brk...@linux.vnet.ibm.com> > --- > > drivers/scsi/ipr.c | 479 > +++++++++++++++++++++++++++++++---------------------- > drivers/scsi/ipr.h | 3 > 2 files changed, 288 insertions(+), 194 deletions(-) > > diff -puN drivers/scsi/ipr.c~ipr_libata_api_change drivers/scsi/ipr.c > --- linux-2.6.git/drivers/scsi/ipr.c~ipr_libata_api_change 2016-08-30 > 20:55:39.209008819 -0500 > +++ linux-2.6.git-bjking1/drivers/scsi/ipr.c 2016-08-30 20:56:44.153224313 > -0500 > @@ -84,6 +84,7 @@ > #include <scsi/scsi_tcq.h> > #include <scsi/scsi_eh.h> > #include <scsi/scsi_cmnd.h> > +#include <scsi/scsi_transport.h> > #include "ipr.h" > > /* > @@ -833,10 +834,14 @@ static void ipr_sata_eh_done(struct ipr_ > { > struct ata_queued_cmd *qc = ipr_cmd->qc; > struct ipr_sata_port *sata_port = qc->ap->private_data; > + unsigned long lock_flags; > > qc->err_mask |= AC_ERR_OTHER; > sata_port->ioasa.status |= ATA_BUSY; > + > + spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags); > list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > + spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags); > ata_qc_complete(qc); > } > > @@ -850,17 +855,72 @@ static void ipr_sata_eh_done(struct ipr_ > * Return value: > * none > **/ > +static void __ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) > +{ > + struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; > + > + scsi_cmd->result |= (DID_ERROR << 16); > + > + scsi_dma_unmap(ipr_cmd->scsi_cmd); > + scsi_cmd->scsi_done(scsi_cmd); > + if (ipr_cmd->eh_comp) > + complete(ipr_cmd->eh_comp); > + spin_lock(&ipr_cmd->hrrq->_lock); > + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > + spin_unlock(&ipr_cmd->hrrq->_lock); > +} > + > +/** > + * ipr_scsi_eh_done - mid-layer done function for aborted ops > + * @ipr_cmd: ipr command struct > + * > + * This function is invoked by the interrupt handler for > + * ops generated by the SCSI mid-layer which are being aborted. > + * > + * Return value: > + * none > + **/ > static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) > { > struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; > + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; > + unsigned long lock_flags; > > scsi_cmd->result |= (DID_ERROR << 16); > > scsi_dma_unmap(ipr_cmd->scsi_cmd); > scsi_cmd->scsi_done(scsi_cmd); > + > + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > if (ipr_cmd->eh_comp) > complete(ipr_cmd->eh_comp); > + spin_lock(&ipr_cmd->hrrq->_lock); > list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > + spin_unlock(&ipr_cmd->hrrq->_lock); > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > +} > + > +static void ipr_send_back_failed_ops(struct ipr_ioa_cfg *ioa_cfg) > +{ > + struct ipr_cmnd *ipr_cmd, *temp; > + struct ipr_hrr_queue *hrrq; > + LIST_HEAD(error_q); > + unsigned long flags = 0; > + > + ENTER; > + for_each_hrrq(hrrq, ioa_cfg) { > + spin_lock_irqsave(hrrq->lock, flags); > + list_splice_init(&hrrq->hrrq_error_q, &error_q); > + spin_unlock_irqrestore(hrrq->lock, flags); > + > + list_for_each_entry_safe(ipr_cmd, temp, &error_q, queue) { > + list_del(&ipr_cmd->queue); > + ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, > IPR_IOASC_IOA_WAS_RESET); > + ipr_cmd->fast_done(ipr_cmd); > + } > + } > + > + LEAVE; > } > > /** > @@ -882,7 +942,7 @@ static void ipr_fail_all_ops(struct ipr_ > spin_lock(&hrrq->_lock); > list_for_each_entry_safe(ipr_cmd, > temp, &hrrq->hrrq_pending_q, queue) { > - list_del(&ipr_cmd->queue); > + list_move_tail(&ipr_cmd->queue, &hrrq->hrrq_error_q); > > ipr_cmd->s.ioasa.hdr.ioasc = > cpu_to_be32(IPR_IOASC_IOA_WAS_RESET); > @@ -890,14 +950,11 @@ static void ipr_fail_all_ops(struct ipr_ > cpu_to_be32(IPR_DRIVER_ILID); > > if (ipr_cmd->scsi_cmd) > - ipr_cmd->done = ipr_scsi_eh_done; > + ipr_cmd->fast_done = ipr_scsi_eh_done; > else if (ipr_cmd->qc) > - ipr_cmd->done = ipr_sata_eh_done; > + ipr_cmd->fast_done = ipr_sata_eh_done; > > - ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, > - IPR_IOASC_IOA_WAS_RESET); > del_timer(&ipr_cmd->timer); > - ipr_cmd->done(ipr_cmd); > } > spin_unlock(&hrrq->_lock); > } > @@ -3267,6 +3324,16 @@ static void ipr_release_dump(struct kref > LEAVE; > } > > +static struct ata_port_info sata_port_info; > + > +static void ipr_sata_eh_work(struct work_struct *work) > +{ > + struct ipr_sata_port *sata_port = container_of(work, struct > ipr_sata_port, work); > + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; > + > + ata_scsi_port_error_handler(ioa_cfg->host, sata_port->ap); > +} > + > /** > * ipr_worker_thread - Worker thread > * @work: ioa config struct > @@ -3282,12 +3349,15 @@ static void ipr_worker_thread(struct wor > { > unsigned long lock_flags; > struct ipr_resource_entry *res; > + struct ipr_sata_port *sata_port; > + struct ata_port *ap; > struct scsi_device *sdev; > struct ipr_dump *dump; > struct ipr_ioa_cfg *ioa_cfg = > container_of(work, struct ipr_ioa_cfg, work_q); > u8 bus, target, lun; > - int did_work; > + int did_work, rc; > + int sata_ports = 0; > > ENTER; > spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > @@ -3324,25 +3394,90 @@ restart: > } > > list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { > - if (res->del_from_ml && res->sdev) { > + if (!res->del_from_ml) > + continue; > + if (res->sdev) { > did_work = 1; > sdev = res->sdev; > if (!scsi_device_get(sdev)) { > - if (!res->add_to_ml) > - list_move_tail(&res->queue, > &ioa_cfg->free_res_q); > - else > - res->del_from_ml = 0; > + if (!res->sata_port) { > + if (!res->add_to_ml) > + > list_move_tail(&res->queue, &ioa_cfg->free_res_q); > + else > + res->del_from_ml = 0; > + } > > spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > scsi_remove_device(sdev); > scsi_device_put(sdev); > > spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > } > break; > + } else if (ipr_is_gata(res)) { > + did_work = 1; > + sata_port = res->sata_port; > + res->sata_port = NULL; > + ap = sata_port->ap; > + if (!res->add_to_ml) > + list_move_tail(&res->queue, > &ioa_cfg->free_res_q); > + else > + res->del_from_ml = 0; > + > + > spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > + spin_lock_irqsave(ap->lock, lock_flags); > + ap->pflags |= ATA_PFLAG_UNLOADING; > + ata_port_schedule_eh(ap); > + spin_unlock_irqrestore(ap->lock, lock_flags); > + > + ata_port_wait_eh(ap); > + ata_sas_port_destroy(ap); > + kfree(sata_port); > + spin_lock_irqsave(ioa_cfg->host->host_lock, > lock_flags); > } > } > } while (did_work); > > list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { > + if (res->add_to_ml && ipr_is_gata(res) && !res->sata_port) { > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, > lock_flags); > + sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); > + ap = ata_sas_port_alloc(&ioa_cfg->ata_host, > &sata_port_info, ioa_cfg->host); > + > + if (!sata_port || !ap) { > + spin_lock_irqsave(ioa_cfg->host->host_lock, > lock_flags); > + res->add_to_ml = 0; > + kfree(sata_port); > + goto restart; > + } > + > + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > + sata_port->ioa_cfg = ioa_cfg; > + sata_port->ap = ap; > + sata_port->res = res; > + INIT_WORK(&sata_port->work, ipr_sata_eh_work); > + > + res->sata_port = sata_port; > + ap->private_data = sata_port; > + ap->cbl = ATA_CBL_SATA; > + ap->scsi_host = ioa_cfg->host; > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, > lock_flags); Do we really need to hold the host_lock in this small hunk? > + rc = ata_sas_port_init(ap); > + if (rc == 0) > + ata_sas_async_probe(ap); > + sata_ports++; > + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > + goto restart; > + } > + } > + > + if (sata_ports) { > + sata_ports = 0; > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > + wait_event(ioa_cfg->host->host_wait, > !scsi_host_in_recovery(ioa_cfg->host)); > + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > + goto restart; > + } > + > + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { > if (res->add_to_ml) { > bus = res->bus; > target = res->target; > @@ -4734,68 +4869,13 @@ static struct ipr_resource_entry *ipr_fi > return NULL; > } > > -static struct ata_port_info sata_port_info; > - > -/** > - * ipr_target_alloc - Prepare for commands to a SCSI target > - * @starget: scsi target struct > - * > - * If the device is a SATA device, this function allocates an > - * ATA port with libata, else it does nothing. > - * > - * Return value: > - * 0 on success / non-0 on failure > - **/ > -static int ipr_target_alloc(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_sata_port *sata_port; > - struct ata_port *ap; > - struct ipr_resource_entry *res; > - unsigned long lock_flags; > - > - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > - 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; > - } > - } > - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > - > - return 0; > -} > - > /** > * 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; > struct Scsi_Host *shost = dev_to_shost(&starget->dev); > struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; > > @@ -4809,12 +4889,6 @@ static void ipr_target_destroy(struct sc > clear_bit(starget->id, ioa_cfg->target_ids); > } > } > - > - if (sata_port) { > - starget->hostdata = NULL; > - ata_sas_port_destroy(sata_port->ap); > - kfree(sata_port); > - } > } > > /** > @@ -4857,8 +4931,6 @@ static void ipr_slave_destroy(struct scs > spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); > res = (struct ipr_resource_entry *) sdev->hostdata; > if (res) { > - if (res->sata_port) > - res->sata_port->ap->link.device[0].class = ATA_DEV_NONE; > sdev->hostdata = NULL; > res->sdev = NULL; > res->sata_port = NULL; > @@ -4918,37 +4990,6 @@ static int ipr_slave_configure(struct sc > } > > /** > - * 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 == 0) > - rc = ata_sas_sync_probe(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 > * > @@ -4980,10 +5021,6 @@ static int ipr_slave_alloc(struct scsi_d > if (!ipr_is_naca_model(res)) > res->needs_sync_complete = 1; > rc = 0; > - if (ipr_is_gata(res)) { > - spin_unlock_irqrestore(ioa_cfg->host->host_lock, > lock_flags); > - return ipr_ata_slave_alloc(sdev); > - } > } > > spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); > @@ -5201,6 +5238,17 @@ static int ipr_sata_reset(struct ata_lin > return rc; > } > > +static void ipr_ata_sched_eh(struct ata_port *ap) > +{ > + struct ipr_sata_port *sata_port = ap->private_data; > + struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; > + > + if (ap->pflags & ATA_PFLAG_INITIALIZING) > + return; > + > + queue_work(ioa_cfg->sata_work_q, &sata_port->work); > +} > + > /** > * ipr_eh_dev_reset - Reset the device > * @scsi_cmd: scsi command struct > @@ -5217,7 +5265,6 @@ static int __ipr_eh_dev_reset(struct scs > struct ipr_cmnd *ipr_cmd; > struct ipr_ioa_cfg *ioa_cfg; > struct ipr_resource_entry *res; > - struct ata_port *ap; > int rc = 0; > struct ipr_hrr_queue *hrrq; > > @@ -5233,7 +5280,7 @@ static int __ipr_eh_dev_reset(struct scs > * mid-layer to call ipr_eh_host_reset, which will then go to sleep and > wait for the > * reset to complete > */ > - if (ioa_cfg->in_reset_reload) > + if (ioa_cfg->in_reset_reload || ipr_is_gata(res)) > return FAILED; > if (ioa_cfg->hrrq[IPR_INIT_HRRQ].ioa_is_dead) > return FAILED; > @@ -5244,13 +5291,6 @@ static int __ipr_eh_dev_reset(struct scs > if (ipr_cmd->ioarcb.res_handle == res->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; > - } > } > } > spin_unlock(&hrrq->_lock); > @@ -5258,26 +5298,7 @@ static int __ipr_eh_dev_reset(struct scs > res->resetting_device = 1; > scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); > > - 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); > - > - for_each_hrrq(hrrq, ioa_cfg) { > - spin_lock(&hrrq->_lock); > - list_for_each_entry(ipr_cmd, > - &hrrq->hrrq_pending_q, queue) { > - if (ipr_cmd->ioarcb.res_handle == > - res->res_handle) { > - rc = -EIO; > - break; > - } > - } > - spin_unlock(&hrrq->_lock); > - } > - } else > - rc = ipr_device_reset(ioa_cfg, res); > + rc = ipr_device_reset(ioa_cfg, res); > res->resetting_device = 0; > res->reset_occurred = 1; > > @@ -5487,6 +5508,69 @@ static int ipr_scan_finished(struct Scsi > return rc; > } > > +static void ipr_eh_strategy(struct Scsi_Host *shost) > +{ > + unsigned long flags; > + LIST_HEAD(eh_work_q); > + LIST_HEAD(eh_done_q); > + LIST_HEAD(eh_sata_q); > + struct scsi_cmnd *scsi_cmd, *tmp; > + struct ipr_resource_entry *res, *last_res; > + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; > + > + spin_lock_irqsave(shost->host_lock, flags); > + list_splice_init(&shost->eh_cmd_q, &eh_work_q); > + spin_unlock_irqrestore(shost->host_lock, flags); > + > + do { > + last_res = NULL; > + res = NULL; > + > + list_for_each_entry_safe(scsi_cmd, tmp, &eh_work_q, eh_entry) { > + if (!scsi_cmd->device->hostdata) > + continue; > + > + res = scsi_cmd->device->hostdata; > + > + if (!ipr_is_gata(res) || !res->sata_port) > + continue; > + > + if (last_res && last_res != res) > + continue; > + > + last_res = res; > + list_move(&scsi_cmd->eh_entry, &eh_sata_q); > + } > + > + if (!list_empty(&eh_sata_q)) { > + struct ata_port *ap = res->sata_port->ap; > + > + ata_scsi_cmd_error_handler(shost, ap, &eh_sata_q); > + > + while (!list_empty(&eh_sata_q)) > + list_del_init(eh_sata_q.next); > + } > + } while (last_res); > + > + if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q)) > + scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); > + > + spin_lock_irqsave(shost->host_lock, flags); > + if (shost->eh_deadline != -1) > + shost->last_reset = 0; > + shost->host_eh_scheduled = 0; > + > + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { > + if (ipr_is_gata(res) && res->sata_port) > + ipr_ata_sched_eh(res->sata_port->ap); > + } > + > + spin_unlock_irqrestore(shost->host_lock, flags); > + > + flush_workqueue(ioa_cfg->sata_work_q); > + scsi_eh_flush_done_q(&eh_done_q); > +} > + > /** > * ipr_eh_host_reset - Reset the host adapter > * @scsi_cmd: scsi command struct > @@ -6262,7 +6346,7 @@ static void ipr_erp_start(struct ipr_ioa > u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK; > > if (!res) { > - ipr_scsi_eh_done(ipr_cmd); > + __ipr_scsi_eh_done(ipr_cmd); > return; > } > > @@ -6568,6 +6652,10 @@ static const char *ipr_ioa_info(struct S > return buffer; > } > > +static struct scsi_transport_template driver_transport = { > + .eh_strategy_handler = ipr_eh_strategy, > +}; > + > static struct scsi_host_template driver_template = { > .module = THIS_MODULE, > .name = "IPR", > @@ -6581,7 +6669,6 @@ static struct scsi_host_template driver_ > .slave_configure = ipr_slave_configure, > .slave_destroy = ipr_slave_destroy, > .scan_finished = ipr_scan_finished, > - .target_alloc = ipr_target_alloc, > .target_destroy = ipr_target_destroy, > .change_queue_depth = ipr_change_queue_depth, > .bios_param = ipr_biosparam, > @@ -6597,46 +6684,6 @@ static struct scsi_host_template driver_ > }; > > /** > - * 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->hrrq[IPR_INIT_HRRQ].allow_cmds) > - goto out_unlock; > - > - rc = ipr_device_reset(ioa_cfg, res); > - > - if (rc) { > - ap->link.device[0].class = ATA_DEV_NONE; > - goto out_unlock; > - } > - > - ap->link.device[0].class = res->ata_class; > - if (ap->link.device[0].class == ATA_DEV_UNKNOWN) > - ap->link.device[0].class = ATA_DEV_NONE; > - > -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 > * > @@ -6650,6 +6697,7 @@ static void ipr_ata_post_internal(struct > struct ipr_cmnd *ipr_cmd; > struct ipr_hrr_queue *hrrq; > unsigned long flags; > + unsigned int found = 0; > > spin_lock_irqsave(ioa_cfg->host->host_lock, flags); > while (ioa_cfg->in_reset_reload) { > @@ -6661,13 +6709,14 @@ static void ipr_ata_post_internal(struct > for_each_hrrq(hrrq, ioa_cfg) { > spin_lock(&hrrq->_lock); > list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) { > - if (ipr_cmd->qc == qc) { > - ipr_device_reset(ioa_cfg, sata_port->res); > - break; > - } > + if (ipr_cmd->qc == qc) > + found++; > } > spin_unlock(&hrrq->_lock); > } > + > + if (found) > + ipr_device_reset(ioa_cfg, sata_port->res); > spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); > } > > @@ -6714,8 +6763,9 @@ static void ipr_sata_done(struct ipr_cmn > 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->s.ioasa.hdr.ioasc); > + unsigned long flags; > > - spin_lock(&ipr_cmd->hrrq->_lock); > + spin_lock_irqsave(ipr_cmd->hrrq->lock, flags); > if (ipr_cmd->ioa_cfg->sis64) > memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata, > sizeof(struct ipr_ioasa_gata)); > @@ -6732,7 +6782,7 @@ static void ipr_sata_done(struct ipr_cmn > else > qc->err_mask |= ac_err_mask(sata_port->ioasa.status); > list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > - spin_unlock(&ipr_cmd->hrrq->_lock); > + spin_unlock_irqrestore(ipr_cmd->hrrq->lock, flags); > ata_qc_complete(qc); > } > > @@ -6902,7 +6952,7 @@ static unsigned int ipr_qc_issue(struct > return AC_ERR_SYSTEM; > } > > - ipr_init_ipr_cmnd(ipr_cmd, ipr_lock_and_done); > + ipr_init_ipr_cmnd(ipr_cmd, ipr_sata_done); > ioarcb = &ipr_cmd->ioarcb; > > if (ioa_cfg->sis64) { > @@ -6992,16 +7042,22 @@ static bool ipr_qc_fill_rtf(struct ata_q > return true; > } > > +static void ipr_ata_end_eh(struct ata_port *ap) { } > + > static struct ata_port_operations ipr_sata_ops = { > - .phy_reset = ipr_ata_phy_reset, > + .prereset = ata_std_prereset, > .hardreset = ipr_sata_reset, > + .postreset = ata_std_postreset, > + .error_handler = ata_std_error_handler, > .post_internal_cmd = ipr_ata_post_internal, > .qc_prep = ata_noop_qc_prep, > .qc_defer = ipr_qc_defer, > .qc_issue = ipr_qc_issue, > .qc_fill_rtf = ipr_qc_fill_rtf, > .port_start = ata_sas_port_start, > - .port_stop = ata_sas_port_stop > + .port_stop = ata_sas_port_stop, > + .sched_eh = ata_std_sched_eh, > + .end_eh = ipr_ata_end_eh, > }; > > static struct ata_port_info sata_port_info = { > @@ -7084,6 +7140,10 @@ static int ipr_ioa_bringdown_done(struct > } > wmb(); > > + spin_unlock_irq(ioa_cfg->host->host_lock); > + ipr_send_back_failed_ops(ioa_cfg); > + spin_lock_irq(ioa_cfg->host->host_lock); > + > list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > wake_up_all(&ioa_cfg->reset_wait_q); > LEAVE; > @@ -7146,9 +7206,10 @@ static int ipr_ioa_reset_done(struct ipr > list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); > wake_up_all(&ioa_cfg->reset_wait_q); > > - spin_unlock(ioa_cfg->host->host_lock); > + spin_unlock_irq(ioa_cfg->host->host_lock); > scsi_unblock_requests(ioa_cfg->host); > - spin_lock(ioa_cfg->host->host_lock); > + ipr_send_back_failed_ops(ioa_cfg); > + spin_lock_irq(ioa_cfg->host->host_lock); > > if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].allow_cmds) > scsi_block_requests(ioa_cfg->host); > @@ -9167,6 +9228,7 @@ static void ipr_initiate_ioa_reset(struc > if (!ioa_cfg->hrrq[IPR_INIT_HRRQ].removing_ioa) { > spin_unlock_irq(ioa_cfg->host->host_lock); > scsi_unblock_requests(ioa_cfg->host); > + ipr_send_back_failed_ops(ioa_cfg); > spin_lock_irq(ioa_cfg->host->host_lock); > } > return; > @@ -9477,6 +9539,7 @@ static void ipr_free_all_resources(struc > ipr_free_irqs(ioa_cfg); > if (ioa_cfg->reset_work_q) > destroy_workqueue(ioa_cfg->reset_work_q); > + destroy_workqueue(ioa_cfg->sata_work_q); > iounmap(ioa_cfg->hdw_dma_regs); > pci_release_regions(pdev); > ipr_free_mem(ioa_cfg); > @@ -9837,6 +9900,7 @@ static void ipr_init_ioa_cfg(struct ipr_ > for (i = 0; i < ARRAY_SIZE(ioa_cfg->hrrq); i++) { > INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_free_q); > INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_pending_q); > + INIT_LIST_HEAD(&ioa_cfg->hrrq[i].hrrq_error_q); > spin_lock_init(&ioa_cfg->hrrq[i]._lock); > if (i == 0) > ioa_cfg->hrrq[i].lock = ioa_cfg->host->host_lock; > @@ -10075,6 +10139,7 @@ static int ipr_probe_ioa(struct pci_dev > > ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; > memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); > + host->transportt = &driver_transport; > ata_host_init(&ioa_cfg->ata_host, &pdev->dev, &ipr_sata_ops); > > ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); > @@ -10294,6 +10359,14 @@ static int ipr_probe_ioa(struct pci_dev > goto cleanup_nolog; > } > > + ioa_cfg->sata_work_q = alloc_ordered_workqueue("ipr_sata_%d", > + WQ_MEM_RECLAIM, > host->host_no); > + > + if (!ioa_cfg->sata_work_q) { > + dev_err(&pdev->dev, "Couldn't register SATA workqueue\n"); > + goto out_free_irq; > + } > + > 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; > @@ -10305,7 +10378,7 @@ static int ipr_probe_ioa(struct pci_dev > if (!ioa_cfg->reset_work_q) { > dev_err(&pdev->dev, "Couldn't register reset > workqueue\n"); > rc = -ENOMEM; > - goto out_free_irq; > + goto out_free_sata_work_q; > } > } else > ioa_cfg->reset = ipr_reset_start_bist; > @@ -10318,6 +10391,8 @@ static int ipr_probe_ioa(struct pci_dev > out: > return rc; > > +out_free_sata_work_q: > + destroy_workqueue(ioa_cfg->sata_work_q); > out_free_irq: > ipr_free_irqs(ioa_cfg); > cleanup_nolog: > @@ -10378,7 +10453,8 @@ static void __ipr_remove(struct pci_dev > { > unsigned long host_lock_flags = 0; > struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); > - int i; > + struct ipr_resource_entry *res; > + int i = 0; > unsigned long driver_lock_flags; > ENTER; > > @@ -10387,6 +10463,20 @@ static void __ipr_remove(struct pci_dev > 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); > + > + list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { > + if (ipr_is_gata(res) && res->sata_port) { > + res->del_from_ml = 1; > + i++; > + } > + } > + > + if (i) { > + spin_unlock_irqrestore(ioa_cfg->host->host_lock, > host_lock_flags); > + schedule_work(&ioa_cfg->work_q); > + flush_work(&ioa_cfg->work_q); > + spin_lock_irqsave(ioa_cfg->host->host_lock, > host_lock_flags); > + } > } > > for (i = 0; i < ioa_cfg->hrrq_num; i++) { > @@ -10402,6 +10492,7 @@ static void __ipr_remove(struct pci_dev > flush_work(&ioa_cfg->work_q); > if (ioa_cfg->reset_work_q) > flush_workqueue(ioa_cfg->reset_work_q); > + flush_workqueue(ioa_cfg->sata_work_q); > INIT_LIST_HEAD(&ioa_cfg->used_res_q); > spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); > > diff -puN drivers/scsi/ipr.h~ipr_libata_api_change drivers/scsi/ipr.h > --- linux-2.6.git/drivers/scsi/ipr.h~ipr_libata_api_change 2016-08-30 > 20:55:39.213008779 -0500 > +++ linux-2.6.git-bjking1/drivers/scsi/ipr.h 2016-08-30 20:55:39.223008679 > -0500 > @@ -510,6 +510,7 @@ struct ipr_hrr_queue { > > struct list_head hrrq_free_q; > struct list_head hrrq_pending_q; > + struct list_head hrrq_error_q; > spinlock_t _lock; > spinlock_t *lock; > > @@ -1288,6 +1289,7 @@ struct ipr_sata_port { > struct ipr_ioa_cfg *ioa_cfg; > struct ata_port *ap; > struct ipr_resource_entry *res; > + struct work_struct work; > struct ipr_ioasa_gata ioasa; > }; > > @@ -1569,6 +1571,7 @@ struct ipr_ioa_cfg { > > struct work_struct work_q; > struct workqueue_struct *reset_work_q; > + struct workqueue_struct *sata_work_q; > > wait_queue_head_t reset_wait_q; > wait_queue_head_t msi_wait_q; > _ > > > ------------------------------------------------------------------------------ > _______________________________________________ > Iprdd-devel mailing list > Iprdd-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/iprdd-devel > -- Gabriel Krisman Bertazi ------------------------------------------------------------------------------ _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel