All of lore.kernel.org
 help / color / mirror / Atom feed
* Converting ipr to use ata_port_operations->error_handler
@ 2016-05-25 19:32 Tejun Heo
  2016-05-26 14:12 ` Brian King
  0 siblings, 1 reply; 7+ messages in thread
From: Tejun Heo @ 2016-05-25 19:32 UTC (permalink / raw)
  To: Brian King, linux-scsi, linux-ide

Hello, Brian.

So, of all the ata drivers, ipr seems to be the only driver which
doesn't implement ata_port_opeations->error_handler and thus depends
on the old error handling path. I'm wondering whether it'd be possible
to convert ipr to implement ->error_handler and drop the old path.
Would that be difficult?

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Converting ipr to use ata_port_operations->error_handler
  2016-05-25 19:32 Converting ipr to use ata_port_operations->error_handler Tejun Heo
@ 2016-05-26 14:12 ` Brian King
  2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
  0 siblings, 1 reply; 7+ messages in thread
From: Brian King @ 2016-05-26 14:12 UTC (permalink / raw)
  To: Tejun Heo, linux-scsi, linux-ide

On 05/25/2016 02:32 PM, Tejun Heo wrote:
> Hello, Brian.
> 
> So, of all the ata drivers, ipr seems to be the only driver which
> doesn't implement ata_port_opeations->error_handler and thus depends
> on the old error handling path. I'm wondering whether it'd be possible
> to convert ipr to implement ->error_handler and drop the old path.
> Would that be difficult?

Last time I looked at that there were a number of challenges in doing that,
but let me take another look and see if we can figure out a way to do that.

Thanks,

Brian


-- 
Brian King
Power Linux I/O
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC] [PATCH 0/3] Convert ipr to use ata_port_operations->error_handler
  2016-05-26 14:12 ` Brian King
@ 2016-06-10 21:33   ` Brian King
  2016-06-10 21:36     ` [RFC] [PATCH 1/3] ipr: Wait to do async scan until scsi host is initialized Brian King
                       ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Brian King @ 2016-06-10 21:33 UTC (permalink / raw)
  To: Tejun Heo, linux-scsi, linux-ide

On 05/26/2016 09:12 AM, Brian King wrote:
> On 05/25/2016 02:32 PM, Tejun Heo wrote:
>> Hello, Brian.
>>
>> So, of all the ata drivers, ipr seems to be the only driver which
>> doesn't implement ata_port_opeations->error_handler and thus depends
>> on the old error handling path. I'm wondering whether it'd be possible
>> to convert ipr to implement ->error_handler and drop the old path.
>> Would that be difficult?
> 
> Last time I looked at that there were a number of challenges in doing that,
> but let me take another look and see if we can figure out a way to do that.

Here is an initial attempt to do this conversion. Probably plenty of bugs
in it, and more testing is needed before this would be ready to apply.

-Brian


-- 
Brian King
Power Linux I/O
IBM Linux Technology Center


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC] [PATCH 1/3] ipr: Wait to do async scan until scsi host is initialized
  2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
@ 2016-06-10 21:36     ` Brian King
  2016-06-10 21:37     ` [RFC] [PATCH 2/3] scsi: Export SCSI EH commands Brian King
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Brian King @ 2016-06-10 21:36 UTC (permalink / raw)
  To: Tejun Heo, linux-scsi, linux-ide


When performing an async scan, make sure the kthread doing scanning
doesn't start before the scsi host is fully initialized.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---

 drivers/scsi/ipr.c |    9 +++++++++
 drivers/scsi/ipr.h |    1 +
 2 files changed, 10 insertions(+)

diff -puN drivers/scsi/ipr.c~ipr_async_scan_fixup drivers/scsi/ipr.c
--- linux-2.6.git/drivers/scsi/ipr.c~ipr_async_scan_fixup	2016-06-01 21:04:14.088698640 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.c	2016-06-10 15:35:56.738201739 -0500
@@ -3287,6 +3287,11 @@ static void ipr_worker_thread(struct wor
 		return;
 	}
 
+	if (!ioa_cfg->scan_enabled) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
 restart:
 	do {
 		did_work = 0;
@@ -10360,6 +10365,7 @@ static void ipr_remove(struct pci_dev *p
 static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
 	struct ipr_ioa_cfg *ioa_cfg;
+	unsigned long flags;
 	int rc, i;
 
 	rc = ipr_probe_ioa(pdev, dev_id);
@@ -10412,7 +10418,10 @@ static int ipr_probe(struct pci_dev *pde
 		}
 	}
 
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	ioa_cfg->scan_enabled = 1;
 	schedule_work(&ioa_cfg->work_q);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 	return 0;
 }
 
diff -puN drivers/scsi/ipr.h~ipr_async_scan_fixup drivers/scsi/ipr.h
--- linux-2.6.git/drivers/scsi/ipr.h~ipr_async_scan_fixup	2016-06-01 21:04:17.186678232 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.h	2016-06-10 15:35:56.739201727 -0500
@@ -1475,6 +1475,7 @@ struct ipr_ioa_cfg {
 	u8 in_ioa_bringdown:1;
 	u8 ioa_unit_checked:1;
 	u8 dump_taken:1;
+	u8 scan_enabled:1;
 	u8 scan_done:1;
 	u8 needs_hard_reset:1;
 	u8 dual_raid:1;
_


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC] [PATCH 2/3] scsi: Export SCSI EH commands
  2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
  2016-06-10 21:36     ` [RFC] [PATCH 1/3] ipr: Wait to do async scan until scsi host is initialized Brian King
@ 2016-06-10 21:37     ` Brian King
  2016-06-10 21:39     ` [RFC] [PATCH 3/3] ipr: Use libata new EH Brian King
  2016-06-13 22:15     ` [RFC] [PATCH 0/3] Convert ipr to use ata_port_operations->error_handler Tejun Heo
  3 siblings, 0 replies; 7+ messages in thread
From: Brian King @ 2016-06-10 21:37 UTC (permalink / raw)
  To: Tejun Heo, linux-scsi, linux-ide


Export the following EH commands so that ipr can be converted to
use libata's new EH.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---

 drivers/scsi/scsi_error.c |    5 +++--
 include/scsi/scsi_eh.h    |    5 +++++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff -puN drivers/scsi/scsi_error.c~scsi_eh_export_scsi_eh_abort_cmds drivers/scsi/scsi_error.c
--- linux-2.6.git/drivers/scsi/scsi_error.c~scsi_eh_export_scsi_eh_abort_cmds	2016-06-10 15:50:03.191155441 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/scsi_error.c	2016-06-10 15:50:03.201155322 -0500
@@ -1320,8 +1320,8 @@ static int scsi_eh_test_devices(struct l
  *    no sense to try and abort the command, since as far as the shost
  *    adapter is concerned, it isn't running.
  */
-static int scsi_eh_abort_cmds(struct list_head *work_q,
-			      struct list_head *done_q)
+int scsi_eh_abort_cmds(struct list_head *work_q,
+		       struct list_head *done_q)
 {
 	struct scsi_cmnd *scmd, *next;
 	LIST_HEAD(check_list);
@@ -1361,6 +1361,7 @@ static int scsi_eh_abort_cmds(struct lis
 
 	return scsi_eh_test_devices(&check_list, work_q, done_q, 0);
 }
+EXPORT_SYMBOL_GPL(scsi_eh_abort_cmds);
 
 /**
  * scsi_eh_try_stu - Send START_UNIT to device.
diff -puN include/scsi/scsi_eh.h~scsi_eh_export_scsi_eh_abort_cmds include/scsi/scsi_eh.h
--- linux-2.6.git/include/scsi/scsi_eh.h~scsi_eh_export_scsi_eh_abort_cmds	2016-06-10 15:50:03.195155394 -0500
+++ linux-2.6.git-bjking1/include/scsi/scsi_eh.h	2016-06-10 15:50:03.201155322 -0500
@@ -17,6 +17,11 @@ extern int scsi_block_when_processing_er
 extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
 					 struct scsi_sense_hdr *sshdr);
 extern int scsi_check_sense(struct scsi_cmnd *);
+extern int scsi_eh_abort_cmds(struct list_head *work_q,
+			      struct list_head *done_q);
+extern void scsi_eh_ready_devs(struct Scsi_Host *shost,
+			       struct list_head *work_q,
+			       struct list_head *done_q);
 
 static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
 {
_


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFC] [PATCH 3/3] ipr: Use libata new EH
  2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
  2016-06-10 21:36     ` [RFC] [PATCH 1/3] ipr: Wait to do async scan until scsi host is initialized Brian King
  2016-06-10 21:37     ` [RFC] [PATCH 2/3] scsi: Export SCSI EH commands Brian King
@ 2016-06-10 21:39     ` Brian King
  2016-06-13 22:15     ` [RFC] [PATCH 0/3] Convert ipr to use ata_port_operations->error_handler Tejun Heo
  3 siblings, 0 replies; 7+ messages in thread
From: Brian King @ 2016-06-10 21:39 UTC (permalink / raw)
  To: Tejun Heo, linux-scsi, linux-ide


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.

Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
---

 drivers/scsi/ipr.c |  425 ++++++++++++++++++++++++++++++-----------------------
 drivers/scsi/ipr.h |    2 
 2 files changed, 246 insertions(+), 181 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-06-10 15:51:43.864962516 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.c	2016-06-10 15:57:35.758792780 -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"
 
 /*
@@ -3244,6 +3245,18 @@ 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;
+
+	ENTER;
+	ata_scsi_port_error_handler(ioa_cfg->host, sata_port->ap);
+	LEAVE;
+}
+
 /**
  * ipr_worker_thread - Worker thread
  * @work:		ioa config struct
@@ -3259,12 +3272,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);
@@ -3301,25 +3317,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);
+			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;
@@ -4653,68 +4734,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;
 
@@ -4728,12 +4754,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);
-	}
 }
 
 /**
@@ -4776,8 +4796,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;
@@ -4837,37 +4855,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
  *
@@ -4899,10 +4886,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);
@@ -5120,6 +5103,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
@@ -5136,7 +5130,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;
 
@@ -5152,7 +5145,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;
@@ -5163,13 +5156,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);
@@ -5177,26 +5163,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;
 
@@ -5406,6 +5373,103 @@ static int ipr_scan_finished(struct Scsi
 	return rc;
 }
 
+static enum blk_eh_timer_return ipr_eh_timed_out(struct scsi_cmnd *scsi_cmd)
+{
+	enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
+	struct ipr_resource_entry *res;
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_cmnd *ipr_cmd;
+	unsigned long flags;
+	struct ipr_hrr_queue *hrrq;
+
+	ENTER;
+	ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
+	res = scsi_cmd->device->hostdata;
+
+	if (ipr_is_gata(res) && res->sata_port) {
+		for_each_hrrq(hrrq, ioa_cfg) {
+			spin_lock_irqsave(&hrrq->_lock, flags);
+			list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
+				if (ipr_cmd->scsi_cmd == scsi_cmd) {
+					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;
+					}
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&hrrq->_lock, flags);
+		}
+	}
+
+	LEAVE;
+	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
@@ -6487,6 +6551,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",
@@ -6496,11 +6564,11 @@ static struct scsi_host_template driver_
 	.eh_abort_handler = ipr_eh_abort,
 	.eh_device_reset_handler = ipr_eh_dev_reset,
 	.eh_host_reset_handler = ipr_eh_host_reset,
+	.eh_timed_out = ipr_eh_timed_out,
 	.slave_alloc = ipr_slave_alloc,
 	.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,
@@ -6516,46 +6584,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
  *
@@ -6633,8 +6661,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));
@@ -6651,7 +6680,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);
 }
 
@@ -6821,7 +6850,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) {
@@ -6911,16 +6940,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 = {
@@ -9392,6 +9427,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);
@@ -9989,6 +10025,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);
@@ -10207,6 +10244,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;
@@ -10217,7 +10262,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");
-			goto out_free_irq;
+			goto out_free_sata_work_q;
 		}
 	} else
 		ioa_cfg->reset = ipr_reset_start_bist;
@@ -10230,6 +10275,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:
@@ -10290,7 +10337,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;
 
@@ -10299,6 +10347,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++) {
@@ -10314,6 +10376,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-06-10 15:51:43.867962480 -0500
+++ linux-2.6.git-bjking1/drivers/scsi/ipr.h	2016-06-10 15:51:43.876962373 -0500
@@ -1283,6 +1283,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;
 };
 
@@ -1563,6 +1564,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;
_


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] [PATCH 0/3] Convert ipr to use ata_port_operations->error_handler
  2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
                       ` (2 preceding siblings ...)
  2016-06-10 21:39     ` [RFC] [PATCH 3/3] ipr: Use libata new EH Brian King
@ 2016-06-13 22:15     ` Tejun Heo
  3 siblings, 0 replies; 7+ messages in thread
