[RFC 3/3] ipr: Use new libata EH API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch converts ipr to use the new libata EH API. This simplifies
a lot of the code, should make it more maintainable, and also provides
more robust error handling.

Signed-off-by: Brian King <brking@xxxxxxxxxxxxxxxxxx>
---

 linux-2.6-bjking1/drivers/scsi/ipr.c |  822 +++++++++++++++++++++++------------
 linux-2.6-bjking1/drivers/scsi/ipr.h |   15 
 2 files changed, 562 insertions(+), 275 deletions(-)

diff -puN drivers/scsi/ipr.c~ipr_sata_scsi_host2 drivers/scsi/ipr.c
--- linux-2.6/drivers/scsi/ipr.c~ipr_sata_scsi_host2	2007-10-29 13:04:12.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/ipr.c	2007-10-29 14:26:24.000000000 -0500
@@ -613,6 +613,54 @@ static int ipr_set_pcix_cmd_reg(struct i
 }
 
 /**
+ * ipr_sata_qc_complete - Schedule completion of a SATA command
+ * @ioa_cfg:	ioa config struct
+ * @done_qc:	ATA qc to complete
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_sata_qc_complete(struct ipr_ioa_cfg *ioa_cfg,
+				 struct ata_queued_cmd *done_qc)
+{
+	unsigned long flags;
+	struct ata_queued_cmd *qc;
+
+	spin_lock_irqsave(&ioa_cfg->qc_done_lock, flags);
+	if (!ioa_cfg->qc_done)
+		ioa_cfg->qc_done = done_qc;
+	else {
+		for (qc = ioa_cfg->qc_done; qc->lldd_task; qc = qc->lldd_task) {}
+		qc->lldd_task = done_qc;
+	}
+	spin_unlock_irqrestore(&ioa_cfg->qc_done_lock, flags);
+
+	tasklet_schedule(&ioa_cfg->tasklet);
+}
+
+/**
+ * ipr_sata_frozen_done - Done function for a SATA command on a frozen port
+ * @ipr_cmd:	ipr command struct
+ *
+ * Once one of our SATA ports is frozen by libata, we can no longer
+ * call ata_qc_complete for it. We change its ipr internal done function
+ * to this function to simply free up the ipr command struct.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_sata_frozen_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ata_queued_cmd *qc = ipr_cmd->qc;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(qc->ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+
+	ipr_cmd->ioa_cfg->request_limit++;
+	sata_port->active_requests--;
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->free_q);
+}
+
+/**
  * ipr_sata_eh_done - done function for aborted SATA commands
  * @ipr_cmd:	ipr command struct
  *
@@ -626,12 +674,15 @@ static void ipr_sata_eh_done(struct ipr_
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	struct ata_queued_cmd *qc = ipr_cmd->qc;
-	struct ipr_sata_port *sata_port = qc->ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(qc->ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 
 	qc->err_mask |= AC_ERR_OTHER;
 	sata_port->ioasa.status |= ATA_BUSY;
+	ioa_cfg->request_limit++;
+	sata_port->active_requests--;
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-	ata_qc_complete(qc);
+	ipr_sata_qc_complete(ioa_cfg, qc);
 }
 
 /**
@@ -652,6 +703,7 @@ static void ipr_scsi_eh_done(struct ipr_
 	scsi_cmd->result |= (DID_ERROR << 16);
 
 	scsi_dma_unmap(ipr_cmd->scsi_cmd);
+	ioa_cfg->request_limit++;
 	scsi_cmd->scsi_done(scsi_cmd);
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 }
@@ -2351,6 +2403,187 @@ static void ipr_release_dump(struct kref
 }
 
 /**
+ * ipr_show_sata_adapter_address - Show the adapter's resource address for this device
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_sata_adapter_address(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	struct ata_port *ap = ata_shost_to_port(host);
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+	ssize_t len = -ENXIO;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (sata_port && sata_port->res)
+		len = snprintf(buf, PAGE_SIZE, "%d:%d:%d:%d\n",
+			       ioa_cfg->host->host_no,
+			       sata_port->res->cfgte.res_addr.bus,
+			       sata_port->res->cfgte.res_addr.target,
+			       sata_port->res->cfgte.res_addr.lun);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+	return len;
+}
+
+static struct class_device_attribute ipr_sata_adapter_address_attr = {
+	.attr = {
+		.name = 	"adapter_address",
+		.mode =		S_IRUSR,
+	},
+	.show = ipr_show_sata_adapter_address
+};
+
+/**
+ * ipr_show_sata_adapter_handle - Show the adapter's resource handle for this SATA rphy
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_sata_adapter_handle(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	struct ata_port *ap = ata_shost_to_port(host);
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+	ssize_t len = -ENXIO;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (sata_port && sata_port->res)
+		len = snprintf(buf, PAGE_SIZE, "%08X\n", sata_port->res->cfgte.res_handle);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+	return len;
+}
+
+static struct class_device_attribute ipr_sata_adapter_handle_attr = {
+	.attr = {
+		.name = 	"adapter_handle",
+		.mode =		S_IRUSR,
+	},
+	.show = ipr_show_sata_adapter_handle
+};
+
+static struct class_device_attribute *ipr_sata_attrs[] = {
+	&ipr_sata_adapter_handle_attr,
+	&ipr_sata_adapter_address_attr,
+	NULL,
+};
+
+/**
+ * ipr_sata_info - Get information about the sata port
+ * @scsi_host:	scsi host struct
+ *
+ * Return value:
+ * 	pointer to buffer with description string
+ **/
+static const char * ipr_sata_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	struct ata_port *ap = ata_shost_to_port(host);
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+	struct ipr_resource_entry *res = sata_port->res;
+
+	sprintf(buffer, "IBM %X Storage Adapter SATA Port: %d:%d:%d:%d",
+		ioa_cfg->type, ioa_cfg->host->host_no, res->cfgte.res_addr.bus,
+		res->cfgte.res_addr.target, res->cfgte.res_addr.lun);
+
+	return buffer;
+}
+
+static struct ata_port_info sata_port_info;
+
+static struct scsi_host_template sata_driver_template = {
+	.module = THIS_MODULE,
+	.name = "IPR",
+	.info = ipr_sata_info,
+	.ioctl = ata_scsi_ioctl,
+	.queuecommand = ata_scsi_queuecmd,
+	.slave_configure = ata_scsi_slave_config,
+	.slave_destroy = ata_scsi_slave_destroy,
+	.change_queue_depth = ata_scsi_change_queue_depth,
+	.bios_param = ata_std_bios_param,
+	.can_queue = 1,
+	.this_id = -1,
+	.sg_tablesize = IPR_MAX_SGLIST,
+	.max_sectors = IPR_IOA_MAX_SECTORS,
+	.cmd_per_lun = 1,
+	.emulated = ATA_SHT_EMULATED,
+	.use_clustering = ENABLE_CLUSTERING,
+	.shost_attrs = ipr_sata_attrs,
+	.proc_name = IPR_NAME
+};
+
+/**
+ * ipr_add_sata_dev - Add a SATA device
+ * @ioa_cfg:	ioa config struct
+ * @res:		resource entry struct
+ *
+ * This function adds a SATA rphy to the device hierarchy.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_add_sata_dev(struct ipr_ioa_cfg *ioa_cfg,
+			     struct ipr_resource_entry *res)
+{
+	int rc;
+	unsigned long flags;
+	struct ata_sas_rphy *rphy;
+	struct device *dev;
+	struct ipr_sata_port *sata_port;
+
+	rphy = ata_sas_rphy_alloc(&ioa_cfg->host->shost_gendev,
+				  &ioa_cfg->pdev->dev, &sata_port_info,
+				  sizeof(*sata_port));
+
+	if (!rphy)
+		return;
+
+	sata_port = rphy_to_sata_port(rphy);
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (!ipr_is_gata(res)) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+		ata_sas_rphy_free(rphy);
+		return;
+	}
+
+	sata_port->ioa_cfg = ioa_cfg;
+	sata_port->res = res;
+	res->sata_port = sata_port;
+	res->add_to_ml = 0;
+	list_add_tail(&sata_port->queue, &ioa_cfg->sata_ports);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+
+	rc = ata_sas_rphy_add(rphy, &sata_driver_template);
+
+	if (rc) {
+		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+		dev = get_device(&sata_port->rphy.dev);
+		list_del(&sata_port->queue);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+
+		ata_sas_rphy_free(rphy);
+
+		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+		sata_port->res->sata_port = NULL;
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+		put_device(dev);
+	}
+}
+
+/**
  * ipr_worker_thread - Worker thread
  * @work:		ioa config struct
  *
@@ -2366,11 +2599,12 @@ static void ipr_worker_thread(struct wor
 	unsigned long lock_flags;
 	struct ipr_resource_entry *res;
 	struct scsi_device *sdev;
+	struct device *dev;
 	struct ipr_dump *dump;
+	struct ipr_sata_port *sata_port;
 	struct ipr_ioa_cfg *ioa_cfg =
 		container_of(work, struct ipr_ioa_cfg, work_q);
 	u8 bus, target, lun;
-	int did_work;
 
 	ENTER;
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -2394,42 +2628,64 @@ static void ipr_worker_thread(struct wor
 	}
 
 restart:
-	do {
-		did_work = 0;
-		if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) {
-			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-			return;
-		}
+	if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
 
-		list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-			if (res->del_from_ml && res->sdev) {
-				did_work = 1;
-				sdev = res->sdev;
-				if (!scsi_device_get(sdev)) {
-					list_move_tail(&res->queue, &ioa_cfg->free_res_q);
-					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;
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (res->del_from_ml && res->sdev) {
+			sdev = res->sdev;
+			if (!scsi_device_get(sdev)) {
+				list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+				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);
 			}
+			goto restart;
 		}
-	} while(did_work);
+	}
 
-	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-		if (res->add_to_ml) {
-			bus = res->cfgte.res_addr.bus;
-			target = res->cfgte.res_addr.target;
-			lun = res->cfgte.res_addr.lun;
-			res->add_to_ml = 0;
+	list_for_each_entry(sata_port, &ioa_cfg->sata_ports, queue) {
+		if (sata_port->res->del_from_ml) {
+			dev = get_device(&sata_port->rphy.dev);
+			list_del(&sata_port->queue);
 			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-			scsi_add_device(ioa_cfg->host, bus, target, lun);
+
+			ata_sas_rphy_delete(&sata_port->rphy);
+
+			spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+			sata_port->res->sata_port = NULL;
+			list_move_tail(&sata_port->res->queue, &ioa_cfg->free_res_q);
+			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+			put_device(dev);
 			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) {
+			if (ipr_is_gata(res)) {
+				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+				ipr_add_sata_dev(ioa_cfg, res);
+				spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+			} else {
+				bus = res->cfgte.res_addr.bus;
+				target = res->cfgte.res_addr.target;
+				lun = res->cfgte.res_addr.lun;
+				res->add_to_ml = 0;
+				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+				scsi_add_device(ioa_cfg->host, bus, target, lun);
+				spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+			}
+
+			goto restart;
+		}
+	}
+
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	kobject_uevent(&ioa_cfg->host->shost_classdev.kobj, KOBJ_CHANGE);
 	LEAVE;
@@ -3366,17 +3622,6 @@ static int ipr_free_dump(struct ipr_ioa_
  **/
 static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
 {
-	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
-	struct ipr_resource_entry *res;
-	unsigned long lock_flags = 0;
-
-	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
-	res = (struct ipr_resource_entry *)sdev->hostdata;
-
-	if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN)
-		qdepth = IPR_MAX_CMD_PER_ATA_LUN;
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-
 	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
 	return sdev->queue_depth;
 }
