// SPDX-License-Identifier: GPL-2.0-only /* * SCSI Zoned Block commands * * Copyright (C) 2014-2015 SUSE Linux GmbH * Written by: Hannes Reinecke <[email protected]> * Modified by: Damien Le Moal <[email protected]> * Modified by: Shaun Tancheff <[email protected]> */ #include <linux/blkdev.h> #include <linux/vmalloc.h> #include <linux/sched/mm.h> #include <linux/mutex.h> #include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include "sd.h" #define CREATE_TRACE_POINTS #include "sd_trace.h" /* Whether or not a SCSI zone descriptor describes a gap zone. */ static bool sd_zbc_is_gap_zone(const u8 buf[64]) { … } /** * sd_zbc_parse_report - Parse a SCSI zone descriptor * @sdkp: SCSI disk pointer. * @buf: SCSI zone descriptor. * @idx: Index of the zone relative to the first zone reported by the current * sd_zbc_report_zones() call. * @cb: Callback function pointer. * @data: Second argument passed to @cb. * * Return: Value returned by @cb. * * Convert a SCSI zone descriptor into struct blk_zone format. Additionally, * call @cb(blk_zone, @data). */ static int sd_zbc_parse_report(struct scsi_disk *sdkp, const u8 buf[64], unsigned int idx, report_zones_cb cb, void *data) { … } /** * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command. * @sdkp: The target disk * @buf: vmalloc-ed buffer to use for the reply * @buflen: the buffer size * @lba: Start LBA of the report * @partial: Do partial report * * For internal use during device validation. * Using partial=true can significantly speed up execution of a report zones * command because the disk does not have to count all possible report matching * zones and will only report the count of zones fitting in the command reply * buffer. */ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, unsigned int buflen, sector_t lba, bool partial) { … } /** * sd_zbc_alloc_report_buffer() - Allocate a buffer for report zones reply. * @sdkp: The target disk * @nr_zones: Maximum number of zones to report * @buflen: Size of the buffer allocated * * Try to allocate a reply buffer for the number of requested zones. * The size of the buffer allocated may be smaller than requested to * satify the device constraint (max_hw_sectors, max_segments, etc). * * Return the address of the allocated buffer and update @buflen with * the size of the allocated buffer. */ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, unsigned int nr_zones, size_t *buflen) { … } /** * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors. * @sdkp: The target disk */ static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) { … } /** * sd_zbc_report_zones - SCSI .report_zones() callback. * @disk: Disk to report zones for. * @sector: Start sector. * @nr_zones: Maximum number of zones to report. * @cb: Callback function called to report zone information. * @data: Second argument passed to @cb. * * Called by the block layer to iterate over zone information. See also the * disk->fops->report_zones() calls in block/blk-zoned.c. */ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, unsigned int nr_zones, report_zones_cb cb, void *data) { … } static blk_status_t sd_zbc_cmnd_checks(struct scsi_cmnd *cmd) { … } /** * sd_zbc_setup_zone_mgmt_cmnd - Prepare a zone ZBC_OUT command. The operations * can be RESET WRITE POINTER, OPEN, CLOSE or FINISH. * @cmd: the command to setup * @op: Operation to be performed * @all: All zones control * * Called from sd_init_command() for REQ_OP_ZONE_RESET, REQ_OP_ZONE_RESET_ALL, * REQ_OP_ZONE_OPEN, REQ_OP_ZONE_CLOSE or REQ_OP_ZONE_FINISH requests. */ blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, unsigned char op, bool all) { … } /** * sd_zbc_complete - ZBC command post processing. * @cmd: Completed command * @good_bytes: Command reply bytes * @sshdr: command sense header * * Called from sd_done() to handle zone commands errors and updates to the * device queue zone write pointer offset cahce. */ unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, struct scsi_sense_hdr *sshdr) { … } /** * sd_zbc_check_zoned_characteristics - Check zoned block device characteristics * @sdkp: Target disk * @buf: Buffer where to store the VPD page data * * Read VPD page B6, get information and check that reads are unconstrained. */ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, unsigned char *buf) { … } /** * sd_zbc_check_capacity - Check the device capacity * @sdkp: Target disk * @buf: command buffer * @zblocks: zone size in logical blocks * * Get the device zone size and check that the device capacity as reported * by READ CAPACITY matches the max_lba value (plus one) of the report zones * command reply for devices with RC_BASIS == 0. * * Returns 0 upon success or an error code upon failure. */ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf, u32 *zblocks) { … } static void sd_zbc_print_zones(struct scsi_disk *sdkp) { … } /* * Call blk_revalidate_disk_zones() if any of the zoned disk properties have * changed that make it necessary to call that function. Called by * sd_revalidate_disk() after the gendisk capacity has been set. */ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp) { … } /** * sd_zbc_read_zones - Read zone information and update the request queue * @sdkp: SCSI disk pointer. * @lim: queue limits to read into * @buf: 512 byte buffer used for storing SCSI command output. * * Read zone information and update the request queue zone characteristics and * also the zoned device information in *sdkp. Called by sd_revalidate_disk() * before the gendisk capacity has been set. */ int sd_zbc_read_zones(struct scsi_disk *sdkp, struct queue_limits *lim, u8 buf[SD_BUF_SIZE]) { … }