From patchwork Wed Apr 22 10:42:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503435 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8697014B4 for ; Wed, 22 Apr 2020 10:43:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6F0E82075A for ; Wed, 22 Apr 2020 10:43:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="RUyAqyRP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730195AbgDVKnF (ORCPT ); Wed, 22 Apr 2020 06:43:05 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22891 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731744AbgDVKmY (ORCPT ); Wed, 22 Apr 2020 06:42:24 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552145; x=1619088145; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BWdN5Uq0KmTBC91tGfCvRVgx7zK7KxpVbt9ZP24cB9I=; b=RUyAqyRP0zTSlqaeEU9Ke6G8bpKoz3jR8kmnUk84u071zEdcQTEYu8wK WHiQXMhVX1cw21RZ3ppucU6xrwsd/r3QLXXAJm+LU3NuKHH5YB7tYK9Bg gqJLtCyIm34XHlTuBoJDtVeLBGUeCQeuSz3kYPxiMHjc7PMeW1F8PY7Sw Pf8xWTPA4oiFKfGXxZzW2Mu7m1ixxfOr2LQ4shJSK1VSw4tUaUJaHMakq EVaYFq+WFEO1nhU1Led3QZUPM0V/zj4tBuemR6nHpijMJNVFh8sqQtB1E McNJnR0854XltFlKS06B+Y/53QpgdEnykqEn4wH5phLmGb3m1dhcTJtfT g==; IronPort-SDR: hNdB/WYq1Oze4rith0+Fh4NUZ+zbL5mfDCj0UdHns9kUOPLXyyXDlaUeb/ijhL/VVky1t1M1Bv Hq3qgJnoMtj1V5ezHu6c2ex2FKV+vN6DBYX3NmjHqiCXIbkcJ5FH+1oVAN0i+DROP/eIX2fE9p gMKq64Zw/2zV5emLjCbFtW1MxXKCez6UCOSTmOEItASFmTAB8lpW1BqWA+hmlrNN5nbKzUmrpN cm52hdWY0o2wh8daS5opOpFVzvH7H9xCPs08GpsbrBX+ZuInL4zmZrjbUDUIvXmCZg7wWLib6S QaM= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230018" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:24 +0800 IronPort-SDR: 8HhRIHpua1Le8tKMj67RWZZTrz1KB45Pqq0YbQ3yuomC8EMKbLdbcSfVlF6Jg2OZsnasNiSVPB FuUSS6QguuioMr290dSJqpracnPiYQ4+M= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:13 -0700 IronPort-SDR: 2oIXxnT3+eGAQApAZTsFkyH0yfHVdfhpX9AZkqDuAmVrQUrvbeYyq49Kxwx1Kw5McC8JPBj/OW 8e7AG0eePvwA== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:22 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 1/7] scsi_debug: add zbc mode and VPD pages Date: Wed, 22 Apr 2020 19:42:15 +0900 Message-Id: <20200422104221.378203-2-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Douglas Gilbert The ZBC standard "piggy-backs" on many, but not all, of the facilities in SBC. Add those ZBC mode pages (plus mode parameter block descriptors (e.g. "WP")) and VPD pages in common with SBC. Add ZBC specific VPD page for the host-managed ZBC device type (ptype=0x14). Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 55 +++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 0eede06fc66c..4aa4d9e58978 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1445,6 +1445,24 @@ static int inquiry_vpd_b2(unsigned char *arr) return 0x4; } +/* Zoned block device characteristics VPD page (ZBC mandatory) */ +static int inquiry_vpd_b6(unsigned char *arr) +{ + memset(arr, 0, 0x3c); + arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ + /* + * Set Optimal number of open sequential write preferred zones and + * Optimal number of non-sequentially written sequential write + * preferred zones and Maximum number of open sequential write + * required zones fields to 'not reported' (0xffffffff). Leave other + * fields set to zero. + */ + put_unaligned_be32(0xffffffff, &arr[4]); + put_unaligned_be32(0xffffffff, &arr[8]); + put_unaligned_be32(0xffffffff, &arr[12]); + return 0x3c; +} + #define SDEBUG_LONG_INQ_SZ 96 #define SDEBUG_MAX_INQ_ARR_SZ 584 @@ -1454,13 +1472,15 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) unsigned char *arr; unsigned char *cmd = scp->cmnd; int alloc_len, n, ret; - bool have_wlun, is_disk; + bool have_wlun, is_disk, is_zbc, is_disk_zbc; alloc_len = get_unaligned_be16(cmd + 3); arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); if (! arr) return DID_REQUEUE << 16; is_disk = (sdebug_ptype == TYPE_DISK); + is_zbc = (sdebug_ptype == TYPE_ZBC); + is_disk_zbc = (is_disk || is_zbc); have_wlun = scsi_is_wlun(scp->device->lun); if (have_wlun) pq_pdt = TYPE_WLUN; /* present, wlun */ @@ -1498,11 +1518,14 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[n++] = 0x86; /* extended inquiry */ arr[n++] = 0x87; /* mode page policy */ arr[n++] = 0x88; /* SCSI ports */ - if (is_disk) { /* SBC only */ + if (is_disk_zbc) { /* SBC or ZBC */ arr[n++] = 0x89; /* ATA information */ arr[n++] = 0xb0; /* Block limits */ arr[n++] = 0xb1; /* Block characteristics */ - arr[n++] = 0xb2; /* Logical Block Prov */ + if (is_disk) + arr[n++] = 0xb2; /* LB Provisioning */ + else if (is_zbc) + arr[n++] = 0xb6; /* ZB dev. char. */ } arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ @@ -1541,19 +1564,22 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } else if (0x88 == cmd[2]) { /* SCSI Ports */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); - } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ + } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ arr[1] = cmd[2]; /*sanity */ n = inquiry_vpd_89(&arr[4]); put_unaligned_be16(n, arr + 2); - } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ + } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b0(&arr[4]); - } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ + } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b1(&arr[4]); } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b2(&arr[4]); + } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_vpd_b6(&arr[4]); } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); kfree(arr); @@ -1591,6 +1617,9 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ put_unaligned_be16(0x525, arr + n); n += 2; + } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ + put_unaligned_be16(0x624, arr + n); + n += 2; } put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ ret = fill_from_dev_buffer(scp, arr, @@ -2180,7 +2209,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, unsigned char *ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = scp->cmnd; - bool dbd, llbaa, msense_6, is_disk, bad_pcode; + bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ pcontrol = (cmd[2] & 0xc0) >> 6; @@ -2189,7 +2218,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, msense_6 = (MODE_SENSE == cmd[0]); llbaa = msense_6 ? false : !!(cmd[1] & 0x10); is_disk = (sdebug_ptype == TYPE_DISK); - if (is_disk && !dbd) + is_zbc = (sdebug_ptype == TYPE_ZBC); + if ((is_disk || is_zbc) && !dbd) bd_len = llbaa ? 16 : 8; else bd_len = 0; @@ -2201,8 +2231,8 @@ static int resp_mode_sense(struct scsi_cmnd *scp, } target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + (devip->target * 1000) - 3; - /* for disks set DPOFUA bit and clear write protect (WP) bit */ - if (is_disk) { + /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ + if (is_disk || is_zbc) { dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ if (sdebug_wp) dev_spec |= 0x80; @@ -2262,7 +2292,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, bad_pcode = true; break; case 0x8: /* Caching page, direct access */ - if (is_disk) { + if (is_disk || is_zbc) { len = resp_caching_pg(ap, pcontrol, target); offset += len; } else @@ -2300,6 +2330,9 @@ static int resp_mode_sense(struct scsi_cmnd *scp, target); len += resp_caching_pg(ap + len, pcontrol, target); + } else if (is_zbc) { + len += resp_caching_pg(ap + len, pcontrol, + target); } len += resp_ctrl_m_pg(ap + len, pcontrol, target); len += resp_sas_sf_m_pg(ap + len, pcontrol, target); From patchwork Wed Apr 22 10:42:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503433 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C853214B4 for ; Wed, 22 Apr 2020 10:43:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9242620656 for ; Wed, 22 Apr 2020 10:43:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="G5JlsMs8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730364AbgDVKnC (ORCPT ); Wed, 22 Apr 2020 06:43:02 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22889 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731745AbgDVKmZ (ORCPT ); Wed, 22 Apr 2020 06:42:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552145; x=1619088145; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LEF/m13ccMqIwtISy7YBzyHbSqENGiR8gM7pDoh2Hdo=; b=G5JlsMs84F/VyVLtW/2Ij4TgAHivlYInGI/8boN7EXi4cI6B9U+G2e1K 03FD36gkYh8XONN1CvXqD5cu4SR3Bz4SPPSAqbgLFUO1DTSBe6bfjqimU CZiQAJqFzeyIzSuomvxwTccgrh3Bv+Ujh/0ovMcGH0Kg0P48kT7i1cCWN 8Da788eEwX6VEMCnpcbQ9GCMKXBHKmTXBDiownmkdOTqPY619gSJnRboS e3fHAUDbMSf2G0pPLYI6pFg3HOx5y8WM1yRvs28VGHYy6AZbtRKZ/dF/k TLYb+cd+1zmEzoFCjlnxIGT2EJQySU2lluDZpqOVa5GHE+I0uQNoctK9+ Q==; IronPort-SDR: 9C79PB+fPhbotNukyHFA3xK10PIPF6Hqul7K1fnaA7EtoKmClveWdLJ22F1AAPM2GKxvvT6/rR HkilSsUQ9SimpMy/tXd72ZR+n7QPfet/c20MdTORZH0gzjmpE0NVY47UCuZf1wz3VbW5pxtihm gc74v219FIp0cSn1TTN671QO6h5hOwzwFOyApnQbbLiWQwr8lo8GSdIeLcv74GiYjG1cjPxZ0a b8bX7KpMbzKmCsqYbAr2mVErZyQjeJ3H7lDW5fBFYU7dm8QIDV0A8aHiMb00FuXN9vKUiMUB5r y8w= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230020" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:24 +0800 IronPort-SDR: hqbnODYHlbkyWPuCCjXMQ9ON6pdZVrVdWPL7yreQE284dMjqKyfTWKn8KF4IkEjVOMSjKFNFhg pRFiVfr7r6pn6NuC6CH2NFh+uuiYu5Iyo= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:14 -0700 IronPort-SDR: lqe9QPAOZy/r3vTF5D/0k7S0EoDcG55k+BKHQaI1qEgtmI9HtrlCNBt9h1nP1TXlbETUxnd6/9 6acC8EOrF+/g== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:23 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 2/7] scsi_debug: add zbc zone commands Date: Wed, 22 Apr 2020 19:42:16 +0900 Message-Id: <20200422104221.378203-3-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Douglas Gilbert Add support for the 5 ZBC commands and enough functionality to emulate a host-managed device with one conventional zone and a set of sequential write required zones up to the disk capacity. Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 819 +++++++++++++++++++++++++++++++++++++- 1 file changed, 804 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 4aa4d9e58978..10214017d478 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -94,6 +94,11 @@ static const char *sdebug_version_date = "20200421"; #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 #define WRITE_ERROR_ASC 0xc +#define UNALIGNED_WRITE_ASCQ 0x4 +#define WRITE_BOUNDARY_ASCQ 0x5 +#define READ_INVDATA_ASCQ 0x6 +#define READ_BOUNDARY_ASCQ 0x7 +#define INSUFF_ZONE_ASCQ 0xe /* Additional Sense Code Qualifier (ASCQ) */ #define ACK_NAK_TO 0x3 @@ -147,6 +152,10 @@ static const char *sdebug_version_date = "20200421"; #define DEF_UUID_CTL 0 #define JDELAY_OVERRIDDEN -9999 +/* Default parameters for ZBC drives */ +#define DEF_ZBC_ZONE_SIZE_MB 128 +#define DEF_ZBC_MAX_OPEN_ZONES 8 + #define SDEBUG_LUN_0_VAL 0 /* bit mask values for sdebug_opts */ @@ -250,6 +259,24 @@ static const char *sdebug_version_date = "20200421"; #define SDEB_XA_NOT_IN_USE XA_MARK_1 +/* enumeration names taken from table 26, zbcr05 */ +enum sdebug_z_cond { + ZBC_NOT_WRITE_POINTER = 0x0, + ZC1_EMPTY = 0x1, + ZC2_IMPLICIT_OPEN = 0x2, + ZC3_EXPLICIT_OPEN = 0x3, + ZC4_CLOSED = 0x4, + ZC6_READ_ONLY = 0xd, + ZC5_FULL = 0xe, + ZC7_OFFLINE = 0xf, +}; + +struct sdeb_zone_state { /* ZBC: per zone state */ + enum sdebug_z_cond z_cond; + unsigned int z_size; + sector_t z_start; + sector_t z_wp; +}; struct sdebug_dev_info { struct list_head dev_list; @@ -262,6 +289,16 @@ struct sdebug_dev_info { atomic_t num_in_q; atomic_t stopped; bool used; + + /* For ZBC devices */ + unsigned int zsize; + unsigned int zsize_shift; + unsigned int nr_zones; + unsigned int nr_imp_open; + unsigned int nr_exp_open; + unsigned int nr_closed; + unsigned int max_open; + struct sdeb_zone_state *zstate; }; struct sdebug_host_info { @@ -369,7 +406,9 @@ enum sdeb_opcode_index { SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ SDEB_I_COMP_WRITE = 28, SDEB_I_PRE_FETCH = 29, /* 10, 16 */ - SDEB_I_LAST_ELEM_P1 = 30, /* keep this last (previous + 1) */ + SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ + SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ + SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ }; @@ -401,7 +440,8 @@ static const unsigned char opcode_ind_arr[256] = { 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, - SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, + SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, + SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, @@ -449,6 +489,11 @@ static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); static int sdebug_do_add_host(bool mk_new_store); static int sdebug_add_host_helper(int per_host_idx); @@ -553,6 +598,24 @@ static const struct opcode_info_t pre_fetch_iarr[] = { 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ }; +static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ + {0, 0x94, 0x1, F_SA_LOW, resp_close_zone, NULL, + {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ + {0, 0x94, 0x2, F_SA_LOW, resp_finish_zone, NULL, + {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ + {0, 0x94, 0x4, F_SA_LOW, resp_rwp_zone, NULL, + {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ +}; + +static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ + {0, 0x95, 0x6, F_SA_LOW | F_D_IN, NULL, NULL, + {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ +}; + /* This array is accessed via SDEB_I_* values. Make sure all are mapped, * plus the terminating elements for logic that scans this table such as @@ -655,6 +718,15 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 0, 0, 0, 0} }, /* PRE-FETCH (10) */ /* 30 */ + {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW, + resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ + {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, + {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_D_IN, + resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ + {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, +/* sentinel */ {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; @@ -742,6 +814,11 @@ static int dix_writes; static int dix_reads; static int dif_errors; +/* ZBC global data */ +static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ +static const int zbc_zone_size_mb; +static const int zbc_max_open_zones = DEF_ZBC_MAX_OPEN_ZONES; + static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ @@ -1446,20 +1523,22 @@ static int inquiry_vpd_b2(unsigned char *arr) } /* Zoned block device characteristics VPD page (ZBC mandatory) */ -static int inquiry_vpd_b6(unsigned char *arr) +static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) { memset(arr, 0, 0x3c); arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ /* * Set Optimal number of open sequential write preferred zones and * Optimal number of non-sequentially written sequential write - * preferred zones and Maximum number of open sequential write - * required zones fields to 'not reported' (0xffffffff). Leave other - * fields set to zero. + * preferred zones fields to 'not reported' (0xffffffff). Leave other + * fields set to zero, apart from Max. number of open swrz_s field. */ put_unaligned_be32(0xffffffff, &arr[4]); put_unaligned_be32(0xffffffff, &arr[8]); - put_unaligned_be32(0xffffffff, &arr[12]); + if (devip->max_open) + put_unaligned_be32(devip->max_open, &arr[12]); + else + put_unaligned_be32(0xffffffff, &arr[12]); return 0x3c; } @@ -1579,7 +1658,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[3] = inquiry_vpd_b2(&arr[4]); } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_vpd_b6(&arr[4]); + arr[3] = inquiry_vpd_b6(devip, &arr[4]); } else { mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); kfree(arr); @@ -2550,9 +2629,185 @@ static int resp_log_sense(struct scsi_cmnd *scp, min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ)); } -static inline int check_device_access_params(struct scsi_cmnd *scp, - unsigned long long lba, unsigned int num, bool write) +static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) +{ + return devip->nr_zones != 0; +} + +static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, + unsigned long long lba) +{ + unsigned int zno; + + if (devip->zsize_shift) + zno = lba >> devip->zsize_shift; + else + zno = lba / devip->zsize; + return &devip->zstate[zno]; +} + +static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) +{ + return zsp->z_cond == ZBC_NOT_WRITE_POINTER; +} + +static void zbc_close_zone(struct sdebug_dev_info *devip, + struct sdeb_zone_state *zsp) +{ + enum sdebug_z_cond zc; + + if (zbc_zone_is_conv(zsp)) + return; + + zc = zsp->z_cond; + if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) + return; + + if (zc == ZC2_IMPLICIT_OPEN) + devip->nr_imp_open--; + else + devip->nr_exp_open--; + + if (zsp->z_wp == zsp->z_start) { + zsp->z_cond = ZC1_EMPTY; + } else { + zsp->z_cond = ZC4_CLOSED; + devip->nr_closed++; + } +} + +static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) +{ + struct sdeb_zone_state *zsp = &devip->zstate[0]; + unsigned int i; + + for (i = 0; i < devip->nr_zones; i++, zsp++) { + if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { + zbc_close_zone(devip, zsp); + return; + } + } +} + +static void zbc_open_zone(struct sdebug_dev_info *devip, + struct sdeb_zone_state *zsp, bool explicit) +{ + enum sdebug_z_cond zc; + + if (zbc_zone_is_conv(zsp)) + return; + + zc = zsp->z_cond; + if ((explicit && zc == ZC3_EXPLICIT_OPEN) || + (!explicit && zc == ZC2_IMPLICIT_OPEN)) + return; + + /* Close an implicit open zone if necessary */ + if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) + zbc_close_zone(devip, zsp); + else if (devip->max_open && + devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) + zbc_close_imp_open_zone(devip); + + if (zsp->z_cond == ZC4_CLOSED) + devip->nr_closed--; + if (explicit) { + zsp->z_cond = ZC3_EXPLICIT_OPEN; + devip->nr_exp_open++; + } else { + zsp->z_cond = ZC2_IMPLICIT_OPEN; + devip->nr_imp_open++; + } +} + +static void zbc_inc_wp(struct sdebug_dev_info *devip, + unsigned long long lba, unsigned int num) +{ + struct sdeb_zone_state *zsp = zbc_zone(devip, lba); + + if (zbc_zone_is_conv(zsp)) + return; + + zsp->z_wp += num; + if (zsp->z_wp >= zsp->z_start + zsp->z_size) + zsp->z_cond = ZC5_FULL; +} + +static int check_zbc_access_params(struct scsi_cmnd *scp, + unsigned long long lba, unsigned int num, bool write) +{ + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; + struct sdeb_zone_state *zsp = zbc_zone(devip, lba); + struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); + + if (!write) { + /* Reads cannot cross zone types boundaries */ + if (zsp_end != zsp && + zbc_zone_is_conv(zsp) && + !zbc_zone_is_conv(zsp_end)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + READ_INVDATA_ASCQ); + return check_condition_result; + } + return 0; + } + + /* No restrictions for writes within conventional zones */ + if (zbc_zone_is_conv(zsp)) { + if (!zbc_zone_is_conv(zsp_end)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + WRITE_BOUNDARY_ASCQ); + return check_condition_result; + } + return 0; + } + + /* Writes cannot cross sequential zone boundaries */ + if (zsp_end != zsp) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + WRITE_BOUNDARY_ASCQ); + return check_condition_result; + } + /* Cannot write full zones */ + if (zsp->z_cond == ZC5_FULL) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + /* Writes must be aligned to the zone WP */ + if (lba != zsp->z_wp) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + UNALIGNED_WRITE_ASCQ); + return check_condition_result; + } + + /* Handle implicit open of closed and empty zones */ + if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { + if (devip->max_open && + devip->nr_exp_open >= devip->max_open) { + mk_sense_buffer(scp, DATA_PROTECT, + INSUFF_RES_ASC, + INSUFF_ZONE_ASCQ); + return check_condition_result; + } + zbc_open_zone(devip, zsp, false); + } + + return 0; +} + +static inline int check_device_access_params + (struct scsi_cmnd *scp, unsigned long long lba, + unsigned int num, bool write) { + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; + if (lba + num > sdebug_capacity) { mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); return check_condition_result; @@ -2567,6 +2822,9 @@ static inline int check_device_access_params(struct scsi_cmnd *scp, mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); return check_condition_result; } + if (sdebug_dev_is_zoned(devip)) + return check_zbc_access_params(scp, lba, num, write); + return 0; } @@ -3153,10 +3411,13 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) sdev_printk(KERN_ERR, scp->device, "Unprotected WR " "to DIF device\n"); } + + write_lock(macc_lckp); ret = check_device_access_params(scp, lba, num, true); - if (ret) + if (ret) { + write_unlock(macc_lckp); return ret; - write_lock(macc_lckp); + } /* DIX + T10 DIF */ if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { @@ -3172,6 +3433,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) ret = do_device_access(sip, scp, 0, lba, num, true); if (unlikely(scsi_debug_lbp())) map_region(sip, lba, num); + /* If ZBC zone then bump its write pointer */ + if (sdebug_dev_is_zoned(devip)) + zbc_inc_wp(devip, lba, num); write_unlock(macc_lckp); if (unlikely(-1 == ret)) return DID_ERROR << 16; @@ -3326,6 +3590,9 @@ static int resp_write_scat(struct scsi_cmnd *scp, } ret = do_device_access(sip, scp, sg_off, lba, num, true); + /* If ZBC zone then bump its write pointer */ + if (sdebug_dev_is_zoned(devip)) + zbc_inc_wp(devip, lba, num); if (unlikely(scsi_debug_lbp())) map_region(sip, lba, num); if (unlikely(-1 == ret)) { @@ -3374,6 +3641,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba, bool unmap, bool ndob) { + struct scsi_device *sdp = scp->device; + struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; unsigned long long i; u64 block, lbaa; u32 lb_size = sdebug_sector_size; @@ -3384,11 +3653,13 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u8 *fs1p; u8 *fsp; + write_lock(macc_lckp); + ret = check_device_access_params(scp, lba, num, true); - if (ret) + if (ret) { + write_unlock(macc_lckp); return ret; - - write_lock(macc_lckp); + } if (unmap && scsi_debug_lbp()) { unmap_region(sip, lba, num); @@ -3421,6 +3692,9 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, } if (scsi_debug_lbp()) map_region(sip, lba, num); + /* If ZBC zone then bump its write pointer */ + if (sdebug_dev_is_zoned(devip)) + zbc_inc_wp(devip, lba, num); out: write_unlock(macc_lckp); @@ -3948,6 +4222,426 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return ret; } +#define RZONES_DESC_HD 64 + +/* Report zones depending on start LBA nad reporting options */ +static int resp_report_zones(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + unsigned int i, max_zones, rep_max_zones, nrz = 0; + int ret = 0; + u32 alloc_len, rep_opts, rep_len; + bool partial; + u64 lba, zs_lba; + u8 *arr = NULL, *desc; + u8 *cmd = scp->cmnd; + struct sdeb_zone_state *zsp; + struct sdeb_store_info *sip = devip2sip(devip); + rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; + + if (!sdebug_dev_is_zoned(devip)) { + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + zs_lba = get_unaligned_be64(cmd + 2); + alloc_len = get_unaligned_be32(cmd + 10); + rep_opts = cmd[14] & 0x3f; + partial = cmd[14] & 0x80; + + if (zs_lba >= sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + return check_condition_result; + } + + max_zones = devip->nr_zones - zs_lba / devip->zsize; + rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), + max_zones); + + arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC); + if (!arr) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, + INSUFF_RES_ASCQ); + return check_condition_result; + } + + read_lock(macc_lckp); + + desc = arr + 64; + for (i = 0; i < max_zones; i++) { + lba = zs_lba + devip->zsize * i; + if (lba > sdebug_capacity) + break; + zsp = zbc_zone(devip, lba); + switch (rep_opts) { + case 0x00: + /* All zones */ + break; + case 0x01: + /* Empty zones */ + if (zsp->z_cond != ZC1_EMPTY) + continue; + break; + case 0x02: + /* Implicit open zones */ + if (zsp->z_cond != ZC2_IMPLICIT_OPEN) + continue; + break; + case 0x03: + /* Explicit open zones */ + if (zsp->z_cond != ZC3_EXPLICIT_OPEN) + continue; + break; + case 0x04: + /* Closed zones */ + if (zsp->z_cond != ZC4_CLOSED) + continue; + break; + case 0x05: + /* Full zones */ + if (zsp->z_cond != ZC5_FULL) + continue; + break; + case 0x06: + case 0x07: + case 0x10: + case 0x11: + /* + * Read-only, offline, reset WP recommended and + * non-seq-resource-used are not emulated: no zones + * to report; + */ + continue; + case 0x3f: + /* Not write pointer (conventional) zones */ + if (!zbc_zone_is_conv(zsp)) + continue; + break; + default: + mk_sense_buffer(scp, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + ret = check_condition_result; + goto fini; + } + + if (nrz < rep_max_zones) { + /* Fill zone descriptor */ + if (zbc_zone_is_conv(zsp)) + desc[0] = 0x1; + else + desc[0] = 0x2; + desc[1] = zsp->z_cond << 4; + put_unaligned_be64((u64)zsp->z_size, desc + 8); + put_unaligned_be64((u64)zsp->z_start, desc + 16); + put_unaligned_be64((u64)zsp->z_wp, desc + 24); + desc += 64; + } + + if (partial && nrz >= rep_max_zones) + break; + + nrz++; + } + + /* Report header */ + put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); + put_unaligned_be64(sdebug_capacity - 1, arr + 8); + + rep_len = (unsigned long)desc - (unsigned long)arr; + ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len)); + +fini: + read_unlock(macc_lckp); + kfree(arr); + return ret; +} + +/* Logic transplanted from tcmu-runner, file_zbc.c */ +static void zbc_open_all(struct sdebug_dev_info *devip) +{ + struct sdeb_zone_state *zsp = &devip->zstate[0]; + unsigned int i; + + for (i = 0; i < devip->nr_zones; i++, zsp++) { + if (zsp->z_cond == ZC4_CLOSED) + zbc_open_zone(devip, &devip->zstate[i], true); + } +} + +static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + int res = 0; + u64 z_id; + enum sdebug_z_cond zc; + u8 *cmd = scp->cmnd; + struct sdeb_zone_state *zsp; + bool all = cmd[14] & 0x01; + struct sdeb_store_info *sip = devip2sip(devip); + rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; + + if (!sdebug_dev_is_zoned(devip)) { + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + + write_lock(macc_lckp); + + if (all) { + /* Check if all closed zones can be open */ + if (devip->max_open && + devip->nr_exp_open + devip->nr_closed > devip->max_open) { + mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, + INSUFF_ZONE_ASCQ); + res = check_condition_result; + goto fini; + } + /* Open all closed zones */ + zbc_open_all(devip); + goto fini; + } + + /* Open the specified zone */ + z_id = get_unaligned_be64(cmd + 2); + if (z_id >= sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + res = check_condition_result; + goto fini; + } + + zsp = zbc_zone(devip, z_id); + if (z_id != zsp->z_start) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + if (zbc_zone_is_conv(zsp)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + + zc = zsp->z_cond; + if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) + goto fini; + + if (devip->max_open && devip->nr_exp_open >= devip->max_open) { + mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, + INSUFF_ZONE_ASCQ); + res = check_condition_result; + goto fini; + } + + if (zc == ZC2_IMPLICIT_OPEN) + zbc_close_zone(devip, zsp); + zbc_open_zone(devip, zsp, true); +fini: + write_unlock(macc_lckp); + return res; +} + +static void zbc_close_all(struct sdebug_dev_info *devip) +{ + unsigned int i; + + for (i = 0; i < devip->nr_zones; i++) + zbc_close_zone(devip, &devip->zstate[i]); +} + +static int resp_close_zone(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + int res = 0; + u64 z_id; + u8 *cmd = scp->cmnd; + struct sdeb_zone_state *zsp; + bool all = cmd[14] & 0x01; + struct sdeb_store_info *sip = devip2sip(devip); + rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; + + if (!sdebug_dev_is_zoned(devip)) { + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + + write_lock(macc_lckp); + + if (all) { + zbc_close_all(devip); + goto fini; + } + + /* Close specified zone */ + z_id = get_unaligned_be64(cmd + 2); + if (z_id >= sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + res = check_condition_result; + goto fini; + } + + zsp = zbc_zone(devip, z_id); + if (z_id != zsp->z_start) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + if (zbc_zone_is_conv(zsp)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + + zbc_close_zone(devip, zsp); +fini: + write_unlock(macc_lckp); + return res; +} + +static void zbc_finish_zone(struct sdebug_dev_info *devip, + struct sdeb_zone_state *zsp, bool empty) +{ + enum sdebug_z_cond zc = zsp->z_cond; + + if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || + zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { + if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) + zbc_close_zone(devip, zsp); + if (zsp->z_cond == ZC4_CLOSED) + devip->nr_closed--; + zsp->z_wp = zsp->z_start + zsp->z_size; + zsp->z_cond = ZC5_FULL; + } +} + +static void zbc_finish_all(struct sdebug_dev_info *devip) +{ + unsigned int i; + + for (i = 0; i < devip->nr_zones; i++) + zbc_finish_zone(devip, &devip->zstate[i], false); +} + +static int resp_finish_zone(struct scsi_cmnd *scp, + struct sdebug_dev_info *devip) +{ + struct sdeb_zone_state *zsp; + int res = 0; + u64 z_id; + u8 *cmd = scp->cmnd; + bool all = cmd[14] & 0x01; + struct sdeb_store_info *sip = devip2sip(devip); + rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; + + if (!sdebug_dev_is_zoned(devip)) { + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + + write_lock(macc_lckp); + + if (all) { + zbc_finish_all(devip); + goto fini; + } + + /* Finish the specified zone */ + z_id = get_unaligned_be64(cmd + 2); + if (z_id >= sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + res = check_condition_result; + goto fini; + } + + zsp = zbc_zone(devip, z_id); + if (z_id != zsp->z_start) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + if (zbc_zone_is_conv(zsp)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + + zbc_finish_zone(devip, zsp, true); +fini: + write_unlock(macc_lckp); + return res; +} + +static void zbc_rwp_zone(struct sdebug_dev_info *devip, + struct sdeb_zone_state *zsp) +{ + enum sdebug_z_cond zc; + + if (zbc_zone_is_conv(zsp)) + return; + + zc = zsp->z_cond; + if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) + zbc_close_zone(devip, zsp); + + if (zsp->z_cond == ZC4_CLOSED) + devip->nr_closed--; + + zsp->z_wp = zsp->z_start; + zsp->z_cond = ZC1_EMPTY; +} + +static void zbc_rwp_all(struct sdebug_dev_info *devip) +{ + unsigned int i; + + for (i = 0; i < devip->nr_zones; i++) + zbc_rwp_zone(devip, &devip->zstate[i]); +} + +static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + struct sdeb_zone_state *zsp; + int res = 0; + u64 z_id; + u8 *cmd = scp->cmnd; + bool all = cmd[14] & 0x01; + struct sdeb_store_info *sip = devip2sip(devip); + rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; + + if (!sdebug_dev_is_zoned(devip)) { + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + + write_lock(macc_lckp); + + if (all) { + zbc_rwp_all(devip); + goto fini; + } + + z_id = get_unaligned_be64(cmd + 2); + if (z_id >= sdebug_capacity) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); + res = check_condition_result; + goto fini; + } + + zsp = zbc_zone(devip, z_id); + if (z_id != zsp->z_start) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + if (zbc_zone_is_conv(zsp)) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); + res = check_condition_result; + goto fini; + } + + zbc_rwp_zone(devip, zsp); +fini: + write_unlock(macc_lckp); + return res; +} + static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) { u32 tag = blk_mq_unique_tag(cmnd->request); @@ -4053,6 +4747,76 @@ static void sdebug_q_cmd_wq_complete(struct work_struct *work) static bool got_shared_uuid; static uuid_t shared_uuid; +static int sdebug_device_create_zones(struct sdebug_dev_info *devip) +{ + struct sdeb_zone_state *zsp; + sector_t capacity = get_sdebug_capacity(); + sector_t zstart = 0; + unsigned int i; + + /* + * Set the zone size: if zbc_zone_size_mb is not set, figure out a + * zone size allowing for at least 4 zones on the device. Otherwise, + * use the specified zone size checking that at least 2 zones can be + * created for the device. + */ + if (!zbc_zone_size_mb) { + devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) + >> ilog2(sdebug_sector_size); + while (capacity < devip->zsize << 2 && devip->zsize >= 2) + devip->zsize >>= 1; + if (devip->zsize < 2) { + pr_err("Device capacity too small\n"); + return -EINVAL; + } + } else { + devip->zsize = (zbc_zone_size_mb * SZ_1M) + >> ilog2(sdebug_sector_size); + if (devip->zsize >= capacity) { + pr_err("Zone size too large for device capacity\n"); + return -EINVAL; + } + } + + if (is_power_of_2(devip->zsize)) + devip->zsize_shift = ilog2(devip->zsize); + devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; + + /* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */ + if (zbc_max_open_zones >= devip->nr_zones - 1) + devip->max_open = (devip->nr_zones - 1) / 2; + else + devip->max_open = zbc_max_open_zones; + + devip->zstate = kcalloc(devip->nr_zones, + sizeof(struct sdeb_zone_state), GFP_KERNEL); + if (!devip->zstate) + return -ENOMEM; + + for (i = 0; i < devip->nr_zones; i++) { + zsp = &devip->zstate[i]; + + zsp->z_start = zstart; + + if (i == 0) { + zsp->z_cond = ZBC_NOT_WRITE_POINTER; + zsp->z_wp = (sector_t)-1; + } else { + zsp->z_cond = ZC1_EMPTY; + zsp->z_wp = zsp->z_start; + } + + if (zsp->z_start + devip->zsize < capacity) + zsp->z_size = devip->zsize; + else + zsp->z_size = capacity - zsp->z_start; + + zstart += zsp->z_size; + } + + return 0; +} + static struct sdebug_dev_info *sdebug_device_create( struct sdebug_host_info *sdbg_host, gfp_t flags) { @@ -4072,6 +4836,13 @@ static struct sdebug_dev_info *sdebug_device_create( } } devip->sdbg_host = sdbg_host; + if (sdeb_zbc_in_use) { + if (sdebug_device_create_zones(devip)) { + kfree(devip); + return NULL; + } + } + devip->sdbg_host = sdbg_host; list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); } return devip; @@ -5059,7 +5830,13 @@ static ssize_t ptype_store(struct device_driver *ddp, const char *buf, { int n; + /* Cannot change from or to TYPE_ZBC with sysfs */ + if (sdebug_ptype == TYPE_ZBC) + return -EINVAL; + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + if (n == TYPE_ZBC) + return -EINVAL; sdebug_ptype = n; return count; } @@ -5318,6 +6095,10 @@ static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, int n; bool changed; + /* Ignore capacity change for ZBC drives for now */ + if (sdeb_zbc_in_use) + return -ENOTSUPP; + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { changed = (sdebug_virtual_gb != n); sdebug_virtual_gb = n; @@ -5708,6 +6489,12 @@ static int __init scsi_debug_init(void) for (k = 0; k < submit_queues; ++k) spin_lock_init(&sdebug_q_arr[k].qc_lock); + /* + * check for host managed zoned block device specified with ptype=0x14. + */ + if (sdebug_ptype == TYPE_ZBC) + sdeb_zbc_in_use = true; + if (sdebug_dev_size_mb < 1) sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sz = (unsigned long)sdebug_dev_size_mb * 1048576; @@ -5999,6 +6786,7 @@ static int sdebug_add_host_helper(int per_host_idx) list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, dev_list) { list_del(&sdbg_devinfo->dev_list); + kfree(sdbg_devinfo->zstate); kfree(sdbg_devinfo); } kfree(sdbg_host); @@ -6410,6 +7198,7 @@ static int sdebug_driver_remove(struct device *dev) list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, dev_list) { list_del(&sdbg_devinfo->dev_list); + kfree(sdbg_devinfo->zstate); kfree(sdbg_devinfo); } From patchwork Wed Apr 22 10:42:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503425 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E722692C for ; Wed, 22 Apr 2020 10:42:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CAA2A2073A for ; Wed, 22 Apr 2020 10:42:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="fKaB29ED" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731756AbgDVKme (ORCPT ); Wed, 22 Apr 2020 06:42:34 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22892 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731747AbgDVKm0 (ORCPT ); Wed, 22 Apr 2020 06:42:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552146; x=1619088146; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BApQX12KK7VHObqatMX8LszPi/l58RbP+elKeXLDErM=; b=fKaB29EDGuGQ0mHxZKbpaFD2tll1Fb3ZgwyvEm+lztw8/uzgle9pVwbk GSkGEhSNjK4gPxJzU+1tGd+sh+nG6HtrUOpFFkNUaLgUtFX+7FTDWQJSu jRl7uKzt+b7BjMOCcVH+qyeo7atgWOcKZQo1PTpfE6nu50qNR/QBhw/R9 kut5ZbBTlqH0d6ykp8HdNzEdJOYUdtUvFMRtP6zfDhGqEzjHI9MgLuyVw hTrydU+PyTqHQQxy/Qm84KQ3DZI6ppPT0Ns/SxE/69ayvMYSWbGYxVo8W JgSCl49vxNKItsRh7fS17HnaqpbW3eOmfO77Th8DfLI7L88qoeU2SVMYe g==; IronPort-SDR: xoEH6UJMDu0v7khClnXaFNJnLQ9F+39Dd5ZLAWBMB3CmXAekF5X4DrWEtpnFD87Y5PP7LF/GfI pkW7KUYVylHour8zI/jy2zzFol7FNAmrR+SIManerC9xhvkhELAaoDCoumgDyzIc18U0ay2Elz Lt+kfzSAfuGkVLtFioiSHAzX1Up4a0ATCF2OK77KEcxhyq3BVfvOUUtEhOL9w+foS2NXISPnXF 7D+1uziMWhYB/r3eCvQH43idy4Jp0YgFFTC7GnqsnOIHx0fesaztEaoACpS72GAmkLMEc03VRR P9k= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230022" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:25 +0800 IronPort-SDR: pQYmhcsIbh9lLfYLbcGLyN7fqk9lff1yur3y9N0UbcyOqlZ0gF4QNxM0Qw8XhaNPvjI7HSxp+B aKEGPSmx/YfopkD6ah8btOvOLKVWj9sew= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:15 -0700 IronPort-SDR: BvvgEYTzfZ82P17X2kixzEbaeLfPXJUKTGc9qqY6sCozbJgeTX4SvekL8nxT/j+QqiMmqn9UkQ EkC1acebKIrg== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:24 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 3/7] scsi_debug: add zbc module parameter Date: Wed, 22 Apr 2020 19:42:17 +0900 Message-Id: <20200422104221.378203-4-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org From: Douglas Gilbert Add the zbc module parameter to take either: 0: none (probably a conventional disk) 1: host-aware 2: host-managed These values are chosen to match 'enum blk_zoned_model' found in include/linux/blkdev.h . Instead of "none", "no" or "0" can be given. Instead of "host-aware", "aware or "1" can be given. Instead of "host-managed", "managed" or "2" can be given. Note: the zbc parameter can only be given at driver/module load time; it cannot be changed via sysfs thereafter. At this time there is no ZBC "host-aware" implementation so that string (or the value '1') results in a modprobe error. Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 81 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 10214017d478..6ef01b97e1ae 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -113,7 +113,9 @@ static const char *sdebug_version_date = "20200421"; #define DEF_ATO 1 #define DEF_CDB_LEN 10 #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ +#define DEF_DEV_SIZE_PRE_INIT 0 #define DEF_DEV_SIZE_MB 8 +#define DEF_ZBC_DEV_SIZE_MB 128 #define DEF_DIF 0 #define DEF_DIX 0 #define DEF_PER_HOST_STORE false @@ -736,7 +738,7 @@ static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ static int sdebug_ato = DEF_ATO; static int sdebug_cdb_len = DEF_CDB_LEN; static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ -static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; +static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; static int sdebug_dif = DEF_DIF; static int sdebug_dix = DEF_DIX; static int sdebug_dsense = DEF_D_SENSE; @@ -785,6 +787,9 @@ static bool have_dif_prot; static bool write_since_sync; static bool sdebug_statistics = DEF_STATISTICS; static bool sdebug_wp; +/* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ +static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; +static char *sdeb_zbc_model_s; static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ @@ -5534,6 +5539,7 @@ module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); module_param_named(write_same_length, sdebug_write_same_length, int, S_IRUGO | S_IWUSR); +module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -5595,6 +5601,7 @@ MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); MODULE_PARM_DESC(wp, "Write Protect (def=0)"); MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); +MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); #define SDEBUG_INFO_LEN 256 static char sdebug_info[SDEBUG_INFO_LEN]; @@ -6359,6 +6366,45 @@ static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, } static DRIVER_ATTR_RW(cdb_len); +static const char * const zbc_model_strs_a[] = { + [BLK_ZONED_NONE] = "none", + [BLK_ZONED_HA] = "host-aware", + [BLK_ZONED_HM] = "host-managed", +}; + +static const char * const zbc_model_strs_b[] = { + [BLK_ZONED_NONE] = "no", + [BLK_ZONED_HA] = "aware", + [BLK_ZONED_HM] = "managed", +}; + +static const char * const zbc_model_strs_c[] = { + [BLK_ZONED_NONE] = "0", + [BLK_ZONED_HA] = "1", + [BLK_ZONED_HM] = "2", +}; + +static int sdeb_zbc_model_str(const char *cp) +{ + int res = sysfs_match_string(zbc_model_strs_a, cp); + + if (res < 0) { + res = sysfs_match_string(zbc_model_strs_b, cp); + if (res < 0) { + res = sysfs_match_string(zbc_model_strs_c, cp); + if (sdeb_zbc_model < 0) + return -EINVAL; + } + } + return res; +} + +static ssize_t zbc_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%s\n", + zbc_model_strs_a[sdeb_zbc_model]); +} +static DRIVER_ATTR_RO(zbc); /* Note: The following array creates attribute files in the /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these @@ -6401,6 +6447,7 @@ static struct attribute *sdebug_drv_attrs[] = { &driver_attr_strict.attr, &driver_attr_uuid_ctl.attr, &driver_attr_cdb_len.attr, + &driver_attr_zbc.attr, NULL, }; ATTRIBUTE_GROUPS(sdebug_drv); @@ -6490,11 +6537,39 @@ static int __init scsi_debug_init(void) spin_lock_init(&sdebug_q_arr[k].qc_lock); /* - * check for host managed zoned block device specified with ptype=0x14. + * check for host managed zoned block device specified with + * ptype=0x14 or zbc=XXX. */ - if (sdebug_ptype == TYPE_ZBC) + if (sdebug_ptype == TYPE_ZBC) { + sdeb_zbc_model = BLK_ZONED_HM; + } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { + k = sdeb_zbc_model_str(sdeb_zbc_model_s); + if (k < 0) { + ret = k; + goto free_vm; + } + sdeb_zbc_model = k; + switch (sdeb_zbc_model) { + case BLK_ZONED_NONE: + sdebug_ptype = TYPE_DISK; + break; + case BLK_ZONED_HM: + sdebug_ptype = TYPE_ZBC; + break; + case BLK_ZONED_HA: + default: + pr_err("Invalid ZBC model\n"); + return -EINVAL; + } + } + if (sdeb_zbc_model != BLK_ZONED_NONE) { sdeb_zbc_in_use = true; + if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) + sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; + } + if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) + sdebug_dev_size_mb = DEF_DEV_SIZE_MB; if (sdebug_dev_size_mb < 1) sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sz = (unsigned long)sdebug_dev_size_mb * 1048576; From patchwork Wed Apr 22 10:42:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503429 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7DF6792C for ; Wed, 22 Apr 2020 10:43:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 65E5320656 for ; Wed, 22 Apr 2020 10:43:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="IHU5AtcB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731737AbgDVKnA (ORCPT ); Wed, 22 Apr 2020 06:43:00 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22891 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731749AbgDVKm0 (ORCPT ); Wed, 22 Apr 2020 06:42:26 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552147; x=1619088147; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=a3cnJUKTxpELMeGC+aZBWL8ZE+rDocPhvLtQoCOLIcY=; b=IHU5AtcBAUhMPN0TKD4mFwSk6m7eWBSvVVvbQ2jQaCXniv87KNbCBkeh Q/LHqhpCZeratf1jcFgbXujUGDM5AFxpb44kmZss/1t4yNRsA7GDD/UL7 IFXSiOTb0g18GP20xzq4g6UpbkWY3OjpxoJfpKT0mTLA4l0gw2vRgJQup HdrsjAsgjZCn2FrwukN8h4nXrvog5K1Mma4mStKDRWq5SWC1pW++g4CHa w+TrxS0DMUvdMICgkwYrBu9+CWpbdyHPwOjwwdWxcKSNbQ4oROCKFaX8j n+X2X+tPbzMiCrXiniQffbgLveDNgbVCOTijQ3EPMG5q/AcLKFfZujL0s w==; IronPort-SDR: 0/zLck5MU0a8+JAYKJ8vriayiryV/7k4wQm6YvQvISI/BwZkD/SHHBtdp66b3kbDt4fW+B5spc VxJ0B2mmdxTTcXay1PDONQt4ZVOjyYHo+4KP1KeefT4+NeuLBUmNXz2kFtvJJKXdL4SU2jjjSv jZtJUCPTVwsJYv60jFzy75n8z2/KavvMFKOCe+5srq4QqNbyTvQDU4zdehEFtHNNFQcr5pzPSS rQ41UopOqJPqXVEnE3jewaVR2qfN4jaeZWFuyL5Qy+NxdmbL1aK1Xh2fB/ZoX/+Ie61qSW8tHt 4DU= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230024" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:26 +0800 IronPort-SDR: Ryv7U3yVa57VQcqIyVEP0F0p0CVbCvbg1pTtrtrOyj75bhxXCyWa7HI9NRYh4CcwlAV2w+5D1I oiriTZI8O7j1lqHbcV5C60AHT0ezR1ieI= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:16 -0700 IronPort-SDR: Ldd9Cm0rfu7vvQJcndFeGnDYS60KTTOGpo9o0XODOIEG3PdjLLQHiXBrzvgeTUgx0dOpyQTtI0 JEhO5LfTmGRw== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:25 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 4/7] scsi_debug: add zone_max_open module parameter Date: Wed, 22 Apr 2020 19:42:18 +0900 Message-Id: <20200422104221.378203-5-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Add the zone_max_open module parameters to control the maximum number of open zones of a ZBC device. This parameter is ignored for device types other than 0x14 (zbc=2 case). Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6ef01b97e1ae..36aeda10a117 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -822,7 +822,7 @@ static int dif_errors; /* ZBC global data */ static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ static const int zbc_zone_size_mb; -static const int zbc_max_open_zones = DEF_ZBC_MAX_OPEN_ZONES; +static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ @@ -4788,10 +4788,10 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; /* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */ - if (zbc_max_open_zones >= devip->nr_zones - 1) + if (sdeb_zbc_max_open >= devip->nr_zones - 1) devip->max_open = (devip->nr_zones - 1) / 2; else - devip->max_open = zbc_max_open_zones; + devip->max_open = sdeb_zbc_max_open; devip->zstate = kcalloc(devip->nr_zones, sizeof(struct sdeb_zone_state), GFP_KERNEL); @@ -5540,6 +5540,7 @@ module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); module_param_named(write_same_length, sdebug_write_same_length, int, S_IRUGO | S_IWUSR); module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); +module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -5602,6 +5603,7 @@ MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique de MODULE_PARM_DESC(wp, "Write Protect (def=0)"); MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); +MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); #define SDEBUG_INFO_LEN 256 static char sdebug_info[SDEBUG_INFO_LEN]; From patchwork Wed Apr 22 10:42:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503431 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BA27B14DD for ; Wed, 22 Apr 2020 10:43:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A2C7120781 for ; Wed, 22 Apr 2020 10:43:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="eyTFJYSU" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731418AbgDVKnA (ORCPT ); Wed, 22 Apr 2020 06:43:00 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22889 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731754AbgDVKmb (ORCPT ); Wed, 22 Apr 2020 06:42:31 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552151; x=1619088151; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+cLDQ57gI+KrE69yCX0VN2j46gSUQU1CHuyPoqo3Odc=; b=eyTFJYSUbOD9cSKfjiyWR4daY/nlTGskAc++lZQEbJkII9zoBQijTiYc 2GVgq3FvznCRw5jaloSMa7Tf6VQ4SaNSaiP4HqxNfnTcQHqanZSdeWwEE hmorDW+n+/mFCJ5DKgGyS0fzXYd/nnTFB72NsR02u+GL2diW280l6sYnb OVgaV8IXgEwDKGTWOKwpwGi0IXmJF0hQWFWO5BcmdxHBBbKrhK9H0K3QO cChuq14vN9vX7H/l0STV6eWYzPqPe9antfVAry47HDva7+2aHh6amhZ4R j41EjvSs8XWhfdJ0jcaPi6M/O18mEdzgd1NuMiL6lVv2hSK9Y5ili2A0I g==; IronPort-SDR: 6QhbFIEMzq6fwwDLpTsSbOHQxsobIls2MFArQfkz4Th2CCvR6f68v89nwE7AmeuPDKg5L7tgHa 0p/CZ3S/gFaKQKgCqZFmfVfWgmdXIPowTmTy/nF0v+1jwVl7de3WQnBe6ExstOh0hR+L91H7As WHbTG5lfhLYn8EnwfFGWJWuC4zDC9oxdwst/oDiXsy6E5uZtBKDMrJsq9r2nBSdr4Lr4F0CzRH lAsnQ4J6CEBdhu2PcEftYfcg0PUo/eDW+mEEPTN+sKXQH+YP2G8N2DZzwnaaudVN9GX1lstYFy 2Vc= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230025" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:27 +0800 IronPort-SDR: rzjMGzGZVmA+58okJBS/EijpjezGXcyQEYKQdCqb2y6DfeiUgU+FqIlPZ52w0XuZWheDBZZ6qP OvOE2jMA85mNlFuScr/uBGoO1k7CztLck= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:16 -0700 IronPort-SDR: HeOiEX9kSnekyyKAp0CP6wGS4ehmVVtZ4v9y0jeNmwOKdQ3AX5G6rKQh5PNtU52K6NDNuwv8+Z YCU6gGqt6ZmQ== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:25 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 5/7] scsi_debug: add zone_nr_conv module parameter Date: Wed, 22 Apr 2020 19:42:19 +0900 Message-Id: <20200422104221.378203-6-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Allow controlling the number of conventional zones of a zbc device with the new zone_nr_conv module parameter. The default value is 1 and the specified value must be less than the total number of zones of the device. This parameter is ignored for device types other than 0x14 (zbc=2 case). Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 36aeda10a117..058e6d19b21d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -157,6 +157,7 @@ static const char *sdebug_version_date = "20200421"; /* Default parameters for ZBC drives */ #define DEF_ZBC_ZONE_SIZE_MB 128 #define DEF_ZBC_MAX_OPEN_ZONES 8 +#define DEF_ZBC_NR_CONV_ZONES 1 #define SDEBUG_LUN_0_VAL 0 @@ -296,6 +297,7 @@ struct sdebug_dev_info { unsigned int zsize; unsigned int zsize_shift; unsigned int nr_zones; + unsigned int nr_conv_zones; unsigned int nr_imp_open; unsigned int nr_exp_open; unsigned int nr_closed; @@ -823,6 +825,7 @@ static int dif_errors; static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ static const int zbc_zone_size_mb; static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; +static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ @@ -4787,6 +4790,12 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) devip->zsize_shift = ilog2(devip->zsize); devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; + if (sdeb_zbc_nr_conv >= devip->nr_zones) { + pr_err("Number of conventional zones too large\n"); + return -EINVAL; + } + devip->nr_conv_zones = sdeb_zbc_nr_conv; + /* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */ if (sdeb_zbc_max_open >= devip->nr_zones - 1) devip->max_open = (devip->nr_zones - 1) / 2; @@ -4803,7 +4812,7 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) zsp->z_start = zstart; - if (i == 0) { + if (i < devip->nr_conv_zones) { zsp->z_cond = ZBC_NOT_WRITE_POINTER; zsp->z_wp = (sector_t)-1; } else { @@ -5541,6 +5550,7 @@ module_param_named(write_same_length, sdebug_write_same_length, int, S_IRUGO | S_IWUSR); module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); +module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -5604,6 +5614,7 @@ MODULE_PARM_DESC(wp, "Write Protect (def=0)"); MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); +MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); #define SDEBUG_INFO_LEN 256 static char sdebug_info[SDEBUG_INFO_LEN]; From patchwork Wed Apr 22 10:42:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503423 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A363314B4 for ; Wed, 22 Apr 2020 10:42:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8AE082073A for ; Wed, 22 Apr 2020 10:42:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="E39VhEhu" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731757AbgDVKmf (ORCPT ); Wed, 22 Apr 2020 06:42:35 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22891 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731755AbgDVKmb (ORCPT ); Wed, 22 Apr 2020 06:42:31 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552152; x=1619088152; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=wIn54DAzeuSnCiK9eWszO2wXPcN+stuUNMbgtoVYqOY=; b=E39VhEhuwDU4hHnRqZlAwOzpzMIsGJupjVmBf4XXl/xG7URJn1P5Bt9Y pUOxT0IUlSSv9WUH2IpaKG0Wp6bOp+fQ3vxrwhAIDvozNrd6V/CHBOkFv JaeWO9lNP+wUHVfd7jHqaZAJU0ZWHN+qa8bdYHxL5y3wdK5lGQ/3kIlRe MgMAmNodoGzRWVios2xvNsRsYRxlHxZPfs3ZvBjh52MKJDD+smYQbSh68 c1CBGinZczN41BeVUsvbTKYx/e+o7g3em3Zl5HVqv6QfjIVG2NRkfqcpR jzpLHTXC1MFmsFAYyRFmhPUGTO0WY//UkWfBfoAy4x/MKDLyjt68R67iL w==; IronPort-SDR: r8We6UTGmXDmWORGHP7zJZhXMG2jEXWDRiI+fOiI1TkttgObmlGKmOuGGhhIxtBzQ8O7TLy+je L31mE4mUkYB+5l9Y1qjlOOSPBb80TAWHC9gLly07p8HaMQ7gemDYiZGj+s+upoSohggItoHAtd CTYDi2Ok9n3qKNqDVHHX0wZRyPAGgSgD/jzN1v2ofnRAWz2oaiv6PaKfCC7syBMAxO46cTrMBL iVvLQ1R2Z2F/K2P+qMqangz2AK888UA+kdouGVAjy3DRETKSUxe5xm5A8Ddrc/1+01S0BIAoEQ T9g= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230026" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:28 +0800 IronPort-SDR: dqktuAvUjR2BSIU8TUFwxBYBnVTM7N6Z+bVzRECC3u6rJ5ZQecumVCh69yRyZfNCXOEtUaQYT5 kFZW4IdOlqu0vzMRaHzjVmAPdYXrV9dzo= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:17 -0700 IronPort-SDR: mbURds7REDBDB4hDxdbpm6PZDQXJtI7db2CySb07Ypw4xDGBwQye+5xwhP27E7KXcbIouhfZ3l Uu3vc7vLxO8w== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:26 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 6/7] scsi_debug: add zone_size_mb module parameter Date: Wed, 22 Apr 2020 19:42:20 +0900 Message-Id: <20200422104221.378203-7-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Add the zone_size_mb module parameters to control the zone size of a ZBC device. If the zone size specified is not a divisor of the device capacity, the last zone of the device will be created as a smaller "runt" zone. This parameter is ignored for device types other than 0x14 (zbc=2 case). Note: for testing purposes, zone sizes that are not a power of 2 are accepted but will result in the drive being rejected by the sd driver. Signed-off-by: Douglas Gilbert Signed-off-by: Damien Le Moal --- drivers/scsi/scsi_debug.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 058e6d19b21d..9279ac9bb98d 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -823,7 +823,7 @@ static int dif_errors; /* ZBC global data */ static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ -static const int zbc_zone_size_mb; +static int sdeb_zbc_zone_size_mb; static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; @@ -4763,12 +4763,12 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) unsigned int i; /* - * Set the zone size: if zbc_zone_size_mb is not set, figure out a - * zone size allowing for at least 4 zones on the device. Otherwise, + * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out + * a zone size allowing for at least 4 zones on the device. Otherwise, * use the specified zone size checking that at least 2 zones can be * created for the device. */ - if (!zbc_zone_size_mb) { + if (!sdeb_zbc_zone_size_mb) { devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) >> ilog2(sdebug_sector_size); while (capacity < devip->zsize << 2 && devip->zsize >= 2) @@ -4778,7 +4778,7 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) return -EINVAL; } } else { - devip->zsize = (zbc_zone_size_mb * SZ_1M) + devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) >> ilog2(sdebug_sector_size); if (devip->zsize >= capacity) { pr_err("Zone size too large for device capacity\n"); @@ -5551,6 +5551,7 @@ module_param_named(write_same_length, sdebug_write_same_length, int, module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); +module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -5615,6 +5616,7 @@ MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xff MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); +MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); #define SDEBUG_INFO_LEN 256 static char sdebug_info[SDEBUG_INFO_LEN]; From patchwork Wed Apr 22 10:42:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Le Moal X-Patchwork-Id: 11503427 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BC44092C for ; Wed, 22 Apr 2020 10:42:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 96EBC2073A for ; Wed, 22 Apr 2020 10:42:59 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=wdc.com header.i=@wdc.com header.b="TztKYEko" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730603AbgDVKm7 (ORCPT ); Wed, 22 Apr 2020 06:42:59 -0400 Received: from esa3.hgst.iphmx.com ([216.71.153.141]:22892 "EHLO esa3.hgst.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731206AbgDVKmc (ORCPT ); Wed, 22 Apr 2020 06:42:32 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1587552152; x=1619088152; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=tDGih+lTeTDkRYh8gGWOlL5S5EIaPC0eMEk6IvRVuaI=; b=TztKYEkomgRqiTe2nZFT888uvbRykOg/aG2BvidqCvglL28/AUF1Ivlf JJBN0TZi+lPP+1ae0w8oSDhK6JPq7ZoEDpEEOkgKRc5RA63h3A26d4j1h 2uqLb3dJvpkieoljwGU/vWb6R0+jHS2fs8voediH93yczumKz5NHfBktM UtEoXZZsI2MbnrwCHMUE4SuQzUYw5Gmm0n5T9QdiqT3B84wJ0Gt/oZE2V YgyMY5icAUfIGg3jRx0ZO6W9OEa26ura0cqND0Zy0Wbi3CuhDR9JGhrDj iN+Q1HaXQNAu7zWCPagV6qgf4rCKPd7Xvrm61nkao6DDTPnrsNhRK1Paf Q==; IronPort-SDR: jNR00oRgeTUxbqgVOap8RqSIufmHCm5yUwrwpXZqFjeM/faigxKbV6U3CgRYKaphyJ3M5tQSx0 sOOjQX7hnODvzbBJsAFhixvVxCWG8WHCqyK3Y4abtcjpFtnadkCQnh9iqvx62jlkS1j2Ysa04r mTRE3a38zeaunz32W6NgAd4+MSkn2jcNz/tKRol2tLC7yV43jJOk7Y8++F3lrnMO424P9KQDpy nHahiHzpOXW+EPP1rLvM17fEuTpWgLQieyzodIZRiyIsbhaU4eTfaYYq35PgajJxlZYu72mq1V AuQ= X-IronPort-AV: E=Sophos;i="5.72,414,1580745600"; d="scan'208";a="140230027" Received: from h199-255-45-14.hgst.com (HELO uls-op-cesaep01.wdc.com) ([199.255.45.14]) by ob1.hgst.iphmx.com with ESMTP; 22 Apr 2020 18:42:28 +0800 IronPort-SDR: Faa4/ySe/7Tu77bCkkgM26Qq+mmS06piom3pzatEob1nHTYkSu3VaG1VAIZesmwgqs0WVml2GA A5k1ZgKna70azdb+rIP3XGfoTzQw5H0NM= Received: from uls-op-cesaip01.wdc.com ([10.248.3.36]) by uls-op-cesaep01.wdc.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Apr 2020 03:33:18 -0700 IronPort-SDR: FmqCFuzAqmYibRjVuBubBXA/sXC4SGDOs56zScUwkIua685AXvXsEbHMiJwfBXOF+/Xik8zkxy 0/k8r9uM4RSQ== WDCIronportException: Internal Received: from washi.fujisawa.hgst.com ([10.149.53.254]) by uls-op-cesaip01.wdc.com with ESMTP; 22 Apr 2020 03:42:27 -0700 From: Damien Le Moal To: linux-scsi@vger.kernel.org, "Martin K . Petersen" Cc: Douglas Gilbert Subject: [PATCH 7/7] scsi_debug: implement zbc host-aware emulation Date: Wed, 22 Apr 2020 19:42:21 +0900 Message-Id: <20200422104221.378203-8-damien.lemoal@wdc.com> X-Mailer: git-send-email 2.25.3 In-Reply-To: <20200422104221.378203-1-damien.lemoal@wdc.com> References: <20200422104221.378203-1-damien.lemoal@wdc.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Implement ZBC host-aware device model emulation. The main changes from the host-managed emulation are the device type (TYPE_DISK is used), relaxation of access checks for read and write operations and different handling of a sequential write preferred zone write pointer as mandated by the ZBC r05 specifications. To facilitate the implementation and avoid a lot of "if" statement, the zmodel field is added to the device information and the z_type field to the zone state data structure. Signed-off-by: Damien Le Moal Tested-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 148 ++++++++++++++++++++++++++------------ 1 file changed, 103 insertions(+), 45 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 9279ac9bb98d..46cd4e64bb9c 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -262,6 +262,13 @@ static const char *sdebug_version_date = "20200421"; #define SDEB_XA_NOT_IN_USE XA_MARK_1 +/* Zone types (zbcr05 table 25) */ +enum sdebug_z_type { + ZBC_ZONE_TYPE_CNV = 0x1, + ZBC_ZONE_TYPE_SWR = 0x2, + ZBC_ZONE_TYPE_SWP = 0x3, +}; + /* enumeration names taken from table 26, zbcr05 */ enum sdebug_z_cond { ZBC_NOT_WRITE_POINTER = 0x0, @@ -275,7 +282,9 @@ enum sdebug_z_cond { }; struct sdeb_zone_state { /* ZBC: per zone state */ + enum sdebug_z_type z_type; enum sdebug_z_cond z_cond; + bool z_non_seq_resource; unsigned int z_size; sector_t z_start; sector_t z_wp; @@ -294,6 +303,7 @@ struct sdebug_dev_info { bool used; /* For ZBC devices */ + enum blk_zoned_model zmodel; unsigned int zsize; unsigned int zsize_shift; unsigned int nr_zones; @@ -822,7 +832,7 @@ static int dix_reads; static int dif_errors; /* ZBC global data */ -static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ +static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ static int sdeb_zbc_zone_size_mb; static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; @@ -1500,13 +1510,15 @@ static int inquiry_vpd_b0(unsigned char *arr) } /* Block device characteristics VPD page (SBC-3) */ -static int inquiry_vpd_b1(unsigned char *arr) +static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) { memset(arr, 0, 0x3c); arr[0] = 0; arr[1] = 1; /* non rotating medium (e.g. solid state) */ arr[2] = 0; arr[3] = 5; /* less than 1.8" */ + if (devip->zmodel == BLK_ZONED_HA) + arr[4] = 1 << 4; /* zoned field = 01b */ return 0x3c; } @@ -1543,7 +1555,7 @@ static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) */ put_unaligned_be32(0xffffffff, &arr[4]); put_unaligned_be32(0xffffffff, &arr[8]); - if (devip->max_open) + if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) put_unaligned_be32(devip->max_open, &arr[12]); else put_unaligned_be32(0xffffffff, &arr[12]); @@ -1566,7 +1578,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (! arr) return DID_REQUEUE << 16; is_disk = (sdebug_ptype == TYPE_DISK); - is_zbc = (sdebug_ptype == TYPE_ZBC); + is_zbc = (devip->zmodel != BLK_ZONED_NONE); is_disk_zbc = (is_disk || is_zbc); have_wlun = scsi_is_wlun(scp->device->lun); if (have_wlun) @@ -1611,7 +1623,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[n++] = 0xb1; /* Block characteristics */ if (is_disk) arr[n++] = 0xb2; /* LB Provisioning */ - else if (is_zbc) + if (is_zbc) arr[n++] = 0xb6; /* ZB dev. char. */ } arr[3] = n - 4; /* number of supported VPD pages */ @@ -1660,7 +1672,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr[3] = inquiry_vpd_b0(&arr[4]); } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_vpd_b1(&arr[4]); + arr[3] = inquiry_vpd_b1(devip, &arr[4]); } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ arr[1] = cmd[2]; /*sanity */ arr[3] = inquiry_vpd_b2(&arr[4]); @@ -2305,7 +2317,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp, msense_6 = (MODE_SENSE == cmd[0]); llbaa = msense_6 ? false : !!(cmd[1] & 0x10); is_disk = (sdebug_ptype == TYPE_DISK); - is_zbc = (sdebug_ptype == TYPE_ZBC); + is_zbc = (devip->zmodel != BLK_ZONED_NONE); if ((is_disk || is_zbc) && !dbd) bd_len = llbaa ? 16 : 8; else @@ -2656,7 +2668,7 @@ static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) { - return zsp->z_cond == ZBC_NOT_WRITE_POINTER; + return zsp->z_type == ZBC_ZONE_TYPE_CNV; } static void zbc_close_zone(struct sdebug_dev_info *devip, @@ -2732,13 +2744,42 @@ static void zbc_inc_wp(struct sdebug_dev_info *devip, unsigned long long lba, unsigned int num) { struct sdeb_zone_state *zsp = zbc_zone(devip, lba); + unsigned long long n, end, zend = zsp->z_start + zsp->z_size; if (zbc_zone_is_conv(zsp)) return; - zsp->z_wp += num; - if (zsp->z_wp >= zsp->z_start + zsp->z_size) - zsp->z_cond = ZC5_FULL; + if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { + zsp->z_wp += num; + if (zsp->z_wp >= zend) + zsp->z_cond = ZC5_FULL; + return; + } + + while (num) { + if (lba != zsp->z_wp) + zsp->z_non_seq_resource = true; + + end = lba + num; + if (end >= zend) { + n = zend - lba; + zsp->z_wp = zend; + } else if (end > zsp->z_wp) { + n = num; + zsp->z_wp = end; + } else { + n = num; + } + if (zsp->z_wp >= zend) + zsp->z_cond = ZC5_FULL; + + num -= n; + lba += n; + if (num) { + zsp++; + zend = zsp->z_start + zsp->z_size; + } + } } static int check_zbc_access_params(struct scsi_cmnd *scp, @@ -2750,7 +2791,9 @@ static int check_zbc_access_params(struct scsi_cmnd *scp, struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); if (!write) { - /* Reads cannot cross zone types boundaries */ + if (devip->zmodel == BLK_ZONED_HA) + return 0; + /* For host-managed, reads cannot cross zone types boundaries */ if (zsp_end != zsp && zbc_zone_is_conv(zsp) && !zbc_zone_is_conv(zsp_end)) { @@ -2773,25 +2816,27 @@ static int check_zbc_access_params(struct scsi_cmnd *scp, return 0; } - /* Writes cannot cross sequential zone boundaries */ - if (zsp_end != zsp) { - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LBA_OUT_OF_RANGE, - WRITE_BOUNDARY_ASCQ); - return check_condition_result; - } - /* Cannot write full zones */ - if (zsp->z_cond == ZC5_FULL) { - mk_sense_buffer(scp, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - /* Writes must be aligned to the zone WP */ - if (lba != zsp->z_wp) { - mk_sense_buffer(scp, ILLEGAL_REQUEST, - LBA_OUT_OF_RANGE, - UNALIGNED_WRITE_ASCQ); - return check_condition_result; + if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { + /* Writes cannot cross sequential zone boundaries */ + if (zsp_end != zsp) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + WRITE_BOUNDARY_ASCQ); + return check_condition_result; + } + /* Cannot write full zones */ + if (zsp->z_cond == ZC5_FULL) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + /* Writes must be aligned to the zone WP */ + if (lba != zsp->z_wp) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, + LBA_OUT_OF_RANGE, + UNALIGNED_WRITE_ASCQ); + return check_condition_result; + } } /* Handle implicit open of closed and empty zones */ @@ -4312,13 +4357,16 @@ static int resp_report_zones(struct scsi_cmnd *scp, case 0x06: case 0x07: case 0x10: - case 0x11: /* - * Read-only, offline, reset WP recommended and - * non-seq-resource-used are not emulated: no zones - * to report; + * Read-only, offline, reset WP recommended are + * not emulated: no zones to report; */ continue; + case 0x11: + /* non-seq-resource set */ + if (!zsp->z_non_seq_resource) + continue; + break; case 0x3f: /* Not write pointer (conventional) zones */ if (!zbc_zone_is_conv(zsp)) @@ -4333,11 +4381,10 @@ static int resp_report_zones(struct scsi_cmnd *scp, if (nrz < rep_max_zones) { /* Fill zone descriptor */ - if (zbc_zone_is_conv(zsp)) - desc[0] = 0x1; - else - desc[0] = 0x2; + desc[0] = zsp->z_type; desc[1] = zsp->z_cond << 4; + if (zsp->z_non_seq_resource) + desc[1] |= 1 << 1; put_unaligned_be64((u64)zsp->z_size, desc + 8); put_unaligned_be64((u64)zsp->z_start, desc + 16); put_unaligned_be64((u64)zsp->z_wp, desc + 24); @@ -4591,6 +4638,7 @@ static void zbc_rwp_zone(struct sdebug_dev_info *devip, if (zsp->z_cond == ZC4_CLOSED) devip->nr_closed--; + zsp->z_non_seq_resource = false; zsp->z_wp = zsp->z_start; zsp->z_cond = ZC1_EMPTY; } @@ -4796,11 +4844,13 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) } devip->nr_conv_zones = sdeb_zbc_nr_conv; - /* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */ - if (sdeb_zbc_max_open >= devip->nr_zones - 1) - devip->max_open = (devip->nr_zones - 1) / 2; - else - devip->max_open = sdeb_zbc_max_open; + if (devip->zmodel == BLK_ZONED_HM) { + /* zbc_max_open_zones can be 0, meaning "not reported" */ + if (sdeb_zbc_max_open >= devip->nr_zones - 1) + devip->max_open = (devip->nr_zones - 1) / 2; + else + devip->max_open = sdeb_zbc_max_open; + } devip->zstate = kcalloc(devip->nr_zones, sizeof(struct sdeb_zone_state), GFP_KERNEL); @@ -4813,9 +4863,14 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip) zsp->z_start = zstart; if (i < devip->nr_conv_zones) { + zsp->z_type = ZBC_ZONE_TYPE_CNV; zsp->z_cond = ZBC_NOT_WRITE_POINTER; zsp->z_wp = (sector_t)-1; } else { + if (devip->zmodel == BLK_ZONED_HM) + zsp->z_type = ZBC_ZONE_TYPE_SWR; + else + zsp->z_type = ZBC_ZONE_TYPE_SWP; zsp->z_cond = ZC1_EMPTY; zsp->z_wp = zsp->z_start; } @@ -4851,10 +4906,13 @@ static struct sdebug_dev_info *sdebug_device_create( } devip->sdbg_host = sdbg_host; if (sdeb_zbc_in_use) { + devip->zmodel = sdeb_zbc_model; if (sdebug_device_create_zones(devip)) { kfree(devip); return NULL; } + } else { + devip->zmodel = BLK_ZONED_NONE; } devip->sdbg_host = sdbg_host; list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); @@ -6566,12 +6624,12 @@ static int __init scsi_debug_init(void) sdeb_zbc_model = k; switch (sdeb_zbc_model) { case BLK_ZONED_NONE: + case BLK_ZONED_HA: sdebug_ptype = TYPE_DISK; break; case BLK_ZONED_HM: sdebug_ptype = TYPE_ZBC; break; - case BLK_ZONED_HA: default: pr_err("Invalid ZBC model\n"); return -EINVAL;