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
_
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).