PERFORCE change 164397 for review
Alexander Motin
mav at FreeBSD.org
Mon Jun 15 06:26:27 UTC 2009
http://perforce.freebsd.org/chv.cgi?CH=164397
Change 164397 by mav at mav_mavbook on 2009/06/15 06:25:36
Use READ LOG EXT command to reveal NCQ commands errors.
Affected files ...
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#31 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#15 edit
Differences ...
==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#31 (text+ko) ====
@@ -52,6 +52,7 @@
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
+#include <cam/cam_xpt_periph.h>
#include <cam/cam_debug.h>
/* local prototypes */
@@ -85,9 +86,14 @@
static int ahci_sata_connect(struct ahci_channel *ch);
static int ahci_sata_phy_reset(device_t dev, int quick);
+static void ahci_issue_read_log(device_t dev);
+static void ahci_process_read_log(device_t dev, union ccb *ccb);
+
static void ahciaction(struct cam_sim *sim, union ccb *ccb);
static void ahcipoll(struct cam_sim *sim);
+MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driver data buffers");
+
/*
* AHCI v1.x compliant SATA chipset support functions
*/
@@ -836,7 +842,7 @@
struct ahci_channel *ch = device_get_softc(dev);
uint32_t istatus, cstatus, sstatus, ok, err;
enum ahci_err_type et;
- int i, ccs;
+ int i, ccs, ncq_err = 0;
mtx_lock(&ch->mtx);
/* Read and clear interrupt statuses. */
@@ -873,7 +879,8 @@
}
/* On error, complete the rest of commands with error statuses. */
if (err) {
- xpt_freeze_simq(ch->sim, ch->numrslots);
+ if (!ch->readlog)
+ xpt_freeze_simq(ch->sim, ch->numrslots);
if (ch->frozen) {
union ccb *fccb = ch->frozen;
ch->frozen = NULL;
@@ -884,10 +891,7 @@
/* XXX: reqests in loading state. */
if (((err >> i) & 1) == 0)
continue;
- if (istatus & AHCI_P_IX_IF) {
- /* SATA error */
- et = AHCI_ERR_SATA;
- } else if (istatus & AHCI_P_IX_TFE) {
+ if (istatus & AHCI_P_IX_TFE) {
/* Task File Error */
if (ch->numtslots == 0) {
/* Untagged operation. */
@@ -897,12 +901,18 @@
et = AHCI_ERR_INNOCENT;
} else {
/* Tagged operation. */
- et = AHCI_ERR_TFE;
+ et = AHCI_ERR_NCQ;
+ ncq_err = 1;
}
+ } else if (istatus & AHCI_P_IX_IF) {
+ /* SATA error */
+ et = AHCI_ERR_SATA;
} else
et = AHCI_ERR_INVALID;
ahci_end_transaction(&ch->slot[i], et);
}
+ if (ncq_err)
+ ahci_issue_read_log(dev);
}
mtx_unlock(&ch->mtx);
}
@@ -1006,7 +1016,8 @@
//device_printf(slot->dev, "%s slot %d\n", __func__, slot->slot);
if (error) {
device_printf(slot->dev, "DMA load error\n");
- xpt_freeze_simq(ch->sim, 1);
+ if (!ch->readlog)
+ xpt_freeze_simq(ch->sim, 1);
ahci_end_transaction(slot, AHCI_ERR_INVALID);
return;
}
@@ -1046,7 +1057,8 @@
/* Setup the FIS for this request */
if (!(fis_size = ahci_setup_fis(ctp, ccb, slot->slot))) {
device_printf(ch->dev, "Setting up SATA FIS failed\n");
- xpt_freeze_simq(ch->sim, 1);
+ if (!ch->readlog)
+ xpt_freeze_simq(ch->sim, 1);
ahci_end_transaction(slot, AHCI_ERR_INVALID);
return;
}
@@ -1155,7 +1167,8 @@
ahci_clo(ch->dev);
ahci_start(ch->dev);
- xpt_freeze_simq(ch->sim, ch->numrslots);
+ if (!ch->readlog)
+ xpt_freeze_simq(ch->sim, ch->numrslots);
/* Handle command with timeout. */
ahci_end_transaction(&ch->slot[slot->slot], AHCI_ERR_TIMEOUT);
/* Handle the rest of commands. */
@@ -1240,8 +1253,9 @@
if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
- } else
- ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
+ } else {
+ ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
+ }
break;
case AHCI_ERR_SATA:
ccb->ccb_h.status |= CAM_UNCOR_PARITY;
@@ -1249,6 +1263,8 @@
case AHCI_ERR_TIMEOUT:
ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
break;
+ case AHCI_ERR_NCQ:
+ ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
default:
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
}
@@ -1273,7 +1289,14 @@
ahci_begin_transaction(dev, ccb);
return;
}
- xpt_done(ccb);
+ /* If it was NCQ command error, put result on hold. */
+ if (et == AHCI_ERR_NCQ) {
+ ch->hold[slot->slot] = ccb;
+ } else if (ch->readlog) /* If it was our READ LOG command - process it. */
+ ahci_process_read_log(dev, ccb);
+ else
+ xpt_done(ccb);
+ /* Unfreeze frozen command. */
if (ch->frozen && ch->numrslots == 0) {
union ccb *fccb = ch->frozen;
//device_printf(dev, "Unfreeze\n");
@@ -1284,6 +1307,104 @@
}
static void
+ahci_issue_read_log(device_t dev)
+{
+ struct ahci_channel *ch = device_get_softc(dev);
+ union ccb *ccb;
+ struct ccb_ataio *ataio;
+ int i;
+
+//device_printf(dev, "%s\n", __func__);
+ ch->readlog = 1;
+ /* Find some holden command. */
+ for (i = 0; i < ch->numslots; i++) {
+ if (ch->hold[i])
+ break;
+ }
+ ccb = xpt_alloc_ccb_nowait();
+ if (ccb == NULL) {
+ device_printf(dev, "Unable allocate READ LOG command");
+ return; /* XXX */
+ }
+ ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */
+ ccb->ccb_h.func_code = XPT_ATA_IO;
+ ccb->ccb_h.flags = CAM_DIR_IN;
+ ccb->ccb_h.timeout = 1000; /* 1s should be enough. */
+ ataio = &ccb->ataio;
+ ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT);
+ if (ataio->data_ptr == NULL) {
+ device_printf(dev, "Unable allocate memory for READ LOG command");
+ return; /* XXX */
+ }
+ ataio->dxfer_len = 512;
+ bzero(&ataio->cmd, sizeof(ataio->cmd));
+ ataio->cmd.flags = CAM_ATAIO_48BIT;
+ ataio->cmd.command = 0x2F; /* READ LOG EXT */
+ ataio->cmd.sector_count = 1;
+ ataio->cmd.sector_count_exp = 0;
+ ataio->cmd.lba_low = 0x10;
+ ataio->cmd.lba_mid = 0;
+ ataio->cmd.lba_mid_exp = 0;
+
+ ahci_begin_transaction(dev, ccb);
+}
+
+static void
+ahci_process_read_log(device_t dev, union ccb *ccb)
+{
+ struct ahci_channel *ch = device_get_softc(dev);
+ uint8_t *data;
+ struct ata_res *res;
+ int i;
+
+//device_printf(dev, "%s\n", __func__);
+ ch->readlog = 0;
+
+ data = ccb->ataio.data_ptr;
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
+ (data[0] & 0x80) == 0) {
+ for (i = 0; i < ch->numslots; i++) {
+ if (!ch->hold[i])
+ continue;
+ if ((data[0] & 0x1F) == i) {
+device_printf(dev, "READ LOG EXT: TAG %d MATCH\n", i);
+ res = &ch->hold[i]->ataio.res;
+ res->status = data[2];
+ res->error = data[3];
+ res->lba_low = data[4];
+ res->lba_mid = data[5];
+ res->lba_high = data[6];
+ res->device = data[7];
+ res->lba_low_exp = data[8];
+ res->lba_mid_exp = data[9];
+ res->lba_high_exp = data[10];
+ res->sector_count = data[12];
+ res->sector_count_exp = data[13];
+ } else {
+ ccb->ccb_h.status &= ~CAM_STATUS_MASK;
+ ccb->ccb_h.status |= CAM_REQUEUE_REQ;
+ }
+ xpt_done(ch->hold[i]);
+ ch->hold[i] = NULL;
+ }
+ } else {
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
+ device_printf(dev, "Error while READ LOG EXT\n");
+ else if ((data[0] & 0x80) == 0) {
+ device_printf(dev, "Non-queued command error in READ LOG EXT\n");
+ }
+ for (i = 0; i < ch->numslots; i++) {
+ if (!ch->hold[i])
+ continue;
+ xpt_done(ch->hold[i]);
+ ch->hold[i] = NULL;
+ }
+ }
+ free(ccb->ataio.data_ptr, M_AHCI);
+ xpt_free_ccb(ccb);
+}
+
+static void
ahci_start(device_t dev)
{
struct ahci_channel *ch = device_get_softc(dev);
==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#15 (text+ko) ====
@@ -341,6 +341,7 @@
int sata_rev; /* Maximum allowed SATA generation */
struct ahci_slot slot[AHCI_MAX_SLOTS];
+ union ccb *hold[AHCI_MAX_SLOTS];
struct mtx mtx; /* state lock */
int devices; /* What is present */
int pm_present; /* PM presence reported */
@@ -348,6 +349,7 @@
uint32_t aslots; /* Slots with atomic commands */
int numrslots; /* Number of running slots */
int numtslots; /* Number of tagged slots */
+ int readlog; /* Our READ LOG active */
int lastslot; /* Last used slot */
int taggedtarget; /* Last tagged target */
union ccb *frozen; /* Frozen command */
@@ -385,6 +387,8 @@
AHCI_ERR_TFE, /* Task File Error. */
AHCI_ERR_SATA, /* SATA error. */
AHCI_ERR_TIMEOUT, /* Command execution timeout. */
+ AHCI_ERR_NCQ, /* NCQ command error. CCB should be put on hold
+ * until READ LOG executed to reveal error. */
};
/* macros to hide busspace uglyness */
More information about the p4-projects
mailing list