@@ -3492,100 +3737,6 @@ static int ipr_biosparam(struct scsi_dev
 }
 
 /**
- * ipr_find_starget - Find target based on bus/target.
- * @starget:	scsi target struct
- *
- * Return value:
- * 	resource entry pointer if found / NULL if not found
- **/
-static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
-{
-	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
-	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
-	struct ipr_resource_entry *res;
-
-	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-		if ((res->cfgte.res_addr.bus == starget->channel) &&
-		    (res->cfgte.res_addr.target == starget->id) &&
-		    (res->cfgte.res_addr.lun == 0)) {
-			return res;
-		}
-	}
-
-	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;
-
-	if (sata_port) {
-		starget->hostdata = NULL;
-		ata_sas_port_destroy(sata_port->ap);
-		kfree(sata_port);
-	}
-}
-
-/**
  * ipr_find_sdev - Find device based on bus/target/lun.
  * @sdev:	scsi device struct
  *
@@ -3625,11 +3776,8 @@ 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)
-			ata_port_disable(res->sata_port->ap);
 		sdev->hostdata = NULL;
 		res->sdev = NULL;
-		res->sata_port = NULL;
 	}
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 }
@@ -3664,45 +3812,13 @@ static int ipr_slave_configure(struct sc
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
 			sdev->allow_restart = 1;
-		if (ipr_is_gata(res) && res->sata_port) {
-			scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
-			ata_sas_slave_configure(sdev, res->sata_port->ap);
-		} else {
-			scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
-		}
+		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
 	}
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	return 0;
 }
 
 /**
- * ipr_ata_slave_alloc - Prepare for commands to a SATA device
- * @sdev:	scsi device struct
- *
- * This function initializes an ATA port so that future commands
- * sent through queuecommand will work.
- *
- * Return value:
- * 	0 on success
- **/
-static int ipr_ata_slave_alloc(struct scsi_device *sdev)
-{
-	struct ipr_sata_port *sata_port = NULL;
-	int rc = -ENXIO;
-
-	ENTER;
-	if (sdev->sdev_target)
-		sata_port = sdev->sdev_target->hostdata;
-	if (sata_port)
-		rc = ata_sas_port_init(sata_port->ap);
-	if (rc)
-		ipr_slave_destroy(sdev);
-
-	LEAVE;
-	return rc;
-}
-
-/**
  * ipr_slave_alloc - Prepare for commands to a device.
  * @sdev:	scsi device struct
  *
@@ -3726,7 +3842,7 @@ static int ipr_slave_alloc(struct scsi_d
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 
 	res = ipr_find_sdev(sdev);
-	if (res) {
+	if (res && !ipr_is_gata(res)) {
 		res->sdev = sdev;
 		res->add_to_ml = 0;
 		res->in_erp = 0;
@@ -3734,10 +3850,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);
@@ -3845,7 +3957,8 @@ static int ipr_device_reset(struct ipr_i
 static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
 				unsigned long deadline)
 {
-	struct ipr_sata_port *sata_port = link->ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(link->ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
 	struct ipr_resource_entry *res;
 	unsigned long lock_flags = 0;
@@ -3859,9 +3972,21 @@ static int ipr_sata_reset(struct ata_lin
 		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 	}
 
+	if (!ioa_cfg->request_limit) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return -EIO;
+	}
+
 	res = sata_port->res;
 	if (res) {
+		ioa_cfg->request_limit--;
+		sata_port->active_requests++;
+
 		rc = ipr_device_reset(ioa_cfg, res);
+
+		ioa_cfg->request_limit++;
+		sata_port->active_requests--;
+
 		switch(res->cfgte.proto) {
 		case IPR_PROTO_SATA:
 		case IPR_PROTO_SAS_STP:
@@ -3898,7 +4023,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;
 
 	ENTER;
@@ -3917,37 +4041,19 @@ static int __ipr_eh_dev_reset(struct scs
 		return FAILED;
 	if (ioa_cfg->ioa_is_dead)
 		return FAILED;
+	if (ipr_is_gata(res))
+		return FAILED;
 
 	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
 		if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
 			if (ipr_cmd->scsi_cmd)
 				ipr_cmd->done = ipr_scsi_eh_done;
-			if (ipr_cmd->qc)
-				ipr_cmd->done = ipr_sata_eh_done;
-			if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
-				ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
-				ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
-			}
 		}
 	}
 
 	res->resetting_device = 1;
 	scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
-
-	if (ipr_is_gata(res) && res->sata_port) {
-		ap = res->sata_port->ap;
-		spin_unlock_irq(scsi_cmd->device->host->host_lock);
-		ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
-		spin_lock_irq(scsi_cmd->device->host->host_lock);
-
-		list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-			if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
-				rc = -EIO;
-				break;
-			}
-		}
-	} else
-		rc = ipr_device_reset(ioa_cfg, res);
+	rc = ipr_device_reset(ioa_cfg, res);
 	res->resetting_device = 0;
 
 	LEAVE;
@@ -4389,6 +4495,7 @@ static void ipr_erp_done(struct ipr_cmnd
 		res->in_erp = 0;
 	}
 	scsi_dma_unmap(ipr_cmd->scsi_cmd);
+	ioa_cfg->request_limit++;
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 	scsi_cmd->scsi_done(scsi_cmd);
 }
@@ -4767,6 +4874,7 @@ static void ipr_erp_start(struct ipr_ioa
 	}
 
 	scsi_dma_unmap(ipr_cmd->scsi_cmd);
+	ioa_cfg->request_limit++;
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 	scsi_cmd->scsi_done(scsi_cmd);
 }
@@ -4791,6 +4899,7 @@ static void ipr_scsi_done(struct ipr_cmn
 
 	if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
 		scsi_dma_unmap(ipr_cmd->scsi_cmd);
+		ioa_cfg->request_limit++;
 		list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 		scsi_cmd->scsi_done(scsi_cmd);
 	} else
@@ -4842,8 +4951,8 @@ static int ipr_queuecommand(struct scsi_
 		return 0;
 	}
 
-	if (ipr_is_gata(res) && res->sata_port)
-		return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+	if (!ioa_cfg->request_limit)
+		return SCSI_MLQUEUE_HOST_BUSY;
 
 	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
 	ioarcb = &ipr_cmd->ioarcb;
@@ -4878,6 +4987,7 @@ static int ipr_queuecommand(struct scsi_
 		rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
 
 	if (likely(rc == 0)) {
+		ioa_cfg->request_limit--;
 		mb();
 		writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
 		       ioa_cfg->regs.ioarrin_reg);
@@ -4890,26 +5000,6 @@ static int ipr_queuecommand(struct scsi_
 }
 
 /**
- * ipr_ioctl - IOCTL handler
- * @sdev:	scsi device struct
- * @cmd:	IOCTL cmd
- * @arg:	IOCTL arg
- *
- * Return value:
- * 	0 on success / other on failure
- **/
-static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
-{
-	struct ipr_resource_entry *res;
-
-	res = (struct ipr_resource_entry *)sdev->hostdata;
-	if (res && ipr_is_gata(res))
-		return ata_scsi_ioctl(sdev, cmd, arg);
-
-	return -EINVAL;
-}
-
-/**
  * ipr_info - Get information about the card/driver
  * @scsi_host:	scsi host struct
  *
@@ -4935,7 +5025,6 @@ static struct scsi_host_template driver_
 	.module = THIS_MODULE,
 	.name = "IPR",
 	.info = ipr_ioa_info,
-	.ioctl = ipr_ioctl,
 	.queuecommand = ipr_queuecommand,
 	.eh_abort_handler = ipr_eh_abort,
 	.eh_device_reset_handler = ipr_eh_dev_reset,
@@ -4943,8 +5032,6 @@ static struct scsi_host_template driver_
 	.slave_alloc = ipr_slave_alloc,
 	.slave_configure = ipr_slave_configure,
 	.slave_destroy = ipr_slave_destroy,
-	.target_alloc = ipr_target_alloc,
-	.target_destroy = ipr_target_destroy,
 	.change_queue_depth = ipr_change_queue_depth,
 	.change_queue_type = ipr_change_queue_type,
 	.bios_param = ipr_biosparam,
@@ -4960,56 +5047,118 @@ static struct scsi_host_template driver_
 };
 
 /**
- * ipr_ata_phy_reset - libata phy_reset handler
- * @ap:		ata port to reset
+ * ipr_tasklet - ipr tasklet for deferred interrupt processing
+ * @data:	ioa_config struct
+ *
+ * Call ata_qc_complete on any completed ATA commands.
  *
+ * Return value:
+ * 	none
  **/
