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 _