1240616Sjimharris/*- 2253112Sjimharris * Copyright (C) 2012-2013 Intel Corporation 3240616Sjimharris * All rights reserved. 4240616Sjimharris * 5240616Sjimharris * Redistribution and use in source and binary forms, with or without 6240616Sjimharris * modification, are permitted provided that the following conditions 7240616Sjimharris * are met: 8240616Sjimharris * 1. Redistributions of source code must retain the above copyright 9240616Sjimharris * notice, this list of conditions and the following disclaimer. 10240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11240616Sjimharris * notice, this list of conditions and the following disclaimer in the 12240616Sjimharris * documentation and/or other materials provided with the distribution. 13240616Sjimharris * 14240616Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17240616Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24240616Sjimharris * SUCH DAMAGE. 25240616Sjimharris */ 26240616Sjimharris 27240616Sjimharris#include <sys/cdefs.h> 28240616Sjimharris__FBSDID("$FreeBSD$"); 29240616Sjimharris 30240616Sjimharris#include "nvme_private.h" 31240616Sjimharris 32240616Sjimharrisvoid 33240616Sjimharrisnvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr, void *payload, 34240616Sjimharris nvme_cb_fn_t cb_fn, void *cb_arg) 35240616Sjimharris{ 36241659Sjimharris struct nvme_request *req; 37240616Sjimharris struct nvme_command *cmd; 38240616Sjimharris 39248913Sjimharris req = nvme_allocate_request_vaddr(payload, 40241659Sjimharris sizeof(struct nvme_controller_data), cb_fn, cb_arg); 41240616Sjimharris 42241659Sjimharris cmd = &req->cmd; 43240616Sjimharris cmd->opc = NVME_OPC_IDENTIFY; 44240616Sjimharris 45240616Sjimharris /* 46240616Sjimharris * TODO: create an identify command data structure, which 47240616Sjimharris * includes this CNS bit in cdw10. 48240616Sjimharris */ 49240616Sjimharris cmd->cdw10 = 1; 50240616Sjimharris 51241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 52240616Sjimharris} 53240616Sjimharris 54240616Sjimharrisvoid 55240616Sjimharrisnvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr, uint16_t nsid, 56240616Sjimharris void *payload, nvme_cb_fn_t cb_fn, void *cb_arg) 57240616Sjimharris{ 58241659Sjimharris struct nvme_request *req; 59240616Sjimharris struct nvme_command *cmd; 60240616Sjimharris 61248913Sjimharris req = nvme_allocate_request_vaddr(payload, 62241659Sjimharris sizeof(struct nvme_namespace_data), cb_fn, cb_arg); 63240616Sjimharris 64241659Sjimharris cmd = &req->cmd; 65240616Sjimharris cmd->opc = NVME_OPC_IDENTIFY; 66240616Sjimharris 67240616Sjimharris /* 68240616Sjimharris * TODO: create an identify command data structure 69240616Sjimharris */ 70240616Sjimharris cmd->nsid = nsid; 71240616Sjimharris 72241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 73240616Sjimharris} 74240616Sjimharris 75240616Sjimharrisvoid 76240616Sjimharrisnvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr, 77240616Sjimharris struct nvme_qpair *io_que, uint16_t vector, nvme_cb_fn_t cb_fn, 78240616Sjimharris void *cb_arg) 79240616Sjimharris{ 80241659Sjimharris struct nvme_request *req; 81240616Sjimharris struct nvme_command *cmd; 82240616Sjimharris 83248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 84240616Sjimharris 85241659Sjimharris cmd = &req->cmd; 86240616Sjimharris cmd->opc = NVME_OPC_CREATE_IO_CQ; 87240616Sjimharris 88240616Sjimharris /* 89240616Sjimharris * TODO: create a create io completion queue command data 90240616Sjimharris * structure. 91240616Sjimharris */ 92240616Sjimharris cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id; 93240616Sjimharris /* 0x3 = interrupts enabled | physically contiguous */ 94240616Sjimharris cmd->cdw11 = (vector << 16) | 0x3; 95240616Sjimharris cmd->prp1 = io_que->cpl_bus_addr; 96240616Sjimharris 97241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 98240616Sjimharris} 99240616Sjimharris 100240616Sjimharrisvoid 101240616Sjimharrisnvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr, 102240616Sjimharris struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 103240616Sjimharris{ 104241659Sjimharris struct nvme_request *req; 105240616Sjimharris struct nvme_command *cmd; 106240616Sjimharris 107248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 108240616Sjimharris 109241659Sjimharris cmd = &req->cmd; 110240616Sjimharris cmd->opc = NVME_OPC_CREATE_IO_SQ; 111240616Sjimharris 112240616Sjimharris /* 113240616Sjimharris * TODO: create a create io submission queue command data 114240616Sjimharris * structure. 115240616Sjimharris */ 116240616Sjimharris cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id; 117240616Sjimharris /* 0x1 = physically contiguous */ 118240616Sjimharris cmd->cdw11 = (io_que->id << 16) | 0x1; 119240616Sjimharris cmd->prp1 = io_que->cmd_bus_addr; 120240616Sjimharris 121241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 122240616Sjimharris} 123240616Sjimharris 124240616Sjimharrisvoid 125240616Sjimharrisnvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr, 126240616Sjimharris struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 127240616Sjimharris{ 128241659Sjimharris struct nvme_request *req; 129240616Sjimharris struct nvme_command *cmd; 130240616Sjimharris 131248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 132240616Sjimharris 133241659Sjimharris cmd = &req->cmd; 134240616Sjimharris cmd->opc = NVME_OPC_DELETE_IO_CQ; 135240616Sjimharris 136240616Sjimharris /* 137240616Sjimharris * TODO: create a delete io completion queue command data 138240616Sjimharris * structure. 139240616Sjimharris */ 140240616Sjimharris cmd->cdw10 = io_que->id; 141240616Sjimharris 142241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 143240616Sjimharris} 144240616Sjimharris 145240616Sjimharrisvoid 146240616Sjimharrisnvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr, 147240616Sjimharris struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg) 148240616Sjimharris{ 149241659Sjimharris struct nvme_request *req; 150240616Sjimharris struct nvme_command *cmd; 151240616Sjimharris 152248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 153240616Sjimharris 154241659Sjimharris cmd = &req->cmd; 155240616Sjimharris cmd->opc = NVME_OPC_DELETE_IO_SQ; 156240616Sjimharris 157240616Sjimharris /* 158240616Sjimharris * TODO: create a delete io submission queue command data 159240616Sjimharris * structure. 160240616Sjimharris */ 161240616Sjimharris cmd->cdw10 = io_que->id; 162240616Sjimharris 163241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 164240616Sjimharris} 165240616Sjimharris 166240616Sjimharrisvoid 167240616Sjimharrisnvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature, 168240616Sjimharris uint32_t cdw11, void *payload, uint32_t payload_size, 169240616Sjimharris nvme_cb_fn_t cb_fn, void *cb_arg) 170240616Sjimharris{ 171241659Sjimharris struct nvme_request *req; 172240616Sjimharris struct nvme_command *cmd; 173240616Sjimharris 174248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 175240616Sjimharris 176241659Sjimharris cmd = &req->cmd; 177240616Sjimharris cmd->opc = NVME_OPC_SET_FEATURES; 178240616Sjimharris cmd->cdw10 = feature; 179240616Sjimharris cmd->cdw11 = cdw11; 180240616Sjimharris 181241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 182240616Sjimharris} 183240616Sjimharris 184240616Sjimharrisvoid 185240616Sjimharrisnvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature, 186240616Sjimharris uint32_t cdw11, void *payload, uint32_t payload_size, 187240616Sjimharris nvme_cb_fn_t cb_fn, void *cb_arg) 188240616Sjimharris{ 189241659Sjimharris struct nvme_request *req; 190240616Sjimharris struct nvme_command *cmd; 191240616Sjimharris 192248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 193240616Sjimharris 194241659Sjimharris cmd = &req->cmd; 195240616Sjimharris cmd->opc = NVME_OPC_GET_FEATURES; 196240616Sjimharris cmd->cdw10 = feature; 197240616Sjimharris cmd->cdw11 = cdw11; 198240616Sjimharris 199241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 200240616Sjimharris} 201240616Sjimharris 202240616Sjimharrisvoid 203240616Sjimharrisnvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr, 204240616Sjimharris uint32_t num_queues, nvme_cb_fn_t cb_fn, void *cb_arg) 205240616Sjimharris{ 206240616Sjimharris uint32_t cdw11; 207240616Sjimharris 208267620Sjimharris cdw11 = ((num_queues - 1) << 16) | (num_queues - 1); 209240616Sjimharris nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES, cdw11, 210240616Sjimharris NULL, 0, cb_fn, cb_arg); 211240616Sjimharris} 212240616Sjimharris 213240616Sjimharrisvoid 214248737Sjimharrisnvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr, 215240616Sjimharris union nvme_critical_warning_state state, nvme_cb_fn_t cb_fn, 216240616Sjimharris void *cb_arg) 217240616Sjimharris{ 218240616Sjimharris uint32_t cdw11; 219240616Sjimharris 220240616Sjimharris cdw11 = state.raw; 221240616Sjimharris nvme_ctrlr_cmd_set_feature(ctrlr, 222248737Sjimharris NVME_FEAT_ASYNC_EVENT_CONFIGURATION, cdw11, NULL, 0, cb_fn, 223240616Sjimharris cb_arg); 224240616Sjimharris} 225240616Sjimharris 226240616Sjimharrisvoid 227240616Sjimharrisnvme_ctrlr_cmd_set_interrupt_coalescing(struct nvme_controller *ctrlr, 228240616Sjimharris uint32_t microseconds, uint32_t threshold, nvme_cb_fn_t cb_fn, void *cb_arg) 229240616Sjimharris{ 230240616Sjimharris uint32_t cdw11; 231240616Sjimharris 232240616Sjimharris if ((microseconds/100) >= 0x100) { 233248773Sjimharris nvme_printf(ctrlr, "invalid coal time %d, disabling\n", 234248773Sjimharris microseconds); 235240616Sjimharris microseconds = 0; 236240616Sjimharris threshold = 0; 237240616Sjimharris } 238240616Sjimharris 239240616Sjimharris if (threshold >= 0x100) { 240248773Sjimharris nvme_printf(ctrlr, "invalid threshold %d, disabling\n", 241248773Sjimharris threshold); 242240616Sjimharris threshold = 0; 243240616Sjimharris microseconds = 0; 244240616Sjimharris } 245240616Sjimharris 246240616Sjimharris cdw11 = ((microseconds/100) << 8) | threshold; 247240616Sjimharris nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_INTERRUPT_COALESCING, cdw11, 248240616Sjimharris NULL, 0, cb_fn, cb_arg); 249240616Sjimharris} 250240616Sjimharris 251240616Sjimharrisvoid 252248740Sjimharrisnvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr, uint8_t log_page, 253248740Sjimharris uint32_t nsid, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, 254248740Sjimharris void *cb_arg) 255240616Sjimharris{ 256241659Sjimharris struct nvme_request *req; 257240616Sjimharris struct nvme_command *cmd; 258240616Sjimharris 259248913Sjimharris req = nvme_allocate_request_vaddr(payload, payload_size, cb_fn, cb_arg); 260240616Sjimharris 261241659Sjimharris cmd = &req->cmd; 262240616Sjimharris cmd->opc = NVME_OPC_GET_LOG_PAGE; 263240616Sjimharris cmd->nsid = nsid; 264248740Sjimharris cmd->cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; 265248740Sjimharris cmd->cdw10 |= log_page; 266240616Sjimharris 267241660Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 268240616Sjimharris} 269248732Sjimharris 270248757Sjimharrisvoid 271248757Sjimharrisnvme_ctrlr_cmd_get_error_page(struct nvme_controller *ctrlr, 272248757Sjimharris struct nvme_error_information_entry *payload, uint32_t num_entries, 273248757Sjimharris nvme_cb_fn_t cb_fn, void *cb_arg) 274248757Sjimharris{ 275248740Sjimharris 276248757Sjimharris KASSERT(num_entries > 0, ("%s called with num_entries==0\n", __func__)); 277248757Sjimharris 278248757Sjimharris /* Controller's error log page entries is 0-based. */ 279248773Sjimharris KASSERT(num_entries <= (ctrlr->cdata.elpe + 1), 280248773Sjimharris ("%s called with num_entries=%d but (elpe+1)=%d\n", __func__, 281248773Sjimharris num_entries, ctrlr->cdata.elpe + 1)); 282248773Sjimharris 283248773Sjimharris if (num_entries > (ctrlr->cdata.elpe + 1)) 284248757Sjimharris num_entries = ctrlr->cdata.elpe + 1; 285248757Sjimharris 286248757Sjimharris nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_ERROR, 287248757Sjimharris NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload) * num_entries, 288248757Sjimharris cb_fn, cb_arg); 289248757Sjimharris} 290248757Sjimharris 291248732Sjimharrisvoid 292248740Sjimharrisnvme_ctrlr_cmd_get_health_information_page(struct nvme_controller *ctrlr, 293248740Sjimharris uint32_t nsid, struct nvme_health_information_page *payload, 294248740Sjimharris nvme_cb_fn_t cb_fn, void *cb_arg) 295248740Sjimharris{ 296248740Sjimharris 297248740Sjimharris nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_HEALTH_INFORMATION, 298248740Sjimharris nsid, payload, sizeof(*payload), cb_fn, cb_arg); 299248740Sjimharris} 300248740Sjimharris 301248740Sjimharrisvoid 302248758Sjimharrisnvme_ctrlr_cmd_get_firmware_page(struct nvme_controller *ctrlr, 303248758Sjimharris struct nvme_firmware_page *payload, nvme_cb_fn_t cb_fn, void *cb_arg) 304248758Sjimharris{ 305248758Sjimharris 306248758Sjimharris nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_FIRMWARE_SLOT, 307248758Sjimharris NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload), cb_fn, 308248758Sjimharris cb_arg); 309248758Sjimharris} 310248758Sjimharris 311248758Sjimharrisvoid 312248732Sjimharrisnvme_ctrlr_cmd_abort(struct nvme_controller *ctrlr, uint16_t cid, 313248732Sjimharris uint16_t sqid, nvme_cb_fn_t cb_fn, void *cb_arg) 314248732Sjimharris{ 315248732Sjimharris struct nvme_request *req; 316248732Sjimharris struct nvme_command *cmd; 317248732Sjimharris 318248913Sjimharris req = nvme_allocate_request_null(cb_fn, cb_arg); 319248732Sjimharris 320248732Sjimharris cmd = &req->cmd; 321248732Sjimharris cmd->opc = NVME_OPC_ABORT; 322248732Sjimharris cmd->cdw10 = (cid << 16) | sqid; 323248732Sjimharris 324248732Sjimharris nvme_ctrlr_submit_admin_request(ctrlr, req); 325248732Sjimharris} 326