-static void ipr_ata_phy_reset(struct ata_port *ap)
+static void ipr_tasklet(unsigned long data)
 {
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)data;
 	unsigned long flags;
-	struct ipr_sata_port *sata_port = ap->private_data;
-	struct ipr_resource_entry *res = sata_port->res;
+	struct ata_port *ap;
+	struct ata_queued_cmd *qc, *next_qc = NULL;
+
+	spin_lock_irqsave(&ioa_cfg->qc_done_lock, flags);
+	qc = ioa_cfg->qc_done;
+	ioa_cfg->qc_done = NULL;
+	spin_unlock_irqrestore(&ioa_cfg->qc_done_lock, flags);
+
+	while (qc) {
+		next_qc = qc->lldd_task;
+		ap = qc->ap;
+		spin_lock_irqsave(ap->lock, flags);
+		ata_qc_complete(qc);
+		spin_unlock_irqrestore(ap->lock, flags);
+		qc = next_qc;
+	}
+}
+
+/**
+ * ipr_sata_error_handler - libata error handler
+ * @ap:	ATA port to perform error recovery on
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_sata_error_handler(struct ata_port *ap)
+{
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
-	int rc;
+	struct ipr_cmnd *ipr_cmd;
+	unsigned long flags;
 
-	ENTER;
+	ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
+
+	/* If commands are still outstanding, reset the adapter */
 	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
