All of lore.kernel.org
 help / color / mirror / Atom feed
From: Brian King <brking@us.ibm.com>
To: Luben Tuikov <luben_tuikov@adaptec.com>
Cc: Jeff Garzik <jgarzik@pobox.com>,
	Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>,
	linux-ide@vger.kernel.org, linux-scsi@vger.kernel.org
Subject: Re: [PATCH 0/2] libata: support SATA devices on SAS HBAs
Date: Tue, 25 Oct 2005 09:27:46 -0500	[thread overview]
Message-ID: <435E40E2.3010600@us.ibm.com> (raw)
In-Reply-To: <435E3C5C.70007@adaptec.com>

[-- Attachment #1: Type: text/plain, Size: 1096 bytes --]

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

[-- Attachment #2: ipr_sata_with_libata_changes.patch --]
[-- Type: text/plain, Size: 24448 bytes --]


Adds support to attach SATA devices to SAS adapters.

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

 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
_

  reply	other threads:[~2005-10-25 14:27 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-03 21:56 [RFC 0/2] libata: support SATA devices on SAS HBAs Brian King
2005-10-03 21:58 ` [RFC 1/2] libata: configurable host_set lock Brian King
2005-10-03 21:58 ` [RFC 2/2] libata: support SATA devices on SAS HBAs Brian King
2005-10-04  9:56 ` [RFC 0/2] " Jeff Garzik
2005-10-04 10:22   ` Bartlomiej Zolnierkiewicz
2005-10-04 20:56     ` Bartlomiej Zolnierkiewicz
2005-10-05 20:59       ` Jeff Garzik
2005-10-24 22:17         ` [PATCH " Brian King
2005-10-24 22:19           ` [PATCH 1/2] libata: Remove dependence on host_set->dev for SAS Brian King
2005-10-25 17:53             ` Jeff Garzik
2005-10-25 19:30               ` Brian King
2005-10-25 19:43                 ` Jeff Garzik
2005-10-25 22:48                   ` Luben Tuikov
2005-10-27 16:05                     ` Brian King
2005-10-27 20:15                       ` Luben Tuikov
2005-11-24  0:53                       ` Douglas Gilbert
2005-11-24  1:07                         ` Jeff Garzik
2005-11-24  8:12                           ` Bartlomiej Zolnierkiewicz
2005-12-02  2:05                             ` Jeff Garzik
2005-12-02  8:07                               ` Bartlomiej Zolnierkiewicz
2005-12-02 10:28                                 ` Douglas Gilbert
2005-12-02 10:48                                   ` Jeff Garzik
2005-11-29 22:13                         ` Brian King
2005-10-24 22:20           ` [PATCH 2/2] libata: Add support for SATA attachment to SAS adapters Brian King
2005-10-25 17:58             ` Jeff Garzik
2005-10-25 12:59           ` [PATCH 0/2] libata: support SATA devices on SAS HBAs Luben Tuikov
2005-10-25 13:39             ` Brian King
2005-10-25 13:40               ` Luben Tuikov
2005-10-25 13:53                 ` Brian King
2005-10-25 14:08                   ` Luben Tuikov
2005-10-25 14:27                     ` Brian King [this message]
2005-10-25 17:51                       ` Jeff Garzik
2005-10-25 17:57         ` [RFC " Brian King
2005-10-25 18:07           ` Jeff Garzik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=435E40E2.3010600@us.ibm.com \
    --to=brking@us.ibm.com \
    --cc=bzolnier@gmail.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=luben_tuikov@adaptec.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.