@@ -1994,7 +1994,7 @@ static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
case NVME_CSI_NVM:
break;
case NVME_CSI_ZNS:
- ret = nvme_update_zone_info(disk, ns, lbaf);
+ ret = nvme_update_zone_info(disk, ns, lbaf, le64_to_cpu(id->nsze));
if (ret)
return ret;
break;
@@ -407,6 +407,7 @@ struct nvme_ns {
u32 sws;
u8 pi_type;
#ifdef CONFIG_BLK_DEV_ZONED
+ u64 nr_zones;
u64 zsze;
#endif
unsigned long features;
@@ -700,7 +701,7 @@ static inline void nvme_mpath_start_freeze(struct nvme_subsystem *subsys)
#ifdef CONFIG_BLK_DEV_ZONED
int nvme_update_zone_info(struct gendisk *disk, struct nvme_ns *ns,
- unsigned lbaf);
+ unsigned int lbaf, sector_t nsze);
int nvme_report_zones(struct gendisk *disk, sector_t sector,
unsigned int nr_zones, report_zones_cb cb, void *data);
@@ -720,7 +721,8 @@ static inline blk_status_t nvme_setup_zone_mgmt_send(struct nvme_ns *ns,
static inline int nvme_update_zone_info(struct gendisk *disk,
struct nvme_ns *ns,
- unsigned lbaf)
+ unsigned int lbaf,
+ sector_t nsze)
{
dev_warn(ns->ctrl->device,
"Please enable CONFIG_BLK_DEV_ZONED to support ZNS devices\n");
@@ -32,13 +32,36 @@ static int nvme_set_max_append(struct nvme_ctrl *ctrl)
return 0;
}
+static u64 nvme_zns_nr_zones(struct nvme_ns *ns)
+{
+ struct nvme_command c = { };
+ struct nvme_zone_report report;
+ int buflen = sizeof(struct nvme_zone_report);
+ int ret;
+
+ c.zmr.opcode = nvme_cmd_zone_mgmt_recv;
+ c.zmr.nsid = cpu_to_le32(ns->head->ns_id);
+ c.zmr.slba = cpu_to_le64(0);
+ c.zmr.numd = cpu_to_le32(nvme_bytes_to_numd(buflen));
+ c.zmr.zra = NVME_ZRA_ZONE_REPORT;
+ c.zmr.zrasf = NVME_ZRASF_ZONE_REPORT_ALL;
+ c.zmr.pr = 0;
+
+ ret = nvme_submit_sync_cmd(ns->queue, &c, &report, buflen);
+ if (ret)
+ return ret;
+
+ return le64_to_cpu(report.nr_zones);
+}
+
int nvme_update_zone_info(struct gendisk *disk, struct nvme_ns *ns,
- unsigned lbaf)
+ unsigned int lbaf, sector_t nsze)
{
struct nvme_effects_log *log = ns->head->effects;
struct request_queue *q = disk->queue;
struct nvme_command c = { };
struct nvme_id_ns_zns *id;
+ sector_t cap_nr_zones;
int status;
/* Driver requires zone append support */
@@ -80,6 +103,20 @@ int nvme_update_zone_info(struct gendisk *disk, struct nvme_ns *ns,
goto free_data;
}
+ ns->nr_zones = nvme_zns_nr_zones(ns);
+ if (!ns->nr_zones) {
+ status = -EINVAL;
+ goto free_data;
+ }
+
+ cap_nr_zones = nvme_lba_to_sect(ns, le64_to_cpu(nsze)) >> ilog2(ns->zsze);
+ if (ns->nr_zones != cap_nr_zones) {
+ dev_err(ns->ctrl->device, "inconsistent zone count: %llu/%llu\n",
+ ns->nr_zones, cap_nr_zones);
+ status = -EINVAL;
+ goto free_data;
+ }
+
q->limits.zoned = BLK_ZONED_HM;
q->zone_flags = BLK_ZONE_REP_CAPACITY | BLK_ZONE_SUP_OFFLINE;
blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);