-	while(ioa_cfg->in_reset_reload) {
-		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
-		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
-		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+		if (ipr_cmd->qc && ipr_cmd->qc->ap == ap) {
+			ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV);
+			break;
+		}
 	}
 
-	if (!ioa_cfg->allow_cmds)
-		goto out_unlock;
+	ioa_cfg->request_limit += sata_port->active_requests;
+	sata_port->active_requests = 0;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
 
-	rc = ipr_device_reset(ioa_cfg, res);
+/**
+ * ipr_sata_freeze - libata freeze handler
+ * @ap:	ATA port to freeze
+ *
+ * Since ipr does not have the ability to freeze a port like a
+ * SATA adapter can, we simply ensure we never call ata_qc_complete for
+ * any commands that are still outstanding to this ATA port.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_sata_freeze(struct ata_port *ap)
+{
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+	struct ipr_cmnd *ipr_cmd;
+	struct ata_queued_cmd *sqc, *dqc, *qc;
+	unsigned long flags;
 
-	if (rc) {
-		ata_port_disable(ap);
-		goto out_unlock;
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+		if (ipr_cmd->qc && ipr_cmd->qc->ap == ap)
+			ipr_cmd->done = ipr_sata_frozen_done;
 	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 
-	switch(res->cfgte.proto) {
-	case IPR_PROTO_SATA:
-	case IPR_PROTO_SAS_STP:
-		ap->link.device[0].class = ATA_DEV_ATA;
-		break;
-	case IPR_PROTO_SATA_ATAPI:
-	case IPR_PROTO_SAS_STP_ATAPI:
-		ap->link.device[0].class = ATA_DEV_ATAPI;
-		break;
-	default:
-		ap->link.device[0].class = ATA_DEV_UNKNOWN;
-		ata_port_disable(ap);
-		break;
-	};
+	spin_lock_irqsave(&ioa_cfg->qc_done_lock, flags);
+	sqc = ioa_cfg->qc_done;
+	ioa_cfg->qc_done = NULL;
+	dqc = NULL;
+	for (qc = sqc; qc; qc = qc->lldd_task) {
+		if (qc->ap != ap) {
+			if (!dqc)
+				ioa_cfg->qc_done = qc;
+			else
+				dqc->lldd_task = qc;
+			dqc = qc;
+		}
+	}
+
+	if (dqc)
+		dqc->lldd_task = NULL;
+	spin_unlock_irqrestore(&ioa_cfg->qc_done_lock, flags);
 
-out_unlock:
-	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 	LEAVE;
 }
 
+static void ipr_sata_thaw(struct ata_port *ap) { }
+
 /**
  * ipr_ata_post_internal - Cleanup after an internal command
  * @qc:	ATA queued command
@@ -5019,7 +5168,9 @@ out_unlock:
  **/
 static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
 {
-	struct ipr_sata_port *sata_port = qc->ap->private_data;
+	struct ata_port *ap = qc->ap;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
 	struct ipr_cmnd *ipr_cmd;
 	unsigned long flags;
@@ -5032,11 +5183,28 @@ static void ipr_ata_post_internal(struct
 	}
 
 	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
-		if (ipr_cmd->qc == qc) {
+		if (ipr_cmd->qc == qc && ioa_cfg->request_limit) {
+			ioa_cfg->request_limit--;
+			sata_port->active_requests++;
+
 			ipr_device_reset(ioa_cfg, sata_port->res);
+
+			ioa_cfg->request_limit++;
+			sata_port->active_requests--;
 			break;
 		}
 	}
+
+	/* If command is still outstanding, reset the adapter */
+	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+		if (ipr_cmd->qc == qc) {
+			ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV);
+			break;
+		}
+	}
+
+	ioa_cfg->request_limit += sata_port->active_requests;
+	sata_port->active_requests = 0;
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
 
