From patchwork Tue Nov 14 21:41:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bart Van Assche X-Patchwork-Id: 13456035 Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2490B33CFA; Tue, 14 Nov 2023 21:42:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=none Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E3B6ED8; Tue, 14 Nov 2023 13:42:16 -0800 (PST) Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-1cc7077d34aso47199625ad.2; Tue, 14 Nov 2023 13:42:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699998136; x=1700602936; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WX1GzJ5gLOwQZNnrUU/eLZl7guwHGfEvifbd2OOUV5Y=; b=dM3pniqF506phfucDnjAtecXNigT/s59xb5AxRuYN+kG8TcLe1sWpSpiIc18nTUVGA wuqigKxU+piSsBF4fra1FU7NpTZplrBmwpCWFiqRc6R0cemFCiY+vrR9Sd0R2cztSuWb WUtKrm4y1r6CAQYZMrr4wZPwndUaU8mhufaHFku2CV+30euqPJfqqIUCfxX0AruDedU3 zOzGPwPis+xJiYxB1YgojcHODWhzpE3GDjZ+GtmU7gA0wOfTx4+PaFLEZuTMYZKi1CAT 2xxUlfhI+TG8vId1o842AhtPyCdS2VuSZSIvStp0zGXgfyg4umdKThvC9+75P9zb9/NT J2lg== X-Gm-Message-State: AOJu0Yzrb4ZPNGvbVP+g2aPKt+L1JkXgm/2lIrb2d1Q+vEAV+K1re6HD cwe0bHG2iej4bUynotq+T7M= X-Google-Smtp-Source: AGHT+IEU5zdUuokXwRh32pOcoUuMPhRCwTOtPShM0n3Q3xuXruiYPGiUnfFbdUD7DHCZpGoSY1A0Ag== X-Received: by 2002:a17:902:968e:b0:1cc:3fc9:1802 with SMTP id n14-20020a170902968e00b001cc3fc91802mr3621526plp.61.1699998136284; Tue, 14 Nov 2023 13:42:16 -0800 (PST) Received: from bvanassche-linux.mtv.corp.google.com ([2620:0:1000:8411:2278:ad72:cefb:4d49]) by smtp.gmail.com with ESMTPSA id o16-20020a170902d4d000b001c3267ae317sm6133926plg.165.2023.11.14.13.42.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Nov 2023 13:42:15 -0800 (PST) From: Bart Van Assche To: "Martin K . Petersen" Cc: linux-scsi@vger.kernel.org, linux-block@vger.kernel.org, linux-fsdevel@vger.kernel.org, Jens Axboe , Christoph Hellwig , Daejun Park , Kanchan Joshi , Bart Van Assche , Damien Le Moal , "James E.J. Bottomley" Subject: [PATCH v4 08/15] sd: Translate data lifetime information Date: Tue, 14 Nov 2023 13:41:03 -0800 Message-ID: <20231114214132.1486867-9-bvanassche@acm.org> X-Mailer: git-send-email 2.43.0.rc0.421.g78406f8d94-goog In-Reply-To: <20231114214132.1486867-1-bvanassche@acm.org> References: <20231114214132.1486867-1-bvanassche@acm.org> Precedence: bulk X-Mailing-List: linux-block@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Recently T10 standardized SBC constrained streams. This mechanism allows to pass data lifetime information to SCSI devices in the group number field. Add support for translating write hint information into a permanent stream number in the sd driver. Use WRITE(10) instead of WRITE(6) if data lifetime information is present because the WRITE(6) command does not have a GROUP NUMBER field. Cc: Martin K. Petersen Cc: Christoph Hellwig Cc: Damien Le Moal Signed-off-by: Bart Van Assche --- drivers/scsi/sd.c | 98 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/scsi/sd.h | 2 + 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 56c4310a741b..61a59f9168bc 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -1080,12 +1081,38 @@ static blk_status_t sd_setup_flush_cmnd(struct scsi_cmnd *cmd) return BLK_STS_OK; } +/** + * sd_group_number() - Compute the GROUP NUMBER field + * @cmd: SCSI command for which to compute the value of the six-bit GROUP NUMBER + * field. + * + * From SBC-5 r05 (https://www.t10.org/cgi-bin/ac.pl?t=f&f=sbc5r05.pdf): + * 0: no relative lifetime. + * 1: shortest relative lifetime. + * 2: second shortest relative lifetime. + * 3 - 0x3d: intermediate relative lifetimes. + * 0x3e: second longest relative lifetime. + * 0x3f: longest relative lifetime. + */ +static u8 sd_group_number(struct scsi_cmnd *cmd) +{ + const struct request *rq = scsi_cmd_to_rq(cmd); + struct scsi_disk *sdkp = scsi_disk(rq->q->disk); + + if (!sdkp->rscs) + return 0; + + return min3((u32)rq->lifetime, (u32)sdkp->permanent_stream_count, + 0x3fu); +} + static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, sector_t lba, unsigned int nr_blocks, unsigned char flags, unsigned int dld) { cmd->cmd_len = SD_EXT_CDB_SIZE; cmd->cmnd[0] = VARIABLE_LENGTH_CMD; + cmd->cmnd[6] = sd_group_number(cmd); cmd->cmnd[7] = 0x18; /* Additional CDB len */ cmd->cmnd[9] = write ? WRITE_32 : READ_32; cmd->cmnd[10] = flags; @@ -1104,7 +1131,7 @@ static blk_status_t sd_setup_rw16_cmnd(struct scsi_cmnd *cmd, bool write, cmd->cmd_len = 16; cmd->cmnd[0] = write ? WRITE_16 : READ_16; cmd->cmnd[1] = flags | ((dld >> 2) & 0x01); - cmd->cmnd[14] = (dld & 0x03) << 6; + cmd->cmnd[14] = ((dld & 0x03) << 6) | sd_group_number(cmd); cmd->cmnd[15] = 0; put_unaligned_be64(lba, &cmd->cmnd[2]); put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); @@ -1119,7 +1146,7 @@ static blk_status_t sd_setup_rw10_cmnd(struct scsi_cmnd *cmd, bool write, cmd->cmd_len = 10; cmd->cmnd[0] = write ? WRITE_10 : READ_10; cmd->cmnd[1] = flags; - cmd->cmnd[6] = 0; + cmd->cmnd[6] = sd_group_number(cmd); cmd->cmnd[9] = 0; put_unaligned_be32(lba, &cmd->cmnd[2]); put_unaligned_be16(nr_blocks, &cmd->cmnd[7]); @@ -1256,7 +1283,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, protect | fua, dld); } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || - sdp->use_10_for_rw || protect) { + sdp->use_10_for_rw || protect || rq->lifetime) { ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, protect | fua); } else { @@ -2996,6 +3023,70 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->DPOFUA = 0; } +static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned stream_id) +{ + u8 cdb[16] = { SERVICE_ACTION_IN_16, SAI_GET_STREAM_STATUS }; + struct { + struct scsi_stream_status_header h; + struct scsi_stream_status s; + } buf; + struct scsi_device *sdev = sdkp->device; + struct scsi_sense_hdr sshdr; + const struct scsi_exec_args exec_args = { + .sshdr = &sshdr, + }; + int res; + + put_unaligned_be16(stream_id, &cdb[4]); + put_unaligned_be32(sizeof(buf), &cdb[10]); + + res = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, &buf, sizeof(buf), + SD_TIMEOUT, sdkp->max_retries, &exec_args); + if (res < 0) + return false; + if (scsi_status_is_check_condition(res) && scsi_sense_valid(&sshdr)) + sd_print_sense_hdr(sdkp, &sshdr); + if (res) + return false; + if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status)) + return false; + return buf.h.stream_status[0].perm; +} + +static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) +{ + struct scsi_device *sdp = sdkp->device; + const struct scsi_io_group_descriptor *desc, *start, *end; + struct scsi_sense_hdr sshdr; + struct scsi_mode_data data; + int res; + + res = scsi_mode_sense(sdp, /*dbd=*/0x8, /*modepage=*/0x0a, + /*subpage=*/0x05, buffer, SD_BUF_SIZE, + SD_TIMEOUT, sdkp->max_retries, &data, &sshdr); + if (res < 0) + return; + start = (void *)buffer + data.header_length + 16; + end = (void *)buffer + ALIGN_DOWN(data.header_length + data.length, + sizeof(*end)); + /* + * From "SBC-5 Constrained Streams with Data Lifetimes": Device severs + * should assign the lowest numbered stream identifiers to permanent + * streams. + */ + for (desc = start; desc < end; desc++) + if (!desc->st_enble || !sd_is_perm_stream(sdkp, desc - start)) + break; + sdkp->permanent_stream_count = desc - start; + if (sdkp->rscs && sdkp->permanent_stream_count < 2) + sd_printk(KERN_INFO, sdkp, + "Unexpected: RSCS has been set and the permanent stream count is %u\n", + sdkp->permanent_stream_count); + else if (sdkp->permanent_stream_count) + sd_printk(KERN_INFO, sdkp, "permanent stream count = %d\n", + sdkp->permanent_stream_count); +} + /* * The ATO bit indicates whether the DIF application tag is available * for use by the operating system. @@ -3479,6 +3570,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); + sd_read_io_hints(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index e4539122f2a2..16cf7c543ccf 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -125,6 +125,8 @@ struct scsi_disk { unsigned int physical_block_size; unsigned int max_medium_access_timeouts; unsigned int medium_access_timed_out; + /* number of permanent streams */ + u16 permanent_stream_count; u8 media_present; u8 write_prot; u8 protection_type;/* Data Integrity Field */