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

Reply via email to