@@ -5050,9 +5218,13 @@ static void ipr_ata_post_internal(struct
  **/
 static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
-	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
 	struct ipr_ioasa_gata *g = &sata_port->ioasa;
+	unsigned long flags;
 
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
 	tf->feature = g->error;
 	tf->nsect = g->nsect;
 	tf->lbal = g->lbal;
@@ -5065,6 +5237,7 @@ static void ipr_tf_read(struct ata_port 
 	tf->hob_lbam = g->hob_lbam;
 	tf->hob_lbah = g->hob_lbah;
 	tf->ctl = g->alt_status;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 }
 
 /**
@@ -5107,7 +5280,8 @@ static void ipr_sata_done(struct ipr_cmn
 {
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	struct ata_queued_cmd *qc = ipr_cmd->qc;
-	struct ipr_sata_port *sata_port = qc->ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(qc->ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	struct ipr_resource_entry *res = sata_port->res;
 	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
 
@@ -5116,15 +5290,17 @@ static void ipr_sata_done(struct ipr_cmn
 	ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
 
 	if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
-		scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
-					 res->cfgte.res_addr.target);
+		scsi_report_device_reset(qc->ap->scsi_host, qc->dev->sdev->channel,
+					 qc->dev->sdev->id);
 
 	if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
 		qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
 	else
 		qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+	ioa_cfg->request_limit++;
+	sata_port->active_requests--;
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
-	ata_qc_complete(qc);
+	ipr_sata_qc_complete(ioa_cfg, qc);
 }
 
 /**
@@ -5172,6 +5348,34 @@ static void ipr_build_ata_ioadl(struct i
 }
 
 /**
+ * ipr_sata_qc_defer - Check to see if a qc needs to be deferred
+ * @qc:	queued command
+ *
+ * Return value:
+ * 	0 if success, ATA_DEFER_PORT is qc needs to be deferred
+ **/
+static int ipr_sata_qc_defer(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+	unsigned long flags;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (unlikely(!ioa_cfg->request_limit ||
+		     (!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead))) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+		return ATA_DEFER_PORT;
+	}
+
+	ioa_cfg->request_limit--;
+	sata_port->active_requests++;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+	return 0;
+}
+
+/**
  * ipr_qc_issue - Issue a SATA qc to a device
  * @qc:	queued command
  *
@@ -5181,15 +5385,25 @@ static void ipr_build_ata_ioadl(struct i
 static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	struct ipr_resource_entry *res = sata_port->res;
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
 	struct ipr_cmnd *ipr_cmd;
 	struct ipr_ioarcb *ioarcb;
 	struct ipr_ioarcb_ata_regs *regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+		return AC_ERR_SYSTEM;
+	}
 
-	if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
+	if (qc->tag == ATA_TAG_INTERNAL && !ioa_cfg->request_limit) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 		return AC_ERR_SYSTEM;
+	}
 
 	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
 	ioarcb = &ipr_cmd->ioarcb;
@@ -5206,6 +5420,7 @@ static unsigned int ipr_qc_issue(struct 
 	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
 	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
 	ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+	qc->lldd_task = NULL;
 
 	ipr_build_ata_ioadl(ipr_cmd, qc);
 	regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
@@ -5234,12 +5449,18 @@ static unsigned int ipr_qc_issue(struct 
 
 	default:
 		WARN_ON(1);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 		return AC_ERR_INVALID;
 	}
 
+	if (qc->tag == ATA_TAG_INTERNAL) {
+		ioa_cfg->request_limit--;
+		sata_port->active_requests++;
+	}
 	mb();
 	writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
 	       ioa_cfg->regs.ioarrin_reg);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
 	return 0;
 }
 
@@ -5252,7 +5473,8 @@ static unsigned int ipr_qc_issue(struct 
  **/
 static u8 ipr_ata_check_status(struct ata_port *ap)
 {
-	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	return sata_port->ioasa.status;
 }
 
