// SPDX-License-Identifier: GPL-2.0/* * NVMe admin command implementation. * Copyright (c) 2015-2016 HGST, a Western Digital Company. */#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt#include <linux/module.h>#include <linux/rculist.h>#include <linux/part_stat.h> #include <generated/utsrelease.h>#include <linux/unaligned.h>#include "nvmet.h" static void nvmet_execute_delete_sq(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 sqid = le16_to_cpu(req->cmd->delete_queue.qid); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } if (!sqid) { status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = nvmet_check_sqid(ctrl, sqid, false); if (status != NVME_SC_SUCCESS) goto complete; status = ctrl->ops->delete_sq(ctrl, sqid); complete: nvmet_req_complete(req, status);} static void nvmet_execute_create_sq(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_command *cmd = req->cmd; u16 sqid = le16_to_cpu(cmd->create_sq.sqid); u16 cqid = le16_to_cpu(cmd->create_sq.cqid); u16 sq_flags = le16_to_cpu(cmd->create_sq.sq_flags); u16 qsize = le16_to_cpu(cmd->create_sq.qsize); u64 prp1 = le64_to_cpu(cmd->create_sq.prp1); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } if (!sqid) { status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = nvmet_check_sqid(ctrl, sqid, true); if (status != NVME_SC_SUCCESS) goto complete; status = nvmet_check_io_cqid(ctrl, cqid, false); if (status != NVME_SC_SUCCESS) { pr_err("SQ %u: Invalid CQID %u\n", sqid, cqid); goto complete; } if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) { status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->create_sq(ctrl, sqid, cqid, sq_flags, qsize, prp1); complete: nvmet_req_complete(req, status);} static void nvmet_execute_delete_cq(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 cqid = le16_to_cpu(req->cmd->delete_queue.qid); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } status = nvmet_check_io_cqid(ctrl, cqid, false); if (status != NVME_SC_SUCCESS) goto complete; if (!ctrl->cqs[cqid] || nvmet_cq_in_use(ctrl->cqs[cqid])) { /* Some SQs are still using this CQ */ status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->delete_cq(ctrl, cqid); complete: nvmet_req_complete(req, status);} static void nvmet_execute_create_cq(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_command *cmd = req->cmd; u16 cqid = le16_to_cpu(cmd->create_cq.cqid); u16 cq_flags = le16_to_cpu(cmd->create_cq.cq_flags); u16 qsize = le16_to_cpu(cmd->create_cq.qsize); u16 irq_vector = le16_to_cpu(cmd->create_cq.irq_vector); u64 prp1 = le64_to_cpu(cmd->create_cq.prp1); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } status = nvmet_check_io_cqid(ctrl, cqid, true); if (status != NVME_SC_SUCCESS) goto complete; if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) { status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->create_cq(ctrl, cqid, cq_flags, qsize, prp1, irq_vector); complete: nvmet_req_complete(req, status);} u32 nvmet_get_log_page_len(struct nvme_command *cmd){ u32 len = le16_to_cpu(cmd->get_log_page.numdu); len <<= 16; len += le16_to_cpu(cmd->get_log_page.numdl); /* NUMD is a 0's based value */ len += 1; len *= sizeof(u32); return len;} static u32 nvmet_feat_data_len(struct nvmet_req *req, u32 cdw10){ switch (cdw10 & 0xff) { case NVME_FEAT_HOST_ID: return sizeof(req->sq->ctrl->hostid); default: return 0; }} u64 nvmet_get_log_page_offset(struct nvme_command *cmd){ return le64_to_cpu(cmd->get_log_page.lpo);} static void nvmet_execute_get_log_page_noop(struct nvmet_req *req){ nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->transfer_len));} static void nvmet_execute_get_log_page_error(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; unsigned long flags; off_t offset = 0; u64 slot; u64 i; spin_lock_irqsave(&ctrl->error_lock, flags); slot = ctrl->err_counter % NVMET_ERROR_LOG_SLOTS; for (i = 0; i < NVMET_ERROR_LOG_SLOTS; i++) { if (nvmet_copy_to_sgl(req, offset, &ctrl->slots[slot], sizeof(struct nvme_error_slot))) break; if (slot == 0) slot = NVMET_ERROR_LOG_SLOTS - 1; else slot--; offset += sizeof(struct nvme_error_slot); } spin_unlock_irqrestore(&ctrl->error_lock, flags); nvmet_req_complete(req, 0);} static void nvmet_execute_get_supported_log_pages(struct nvmet_req *req){ struct nvme_supported_log *logs; u16 status; logs = kzalloc_obj(*logs); if (!logs) { status = NVME_SC_INTERNAL; goto out; } logs->lids[NVME_LOG_SUPPORTED] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ERROR] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_SMART] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_FW_SLOT] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_CHANGED_NS] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_CMD_EFFECTS] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ENDURANCE_GROUP] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ANA] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_FEATURES] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_RMI] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_RESERVATION] = cpu_to_le32(NVME_LIDS_LSUPP); status = nvmet_copy_to_sgl(req, 0, logs, sizeof(*logs)); kfree(logs);out: nvmet_req_complete(req, status);} static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, struct nvme_smart_log *slog){ u64 host_reads, host_writes, data_units_read, data_units_written; u16 status; status = nvmet_req_find_ns(req); if (status) return status; /* we don't have the right data for file backed ns */ if (!req->ns->bdev) return NVME_SC_SUCCESS; host_reads = part_stat_read(req->ns->bdev, ios[READ]); data_units_read = DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000); host_writes = part_stat_read(req->ns->bdev, ios[WRITE]); data_units_written = DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000); put_unaligned_le64(host_reads, &slog->host_reads[0]); put_unaligned_le64(data_units_read, &slog->data_units_read[0]); put_unaligned_le64(host_writes, &slog->host_writes[0]); put_unaligned_le64(data_units_written, &slog->data_units_written[0]); return NVME_SC_SUCCESS;} static u16 nvmet_get_smart_log_all(struct nvmet_req *req, struct nvme_smart_log *slog){ u64 host_reads = 0, host_writes = 0; u64 data_units_read = 0, data_units_written = 0; struct nvmet_ns *ns; struct nvmet_ctrl *ctrl; unsigned long idx; ctrl = req->sq->ctrl; nvmet_for_each_enabled_ns(&ctrl->subsys->namespaces, idx, ns) { /* we don't have the right data for file backed ns */ if (!ns->bdev) continue; host_reads += part_stat_read(ns->bdev, ios[READ]); data_units_read += DIV_ROUND_UP( part_stat_read(ns->bdev, sectors[READ]), 1000); host_writes += part_stat_read(ns->bdev, ios[WRITE]); data_units_written += DIV_ROUND_UP( part_stat_read(ns->bdev, sectors[WRITE]), 1000); } put_unaligned_le64(host_reads, &slog->host_reads[0]); put_unaligned_le64(data_units_read, &slog->data_units_read[0]); put_unaligned_le64(host_writes, &slog->host_writes[0]); put_unaligned_le64(data_units_written, &slog->data_units_written[0]); return NVME_SC_SUCCESS;} static void nvmet_execute_get_log_page_rmi(struct nvmet_req *req){ struct nvme_rotational_media_log *log; struct gendisk *disk; u16 status; req->cmd->common.nsid = cpu_to_le32(le16_to_cpu( req->cmd->get_log_page.lsi)); status = nvmet_req_find_ns(req); if (status) goto out; if (!req->ns->bdev || !bdev_rot(req->ns->bdev)) { status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; goto out; } if (req->transfer_len != sizeof(*log)) { status = NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR; goto out; } log = kzalloc_obj(*log); if (!log) { status = NVME_SC_INTERNAL; goto out; } log->endgid = req->cmd->get_log_page.lsi; disk = req->ns->bdev->bd_disk; if (disk && disk->ia_ranges) log->numa = cpu_to_le16(disk->ia_ranges->nr_ia_ranges); else log->numa = cpu_to_le16(1); status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); kfree(log);out: nvmet_req_complete(req, status);} static void nvmet_execute_get_log_page_smart(struct nvmet_req *req){ struct nvme_smart_log *log; u16 status = NVME_SC_INTERNAL; unsigned long flags; if (req->transfer_len != sizeof(*log)) goto out; log = kzalloc_obj(*log); if (!log) goto out; if (req->cmd->get_log_page.nsid == cpu_to_le32(NVME_NSID_ALL)) status = nvmet_get_smart_log_all(req, log); else status = nvmet_get_smart_log_nsid(req, log); if (status) goto out_free_log; spin_lock_irqsave(&req->sq->ctrl->error_lock, flags); put_unaligned_le64(req->sq->ctrl->err_counter, &log->num_err_log_entries); spin_unlock_irqrestore(&req->sq->ctrl->error_lock, flags); status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));out_free_log: kfree(log);out: nvmet_req_complete(req, status);} static void nvmet_get_cmd_effects_admin(struct nvmet_ctrl *ctrl, struct nvme_effects_log *log){ /* For a PCI target controller, advertize support for the . */ if (nvmet_is_pci_ctrl(ctrl)) { log->acs[nvme_admin_delete_sq] = log->acs[nvme_admin_create_sq] = log->acs[nvme_admin_delete_cq] = log->acs[nvme_admin_create_cq] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); } log->acs[nvme_admin_get_log_page] = log->acs[nvme_admin_identify] = log->acs[nvme_admin_abort_cmd] = log->acs[nvme_admin_set_features] = log->acs[nvme_admin_get_features] = log->acs[nvme_admin_async_event] = log->acs[nvme_admin_keep_alive] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP);} static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log){ log->iocs[nvme_cmd_read] = log->iocs[nvme_cmd_flush] = log->iocs[nvme_cmd_dsm] = log->iocs[nvme_cmd_resv_acquire] = log->iocs[nvme_cmd_resv_register] = log->iocs[nvme_cmd_resv_release] = log->iocs[nvme_cmd_resv_report] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); log->iocs[nvme_cmd_write] = log->iocs[nvme_cmd_write_zeroes] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC);} static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log){ log->iocs[nvme_cmd_zone_append] = log->iocs[nvme_cmd_zone_mgmt_send] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC); log->iocs[nvme_cmd_zone_mgmt_recv] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP);} static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_effects_log *log; u16 status = NVME_SC_SUCCESS; log = kzalloc_obj(*log); if (!log) { status = NVME_SC_INTERNAL; goto out; } switch (req->cmd->get_log_page.csi) { case NVME_CSI_NVM: nvmet_get_cmd_effects_admin(ctrl, log); nvmet_get_cmd_effects_nvm(log); break; case NVME_CSI_ZNS: if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) { status = NVME_SC_INVALID_IO_CMD_SET; goto free; } nvmet_get_cmd_effects_admin(ctrl, log); nvmet_get_cmd_effects_nvm(log); nvmet_get_cmd_effects_zns(log); break; default: status = NVME_SC_INVALID_LOG_PAGE; goto free; } status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log));free: kfree(log);out: nvmet_req_complete(req, status);} static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req){ struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 status = NVME_SC_INTERNAL; size_t len; if (req->transfer_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32)) goto out; mutex_lock(&ctrl->lock); if (ctrl->nr_changed_ns == U32_MAX) len = sizeof(__le32); else len = ctrl->nr_changed_ns * sizeof(__le32); status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len); if (!status) status = nvmet_zero_sgl(req, len, req->transfer_len - len); ctrl->nr_changed_ns = 0; nvmet_clear_aen_bit(req, NVME_AEN_BIT_NS_ATTR); mutex_unlock(&ctrl->lock);out: nvmet_req_complete(req, status);} static u32 nvmet_format_ana_group(struct nvmet_req *req, u32 grpid, struct nvme_ana_group_desc *desc){ struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvmet_ns *ns; unsigned long idx; u32 count = 0; if (!(req->cmd->get_log_page.lsp & NVME_ANA_LOG_RGO)) { nvmet_for_each_enabled_ns(&ctrl->subsys->namespaces, idx, ns) { if (ns->anagrpid == grpid) desc->nsids[count++] = cpu_to_le32(ns->nsid); } } desc->grpid = cpu_to_le32(grpid); desc->nnsids = cpu_to_le32(count); desc->chgcnt = cpu_to_le64(nvmet_ana_chgcnt); desc->state = req->port->ana_state[grpid]; memset(desc->rsvd17, 0, sizeof(desc->rsvd17)); return struct_size(desc, nsids, count);} static void nvmet_execute_get_log_page_endgrp(struct nvmet_req *req){ u64 host_reads, host_writes, data_units_read, data_units_written; struct nvme_endurance_group_log *log; u16 status; /* * The target driver emulates each endurance group as its ownLines 1–500 of 1691. Load more
// SPDX-License-Identifier: GPL-2.0 /* * NVMe admin command implementation. * Copyright (c) 2015-2016 HGST, a Western Digital Company. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/rculist.h> #include <linux/part_stat.h> #include <generated/utsrelease.h> #include <linux/unaligned.h> #include "nvmet.h" static void nvmet_execute_delete_sq(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 sqid = le16_to_cpu(req->cmd->delete_queue.qid); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } if (!sqid) { status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = nvmet_check_sqid(ctrl, sqid, false); if (status != NVME_SC_SUCCESS) goto complete; status = ctrl->ops->delete_sq(ctrl, sqid); complete: nvmet_req_complete(req, status); } static void nvmet_execute_create_sq(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_command *cmd = req->cmd; u16 sqid = le16_to_cpu(cmd->create_sq.sqid); u16 cqid = le16_to_cpu(cmd->create_sq.cqid); u16 sq_flags = le16_to_cpu(cmd->create_sq.sq_flags); u16 qsize = le16_to_cpu(cmd->create_sq.qsize); u64 prp1 = le64_to_cpu(cmd->create_sq.prp1); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } if (!sqid) { status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = nvmet_check_sqid(ctrl, sqid, true); if (status != NVME_SC_SUCCESS) goto complete; status = nvmet_check_io_cqid(ctrl, cqid, false); if (status != NVME_SC_SUCCESS) { pr_err("SQ %u: Invalid CQID %u\n", sqid, cqid); goto complete; } if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) { status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->create_sq(ctrl, sqid, cqid, sq_flags, qsize, prp1); complete: nvmet_req_complete(req, status); } static void nvmet_execute_delete_cq(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 cqid = le16_to_cpu(req->cmd->delete_queue.qid); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } status = nvmet_check_io_cqid(ctrl, cqid, false); if (status != NVME_SC_SUCCESS) goto complete; if (!ctrl->cqs[cqid] || nvmet_cq_in_use(ctrl->cqs[cqid])) { /* Some SQs are still using this CQ */ status = NVME_SC_QID_INVALID | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->delete_cq(ctrl, cqid); complete: nvmet_req_complete(req, status); } static void nvmet_execute_create_cq(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_command *cmd = req->cmd; u16 cqid = le16_to_cpu(cmd->create_cq.cqid); u16 cq_flags = le16_to_cpu(cmd->create_cq.cq_flags); u16 qsize = le16_to_cpu(cmd->create_cq.qsize); u16 irq_vector = le16_to_cpu(cmd->create_cq.irq_vector); u64 prp1 = le64_to_cpu(cmd->create_cq.prp1); u16 status; if (!nvmet_is_pci_ctrl(ctrl)) { status = nvmet_report_invalid_opcode(req); goto complete; } status = nvmet_check_io_cqid(ctrl, cqid, true); if (status != NVME_SC_SUCCESS) goto complete; if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) { status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR; goto complete; } status = ctrl->ops->create_cq(ctrl, cqid, cq_flags, qsize, prp1, irq_vector); complete: nvmet_req_complete(req, status); } u32 nvmet_get_log_page_len(struct nvme_command *cmd) { u32 len = le16_to_cpu(cmd->get_log_page.numdu); len <<= 16; len += le16_to_cpu(cmd->get_log_page.numdl); /* NUMD is a 0's based value */ len += 1; len *= sizeof(u32); return len; } static u32 nvmet_feat_data_len(struct nvmet_req *req, u32 cdw10) { switch (cdw10 & 0xff) { case NVME_FEAT_HOST_ID: return sizeof(req->sq->ctrl->hostid); default: return 0; } } u64 nvmet_get_log_page_offset(struct nvme_command *cmd) { return le64_to_cpu(cmd->get_log_page.lpo); } static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) { nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->transfer_len)); } static void nvmet_execute_get_log_page_error(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; unsigned long flags; off_t offset = 0; u64 slot; u64 i; spin_lock_irqsave(&ctrl->error_lock, flags); slot = ctrl->err_counter % NVMET_ERROR_LOG_SLOTS; for (i = 0; i < NVMET_ERROR_LOG_SLOTS; i++) { if (nvmet_copy_to_sgl(req, offset, &ctrl->slots[slot], sizeof(struct nvme_error_slot))) break; if (slot == 0) slot = NVMET_ERROR_LOG_SLOTS - 1; else slot--; offset += sizeof(struct nvme_error_slot); } spin_unlock_irqrestore(&ctrl->error_lock, flags); nvmet_req_complete(req, 0); } static void nvmet_execute_get_supported_log_pages(struct nvmet_req *req) { struct nvme_supported_log *logs; u16 status; logs = kzalloc_obj(*logs); if (!logs) { status = NVME_SC_INTERNAL; goto out; } logs->lids[NVME_LOG_SUPPORTED] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ERROR] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_SMART] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_FW_SLOT] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_CHANGED_NS] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_CMD_EFFECTS] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ENDURANCE_GROUP] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_ANA] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_FEATURES] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_RMI] = cpu_to_le32(NVME_LIDS_LSUPP); logs->lids[NVME_LOG_RESERVATION] = cpu_to_le32(NVME_LIDS_LSUPP); status = nvmet_copy_to_sgl(req, 0, logs, sizeof(*logs)); kfree(logs); out: nvmet_req_complete(req, status); } static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, struct nvme_smart_log *slog) { u64 host_reads, host_writes, data_units_read, data_units_written; u16 status; status = nvmet_req_find_ns(req); if (status) return status; /* we don't have the right data for file backed ns */ if (!req->ns->bdev) return NVME_SC_SUCCESS; host_reads = part_stat_read(req->ns->bdev, ios[READ]); data_units_read = DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000); host_writes = part_stat_read(req->ns->bdev, ios[WRITE]); data_units_written = DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000); put_unaligned_le64(host_reads, &slog->host_reads[0]); put_unaligned_le64(data_units_read, &slog->data_units_read[0]); put_unaligned_le64(host_writes, &slog->host_writes[0]); put_unaligned_le64(data_units_written, &slog->data_units_written[0]); return NVME_SC_SUCCESS; } static u16 nvmet_get_smart_log_all(struct nvmet_req *req, struct nvme_smart_log *slog) { u64 host_reads = 0, host_writes = 0; u64 data_units_read = 0, data_units_written = 0; struct nvmet_ns *ns; struct nvmet_ctrl *ctrl; unsigned long idx; ctrl = req->sq->ctrl; nvmet_for_each_enabled_ns(&ctrl->subsys->namespaces, idx, ns) { /* we don't have the right data for file backed ns */ if (!ns->bdev) continue; host_reads += part_stat_read(ns->bdev, ios[READ]); data_units_read += DIV_ROUND_UP( part_stat_read(ns->bdev, sectors[READ]), 1000); host_writes += part_stat_read(ns->bdev, ios[WRITE]); data_units_written += DIV_ROUND_UP( part_stat_read(ns->bdev, sectors[WRITE]), 1000); } put_unaligned_le64(host_reads, &slog->host_reads[0]); put_unaligned_le64(data_units_read, &slog->data_units_read[0]); put_unaligned_le64(host_writes, &slog->host_writes[0]); put_unaligned_le64(data_units_written, &slog->data_units_written[0]); return NVME_SC_SUCCESS; } static void nvmet_execute_get_log_page_rmi(struct nvmet_req *req) { struct nvme_rotational_media_log *log; struct gendisk *disk; u16 status; req->cmd->common.nsid = cpu_to_le32(le16_to_cpu( req->cmd->get_log_page.lsi)); status = nvmet_req_find_ns(req); if (status) goto out; if (!req->ns->bdev || !bdev_rot(req->ns->bdev)) { status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; goto out; } if (req->transfer_len != sizeof(*log)) { status = NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR; goto out; } log = kzalloc_obj(*log); if (!log) { status = NVME_SC_INTERNAL; goto out; } log->endgid = req->cmd->get_log_page.lsi; disk = req->ns->bdev->bd_disk; if (disk && disk->ia_ranges) log->numa = cpu_to_le16(disk->ia_ranges->nr_ia_ranges); else log->numa = cpu_to_le16(1); status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); kfree(log); out: nvmet_req_complete(req, status); } static void nvmet_execute_get_log_page_smart(struct nvmet_req *req) { struct nvme_smart_log *log; u16 status = NVME_SC_INTERNAL; unsigned long flags; if (req->transfer_len != sizeof(*log)) goto out; log = kzalloc_obj(*log); if (!log) goto out; if (req->cmd->get_log_page.nsid == cpu_to_le32(NVME_NSID_ALL)) status = nvmet_get_smart_log_all(req, log); else status = nvmet_get_smart_log_nsid(req, log); if (status) goto out_free_log; spin_lock_irqsave(&req->sq->ctrl->error_lock, flags); put_unaligned_le64(req->sq->ctrl->err_counter, &log->num_err_log_entries); spin_unlock_irqrestore(&req->sq->ctrl->error_lock, flags); status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); out_free_log: kfree(log); out: nvmet_req_complete(req, status); } static void nvmet_get_cmd_effects_admin(struct nvmet_ctrl *ctrl, struct nvme_effects_log *log) { /* For a PCI target controller, advertize support for the . */ if (nvmet_is_pci_ctrl(ctrl)) { log->acs[nvme_admin_delete_sq] = log->acs[nvme_admin_create_sq] = log->acs[nvme_admin_delete_cq] = log->acs[nvme_admin_create_cq] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); } log->acs[nvme_admin_get_log_page] = log->acs[nvme_admin_identify] = log->acs[nvme_admin_abort_cmd] = log->acs[nvme_admin_set_features] = log->acs[nvme_admin_get_features] = log->acs[nvme_admin_async_event] = log->acs[nvme_admin_keep_alive] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); } static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log) { log->iocs[nvme_cmd_read] = log->iocs[nvme_cmd_flush] = log->iocs[nvme_cmd_dsm] = log->iocs[nvme_cmd_resv_acquire] = log->iocs[nvme_cmd_resv_register] = log->iocs[nvme_cmd_resv_release] = log->iocs[nvme_cmd_resv_report] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); log->iocs[nvme_cmd_write] = log->iocs[nvme_cmd_write_zeroes] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC); } static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log) { log->iocs[nvme_cmd_zone_append] = log->iocs[nvme_cmd_zone_mgmt_send] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC); log->iocs[nvme_cmd_zone_mgmt_recv] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); } static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_effects_log *log; u16 status = NVME_SC_SUCCESS; log = kzalloc_obj(*log); if (!log) { status = NVME_SC_INTERNAL; goto out; } switch (req->cmd->get_log_page.csi) { case NVME_CSI_NVM: nvmet_get_cmd_effects_admin(ctrl, log); nvmet_get_cmd_effects_nvm(log); break; case NVME_CSI_ZNS: if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) { status = NVME_SC_INVALID_IO_CMD_SET; goto free; } nvmet_get_cmd_effects_admin(ctrl, log); nvmet_get_cmd_effects_nvm(log); nvmet_get_cmd_effects_zns(log); break; default: status = NVME_SC_INVALID_LOG_PAGE; goto free; } status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); free: kfree(log); out: nvmet_req_complete(req, status); } static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; u16 status = NVME_SC_INTERNAL; size_t len; if (req->transfer_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32)) goto out; mutex_lock(&ctrl->lock); if (ctrl->nr_changed_ns == U32_MAX) len = sizeof(__le32); else len = ctrl->nr_changed_ns * sizeof(__le32); status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len); if (!status) status = nvmet_zero_sgl(req, len, req->transfer_len - len); ctrl->nr_changed_ns = 0; nvmet_clear_aen_bit(req, NVME_AEN_BIT_NS_ATTR); mutex_unlock(&ctrl->lock); out: nvmet_req_complete(req, status); } static u32 nvmet_format_ana_group(struct nvmet_req *req, u32 grpid, struct nvme_ana_group_desc *desc) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvmet_ns *ns; unsigned long idx; u32 count = 0; if (!(req->cmd->get_log_page.lsp & NVME_ANA_LOG_RGO)) { nvmet_for_each_enabled_ns(&ctrl->subsys->namespaces, idx, ns) { if (ns->anagrpid == grpid) desc->nsids[count++] = cpu_to_le32(ns->nsid); } } desc->grpid = cpu_to_le32(grpid); desc->nnsids = cpu_to_le32(count); desc->chgcnt = cpu_to_le64(nvmet_ana_chgcnt); desc->state = req->port->ana_state[grpid]; memset(desc->rsvd17, 0, sizeof(desc->rsvd17)); return struct_size(desc, nsids, count); } static void nvmet_execute_get_log_page_endgrp(struct nvmet_req *req) { u64 host_reads, host_writes, data_units_read, data_units_written; struct nvme_endurance_group_log *log; u16 status; /* * The target driver emulates each endurance group as its own