Re: [PATCH 0/2] libata: support SATA devices on SAS HBAs

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

 



Luben Tuikov wrote:
> On 10/25/05 09:53, Brian King wrote:
>>I am still trying to get the patches tested
>>in my environment, but since there has been some discussion on the
>>list about others needing the same function I figured I would share
>>what I have with a wider audience.
> 
> 
> That's great.  Keep me posted on how it fares in your environment.
> I'll also give them a try.
> 
> I think that there will be quite a few things that the ipr driver
> and the SAS Transport Layer would set in exactly the same way,
> like say, the device id, DMA (rate), etc.  Those commonalities can be
> abstracted away later I guess.
> 
> If you have a patch introducing this patch to ipr, send it to me please.

Here is the ipr patch. Its queued up behind a bunch of other ipr patches 
I'm getting ready to push, and it won't apply without them.
I uploaded the whole patchset to sourceforge, so you can just apply the whole
set and have a working tree.

http://prdownloads.sourceforge.net/iprdd/ipr-sas-patches.tgz?download

Thanks

Brian

-- 
Brian King
eServer Storage I/O
IBM Linux Technology Center
Adds support to attach SATA devices to SAS adapters.

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

 linux-2.6-bjking1/drivers/scsi/Kconfig  |    1 
 linux-2.6-bjking1/drivers/scsi/Makefile |    2 
 linux-2.6-bjking1/drivers/scsi/ipr.c    |  477 ++++++++++++++++++++++++++++----
 linux-2.6-bjking1/drivers/scsi/ipr.h    |   85 +++++
 4 files changed, 516 insertions(+), 49 deletions(-)

diff -puN drivers/scsi/ipr.h~ipr_sata_with_libata_changes drivers/scsi/ipr.h
--- linux-2.6/drivers/scsi/ipr.h~ipr_sata_with_libata_changes	2005-10-25 09:15:49.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/ipr.h	2005-10-25 09:15:49.000000000 -0500
@@ -45,6 +45,7 @@
  *	This can be adjusted at runtime through sysfs device attributes.
  */
 #define IPR_MAX_CMD_PER_LUN				6
+#define IPR_MAX_CMD_PER_ATA_LUN			1
 
 /*
  * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
@@ -144,6 +145,7 @@
 #define	IPR_LUN_RESET					0x40
 #define	IPR_TARGET_RESET					0x20
 #define	IPR_BUS_RESET					0x10
+#define	IPR_HARDWARE_RESET				0x80
 #define IPR_ID_HOST_RR_Q				0xC4
 #define IPR_QUERY_IOA_CONFIG				0xC5
 #define IPR_CANCEL_ALL_REQUESTS			0xCE
@@ -294,7 +296,13 @@ struct ipr_std_inq_data {
 }__attribute__ ((packed));
 
 struct ipr_config_table_entry {
-	u8 service_level;
+	u8 proto;
+#define IPR_PROTO_SPI			0x00
+#define IPR_PROTO_SATA			0x02
+#define IPR_PROTO_SATA_ATAPI		0x03
+#define IPR_PROTO_SAS			0x04
+#define IPR_PROTO_SAS_STP		0x06
+#define IPR_PROTO_SAS_STP_ATAPI	0x07
 	u8 array_id;
 	u8 flags;
 #define IPR_IS_IOA_RESOURCE	0x80
@@ -306,6 +314,7 @@ struct ipr_config_table_entry {
 #define IPR_SUBTYPE_AF_DASD			0
 #define IPR_SUBTYPE_GENERIC_SCSI	1
 #define IPR_SUBTYPE_VOLUME_SET		2
+#define IPR_SUBTYPE_GENERIC_ATA	4
 
 #define IPR_QUEUEING_MODEL(res)	((((res)->cfgte.flags) & 0x70) >> 4)
 #define IPR_QUEUE_FROZEN_MODEL	0
@@ -372,6 +381,37 @@ struct ipr_cmd_pkt {
 	__be16 timeout;
 }__attribute__ ((packed, aligned(4)));
 
+struct ipr_ioarcb_ata_regs {
+	u8 flags;
+#define IPR_ATA_FLAG_PACKET_CMD			0x80
+#define IPR_ATA_FLAG_XFER_TYPE_DMA			0x40
+#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION	0x20
+	u8 reserved[3];
+
+	__be16 data;
+	u8 feature;
+	u8 nsect;
+	u8 lbal;
+	u8 lbam;
+	u8 lbah;
+	u8 device;
+	u8 command;
+	u8 reserved2[3];
+	u8 hob_feature;
+	u8 hob_nsect;
+	u8 hob_lbal;
+	u8 hob_lbam;
+	u8 hob_lbah;
+	u8 ctl;
+}__attribute__ ((packed, aligned(4)));
+
+struct ipr_ioarcb_add_data {
+	union {
+		struct ipr_ioarcb_ata_regs regs;
+		__be32 add_cmd_parms[10];
+	}u;
+}__attribute__ ((packed, aligned(4)));
+
 /* IOA Request Control Block    128 bytes  */
 struct ipr_ioarcb {
 	__be32 ioarcb_host_pci_addr;
@@ -396,7 +436,7 @@ struct ipr_ioarcb {
 	struct ipr_cmd_pkt cmd_pkt;
 
 	__be32 add_cmd_parms_len;
-	__be32 add_cmd_parms[10];
+	struct ipr_ioarcb_add_data add_data;;
 }__attribute__((packed, aligned (4)));
 
 struct ipr_ioadl_desc {
@@ -432,6 +472,21 @@ struct ipr_ioasa_gpdd {
 	__be32 ioa_data[2];
 }__attribute__((packed, aligned (4)));
 
+struct ipr_ioasa_gata {
+	u8 error;
+	u8 nsect;		/* Interrupt reason */
+	u8 lbal;
+	u8 lbam;
+	u8 lbah;
+	u8 device;
+	u8 status;
+	u8 alt_status;	/* ATA CTL */
+	u8 hob_nsect;
+	u8 hob_lbal;
+	u8 hob_lbam;
+	u8 hob_lbah;
+}__attribute__((packed, aligned (4)));
+
 struct ipr_auto_sense {
 	__be16 auto_sense_len;
 	__be16 ioa_data_len;
@@ -473,6 +528,7 @@ struct ipr_ioasa {
 		struct ipr_ioasa_vset vset;
 		struct ipr_ioasa_af_dasd dasd;
 		struct ipr_ioasa_gpdd gpdd;
+		struct ipr_ioasa_gata gata;
 	} u;
 
 	struct ipr_auto_sense auto_sense;
@@ -789,6 +845,13 @@ struct ipr_bus_attributes {
 	u32 max_xfer_rate;
 };
 
+struct ipr_sata_port {
+	struct ata_port *ap;
+	struct ipr_resource_entry *res;
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_ioasa_gata ioasa;
+};
+
 struct ipr_resource_entry {
 	struct ipr_config_table_entry cfgte;
 	u8 needs_sync_complete:1;
@@ -798,6 +861,7 @@ struct ipr_resource_entry {
 	u8 resetting_device:1;
 
 	struct scsi_device *sdev;
+	struct ipr_sata_port *sata_port;
 	struct list_head queue;
 };
 
@@ -1025,6 +1089,7 @@ struct ipr_cmnd {
 	struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
 	struct list_head queue;
 	struct scsi_cmnd *scsi_cmd;
+	struct ata_queued_cmd *qc;
 	struct completion completion;
 	struct timer_list timer;
 	void (*done) (struct ipr_cmnd *);
@@ -1302,6 +1367,22 @@ static inline int ipr_is_gscsi(struct ip
 }
 
 /**
+ * ipr_is_gata - Determine if a resource is a generic ATA resource
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if GATA / 0 if not GATA
+ **/
+static inline int ipr_is_gata(struct ipr_resource_entry *res)
+{
+	if (!ipr_is_ioa_resource(res) &&
+	    IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_ATA)
+		return 1;
+	else
+		return 0;
+}
+
+/**
  * ipr_is_naca_model - Determine if a resource is using NACA queueing model
  * @res:	resource entry struct
  *
diff -puN drivers/scsi/ipr.c~ipr_sata_with_libata_changes drivers/scsi/ipr.c
--- linux-2.6/drivers/scsi/ipr.c~ipr_sata_with_libata_changes	2005-10-25 09:15:49.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/ipr.c	2005-10-25 09:15:49.000000000 -0500
@@ -71,6 +71,8 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include "scsi_typedefs.h"
+#include <linux/libata.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
@@ -821,6 +823,7 @@ static void ipr_init_res_entry(struct ip
 	res->del_from_ml = 0;
 	res->resetting_device = 0;
 	res->sdev = NULL;
+	res->sata_port = NULL;
 }
 
 /**
@@ -3043,6 +3046,17 @@ 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;
 }
@@ -3169,6 +3183,8 @@ static void ipr_slave_destroy(struct scs
 	struct ipr_resource_entry *res;
 	struct ipr_ioa_cfg *ioa_cfg;
 	unsigned long lock_flags = 0;
+	struct ipr_sata_port *sata_port = NULL;
+	struct ata_port *ap = NULL;
 
 	ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
 
@@ -3177,8 +3193,14 @@ static void ipr_slave_destroy(struct scs
 	if (res) {
 		sdev->hostdata = NULL;
 		res->sdev = NULL;
+		sata_port = res->sata_port;
+		res->sata_port = NULL;
+		if (sata_port)
+			ap = sata_port->ap;
 	}
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	kfree(sata_port);
+	ata_sas_port_destroy(ap);
 }
 
 /**
@@ -3211,12 +3233,92 @@ static int ipr_slave_configure(struct sc
 		}
 		if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))
 			sdev->allow_restart = 1;
-		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+		if (ipr_is_gata(res)) {
+			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);
+		}
 	}
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
 	return 0;
 }
 
+static struct ata_port_info sata_port_info;
+
+/**
+ * ipr_ata_slave_alloc - Prepare for commands to a SATA device
+ * @sdev:	scsi device struct
+ *
+ * This function allocates an ATA port and initializes the SATA
+ * device 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_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+	struct ata_port *ap;
+	struct ipr_sata_port *sata_port;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags;
+	int rc = -ENXIO;
+
+	sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL);
+	if (!sata_port) {
+		ipr_slave_destroy(sdev);
+		return -ENOMEM;
+	}
+
+	ap = ata_sas_port_alloc(ioa_cfg->pdev, &sata_port_info);
+	if (!ap) {
+		kfree(sata_port);
+		ipr_slave_destroy(sdev);
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = sdev->hostdata;
+	if (res && ipr_is_gata(res)) {
+		sata_port->ap = ap;
+		sata_port->ioa_cfg = ioa_cfg;
+		sata_port->res = res;
+		ap->private_data = sata_port;
+		res->sata_port = sata_port;
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		rc = ata_sas_port_init(ap);
+	} else
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	if (rc)
+		ipr_slave_destroy(sdev);
+	return rc;
+}
+
+/**
+ * ipr_find_sdev - Find device based on bus/target/lun.
+ * @sdev:	scsi device struct
+ *
+ * Return value:
+ * 	resource entry pointer if found / NULL if not found
+ **/
+static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
+{
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if ((res->cfgte.res_addr.bus == sdev->channel) &&
+		    (res->cfgte.res_addr.target == sdev->id) &&
+		    (res->cfgte.res_addr.lun == sdev->lun))
+			return res;
+	}
+
+	return NULL;
+}
+
 /**
  * ipr_slave_alloc - Prepare for commands to a device.
  * @sdev:	scsi device struct
@@ -3240,18 +3342,18 @@ static int ipr_slave_alloc(struct scsi_d
 
 	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 
-	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
-		if ((res->cfgte.res_addr.bus == sdev->channel) &&
-		    (res->cfgte.res_addr.target == sdev->id) &&
-		    (res->cfgte.res_addr.lun == sdev->lun)) {
-			res->sdev = sdev;
-			res->add_to_ml = 0;
-			res->in_erp = 0;
-			sdev->hostdata = res;
-			if (!ipr_is_naca_model(res))
-				res->needs_sync_complete = 1;
-			rc = 0;
-			break;
+	res = ipr_find_sdev(sdev);
+	if (res) {
+		res->sdev = sdev;
+		res->add_to_ml = 0;
+		res->in_erp = 0;
+		sdev->hostdata = res;
+		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);
 		}
 	}
 
@@ -3350,6 +3452,7 @@ static int __ipr_eh_dev_reset(struct scs
 	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
 	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
 
+	/* xxx SATA - issue hard reset if soft reset fails? */
 	ipr_sdev_err(scsi_cmd->device, "Resetting device\n");
 	ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
 
@@ -3426,6 +3529,7 @@ static void ipr_abort_timeout(struct ipr
 	struct ipr_cmnd *reset_cmd;
 	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
 	struct ipr_cmd_pkt *cmd_pkt;
+	struct ipr_resource_entry *res = ipr_cmd->u.sdev->hostdata;
 	unsigned long lock_flags = 0;
 
 	ENTER;
@@ -3443,7 +3547,8 @@ static void ipr_abort_timeout(struct ipr
 	cmd_pkt = &reset_cmd->ioarcb.cmd_pkt;
 	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
 	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
-	cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET;
+	if (!res || !ipr_is_gata(res))
+		cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET;
 
 	ipr_do_req(reset_cmd, ipr_bus_reset_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
 	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -3476,9 +3581,7 @@ static int ipr_cancel_op(struct scsi_cmn
 	 * This will force the 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 || ioa_cfg->ioa_is_dead)
-		return FAILED;
-	if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+	if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead || !res)
 		return FAILED;
 
 	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
@@ -3676,6 +3779,46 @@ static irqreturn_t ipr_isr(int irq, void
 }
 
 /**
+ * ipr_build_mapped_ioadl - Build a scatter/gather list
+ * @ipr_cmd:	ipr command struct
+ * @sglist:		scatter/gather list
+ * @len:		total transfer length
+ * @dma_dir:	direction of transfer
+ *
+ **/
+static void ipr_build_mapped_ioadl(struct ipr_cmnd *ipr_cmd,
+				   struct scatterlist *sglist, int len, int dma_dir)
+{
+	int i;
+	u32 ioadl_flags = 0;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+
+	if (dma_dir == DMA_TO_DEVICE) {
+		ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+		ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+		ioarcb->write_data_transfer_length = cpu_to_be32(len);
+		ioarcb->write_ioadl_len =
+			cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+	} else if (dma_dir == DMA_FROM_DEVICE) {
+		ioadl_flags = IPR_IOADL_FLAGS_READ;
+		ioarcb->read_data_transfer_length = cpu_to_be32(len);
+		ioarcb->read_ioadl_len =
+			cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+	}
+
+	for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+		ioadl[i].flags_and_data_len =
+			cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
+		ioadl[i].address =
+			cpu_to_be32(sg_dma_address(&sglist[i]));
+	}
+
+	ioadl[i-1].flags_and_data_len |=
+		cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+}
+
+/**
  * ipr_build_ioadl - Build a scatter/gather list and map the buffer
  * @ioa_cfg:	ioa config struct
  * @ipr_cmd:	ipr command struct
@@ -3686,8 +3829,7 @@ static irqreturn_t ipr_isr(int irq, void
 static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
 			   struct ipr_cmnd *ipr_cmd)
 {
-	int i;
-	struct scatterlist *sglist;
+	int rc = 0;
 	u32 length;
 	u32 ioadl_flags = 0;
 	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
@@ -3705,34 +3847,13 @@ static int ipr_build_ioadl(struct ipr_io
 						 scsi_cmd->use_sg,
 						 scsi_cmd->sc_data_direction);
 
-		if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
-			ioadl_flags = IPR_IOADL_FLAGS_WRITE;
-			ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
-			ioarcb->write_data_transfer_length = cpu_to_be32(length);
-			ioarcb->write_ioadl_len =
-				cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
-		} else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
-			ioadl_flags = IPR_IOADL_FLAGS_READ;
-			ioarcb->read_data_transfer_length = cpu_to_be32(length);
-			ioarcb->read_ioadl_len =
-				cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
-		}
-
-		sglist = scsi_cmd->request_buffer;
-
-		for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
-			ioadl[i].flags_and_data_len =
-				cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
-			ioadl[i].address =
-				cpu_to_be32(sg_dma_address(&sglist[i]));
+		if (unlikely(ipr_cmd->dma_use_sg == 0)) {
+			dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+			return -1;
 		}
 
-		if (likely(ipr_cmd->dma_use_sg)) {
-			ioadl[i-1].flags_and_data_len |=
-				cpu_to_be32(IPR_IOADL_FLAGS_LAST);
-			return 0;
-		} else
-			dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+		ipr_build_mapped_ioadl(ipr_cmd, scsi_cmd->request_buffer,
+				       length, scsi_cmd->sc_data_direction);
 	} else {
 		if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
 			ioadl_flags = IPR_IOADL_FLAGS_WRITE;
@@ -3759,7 +3880,7 @@ static int ipr_build_ioadl(struct ipr_io
 			dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n");
 	}
 
-	return -1;
+	return rc;
 }
 
 /**
@@ -4231,6 +4352,29 @@ static void ipr_scsi_done(struct ipr_cmn
 }
 
 /**
+ * ipr_sata_done - done function for SATA commands
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer to SATA devices
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
+{
+	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;
+	u8 status;
+
+	memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata, sizeof(sata_port->ioasa));
+	status = ata_chk_status(qc->ap);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	ata_qc_complete(qc, status);
+}
+
+/**
  * ipr_save_ioafp_mode_select - Save adapters mode select data
  * @ioa_cfg:	ioa config struct
  * @scsi_cmd:	scsi command struct
@@ -4304,6 +4448,9 @@ static int ipr_queuecommand(struct scsi_
 		return 0;
 	}
 
+	if (ipr_is_gata(res))
+		return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+
 	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
 	ioarcb = &ipr_cmd->ioarcb;
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
@@ -4398,6 +4545,244 @@ static struct scsi_host_template driver_
 	.proc_name = IPR_NAME
 };
 
+static void ipr_ata_qc_prep(struct ata_queued_cmd *qc) { }
+static int ipr_ata_port_start(struct ata_port *ap) { return 0; }
+static void ipr_ata_port_stop(struct ata_port *ap) { }
+static void ipr_ata_bmdma_stop(struct ata_queued_cmd *qc) { }
+static u8 ipr_ata_bmdma_status(struct ata_port *ap) { return 0; }
+
+/**
+ * __ipr_ata_phy_reset - Issue a PHY reset to a SATA device
+ * @ap:	ata port to reset
+ *
+ **/
+static void __ipr_ata_phy_reset(struct ata_port *ap)
+{
+	struct ipr_cmnd *ipr_cmd;
+	struct ipr_cmd_pkt *cmd_pkt;
+	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ipr_cmd->ioarcb.res_handle = sata_port->res->cfgte.res_handle;
+	cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
+	cmd_pkt->cdb[2] = IPR_HARDWARE_RESET;
+	ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
+	memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata, sizeof(sata_port->ioasa));
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+}
+
+/**
+ * ipr_ata_phy_reset - libata phy_reset handler
+ * @ap:	ata port to reset
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_ata_phy_reset(struct ata_port *ap)
+{
+	unsigned long flags;
+	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+
+	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->allow_cmds) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+		return;
+	}
+
+	__ipr_ata_phy_reset(ap);
+
+	if (sata_port->res) {
+		switch(sata_port->res->cfgte.proto) {
+		case IPR_PROTO_SATA:
+		case IPR_PROTO_SAS_STP:
+			if (ata_chk_status(ap) == 0)
+				ap->ops->port_disable(ap);
+			else
+				ap->device[0].class = ATA_DEV_ATA;
+			break;
+		case IPR_PROTO_SATA_ATAPI:
+		case IPR_PROTO_SAS_STP_ATAPI:
+			ap->device[0].class = ATA_DEV_ATAPI;
+			break;
+		default:
+			ap->ops->port_disable(ap);
+			break;
+		};
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
+
+/**
+ * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure
+ * @regs:	destination
+ * @tf:	source ATA taskfile
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs,
+			     struct ata_taskfile *tf)
+{
+	regs->feature = tf->feature;
+	regs->nsect = tf->nsect;
+	regs->lbal = tf->lbal;
+	regs->lbam = tf->lbam;
+	regs->lbah = tf->lbah;
+	regs->device = tf->device;
+	regs->command = tf->command;
+	regs->hob_feature = tf->hob_feature;
+	regs->hob_nsect = tf->hob_nsect;
+	regs->hob_lbal = tf->hob_lbal;
+	regs->hob_lbam = tf->hob_lbam;
+	regs->hob_lbah = tf->hob_lbah;
+	regs->ctl = tf->ctl;
+}
+
+/**
+ * ipr_qc_issue - Issue a SATA qc to a device
+ * @qc:	queued command
+ *
+ * Return value:
+ * 	0 if success
+ **/
+static 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 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;
+
+	if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead || !res))
+		return -EIO;
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ioarcb = &ipr_cmd->ioarcb;
+	regs = &ioarcb->add_data.u.regs;
+
+	memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
+	ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
+
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+	ipr_cmd->qc = qc;
+	ipr_cmd->done = ipr_sata_done;
+	ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+	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->n_elem;
+
+	ipr_build_mapped_ioadl(ipr_cmd, qc->sg, qc->nbytes, qc->dma_dir);
+	ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+	regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
+	ipr_copy_sata_tf(regs, &qc->tf);
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_NODATA:
+	case ATA_PROT_PIO:
+		break;
+
+	case ATA_PROT_DMA:
+		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+		break;
+
+	case ATA_PROT_ATAPI:
+	case ATA_PROT_ATAPI_NODATA:
+		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+		break;
+
+	case ATA_PROT_ATAPI_DMA:
+		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+		break;
+
+	default:
+		WARN_ON(1);
+		return -1;
+	}
+
+	mb();
+	writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
+	       ioa_cfg->regs.ioarrin_reg);
+	return 0;
+}
+
+/**
+ * ipr_ata_check_status - Return last ATA status
+ * @ap:	ATA port
+ *
+ * Return value:
+ * 	ATA status
+ **/
+static u8 ipr_ata_check_status(struct ata_port *ap)
+{
+	struct ipr_sata_port *sata_port = ap->private_data;
+	return sata_port->ioasa.status;
+}
+
+/**
+ * ipr_ata_check_altstatus - Return last ATA altstatus
+ * @ap:	ATA port
+ *
+ * Return value:
+ * 	Alt ATA status
+ **/
+static u8 ipr_ata_check_altstatus(struct ata_port *ap)
+{
+	struct ipr_sata_port *sata_port = ap->private_data;
+	return sata_port->ioasa.alt_status;
+}
+
+/**
+ * ipr_ata_check_err - Return last error status
+ * @ap:	ATA port
+ *
+ * Return value:
+ * 	ATA error status
+ **/
+static u8 ipr_ata_check_err(struct ata_port *ap)
+{
+	struct ipr_sata_port *sata_port = ap->private_data;
+	return sata_port->ioasa.error;
+}
+
+static struct ata_port_operations ipr_sata_ops = {
+	.port_disable = ata_port_disable,
+	.check_status = ipr_ata_check_status,
+	.check_altstatus = ipr_ata_check_altstatus,
+	.check_err = ipr_ata_check_err,
+	.dev_select = ata_noop_dev_select,
+	.phy_reset = ipr_ata_phy_reset,
+	.qc_prep = ipr_ata_qc_prep,
+	.qc_issue = ipr_qc_issue,
+	.port_start = ipr_ata_port_start,
+	.port_stop = ipr_ata_port_stop,
+	.bmdma_stop = ipr_ata_bmdma_stop,
+	.bmdma_status = ipr_ata_bmdma_status,
+};
+
+static struct ata_port_info sata_port_info = {
+	.sht		= &driver_template,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+	ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, /* xxx */
+	.pio_mask	= 0x10, /* pio4 */
+	.mwdma_mask = 0x07,
+	.udma_mask	= 0x7f, /* udma0-6 */
+	.port_ops	= &ipr_sata_ops
+};
+
 #ifdef CONFIG_PPC_PSERIES
 static const u16 ipr_blocked_processors[] = {
 	PV_NORTHSTAR,
diff -puN drivers/scsi/Kconfig~ipr_sata_with_libata_changes drivers/scsi/Kconfig
--- linux-2.6/drivers/scsi/Kconfig~ipr_sata_with_libata_changes	2005-10-25 09:15:49.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/Kconfig	2005-10-25 09:15:49.000000000 -0500
@@ -1071,6 +1071,7 @@ config SCSI_IPR
 	tristate "IBM Power Linux RAID adapter support"
 	depends on PCI && SCSI
 	select FW_LOADER
+	select SCSI_SATA
 	---help---
 	  This driver supports the IBM Power Linux family RAID adapters.
 	  This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
diff -puN drivers/scsi/Makefile~ipr_sata_with_libata_changes drivers/scsi/Makefile
--- linux-2.6/drivers/scsi/Makefile~ipr_sata_with_libata_changes	2005-10-25 09:15:49.000000000 -0500
+++ linux-2.6-bjking1/drivers/scsi/Makefile	2005-10-25 09:15:49.000000000 -0500
@@ -122,7 +122,7 @@ obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
-obj-$(CONFIG_SCSI_IPR)		+= ipr.o
+obj-$(CONFIG_SCSI_IPR)		+= libata.o ipr.o
 obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_SATA_AHCI)	+= libata.o ahci.o
 obj-$(CONFIG_SCSI_SATA_SVW)	+= libata.o sata_svw.o
_

[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