@@ -5265,7 +5487,8 @@ static u8 ipr_ata_check_status(struct at
  **/
 static u8 ipr_ata_check_altstatus(struct ata_port *ap)
 {
-	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ata_sas_rphy *rphy = dev_to_sata_rphy(ap->dev);
+	struct ipr_sata_port *sata_port = rphy_to_sata_port(rphy);
 	return sata_port->ioasa.alt_status;
 }
 
@@ -5273,13 +5496,16 @@ static struct ata_port_operations ipr_sa
 	.check_status = ipr_ata_check_status,
 	.check_altstatus = ipr_ata_check_altstatus,
 	.dev_select = ata_noop_dev_select,
-	.phy_reset = ipr_ata_phy_reset,
+	.error_handler = ipr_sata_error_handler,
+	.freeze = ipr_sata_freeze,
+	.thaw = ipr_sata_thaw,
 	.post_internal_cmd = ipr_ata_post_internal,
 	.tf_read = ipr_tf_read,
+	.qc_defer = ipr_sata_qc_defer,
 	.qc_prep = ata_noop_qc_prep,
 	.qc_issue = ipr_qc_issue,
 	.port_start = ata_sas_port_start,
-	.port_stop = ata_sas_port_stop
+	.port_stop = ata_sas_port_stop,
 };
 
 static struct ata_port_info sata_port_info = {
@@ -7357,6 +7583,7 @@ static void __devinit ipr_init_ioa_cfg(s
 	ioa_cfg->pdev = pdev;
 	ioa_cfg->log_level = ipr_log_level;
 	ioa_cfg->doorbell = IPR_DOORBELL;
+	ioa_cfg->request_limit = IPR_MAX_COMMANDS;
 	sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
 	sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
 	sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
@@ -7372,7 +7599,10 @@ static void __devinit ipr_init_ioa_cfg(s
 	INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
 	INIT_LIST_HEAD(&ioa_cfg->free_res_q);
 	INIT_LIST_HEAD(&ioa_cfg->used_res_q);
+	INIT_LIST_HEAD(&ioa_cfg->sata_ports);
 	INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread);
+	spin_lock_init(&ioa_cfg->qc_done_lock);
+	tasklet_init(&ioa_cfg->tasklet, ipr_tasklet, (unsigned long) ioa_cfg);
 	init_waitqueue_head(&ioa_cfg->reset_wait_q);
 	ioa_cfg->sdt_state = INACTIVE;
 	if (ipr_enable_cache)
@@ -7460,8 +7690,6 @@ static int __devinit ipr_probe_ioa(struc
 
 	ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
 	memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
-	ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
-		      sata_port_info.flags, &ipr_sata_ops);
 
 	ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
 
@@ -7640,6 +7868,45 @@ static void ipr_initiate_ioa_bringdown(s
 }
 
 /**
+ * ipr_remove_sata_devs - Remove all SATA devices from the adapter
+ * @ioa_cfg:		ioa config struct
+ *
+ * Description: This function will delete all previously allocated
+ * SATA rphys.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_remove_sata_devs(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_sata_port *sata_port;
+	struct device *dev;
+	unsigned long flags;
+
+	ENTER;
+restart:
+	spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+	list_for_each_entry(sata_port, &ioa_cfg->sata_ports, queue) {
+		dev = get_device(&sata_port->rphy.dev);
+		list_del(&sata_port->queue);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+
+		ata_sas_rphy_delete(&sata_port->rphy);
+
+		spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+		sata_port->res->sata_port = NULL;
+		list_move_tail(&sata_port->res->queue, &ioa_cfg->free_res_q);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+
+		if (dev)
+			put_device(dev);
+		goto restart;
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+	LEAVE;
+}
+
+/**
  * __ipr_remove - Remove a single adapter
  * @pdev:	pci device struct
  *
@@ -7655,6 +7922,15 @@ static void __ipr_remove(struct pci_dev 
 	ENTER;
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+	ioa_cfg->allow_ml_add_del = 0;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+
+	flush_scheduled_work();
+	ipr_remove_sata_devs(ioa_cfg);
+	tasklet_disable(&ioa_cfg->tasklet);
+	ipr_tasklet((unsigned long)ioa_cfg);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
 	while(ioa_cfg->in_reset_reload) {
 		spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
 		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
@@ -7662,11 +7938,10 @@ static void __ipr_remove(struct pci_dev 
 	}
 
 	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
-
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
 	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+	schedule_work(&ioa_cfg->work_q);
 	flush_scheduled_work();
-	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
 
 	spin_lock(&ipr_driver_lock);
 	list_del(&ioa_cfg->queue);
@@ -7765,6 +8040,7 @@ static int __devinit ipr_probe(struct pc
 	ioa_cfg->allow_ml_add_del = 1;
 	ioa_cfg->host->max_channel = IPR_VSET_BUS;
 	schedule_work(&ioa_cfg->work_q);
+	flush_scheduled_work();
 	return 0;
 }
 
diff -puN drivers/scsi/ipr.h~ipr_sata_scsi_host2 drivers/scsi/ipr.h
--- linux-2.6/drivers/scsi/ipr.h~ipr_sata_scsi_host2	2007-10-29 13:04:13.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/ipr.h	2007-10-29 14:00:22.000000000 -0500
@@ -951,11 +951,16 @@ struct ipr_bus_attributes {
 	u32 max_xfer_rate;
 };
 
+#define rphy_to_sata_port(d) \
+	container_of((d), struct ipr_sata_port, rphy)
+
 struct ipr_sata_port {
+	struct ata_sas_rphy rphy;
+	unsigned int active_requests;
 	struct ipr_ioa_cfg *ioa_cfg;
-	struct ata_port *ap;
 	struct ipr_resource_entry *res;
 	struct ipr_ioasa_gata ioasa;
+	struct list_head queue;
 };
 
 struct ipr_resource_entry {
@@ -1137,6 +1142,8 @@ struct ipr_ioa_cfg {
 	struct list_head free_res_q;
 	struct list_head used_res_q;
 
+	struct list_head sata_ports;
+
 	char ipr_hcam_label[8];
 #define IPR_HCAM_LABEL			"hcams"
 	struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS];
@@ -1170,6 +1177,7 @@ struct ipr_ioa_cfg {
 
 	u32 errors_logged;
 	u32 doorbell;
+	unsigned int request_limit;
 
 	struct Scsi_Host *host;
 	struct pci_dev *pdev;
@@ -1177,6 +1185,7 @@ struct ipr_ioa_cfg {
 	u8 saved_mode_page_len;
 
 	struct work_struct work_q;
+	struct tasklet_struct tasklet;
 
 	wait_queue_head_t reset_wait_q;
 
@@ -1191,7 +1200,9 @@ struct ipr_ioa_cfg {
 	struct ipr_cmnd *reset_cmd;
 	int (*reset) (struct ipr_cmnd *);
 
-	struct ata_host ata_host;
+	spinlock_t	qc_done_lock;
+	struct ata_queued_cmd *qc_done;
+
 	char ipr_cmd_label[8];
 #define IPR_CMD_LABEL		"ipr_cmnd"
 	struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
_

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux