From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pat LaVarre Subject: Re: SATA ATAPI work in progress Date: 12 May 2004 17:14:14 -0600 Sender: linux-ide-owner@vger.kernel.org Message-ID: <1084403654.3196.31.camel@patibmrh9> References: <1084393233.3999.2.camel@patibmrh9> <40A28BB6.7090204@pobox.com> Mime-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 7bit Return-path: Received: from email-out1.iomega.com ([147.178.1.82]:7630 "EHLO email.iomega.com") by vger.kernel.org with ESMTP id S263169AbUELXOj (ORCPT ); Wed, 12 May 2004 19:14:39 -0400 In-Reply-To: <40A28BB6.7090204@pobox.com> List-Id: linux-ide@vger.kernel.org To: jgarzik@pobox.com Cc: linux-ide@vger.kernel.org Jeff G: > decent first step ... > Good guess ... > .. > [1] not sure you should bother ... > [2] don't use ifdef, test ATA_QCFLAG_DMA ... > [3] for DMA, ... zero > [4] for PIO, ... 8K (one SATA FIS) ... > [5] eliminate the dev->class test ... > [6] modify ata_get_xlat_func > to return atapi_xlat when dev->class == ATAPI Changes complete as requested, I hope, in the new patch inline. > > - VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap)); > > ... > > - atapi_start(qc); > > Note that by deleting this, there is no > longer anything to start the ATAPI transfer > really. Aye, the dmesg tell me I'm timing out with command incomplete. > You must the latter half of the above code > [the part you are deleting] either to > ata_qc_issue_prot() or your new atapi_xlat(). The dmesg tell me my guess below of how to do this actually ended up writing the x1F7 Command = xA0 Packet twice, whoops. Please choose for me from: 1) Keep only the atapi_start/ ata_tf_to_host_nolock/ ata_exec_command_pio. 2) Keep only the worker_thread/ atapi_packet_task/ ata_bmdma_start_pio/ ata_exec_command_pio. 3) Try something else entirely. > drivers/ide and Hale Landis's ATADRVR > (http://www.ata-atapi.com/) for comparing IO > write-for-write, to make sure I have the steps > and the state machine correct. And of course > the state machine docs itself, in ATA/ATAPI7. Yes. Myself, I have experience making Dos talk UDMA, a PATA bus analyser on my desk, and intermittent access to a SATA bus analyser. > you need to make sure your ATAPI device > supports ultra DMA, Please tell me if you want more evidence. The paper that accompanied my (Silicon Image 3611CT80 1.5) SATA/ PATA bridge tells me it talks UDMA "66, 100, 133 and 150" Mb/s though not UDMA 33/ MWDMA/ SWMA. I remember the paper that accompanied my PATA device tells me it talks at least UDMA 4, maybe actually UDMA 5. I know I have myself seen this device sustain about 1.5 GB/min = 25 MB/s. I could reboot to quote its op xEC Identify "word"s any time we like. > as you don't want > to bother with PIO or [SM]WDMA right now. I'm happy starting with SATA PIO, if you like that better. I do eventually want to talk SATA UDMA because I hope to end by achieving burst rates more like the 133 MB/s of UDMA, well above the 16.7 MB/s limit of PATA PIO 4. For ATAPI myself I recommend DMA only for well-known block ops, in order to get the exact byte counting of PIO otherwise. > > modprobe -r ata-piix > > modprobe ata-piix modprobe's still mostly work, but depending on my patch, I see that `modprobe ata-piix` may appear to halt my kernel with the HDD activity light lit after the dmesg: ata_bus_reset: ENTER, host 2, port 1 ata_bus_softreset: ata2: bus reset via SRST Pat LaVarre diff -Nurp linux-2.6.6-bk1/drivers/scsi/libata-core.c linux-2.6.6-bk1-pel/drivers/scsi/libata-core.c --- linux-2.6.6-bk1/drivers/scsi/libata-core.c 2004-05-12 09:57:09.000000000 -0600 +++ linux-2.6.6-bk1-pel/drivers/scsi/libata-core.c 2004-05-12 16:32:20.000000000 -0600 @@ -245,6 +245,9 @@ void ata_tf_load_mmio(struct ata_port *a void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); +if (tf->command == 0xA0) { + dump_stack(); +} outb(tf->command, ap->ioaddr.command_addr); ata_pause(ap); @@ -2438,6 +2441,7 @@ static int ata_qc_issue_prot(struct ata_ ata_dev_select(ap, qc->dev->devno, 1, 0); + DPRINTK("qc->tf.protocol = %d\n", qc->tf.protocol); switch (qc->tf.protocol) { case ATA_PROT_NODATA: ata_tf_to_host_nolock(ap, &qc->tf); @@ -2456,6 +2460,12 @@ static int ata_qc_issue_prot(struct ata_ queue_work(ata_wq, &ap->pio_task); break; + case ATA_PROT_ATAPI_DMA: + atapi_start(qc); + break; + + case ATA_PROT_ATAPI: + DPRINTK("Assertion fail: qc->tf.protocol != ATA_PROT_ATAPI\n"); default: WARN_ON(1); return -1; @@ -2812,6 +2822,9 @@ static void atapi_packet_task(void *_dat /* if we are DMA'ing, irq handler takes over from here */ if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) { /* FIXME: start DMA here */ + DPRINTK("before bmdma_start\n"); + ap->ops->bmdma_start(qc); + DPRINTK("after bmdma_start\n"); } else { ap->pio_task_state = PIO_ST; queue_work(ata_wq, &ap->pio_task); diff -Nurp linux-2.6.6-bk1/drivers/scsi/libata-scsi.c linux-2.6.6-bk1-pel/drivers/scsi/libata-scsi.c --- linux-2.6.6-bk1/drivers/scsi/libata-scsi.c 2004-05-12 09:57:09.000000000 -0600 +++ linux-2.6.6-bk1-pel/drivers/scsi/libata-scsi.c 2004-05-12 15:51:10.000000000 -0600 @@ -215,6 +215,45 @@ int ata_scsi_error(struct Scsi_Host *hos DPRINTK("EXIT\n"); return 0; +} + +/** + * atapi_xlat - Pass SCSI r/w command thru to ATAPI + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Trust caller already cleared *qc->tf (often via ata_tf_init), + * deciding tf->device & (0x10 ATA_DEV1 | 0x07 SFF 8070i LUN), etc. + * + * Choose ATAPI PIO BCL from: + * + * 0x2000 = 8 Ki = one SATA FIS + * 0xFFFE = largest specified in oldest public docs + * 0xFFFF = first massively distributed (Win 95B) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + int bcl = (8 * 0x400); /* PIO "byte count limit" */ + struct ata_taskfile *tf = &qc->tf; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = qc->dev->xfer_protocol; + tf->command = ATA_CMD_PACKET; /* often 0xA0 */ + if (qc->flags & ATA_QCFLAG_DMA) { + DPRINTK("DMA ATAPI 0x%lX %d\n", qc->flags, qc->tf.protocol); + qc->tf.protocol = ATA_PROT_ATAPI_DMA; + tf->feature = ATAPI_PKT_DMA; /* often x01 */ + } else { + DPRINTK("PIO ATAPI 0x%lX %d\n", qc->flags, qc->tf.protocol); + qc->tf.protocol = ATA_PROT_ATAPI; + tf->lbam = bcl >> 8; + tf->lbah = bcl; + } + qc->flags |= ATA_QCFLAG_ATAPI; + return 0; } /** @@ -885,78 +924,6 @@ void ata_scsi_badcmd(struct scsi_cmnd *c } /** - * atapi_scsi_queuecmd - Send CDB to ATAPI device - * @ap: Port to which ATAPI device is attached. - * @dev: Target device for CDB. - * @cmd: SCSI command being sent to device. - * @done: SCSI command completion function. - * - * Sends CDB to ATAPI device. If the Linux SCSI layer sends a - * non-data command, then this function handles the command - * directly, via polling. Otherwise, the bmdma engine is started. - * - * LOCKING: - * spin_lock_irqsave(host_set lock) - */ - -static void atapi_scsi_queuecmd(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct ata_queued_cmd *qc; - u8 *scsicmd = cmd->cmnd; - - VPRINTK("ENTER, drv_stat = 0x%x\n", ata_chk_status(ap)); - - if (cmd->sc_data_direction == SCSI_DATA_UNKNOWN) { - DPRINTK("unknown data, scsicmd 0x%x\n", scsicmd[0]); - ata_bad_cdb(cmd, done); - return; - } - - switch(scsicmd[0]) { - case READ_6: - case WRITE_6: - case MODE_SELECT: - case MODE_SENSE: - DPRINTK("read6/write6/modesel/modesense trap\n"); - ata_bad_scsiop(cmd, done); - return; - - default: - /* do nothing */ - break; - } - - qc = ata_scsi_qc_new(ap, dev, cmd, done); - if (!qc) { - printk(KERN_ERR "ata%u: command queue empty\n", ap->id); - return; - } - - qc->flags |= ATA_QCFLAG_ATAPI; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - if (cmd->sc_data_direction == SCSI_DATA_WRITE) { - qc->tf.flags |= ATA_TFLAG_WRITE; - DPRINTK("direction: write\n"); - } - - qc->tf.command = ATA_CMD_PACKET; - - if (cmd->sc_data_direction == SCSI_DATA_NONE) { - qc->tf.protocol = ATA_PROT_ATAPI; - qc->flags |= ATA_QCFLAG_POLL; - qc->tf.ctl |= ATA_NIEN; /* disable interrupts */ - } else { - qc->tf.protocol = ATA_PROT_ATAPI_DMA; - qc->flags |= ATA_QCFLAG_SG; /* data is present; dma-map it */ - qc->tf.feature |= ATAPI_PKT_DMA; - } - - atapi_start(qc); -} - -/** * ata_scsi_find_dev - lookup ata_device from scsi_cmnd * @ap: ATA port to which the device is attached * @cmd: SCSI command to be sent to the device @@ -1010,8 +977,12 @@ ata_scsi_find_dev(struct ata_port *ap, s * Pointer to translation function if possible, %NULL if not. */ -static inline ata_xlat_func_t ata_get_xlat_func(u8 cmd) +static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) { + if (dev->class == ATA_DEV_ATAPI) { /* (thus != ATA_DEV_ATAPI_UNSUP) */ + return atapi_xlat; + } + switch (cmd) { case READ_6: case READ_10: @@ -1072,6 +1043,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd * { struct ata_port *ap; struct ata_device *dev; + ata_xlat_func_t xlat_func; ap = (struct ata_port *) &cmd->device->host->hostdata[0]; @@ -1084,15 +1056,11 @@ int ata_scsi_queuecmd(struct scsi_cmnd * goto out_unlock; } - if (dev->class == ATA_DEV_ATA) { - ata_xlat_func_t xlat_func = ata_get_xlat_func(cmd->cmnd[0]); - - if (xlat_func) - ata_scsi_translate(ap, dev, cmd, done, xlat_func); - else - ata_scsi_simulate(ap, dev, cmd, done); - } else - atapi_scsi_queuecmd(ap, dev, cmd, done); + xlat_func = ata_get_xlat_func(dev, cmd->cmnd[0]); + if (xlat_func) + ata_scsi_translate(ap, dev, cmd, done, xlat_func); + else + ata_scsi_simulate(ap, dev, cmd, done); out_unlock: return 0;