From owner-p4-projects@FreeBSD.ORG Mon Jun 15 06:26:27 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2B8311065673; Mon, 15 Jun 2009 06:26:27 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DC1C41065670 for ; Mon, 15 Jun 2009 06:26:26 +0000 (UTC) (envelope-from mav@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id C94128FC13 for ; Mon, 15 Jun 2009 06:26:26 +0000 (UTC) (envelope-from mav@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n5F6QQDs072261 for ; Mon, 15 Jun 2009 06:26:26 GMT (envelope-from mav@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n5F6QQB6072259 for perforce@freebsd.org; Mon, 15 Jun 2009 06:26:26 GMT (envelope-from mav@freebsd.org) Date: Mon, 15 Jun 2009 06:26:26 GMT Message-Id: <200906150626.n5F6QQB6072259@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to mav@freebsd.org using -f From: Alexander Motin To: Perforce Change Reviews Cc: Subject: PERFORCE change 164397 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Jun 2009 06:26:27 -0000 http://perforce.freebsd.org/chv.cgi?CH=164397 Change 164397 by mav@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 #include #include +#include #include /* 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 */