From owner-svn-src-all@freebsd.org Thu Feb 22 13:32:33 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7064FF03617; Thu, 22 Feb 2018 13:32:33 +0000 (UTC) (envelope-from wma@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 0155882795; Thu, 22 Feb 2018 13:32:33 +0000 (UTC) (envelope-from wma@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id D615148C; Thu, 22 Feb 2018 13:32:32 +0000 (UTC) (envelope-from wma@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w1MDWWY1004580; Thu, 22 Feb 2018 13:32:32 GMT (envelope-from wma@FreeBSD.org) Received: (from wma@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w1MDWVao004564; Thu, 22 Feb 2018 13:32:31 GMT (envelope-from wma@FreeBSD.org) Message-Id: <201802221332.w1MDWVao004564@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: wma set sender to wma@FreeBSD.org using -f From: Wojciech Macek Date: Thu, 22 Feb 2018 13:32:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r329824 - in head: sbin/nvmecontrol sys/cam/nvme sys/conf sys/dev/mpr sys/dev/nvme X-SVN-Group: head X-SVN-Commit-Author: wma X-SVN-Commit-Paths: in head: sbin/nvmecontrol sys/cam/nvme sys/conf sys/dev/mpr sys/dev/nvme X-SVN-Commit-Revision: 329824 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 22 Feb 2018 13:32:33 -0000 Author: wma Date: Thu Feb 22 13:32:31 2018 New Revision: 329824 URL: https://svnweb.freebsd.org/changeset/base/329824 Log: NVMe: Add big-endian support Remove bitfields from defined structures as they are not portable. Instead use shift and mask macros in the driver and nvmecontrol application. NVMe is now working on powerpc64 host. Submitted by: Michal Stanek Obtained from: Semihalf Reviewed by: imp, wma Sponsored by: IBM, QCM Technologies Differential revision: https://reviews.freebsd.org/D13916 Modified: head/sbin/nvmecontrol/devlist.c head/sbin/nvmecontrol/firmware.c head/sbin/nvmecontrol/identify.c head/sbin/nvmecontrol/logpage.c head/sbin/nvmecontrol/nvmecontrol.c head/sbin/nvmecontrol/perftest.c head/sbin/nvmecontrol/power.c head/sbin/nvmecontrol/wdc.c head/sys/cam/nvme/nvme_all.c head/sys/cam/nvme/nvme_da.c head/sys/conf/files head/sys/dev/mpr/mpr_sas.c head/sys/dev/nvme/nvme.c head/sys/dev/nvme/nvme.h head/sys/dev/nvme/nvme_ctrlr.c head/sys/dev/nvme/nvme_ctrlr_cmd.c head/sys/dev/nvme/nvme_ns.c head/sys/dev/nvme/nvme_ns_cmd.c head/sys/dev/nvme/nvme_private.h head/sys/dev/nvme/nvme_qpair.c Modified: head/sbin/nvmecontrol/devlist.c ============================================================================== --- head/sbin/nvmecontrol/devlist.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/devlist.c Thu Feb 22 13:32:31 2018 (r329824) @@ -54,8 +54,14 @@ devlist_usage(void) static inline uint32_t ns_get_sector_size(struct nvme_namespace_data *nsdata) { + uint8_t flbas_fmt, lbads; - return (1 << nsdata->lbaf[nsdata->flbas.format].lbads); + flbas_fmt = (nsdata->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) & + NVME_NS_DATA_FLBAS_FORMAT_MASK; + lbads = (nsdata->lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & + NVME_NS_DATA_LBAF_LBADS_MASK; + + return (1 << lbads); } void Modified: head/sbin/nvmecontrol/firmware.c ============================================================================== --- head/sbin/nvmecontrol/firmware.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/firmware.c Thu Feb 22 13:32:31 2018 (r329824) @@ -125,9 +125,9 @@ update_firmware(int fd, uint8_t *payload, int32_t payl memcpy(chunk, payload + off, size); memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; - pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1; - pt.cmd.cdw11 = (off / sizeof(uint32_t)); + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD); + pt.cmd.cdw10 = htole32((size / sizeof(uint32_t)) - 1); + pt.cmd.cdw11 = htole32(off / sizeof(uint32_t)); pt.buf = chunk; pt.len = size; pt.is_read = 0; @@ -147,17 +147,21 @@ static int activate_firmware(int fd, int slot, int activate_action) { struct nvme_pt_command pt; + uint16_t sct, sc; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_FIRMWARE_ACTIVATE; - pt.cmd.cdw10 = (activate_action << 3) | slot; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_FIRMWARE_ACTIVATE); + pt.cmd.cdw10 = htole32((activate_action << 3) | slot); pt.is_read = 0; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "firmware activate request failed"); - if (pt.cpl.status.sct == NVME_SCT_COMMAND_SPECIFIC && - pt.cpl.status.sc == NVME_SC_FIRMWARE_REQUIRES_RESET) + sct = NVME_STATUS_GET_SCT(pt.cpl.status); + sc = NVME_STATUS_GET_SC(pt.cpl.status); + + if (sct == NVME_SCT_COMMAND_SPECIFIC && + sc == NVME_SC_FIRMWARE_REQUIRES_RESET) return 1; if (nvme_completion_is_error(&pt.cpl)) @@ -180,16 +184,19 @@ firmware(int argc, char *argv[]) int fd = -1, slot = 0; int a_flag, s_flag, f_flag; int activate_action, reboot_required; - char ch, *p, *image = NULL; + int opt; + char *p, *image = NULL; char *controller = NULL, prompt[64]; void *buf = NULL; int32_t size = 0; + uint16_t oacs_fw; + uint8_t fw_slot1_ro, fw_num_slots; struct nvme_controller_data cdata; a_flag = s_flag = f_flag = false; - while ((ch = getopt(argc, argv, "af:s:")) != -1) { - switch (ch) { + while ((opt = getopt(argc, argv, "af:s:")) != -1) { + switch (opt) { case 'a': a_flag = true; break; @@ -243,17 +250,26 @@ firmware(int argc, char *argv[]) open_dev(controller, &fd, 1, 1); read_controller_data(fd, &cdata); - if (cdata.oacs.firmware == 0) + oacs_fw = (cdata.oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) & + NVME_CTRLR_DATA_OACS_FIRMWARE_MASK; + + if (oacs_fw == 0) errx(1, "controller does not support firmware activate/download"); - if (f_flag && slot == 1 && cdata.frmw.slot1_ro) + fw_slot1_ro = (cdata.frmw >> NVME_CTRLR_DATA_FRMW_SLOT1_RO_SHIFT) & + NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK; + + if (f_flag && slot == 1 && fw_slot1_ro) errx(1, "slot %d is marked as read only", slot); - if (slot > cdata.frmw.num_slots) + fw_num_slots = (cdata.frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) & + NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK; + + if (slot > fw_num_slots) errx(1, "slot %d specified but controller only supports %d slots", - slot, cdata.frmw.num_slots); + slot, fw_num_slots); if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot)) errx(1, Modified: head/sbin/nvmecontrol/identify.c ============================================================================== --- head/sbin/nvmecontrol/identify.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/identify.c Thu Feb 22 13:32:31 2018 (r329824) @@ -47,7 +47,52 @@ print_controller(struct nvme_controller_data *cdata) { uint8_t str[128]; char cbuf[UINT128_DIG + 1]; + uint16_t oncs, oacs; + uint8_t compare, write_unc, dsm, vwc_present; + uint8_t security, fmt, fw, nsmgmt; + uint8_t fw_slot1_ro, fw_num_slots; + uint8_t ns_smart; + uint8_t sqes_max, sqes_min; + uint8_t cqes_max, cqes_min; + oncs = cdata->oncs; + compare = (oncs >> NVME_CTRLR_DATA_ONCS_COMPARE_SHIFT) & + NVME_CTRLR_DATA_ONCS_COMPARE_MASK; + write_unc = (oncs >> NVME_CTRLR_DATA_ONCS_WRITE_UNC_SHIFT) & + NVME_CTRLR_DATA_ONCS_WRITE_UNC_MASK; + dsm = (oncs >> NVME_CTRLR_DATA_ONCS_DSM_SHIFT) & + NVME_CTRLR_DATA_ONCS_DSM_MASK; + vwc_present = (cdata->vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) & + NVME_CTRLR_DATA_VWC_PRESENT_MASK; + + oacs = cdata->oacs; + security = (oacs >> NVME_CTRLR_DATA_OACS_SECURITY_SHIFT) & + NVME_CTRLR_DATA_OACS_SECURITY_MASK; + fmt = (oacs >> NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) & + NVME_CTRLR_DATA_OACS_FORMAT_MASK; + fw = (oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) & + NVME_CTRLR_DATA_OACS_FIRMWARE_MASK; + nsmgmt = (oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) & + NVME_CTRLR_DATA_OACS_NSMGMT_MASK; + + fw_num_slots = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) & + NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK; + fw_slot1_ro = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_SLOT1_RO_SHIFT) & + NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK; + + ns_smart = (cdata->lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) & + NVME_CTRLR_DATA_LPA_NS_SMART_MASK; + + sqes_min = (cdata->sqes >> NVME_CTRLR_DATA_SQES_MIN_SHIFT) & + NVME_CTRLR_DATA_SQES_MIN_MASK; + sqes_max = (cdata->sqes >> NVME_CTRLR_DATA_SQES_MAX_SHIFT) & + NVME_CTRLR_DATA_SQES_MAX_MASK; + + cqes_min = (cdata->cqes >> NVME_CTRLR_DATA_CQES_MIN_SHIFT) & + NVME_CTRLR_DATA_CQES_MIN_MASK; + cqes_max = (cdata->cqes >> NVME_CTRLR_DATA_CQES_MAX_SHIFT) & + NVME_CTRLR_DATA_CQES_MAX_MASK; + printf("Controller Capabilities/Features\n"); printf("================================\n"); printf("Vendor ID: %04x\n", cdata->vid); @@ -67,34 +112,34 @@ print_controller(struct nvme_controller_data *cdata) if (cdata->mdts == 0) printf("Unlimited\n"); else - printf("%d\n", PAGE_SIZE * (1 << cdata->mdts)); + printf("%ld\n", PAGE_SIZE * (1 << cdata->mdts)); printf("Controller ID: 0x%02x\n", cdata->ctrlr_id); printf("\n"); printf("Admin Command Set Attributes\n"); printf("============================\n"); printf("Security Send/Receive: %s\n", - cdata->oacs.security ? "Supported" : "Not Supported"); + security ? "Supported" : "Not Supported"); printf("Format NVM: %s\n", - cdata->oacs.format ? "Supported" : "Not Supported"); + fmt ? "Supported" : "Not Supported"); printf("Firmware Activate/Download: %s\n", - cdata->oacs.firmware ? "Supported" : "Not Supported"); + fw ? "Supported" : "Not Supported"); printf("Namespace Managment: %s\n", - cdata->oacs.nsmgmt ? "Supported" : "Not Supported"); + nsmgmt ? "Supported" : "Not Supported"); printf("Abort Command Limit: %d\n", cdata->acl+1); printf("Async Event Request Limit: %d\n", cdata->aerl+1); printf("Number of Firmware Slots: "); - if (cdata->oacs.firmware != 0) - printf("%d\n", cdata->frmw.num_slots); + if (fw != 0) + printf("%d\n", fw_num_slots); else printf("N/A\n"); printf("Firmware Slot 1 Read-Only: "); - if (cdata->oacs.firmware != 0) - printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No"); + if (fw != 0) + printf("%s\n", fw_slot1_ro ? "Yes" : "No"); else printf("N/A\n"); printf("Per-Namespace SMART Log: %s\n", - cdata->lpa.ns_smart ? "Yes" : "No"); + ns_smart ? "Yes" : "No"); printf("Error Log Page Entries: %d\n", cdata->elpe+1); printf("Number of Power States: %d\n", cdata->npss+1); @@ -102,22 +147,22 @@ print_controller(struct nvme_controller_data *cdata) printf("NVM Command Set Attributes\n"); printf("==========================\n"); printf("Submission Queue Entry Size\n"); - printf(" Max: %d\n", 1 << cdata->sqes.max); - printf(" Min: %d\n", 1 << cdata->sqes.min); + printf(" Max: %d\n", 1 << sqes_max); + printf(" Min: %d\n", 1 << sqes_min); printf("Completion Queue Entry Size\n"); - printf(" Max: %d\n", 1 << cdata->cqes.max); - printf(" Min: %d\n", 1 << cdata->cqes.min); + printf(" Max: %d\n", 1 << cqes_max); + printf(" Min: %d\n", 1 << cqes_min); printf("Number of Namespaces: %d\n", cdata->nn); printf("Compare Command: %s\n", - cdata->oncs.compare ? "Supported" : "Not Supported"); + compare ? "Supported" : "Not Supported"); printf("Write Uncorrectable Command: %s\n", - cdata->oncs.write_unc ? "Supported" : "Not Supported"); + write_unc ? "Supported" : "Not Supported"); printf("Dataset Management Command: %s\n", - cdata->oncs.dsm ? "Supported" : "Not Supported"); + dsm ? "Supported" : "Not Supported"); printf("Volatile Write Cache: %s\n", - cdata->vwc.present ? "Present" : "Not Present"); + vwc_present ? "Present" : "Not Present"); - if (cdata->oacs.nsmgmt) { + if (nsmgmt) { printf("\n"); printf("Namespace Drive Attributes\n"); printf("==========================\n"); @@ -132,7 +177,16 @@ static void print_namespace(struct nvme_namespace_data *nsdata) { uint32_t i; + uint32_t lbaf, lbads, ms; + uint8_t thin_prov; + uint8_t flbas_fmt; + thin_prov = (nsdata->nsfeat >> NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT) & + NVME_NS_DATA_NSFEAT_THIN_PROV_MASK; + + flbas_fmt = (nsdata->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) & + NVME_NS_DATA_FLBAS_FORMAT_MASK; + printf("Size (in LBAs): %lld (%lldM)\n", (long long)nsdata->nsze, (long long)nsdata->nsze / 1024 / 1024); @@ -143,13 +197,18 @@ print_namespace(struct nvme_namespace_data *nsdata) (long long)nsdata->nuse, (long long)nsdata->nuse / 1024 / 1024); printf("Thin Provisioning: %s\n", - nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported"); + thin_prov ? "Supported" : "Not Supported"); printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1); - printf("Current LBA Format: LBA Format #%02d\n", - nsdata->flbas.format); - for (i = 0; i <= nsdata->nlbaf; i++) + printf("Current LBA Format: LBA Format #%02d\n", flbas_fmt); + for (i = 0; i <= nsdata->nlbaf; i++) { + lbaf = nsdata->lbaf[i]; + lbads = (lbaf >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & + NVME_NS_DATA_LBAF_LBADS_MASK; + ms = (lbaf >> NVME_NS_DATA_LBAF_MS_SHIFT) & + NVME_NS_DATA_LBAF_MS_MASK; printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n", - i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms); + i, 1 << lbads, ms); + } } static void Modified: head/sbin/nvmecontrol/logpage.c ============================================================================== --- head/sbin/nvmecontrol/logpage.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/logpage.c Thu Feb 22 13:32:31 2018 (r329824) @@ -46,10 +46,6 @@ __FBSDID("$FreeBSD$"); #include #include -#if _BYTE_ORDER != _LITTLE_ENDIAN -#error "Code only works on little endian machines" -#endif - #include "nvmecontrol.h" #define DEFAULT_SIZE (4096) @@ -107,12 +103,15 @@ read_logpage(int fd, uint8_t log_page, int nsid, void uint32_t payload_size) { struct nvme_pt_command pt; + struct nvme_error_information_entry *err_entry; + int i, err_pages; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; - pt.cmd.nsid = nsid; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_GET_LOG_PAGE); + pt.cmd.nsid = htole32(nsid); pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; pt.cmd.cdw10 |= log_page; + pt.cmd.cdw10 = htole32(pt.cmd.cdw10); pt.buf = payload; pt.len = payload_size; pt.is_read = 1; @@ -120,6 +119,30 @@ read_logpage(int fd, uint8_t log_page, int nsid, void if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "get log page request failed"); + /* Convert data to host endian */ + switch (log_page) { + case NVME_LOG_ERROR: + err_entry = (struct nvme_error_information_entry *)payload; + err_pages = payload_size / sizeof(struct nvme_error_information_entry); + for (i = 0; i < err_pages; i++) + nvme_error_information_entry_swapbytes(err_entry++); + break; + case NVME_LOG_HEALTH_INFORMATION: + nvme_health_information_page_swapbytes( + (struct nvme_health_information_page *)payload); + break; + case NVME_LOG_FIRMWARE_SLOT: + nvme_firmware_page_swapbytes( + (struct nvme_firmware_page *)payload); + break; + case INTEL_LOG_TEMP_STATS: + intel_log_temp_stats_swapbytes( + (struct intel_log_temp_stats *)payload); + break; + default: + break; + } + if (nvme_completion_is_error(&pt.cpl)) errx(1, "get log page request returned error"); } @@ -128,8 +151,9 @@ static void print_log_error(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size) { int i, nentries; + uint16_t status; + uint8_t p, sc, sct, m, dnr; struct nvme_error_information_entry *entry = buf; - struct nvme_status *status; printf("Error Information Log\n"); printf("=====================\n"); @@ -144,7 +168,14 @@ print_log_error(const struct nvme_controller_data *cda if (entry->error_count == 0) break; - status = &entry->status; + status = entry->status; + + p = NVME_STATUS_GET_P(status); + sc = NVME_STATUS_GET_SC(status); + sct = NVME_STATUS_GET_SCT(status); + m = NVME_STATUS_GET_M(status); + dnr = NVME_STATUS_GET_DNR(status); + printf("Entry %02d\n", i + 1); printf("=========\n"); printf(" Error count: %ju\n", entry->error_count); @@ -152,11 +183,11 @@ print_log_error(const struct nvme_controller_data *cda printf(" Command ID: %u\n", entry->cid); /* TODO: Export nvme_status_string structures from kernel? */ printf(" Status:\n"); - printf(" Phase tag: %d\n", status->p); - printf(" Status code: %d\n", status->sc); - printf(" Status code type: %d\n", status->sct); - printf(" More: %d\n", status->m); - printf(" DNR: %d\n", status->dnr); + printf(" Phase tag: %d\n", p); + printf(" Status code: %d\n", sc); + printf(" Status code type: %d\n", sct); + printf(" More: %d\n", m); + printf(" DNR: %d\n", dnr); printf(" Error location: %u\n", entry->error_location); printf(" LBA: %ju\n", entry->lba); printf(" Namespace ID: %u\n", entry->nsid); @@ -176,23 +207,25 @@ print_log_health(const struct nvme_controller_data *cd { struct nvme_health_information_page *health = buf; char cbuf[UINT128_DIG + 1]; + uint8_t warning; int i; + warning = health->critical_warning; + printf("SMART/Health Information Log\n"); printf("============================\n"); - printf("Critical Warning State: 0x%02x\n", - health->critical_warning.raw); + printf("Critical Warning State: 0x%02x\n", warning); printf(" Available spare: %d\n", - health->critical_warning.bits.available_spare); + !!(warning & NVME_CRIT_WARN_ST_AVAILABLE_SPARE)); printf(" Temperature: %d\n", - health->critical_warning.bits.temperature); + !!(warning & NVME_CRIT_WARN_ST_TEMPERATURE)); printf(" Device reliability: %d\n", - health->critical_warning.bits.device_reliability); + !!(warning & NVME_CRIT_WARN_ST_DEVICE_RELIABILITY)); printf(" Read only: %d\n", - health->critical_warning.bits.read_only); + !!(warning & NVME_CRIT_WARN_ST_READ_ONLY)); printf(" Volatile memory backup: %d\n", - health->critical_warning.bits.volatile_memory_backup); + !!(warning & NVME_CRIT_WARN_ST_VOLATILE_MEMORY_BACKUP)); printf("Temperature: "); print_temp(health->temperature); printf("Available spare: %u\n", @@ -225,7 +258,7 @@ print_log_health(const struct nvme_controller_data *cd printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); printf("Error Temp Composite Time: %d\n", health->error_temp_time); - for (i = 0; i < 7; i++) { + for (i = 0; i < 8; i++) { if (health->temp_sensor[i] == 0) continue; printf("Temperature Sensor %d: ", i + 1); @@ -234,23 +267,34 @@ print_log_health(const struct nvme_controller_data *cd } static void -print_log_firmware(const struct nvme_controller_data *cdata __unused, void *buf, uint32_t size __unused) +print_log_firmware(const struct nvme_controller_data *cdata, void *buf, uint32_t size __unused) { int i, slots; const char *status; struct nvme_firmware_page *fw = buf; + uint8_t afi_slot; + uint16_t oacs_fw; + uint8_t fw_num_slots; + afi_slot = fw->afi >> NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT; + afi_slot &= NVME_FIRMWARE_PAGE_AFI_SLOT_MASK; + + oacs_fw = (cdata->oacs >> NVME_CTRLR_DATA_OACS_FIRMWARE_SHIFT) & + NVME_CTRLR_DATA_OACS_FIRMWARE_MASK; + fw_num_slots = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT) & + NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK; + printf("Firmware Slot Log\n"); printf("=================\n"); - if (cdata->oacs.firmware == 0) + if (oacs_fw == 0) slots = 1; else - slots = MIN(cdata->frmw.num_slots, MAX_FW_SLOTS); + slots = MIN(fw_num_slots, MAX_FW_SLOTS); for (i = 0; i < slots; i++) { printf("Slot %d: ", i + 1); - if (fw->afi.slot == i + 1) + if (afi_slot == i + 1) status = " Active"; else status = "Inactive"; @@ -868,7 +912,8 @@ logpage(int argc, char *argv[]) int fd, nsid; int log_page = 0, pageflag = false; int binflag = false, hexflag = false, ns_specified; - char ch, *p; + int opt; + char *p; char cname[64]; uint32_t size; void *buf; @@ -876,9 +921,10 @@ logpage(int argc, char *argv[]) struct logpage_function *f; struct nvme_controller_data cdata; print_fn_t print_fn; + uint8_t ns_smart; - while ((ch = getopt(argc, argv, "bp:xv:")) != -1) { - switch (ch) { + while ((opt = getopt(argc, argv, "bp:xv:")) != -1) { + switch (opt) { case 'b': binflag = true; break; @@ -928,6 +974,9 @@ logpage(int argc, char *argv[]) read_controller_data(fd, &cdata); + ns_smart = (cdata.lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) & + NVME_CTRLR_DATA_LPA_NS_SMART_MASK; + /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per @@ -937,7 +986,7 @@ logpage(int argc, char *argv[]) if (log_page != NVME_LOG_HEALTH_INFORMATION) errx(1, "log page %d valid only at controller level", log_page); - if (cdata.lpa.ns_smart == 0) + if (ns_smart == 0) errx(1, "controller does not support per namespace " "smart/health information"); Modified: head/sbin/nvmecontrol/nvmecontrol.c ============================================================================== --- head/sbin/nvmecontrol/nvmecontrol.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/nvmecontrol.c Thu Feb 22 13:32:31 2018 (r329824) @@ -146,8 +146,8 @@ read_controller_data(int fd, struct nvme_controller_da struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_IDENTIFY; - pt.cmd.cdw10 = 1; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY); + pt.cmd.cdw10 = htole32(1); pt.buf = cdata; pt.len = sizeof(*cdata); pt.is_read = 1; @@ -155,6 +155,9 @@ read_controller_data(int fd, struct nvme_controller_da if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); + /* Convert data to host endian */ + nvme_controller_data_swapbytes(cdata); + if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); } @@ -165,14 +168,17 @@ read_namespace_data(int fd, int nsid, struct nvme_name struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_IDENTIFY; - pt.cmd.nsid = nsid; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_IDENTIFY); + pt.cmd.nsid = htole32(nsid); pt.buf = nsdata; pt.len = sizeof(*nsdata); pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "identify request failed"); + + /* Convert data to host endian */ + nvme_namespace_data_swapbytes(nsdata); if (nvme_completion_is_error(&pt.cpl)) errx(1, "identify request returned error"); Modified: head/sbin/nvmecontrol/perftest.c ============================================================================== --- head/sbin/nvmecontrol/perftest.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/perftest.c Thu Feb 22 13:32:31 2018 (r329824) @@ -81,7 +81,7 @@ perftest(int argc, char *argv[]) { struct nvme_io_test io_test; int fd; - char ch; + int opt; char *p; u_long ioctl_cmd = NVME_IO_TEST; bool nflag, oflag, sflag, tflag; @@ -91,8 +91,8 @@ perftest(int argc, char *argv[]) memset(&io_test, 0, sizeof(io_test)); - while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { - switch (ch) { + while ((opt = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) { + switch (opt) { case 'f': if (!strcmp(optarg, "refthread")) io_test.flags |= NVME_TEST_FLAG_REFTHREAD; Modified: head/sbin/nvmecontrol/power.c ============================================================================== --- head/sbin/nvmecontrol/power.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/power.c Thu Feb 22 13:32:31 2018 (r329824) @@ -56,22 +56,32 @@ static void power_list_one(int i, struct nvme_power_state *nps) { int mpower, apower, ipower; + uint8_t mps, nops, aps, apw; + mps = (nps->mps_nops >> NVME_PWR_ST_MPS_SHIFT) & + NVME_PWR_ST_MPS_MASK; + nops = (nps->mps_nops >> NVME_PWR_ST_NOPS_SHIFT) & + NVME_PWR_ST_NOPS_MASK; + apw = (nps->apw_aps >> NVME_PWR_ST_APW_SHIFT) & + NVME_PWR_ST_APW_MASK; + aps = (nps->apw_aps >> NVME_PWR_ST_APS_SHIFT) & + NVME_PWR_ST_APS_MASK; + mpower = nps->mp; - if (nps->mps == 0) + if (mps == 0) mpower *= 100; ipower = nps->idlp; if (nps->ips == 1) ipower *= 100; apower = nps->actp; - if (nps->aps == 1) + if (aps == 1) apower *= 100; printf("%2d: %2d.%04dW%c %3d.%03dms %3d.%03dms %2d %2d %2d %2d %2d.%04dW %2d.%04dW %d\n", i, mpower / 10000, mpower % 10000, - nps->nops ? '*' : ' ', nps->enlat / 1000, nps->enlat % 1000, + nops ? '*' : ' ', nps->enlat / 1000, nps->enlat % 1000, nps->exlat / 1000, nps->exlat % 1000, nps->rrt, nps->rrl, nps->rwt, nps->rwl, ipower / 10000, ipower % 10000, - apower / 10000, apower % 10000, nps->apw); + apower / 10000, apower % 10000, apw); } static void @@ -94,9 +104,9 @@ power_set(int fd, int power_val, int workload, int per p = perm ? (1u << 31) : 0; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_SET_FEATURES; - pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT | p; - pt.cmd.cdw11 = power_val | (workload << 5); + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_SET_FEATURES); + pt.cmd.cdw10 = htole32(NVME_FEAT_POWER_MANAGEMENT | p); + pt.cmd.cdw11 = htole32(power_val | (workload << 5)); if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "set feature power mgmt request failed"); @@ -111,8 +121,8 @@ power_show(int fd) struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = NVME_OPC_GET_FEATURES; - pt.cmd.cdw10 = NVME_FEAT_POWER_MANAGEMENT; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_GET_FEATURES); + pt.cmd.cdw10 = htole32(NVME_FEAT_POWER_MANAGEMENT); if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "set feature power mgmt request failed"); Modified: head/sbin/nvmecontrol/wdc.c ============================================================================== --- head/sbin/nvmecontrol/wdc.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sbin/nvmecontrol/wdc.c Thu Feb 22 13:32:31 2018 (r329824) @@ -81,10 +81,10 @@ wdc_get_data(int fd, uint32_t opcode, uint32_t len, ui struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); - pt.cmd.opc = opcode; - pt.cmd.cdw10 = len / sizeof(uint32_t); /* - 1 like all the others ??? */ - pt.cmd.cdw11 = off / sizeof(uint32_t); - pt.cmd.cdw12 = cmd; + pt.cmd.opc_fuse = NVME_CMD_SET_OPC(opcode); + pt.cmd.cdw10 = htole32(len / sizeof(uint32_t)); /* - 1 like all the others ??? */ + pt.cmd.cdw11 = htole32(off / sizeof(uint32_t)); + pt.cmd.cdw12 = htole32(cmd); pt.buf = buffer; pt.len = buflen; pt.is_read = 1; Modified: head/sys/cam/nvme/nvme_all.c ============================================================================== --- head/sys/cam/nvme/nvme_all.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/cam/nvme/nvme_all.c Thu Feb 22 13:32:31 2018 (r329824) @@ -70,14 +70,14 @@ nvme_ns_cmd(struct ccb_nvmeio *nvmeio, uint8_t cmd, ui uint32_t cdw14, uint32_t cdw15) { bzero(&nvmeio->cmd, sizeof(struct nvme_command)); - nvmeio->cmd.opc = cmd; - nvmeio->cmd.nsid = nsid; - nvmeio->cmd.cdw10 = cdw10; - nvmeio->cmd.cdw11 = cdw11; - nvmeio->cmd.cdw12 = cdw12; - nvmeio->cmd.cdw13 = cdw13; - nvmeio->cmd.cdw14 = cdw14; - nvmeio->cmd.cdw15 = cdw15; + nvmeio->cmd.opc_fuse = NVME_CMD_SET_OPC(cmd); + nvmeio->cmd.nsid = htole32(nsid); + nvmeio->cmd.cdw10 = htole32(cdw10); + nvmeio->cmd.cdw11 = htole32(cdw11); + nvmeio->cmd.cdw12 = htole32(cdw12); + nvmeio->cmd.cdw13 = htole32(cdw13); + nvmeio->cmd.cdw14 = htole32(cdw14); + nvmeio->cmd.cdw15 = htole32(cdw15); } int @@ -118,24 +118,32 @@ nvme_opc2str[] = { const char * nvme_op_string(const struct nvme_command *cmd) { - if (cmd->opc > nitems(nvme_opc2str)) + uint8_t opc; + + opc = (cmd->opc_fuse >> NVME_CMD_OPC_SHIFT) & NVME_CMD_OPC_MASK; + if (opc > nitems(nvme_opc2str)) return "UNKNOWN"; - return nvme_opc2str[cmd->opc]; + return nvme_opc2str[opc]; } const char * nvme_cmd_string(const struct nvme_command *cmd, char *cmd_string, size_t len) { + uint8_t opc, fuse; + + opc = (cmd->opc_fuse >> NVME_CMD_OPC_SHIFT) & NVME_CMD_OPC_MASK; + fuse = (cmd->opc_fuse >> NVME_CMD_FUSE_SHIFT) & NVME_CMD_FUSE_MASK; /* * cid, rsvd areas and mptr not printed, since they are used * only internally by the SIM. */ snprintf(cmd_string, len, "opc=%x fuse=%x nsid=%x prp1=%llx prp2=%llx cdw=%x %x %x %x %x %x", - cmd->opc, cmd->fuse, cmd->nsid, + opc, fuse, cmd->nsid, (unsigned long long)cmd->prp1, (unsigned long long)cmd->prp2, - cmd->cdw10, cmd->cdw11, cmd->cdw12, cmd->cdw13, cmd->cdw14, cmd->cdw15); + cmd->cdw10, cmd->cdw11, cmd->cdw12, + cmd->cdw13, cmd->cdw14, cmd->cdw15); return cmd_string; } Modified: head/sys/cam/nvme/nvme_da.c ============================================================================== --- head/sys/cam/nvme/nvme_da.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/cam/nvme/nvme_da.c Thu Feb 22 13:32:31 2018 (r329824) @@ -676,6 +676,7 @@ ndaregister(struct cam_periph *periph, void *arg) const struct nvme_namespace_data *nsd; const struct nvme_controller_data *cd; char announce_buf[80]; + uint8_t flbas_fmt, lbads, vwc_present; u_int maxio; int quirks; @@ -744,13 +745,19 @@ ndaregister(struct cam_periph *periph, void *arg) else if (maxio > MAXPHYS) maxio = MAXPHYS; /* for safety */ disk->d_maxsize = maxio; - disk->d_sectorsize = 1 << nsd->lbaf[nsd->flbas.format].lbads; + flbas_fmt = (nsd->flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) & + NVME_NS_DATA_FLBAS_FORMAT_MASK; + lbads = (nsd->lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) & + NVME_NS_DATA_LBAF_LBADS_MASK; + disk->d_sectorsize = 1 << lbads; disk->d_mediasize = (off_t)(disk->d_sectorsize * nsd->nsze); disk->d_delmaxsize = disk->d_mediasize; disk->d_flags = DISKFLAG_DIRECT_COMPLETION; // if (cd->oncs.dsm) // XXX broken? disk->d_flags |= DISKFLAG_CANDELETE; - if (cd->vwc.present) + vwc_present = (cd->vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) & + NVME_CTRLR_DATA_VWC_PRESENT_MASK; + if (vwc_present) disk->d_flags |= DISKFLAG_CANFLUSHCACHE; if ((cpi.hba_misc & PIM_UNMAPPED) != 0) { disk->d_flags |= DISKFLAG_UNMAPPED_BIO; @@ -905,9 +912,9 @@ ndastart(struct cam_periph *periph, union ccb *start_c return; } dsm_range->length = - bp->bio_bcount / softc->disk->d_sectorsize; + htole32(bp->bio_bcount / softc->disk->d_sectorsize); dsm_range->starting_lba = - bp->bio_offset / softc->disk->d_sectorsize; + htole64(bp->bio_offset / softc->disk->d_sectorsize); bp->bio_driver2 = dsm_range; nda_nvme_trim(softc, &start_ccb->nvmeio, dsm_range, 1); start_ccb->ccb_h.ccb_state = NDA_CCB_TRIM; Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/conf/files Thu Feb 22 13:32:31 2018 (r329824) @@ -2535,6 +2535,17 @@ dev/nmdm/nmdm.c optional nmdm dev/nsp/nsp.c optional nsp dev/nsp/nsp_pccard.c optional nsp pccard dev/null/null.c standard +dev/nvd/nvd.c optional nvd nvme +dev/nvme/nvme.c optional nvme +dev/nvme/nvme_ctrlr.c optional nvme +dev/nvme/nvme_ctrlr_cmd.c optional nvme +dev/nvme/nvme_ns.c optional nvme +dev/nvme/nvme_ns_cmd.c optional nvme +dev/nvme/nvme_qpair.c optional nvme +dev/nvme/nvme_sim.c optional nvme scbus +dev/nvme/nvme_sysctl.c optional nvme +dev/nvme/nvme_test.c optional nvme +dev/nvme/nvme_util.c optional nvme dev/oce/oce_hw.c optional oce pci dev/oce/oce_if.c optional oce pci dev/oce/oce_mbox.c optional oce pci Modified: head/sys/dev/mpr/mpr_sas.c ============================================================================== --- head/sys/dev/mpr/mpr_sas.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/dev/mpr/mpr_sas.c Thu Feb 22 13:32:31 2018 (r329824) @@ -1839,7 +1839,7 @@ mprsas_build_nvme_unmap(struct mpr_softc *sc, struct m /* Build NVMe DSM command */ c = (struct nvme_command *) req->NVMe_Command; - c->opc = NVME_OPC_DATASET_MANAGEMENT; + c->opc_fuse = NVME_CMD_SET_OPC(NVME_OPC_DATASET_MANAGEMENT); c->nsid = htole32(csio->ccb_h.target_lun + 1); c->cdw10 = htole32(ndesc - 1); c->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE); @@ -2263,22 +2263,26 @@ mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb * Returns appropriate scsi_status */ static u8 -mprsas_nvme_trans_status_code(struct nvme_status nvme_status, +mprsas_nvme_trans_status_code(uint16_t nvme_status, struct mpr_command *cm) { u8 status = MPI2_SCSI_STATUS_GOOD; int skey, asc, ascq; union ccb *ccb = cm->cm_complete_data; int returned_sense_len; + uint8_t sct, sc; + sct = NVME_STATUS_GET_SCT(nvme_status); + sc = NVME_STATUS_GET_SC(nvme_status); + status = MPI2_SCSI_STATUS_CHECK_CONDITION; skey = SSD_KEY_ILLEGAL_REQUEST; asc = SCSI_ASC_NO_SENSE; ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; - switch (nvme_status.sct) { + switch (sct) { case NVME_SCT_GENERIC: - switch (nvme_status.sc) { + switch (sc) { case NVME_SC_SUCCESS: status = MPI2_SCSI_STATUS_GOOD; skey = SSD_KEY_NO_SENSE; @@ -2351,7 +2355,7 @@ mprsas_nvme_trans_status_code(struct nvme_status nvme_ } break; case NVME_SCT_COMMAND_SPECIFIC: - switch (nvme_status.sc) { + switch (sc) { case NVME_SC_INVALID_FORMAT: status = MPI2_SCSI_STATUS_CHECK_CONDITION; skey = SSD_KEY_ILLEGAL_REQUEST; @@ -2367,7 +2371,7 @@ mprsas_nvme_trans_status_code(struct nvme_status nvme_ } break; case NVME_SCT_MEDIA_ERROR: - switch (nvme_status.sc) { + switch (sc) { case NVME_SC_WRITE_FAULTS: status = MPI2_SCSI_STATUS_CHECK_CONDITION; skey = SSD_KEY_MEDIUM_ERROR; Modified: head/sys/dev/nvme/nvme.c ============================================================================== --- head/sys/dev/nvme/nvme.c Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/dev/nvme/nvme.c Thu Feb 22 13:32:31 2018 (r329824) @@ -222,23 +222,38 @@ nvme_modevent(module_t mod, int type, void *arg) void nvme_dump_command(struct nvme_command *cmd) { + uint8_t opc, fuse; + + opc = (cmd->opc_fuse >> NVME_CMD_OPC_SHIFT) & NVME_CMD_OPC_MASK; + fuse = (cmd->opc_fuse >> NVME_CMD_FUSE_SHIFT) & NVME_CMD_FUSE_MASK; + printf( -"opc:%x f:%x r1:%x cid:%x nsid:%x r2:%x r3:%x mptr:%jx prp1:%jx prp2:%jx cdw:%x %x %x %x %x %x\n", - cmd->opc, cmd->fuse, cmd->rsvd1, cmd->cid, cmd->nsid, +"opc:%x f:%x cid:%x nsid:%x r2:%x r3:%x mptr:%jx prp1:%jx prp2:%jx cdw:%x %x %x %x %x %x\n", + opc, fuse, cmd->cid, le32toh(cmd->nsid), cmd->rsvd2, cmd->rsvd3, - (uintmax_t)cmd->mptr, (uintmax_t)cmd->prp1, (uintmax_t)cmd->prp2, - cmd->cdw10, cmd->cdw11, cmd->cdw12, cmd->cdw13, cmd->cdw14, - cmd->cdw15); + (uintmax_t)le64toh(cmd->mptr), (uintmax_t)le64toh(cmd->prp1), (uintmax_t)le64toh(cmd->prp2), + le32toh(cmd->cdw10), le32toh(cmd->cdw11), le32toh(cmd->cdw12), + le32toh(cmd->cdw13), le32toh(cmd->cdw14), le32toh(cmd->cdw15)); } void nvme_dump_completion(struct nvme_completion *cpl) { + uint8_t p, sc, sct, m, dnr; + uint16_t status; + + status = le16toh(cpl->status); + + p = NVME_STATUS_GET_P(status); + sc = NVME_STATUS_GET_SC(status); + sct = NVME_STATUS_GET_SCT(status); + m = NVME_STATUS_GET_M(status); + dnr = NVME_STATUS_GET_DNR(status); + printf("cdw0:%08x sqhd:%04x sqid:%04x " "cid:%04x p:%x sc:%02x sct:%x m:%x dnr:%x\n", - cpl->cdw0, cpl->sqhd, cpl->sqid, - cpl->cid, cpl->status.p, cpl->status.sc, cpl->status.sct, - cpl->status.m, cpl->status.dnr); + le32toh(cpl->cdw0), le16toh(cpl->sqhd), le16toh(cpl->sqid), + cpl->cid, p, sc, sct, m, dnr); } static int Modified: head/sys/dev/nvme/nvme.h ============================================================================== --- head/sys/dev/nvme/nvme.h Thu Feb 22 13:06:27 2018 (r329823) +++ head/sys/dev/nvme/nvme.h Thu Feb 22 13:32:31 2018 (r329824) @@ -36,6 +36,7 @@ #endif #include +#include #define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command) #define NVME_RESET_CONTROLLER _IO('n', 1) @@ -59,153 +60,264 @@ /* Cap nvme to 1MB transfers driver explodes with larger sizes */ #define NVME_MAX_XFER_SIZE (MAXPHYS < (1<<20) ? MAXPHYS : (1<<20)) -union cap_lo_register { - uint32_t raw; - struct { - /** maximum queue entries supported */ - uint32_t mqes : 16; +/* Register field definitions */ +#define NVME_CAP_LO_REG_MQES_SHIFT (0) +#define NVME_CAP_LO_REG_MQES_MASK (0xFFFF) +#define NVME_CAP_LO_REG_CQR_SHIFT (16) +#define NVME_CAP_LO_REG_CQR_MASK (0x1) +#define NVME_CAP_LO_REG_AMS_SHIFT (17) +#define NVME_CAP_LO_REG_AMS_MASK (0x3) +#define NVME_CAP_LO_REG_TO_SHIFT (24) +#define NVME_CAP_LO_REG_TO_MASK (0xFF) - /** contiguous queues required */ - uint32_t cqr : 1; +#define NVME_CAP_HI_REG_DSTRD_SHIFT (0) +#define NVME_CAP_HI_REG_DSTRD_MASK (0xF) +#define NVME_CAP_HI_REG_CSS_NVM_SHIFT (5) +#define NVME_CAP_HI_REG_CSS_NVM_MASK (0x1) +#define NVME_CAP_HI_REG_MPSMIN_SHIFT (16) +#define NVME_CAP_HI_REG_MPSMIN_MASK (0xF) +#define NVME_CAP_HI_REG_MPSMAX_SHIFT (20) +#define NVME_CAP_HI_REG_MPSMAX_MASK (0xF) - /** arbitration mechanism supported */ - uint32_t ams : 2; +#define NVME_CC_REG_EN_SHIFT (0) +#define NVME_CC_REG_EN_MASK (0x1) +#define NVME_CC_REG_CSS_SHIFT (4) +#define NVME_CC_REG_CSS_MASK (0x7) +#define NVME_CC_REG_MPS_SHIFT (7) +#define NVME_CC_REG_MPS_MASK (0xF) +#define NVME_CC_REG_AMS_SHIFT (11) +#define NVME_CC_REG_AMS_MASK (0x7) +#define NVME_CC_REG_SHN_SHIFT (14) +#define NVME_CC_REG_SHN_MASK (0x3) +#define NVME_CC_REG_IOSQES_SHIFT (16) +#define NVME_CC_REG_IOSQES_MASK (0xF) +#define NVME_CC_REG_IOCQES_SHIFT (20) +#define NVME_CC_REG_IOCQES_MASK (0xF) - uint32_t reserved1 : 5; +#define NVME_CSTS_REG_RDY_SHIFT (0) +#define NVME_CSTS_REG_RDY_MASK (0x1) +#define NVME_CSTS_REG_CFS_SHIFT (1) +#define NVME_CSTS_REG_CFS_MASK (0x1) +#define NVME_CSTS_REG_SHST_SHIFT (2) +#define NVME_CSTS_REG_SHST_MASK (0x3) - /** timeout */ - uint32_t to : 8; - } bits __packed; -} __packed; +#define NVME_CSTS_GET_SHST(csts) (((csts) >> NVME_CSTS_REG_SHST_SHIFT) & NVME_CSTS_REG_SHST_MASK) -_Static_assert(sizeof(union cap_lo_register) == 4, "bad size for cap_lo_register"); +#define NVME_AQA_REG_ASQS_SHIFT (0) +#define NVME_AQA_REG_ASQS_MASK (0xFFF) +#define NVME_AQA_REG_ACQS_SHIFT (16) +#define NVME_AQA_REG_ACQS_MASK (0xFFF) -union cap_hi_register { - uint32_t raw; - struct { - /** doorbell stride */ - uint32_t dstrd : 4; +/* Command field definitions */ - uint32_t reserved3 : 1; +#define NVME_CMD_OPC_SHIFT (0) +#define NVME_CMD_OPC_MASK (0xFF) +#define NVME_CMD_FUSE_SHIFT (8) +#define NVME_CMD_FUSE_MASK (0x3) - /** command sets supported */ - uint32_t css_nvm : 1; +#define NVME_CMD_SET_OPC(opc) (htole16(((opc) & NVME_CMD_OPC_MASK) << NVME_CMD_OPC_SHIFT)) - uint32_t css_reserved : 3; - uint32_t reserved2 : 7; +#define NVME_STATUS_P_SHIFT (0) +#define NVME_STATUS_P_MASK (0x1) +#define NVME_STATUS_SC_SHIFT (1) +#define NVME_STATUS_SC_MASK (0xFF) +#define NVME_STATUS_SCT_SHIFT (9) +#define NVME_STATUS_SCT_MASK (0x7) +#define NVME_STATUS_M_SHIFT (14) +#define NVME_STATUS_M_MASK (0x1) +#define NVME_STATUS_DNR_SHIFT (15) +#define NVME_STATUS_DNR_MASK (0x1) *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***