From: Tejun Heo @ 2016-06-13 22:15 UTC (permalink / raw)
  To: Brian King; +Cc: linux-scsi, linux-ide

On Fri, Jun 10, 2016 at 04:33:09PM -0500, Brian King wrote:
> On 05/26/2016 09:12 AM, Brian King wrote:
> > On 05/25/2016 02:32 PM, Tejun Heo wrote:
> >> Hello, Brian.
> >>
> >> So, of all the ata drivers, ipr seems to be the only driver which
> >> doesn't implement ata_port_opeations->error_handler and thus depends
> >> on the old error handling path. I'm wondering whether it'd be possible
> >> to convert ipr to implement ->error_handler and drop the old path.
> >> Would that be difficult?
> > 
> > Last time I looked at that there were a number of challenges in doing that,
> > but let me take another look and see if we can figure out a way to do that.
> 
> Here is an initial attempt to do this conversion. Probably plenty of bugs
> in it, and more testing is needed before this would be ready to apply.

Thanks a lot for working on this. :)

-- 
tejun

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-06-13 22:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-25 19:32 Converting ipr to use ata_port_operations->error_handler Tejun Heo
2016-05-26 14:12 ` Brian King
2016-06-10 21:33   ` [RFC] [PATCH 0/3] Convert " Brian King
2016-06-10 21:36     ` [RFC] [PATCH 1/3] ipr: Wait to do async scan until scsi host is initialized Brian King
2016-06-10 21:37     ` [RFC] [PATCH 2/3] scsi: Export SCSI EH commands Brian King
2016-06-10 21:39     ` [RFC] [PATCH 3/3] ipr: Use libata new EH Brian King
2016-06-13 22:15     ` [RFC] [PATCH 0/3] Convert ipr to use ata_port_operations->error_handler Tejun Heo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.