[PATCH] REQUEST_SENSE support for ATAPI

It is quite different from your patch:
* uses ata_qc_issue()
* supports both DMA and PIO
* ->sense_buffer[] mangling dropped for now

Now libata works with ATAPI devices (yeah!)...
...unless PIO is used, then it fails in mysterious way.
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 8a3f059a
......@@ -39,6 +39,7 @@
#include <linux/workqueue.h>
#include <scsi/scsi.h>
#include "scsi.h"
#include "scsi_priv.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/io.h>
......@@ -58,6 +59,7 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
u8 *xfer_mode_out,
unsigned int *xfer_shift_out);
static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
static void __ata_qc_complete(struct ata_queued_cmd *qc);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
......@@ -2335,6 +2337,59 @@ static void ata_pio_task(void *_data)
}
}
static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
struct scsi_cmnd *cmd)
{
DECLARE_COMPLETION(wait);
struct ata_queued_cmd *qc;
unsigned long flags;
int using_pio = dev->flags & ATA_DFLAG_PIO;
int rc;
DPRINTK("ATAPI request sense\n");
qc = ata_qc_new_init(ap, dev);
BUG_ON(qc == NULL);
/* FIXME: is this needed? */
memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
qc->pci_dma_dir = PCI_DMA_FROMDEVICE;
memset(&qc->cdb, 0, sizeof(ap->cdb_len));
qc->cdb[0] = REQUEST_SENSE;
qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
qc->tf.command = ATA_CMD_PACKET;
if (using_pio) {
qc->tf.protocol = ATA_PROT_ATAPI;
qc->tf.lbam = (8 * 1024) & 0xff;
qc->tf.lbah = (8 * 1024) >> 8;
qc->nbytes = SCSI_SENSE_BUFFERSIZE;
} else {
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
qc->tf.feature |= ATAPI_PKT_DMA;
}
qc->waiting = &wait;
qc->complete_fn = ata_qc_complete_noop;
spin_lock_irqsave(&ap->host_set->lock, flags);
rc = ata_qc_issue(qc);
spin_unlock_irqrestore(&ap->host_set->lock, flags);
if (rc)
ata_port_disable(ap);
else
wait_for_completion(&wait);
DPRINTK("EXIT\n");
}
/**
* ata_qc_timeout - Handle timeout of queued command
* @qc: Command that timed out
......@@ -2356,10 +2411,29 @@ static void ata_pio_task(void *_data)
static void ata_qc_timeout(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ata_device *dev = qc->dev;
u8 host_stat = 0, drv_stat;
DPRINTK("ENTER\n");
/* FIXME: doesn't this conflict with timeout handling? */
if (qc->dev->class == ATA_DEV_ATAPI && qc->scsicmd) {
struct scsi_cmnd *cmd = qc->scsicmd;
if (!scsi_eh_eflags_chk(cmd, SCSI_EH_CANCEL_CMD)) {
/* finish completing original command */
__ata_qc_complete(qc);
atapi_request_sense(ap, dev, cmd);
cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
scsi_finish_command(cmd);
goto out;
}
}
/* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
......@@ -2393,7 +2467,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
ata_qc_complete(qc, drv_stat);
break;
}
out:
DPRINTK("EXIT\n");
}
......@@ -2497,6 +2571,30 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
return 0;
}
static void __ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int tag, do_clear = 0;
qc->flags = 0;
tag = qc->tag;
if (likely(ata_tag_valid(tag))) {
if (tag == ap->active_tag)
ap->active_tag = ATA_TAG_POISON;
qc->tag = ATA_TAG_POISON;
do_clear = 1;
}
if (qc->waiting) {
struct completion *waiting = qc->waiting;
qc->waiting = NULL;
complete(waiting);
}
if (likely(do_clear))
clear_bit(tag, &ap->qactive);
}
/**
* ata_qc_complete - Complete an active ATA command
* @qc: Command to complete
......@@ -2508,8 +2606,6 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
{
struct ata_port *ap = qc->ap;
unsigned int tag, do_clear = 0;
int rc;
assert(qc != NULL); /* ata_qc_from_tag _might_ return NULL */
......@@ -2527,23 +2623,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
if (rc != 0)
return;
qc->flags = 0;
tag = qc->tag;
if (likely(ata_tag_valid(tag))) {
if (tag == ap->active_tag)
ap->active_tag = ATA_TAG_POISON;
qc->tag = ATA_TAG_POISON;
do_clear = 1;
}
if (qc->waiting) {
struct completion *waiting = qc->waiting;
qc->waiting = NULL;
complete(waiting);
}
if (likely(do_clear))
clear_bit(tag, &ap->qactive);
__ata_qc_complete(qc);
VPRINTK("EXIT\n");
}
......
......@@ -1248,9 +1248,15 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
{
struct scsi_cmnd *cmd = qc->scsicmd;
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
DPRINTK("request check condition\n");
cmd->result = SAM_STAT_CHECK_CONDITION;
else {
qc->scsidone(cmd);
return 1;
} else {
u8 *scsicmd = cmd->cmnd;
if (scsicmd[0] == INQUIRY) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment