Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 110264
b: refs/heads/master
c: 11fc33d
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Sep 29, 2008
1 parent 80fe0c5 commit 8bb559e
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d09addf65cb5b3b19a536aa3329efeedbc6bb56c
refs/heads/master: 11fc33da8d8413d6bfa5143f454dfcb998c27617
94 changes: 94 additions & 0 deletions trunk/drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ enum {
*/
ATA_EH_PRERESET_TIMEOUT = 10000,
ATA_EH_FASTDRAIN_INTERVAL = 3000,

ATA_EH_UA_TRIES = 5,
};

/* The following table determines how we sequence resets. Each entry
Expand Down Expand Up @@ -1356,6 +1358,37 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
return 0;
}

/**
* atapi_eh_tur - perform ATAPI TEST_UNIT_READY
* @dev: target ATAPI device
* @r_sense_key: out parameter for sense_key
*
* Perform ATAPI TEST_UNIT_READY.
*
* LOCKING:
* EH context (may sleep).
*
* RETURNS:
* 0 on success, AC_ERR_* mask on failure.
*/
static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
struct ata_taskfile tf;
unsigned int err_mask;

ata_tf_init(dev, &tf);

tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
tf.protocol = ATAPI_PROT_NODATA;

err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
if (err_mask == AC_ERR_DEV)
*r_sense_key = tf.feature >> 4;
return err_mask;
}

/**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to
Expand Down Expand Up @@ -2774,6 +2807,53 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
return rc;
}

/**
* atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
* @dev: ATAPI device to clear UA for
*
* Resets and other operations can make an ATAPI device raise
* UNIT ATTENTION which causes the next operation to fail. This
* function clears UA.
*
* LOCKING:
* EH context (may sleep).
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int atapi_eh_clear_ua(struct ata_device *dev)
{
int i;

for (i = 0; i < ATA_EH_UA_TRIES; i++) {
u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
u8 sense_key = 0;
unsigned int err_mask;

err_mask = atapi_eh_tur(dev, &sense_key);
if (err_mask != 0 && err_mask != AC_ERR_DEV) {
ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
"failed (err_mask=0x%x)\n", err_mask);
return -EIO;
}

if (!err_mask || sense_key != UNIT_ATTENTION)
return 0;

err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
if (err_mask) {
ata_dev_printk(dev, KERN_WARNING, "failed to clear "
"UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
return -EIO;
}
}

ata_dev_printk(dev, KERN_WARNING,
"UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);

return 0;
}

static int ata_link_nr_enabled(struct ata_link *link)
{
struct ata_device *dev;
Expand Down Expand Up @@ -3066,6 +3146,20 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ehc->i.flags &= ~ATA_EHI_SETMODE;
}

/* If reset has been issued, clear UA to avoid
* disrupting the current users of the device.
*/
if (ehc->i.flags & ATA_EHI_DID_RESET) {
ata_link_for_each_dev(dev, link) {
if (dev->class != ATA_DEV_ATAPI)
continue;
rc = atapi_eh_clear_ua(dev);
if (rc)
goto dev_fail;
}
}

/* configure link power saving */
if (ehc->i.action & ATA_EH_LPM)
ata_link_for_each_dev(dev, link)
ata_dev_enable_pm(dev, ap->pm_policy);
Expand Down

0 comments on commit 8bb559e

Please sign in to comment.