From owner-svn-src-stable-11@freebsd.org Wed Mar 22 07:52:26 2017 Return-Path: Delivered-To: svn-src-stable-11@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CFCB9D170F1; Wed, 22 Mar 2017 07:52:26 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A723819DE; Wed, 22 Mar 2017 07:52:26 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v2M7qPKh086392; Wed, 22 Mar 2017 07:52:25 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v2M7qPfo086391; Wed, 22 Mar 2017 07:52:25 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201703220752.v2M7qPfo086391@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Wed, 22 Mar 2017 07:52:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r315703 - stable/11/sys/cam/scsi X-SVN-Group: stable-11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-11@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for only the 11-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 Mar 2017 07:52:26 -0000 Author: mav Date: Wed Mar 22 07:52:25 2017 New Revision: 315703 URL: https://svnweb.freebsd.org/changeset/base/315703 Log: MFC r314906: Add initial support for UNMAP granularity. Report UNMAP granularity as stripesize/-offset if we have no other values to report there. Add new quirk DA_Q_STRICT_UNMAP for cases when target is too critical to misaligned UNMAP request, reporting errors instead of being suboptimal. Setting this quirk makes da periph to forcefully align all UNMAP requests to avoid those errors by the cost of some odd ranges not being UNMAP'ed. This makes UNMAP usable within VMware 6.x VMs, just now 100% efficient. Modified: stable/11/sys/cam/scsi/scsi_da.c Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/cam/scsi/scsi_da.c ============================================================================== --- stable/11/sys/cam/scsi/scsi_da.c Wed Mar 22 07:09:30 2017 (r315702) +++ stable/11/sys/cam/scsi/scsi_da.c Wed Mar 22 07:52:25 2017 (r315703) @@ -123,7 +123,8 @@ typedef enum { DA_Q_NO_RC16 = 0x10, DA_Q_NO_UNMAP = 0x20, DA_Q_RETRY_BUSY = 0x40, - DA_Q_SMR_DM = 0x80 + DA_Q_SMR_DM = 0x80, + DA_Q_STRICT_UNMAP = 0x100 } da_quirks; #define DA_Q_BIT_STRING \ @@ -135,7 +136,8 @@ typedef enum { "\005NO_RC16" \ "\006NO_UNMAP" \ "\007RETRY_BUSY" \ - "\008SMR_DM" + "\010SMR_DM" \ + "\011STRICT_UNMAP" typedef enum { DA_CCB_PROBE_RC = 0x01, @@ -310,6 +312,8 @@ struct da_softc { u_int maxio; uint32_t unmap_max_ranges; uint32_t unmap_max_lba; /* Max LBAs in UNMAP req */ + uint32_t unmap_gran; + uint32_t unmap_gran_align; uint64_t ws_max_blks; da_delete_methods delete_method_pref; da_delete_methods delete_method; @@ -468,9 +472,10 @@ static struct da_quirk_entry da_quirk_ta /* * VMware returns BUSY status when storage has transient * connectivity problems, so better wait. + * Also VMware returns odd errors on misaligned UNMAPs. */ {T_DIRECT, SIP_MEDIA_FIXED, "VMware*", "*", "*"}, - /*quirks*/ DA_Q_RETRY_BUSY + /*quirks*/ DA_Q_RETRY_BUSY | DA_Q_STRICT_UNMAP }, /* USB mass storage devices supported by umass(4) */ { @@ -2395,6 +2400,8 @@ daregister(struct cam_periph *periph, vo softc->flags |= DA_FLAG_PACK_REMOVABLE; softc->unmap_max_ranges = UNMAP_MAX_RANGES; softc->unmap_max_lba = UNMAP_RANGE_MAX; + softc->unmap_gran = 0; + softc->unmap_gran_align = 0; softc->ws_max_blks = WS16_MAX_BLKS; softc->trim_max_ranges = ATA_TRIM_MAX_RANGES; softc->rotating = 1; @@ -3504,11 +3511,11 @@ da_delete_unmap(struct cam_periph *perip struct da_softc *softc = (struct da_softc *)periph->softc;; struct bio *bp1; uint8_t *buf = softc->unmap_buf; + struct scsi_unmap_desc *d = (void *)&buf[UNMAP_HEAD_SIZE]; uint64_t lba, lastlba = (uint64_t)-1; uint64_t totalcount = 0; uint64_t count; - uint32_t lastcount = 0, c; - uint32_t off, ranges = 0; + uint32_t c, lastcount = 0, ranges = 0; /* * Currently this doesn't take the UNMAP @@ -3541,13 +3548,39 @@ da_delete_unmap(struct cam_periph *perip /* Try to extend the previous range. */ if (lba == lastlba) { c = omin(count, UNMAP_RANGE_MAX - lastcount); + lastlba += c; lastcount += c; - off = ((ranges - 1) * UNMAP_RANGE_SIZE) + - UNMAP_HEAD_SIZE; - scsi_ulto4b(lastcount, &buf[off + 8]); + scsi_ulto4b(lastcount, d[ranges - 1].length); count -= c; - lba +=c; + lba += c; totalcount += c; + } else if ((softc->quirks & DA_Q_STRICT_UNMAP) && + softc->unmap_gran != 0) { + /* Align length of the previous range. */ + if ((c = lastcount % softc->unmap_gran) != 0) { + if (lastcount <= c) { + totalcount -= lastcount; + lastlba = (uint64_t)-1; + lastcount = 0; + ranges--; + } else { + totalcount -= c; + lastlba -= c; + lastcount -= c; + scsi_ulto4b(lastcount, d[ranges - 1].length); + } + } + /* Align beginning of the new range. */ + c = (lba - softc->unmap_gran_align) % softc->unmap_gran; + if (c != 0) { + c = softc->unmap_gran - c; + if (count <= c) { + count = 0; + } else { + lba += c; + count -= c; + } + } } while (count > 0) { @@ -3562,16 +3595,15 @@ da_delete_unmap(struct cam_periph *perip ranges, softc->unmap_max_ranges); break; } - off = (ranges * UNMAP_RANGE_SIZE) + UNMAP_HEAD_SIZE; - scsi_u64to8b(lba, &buf[off + 0]); - scsi_ulto4b(c, &buf[off + 8]); + scsi_u64to8b(lba, d[ranges].lba); + scsi_ulto4b(c, d[ranges].length); lba += c; totalcount += c; ranges++; count -= c; + lastlba = lba; lastcount = c; } - lastlba = lba; bp1 = cam_iosched_next_trim(softc->cam_iosched); if (bp1 == NULL) break; @@ -3582,6 +3614,16 @@ da_delete_unmap(struct cam_periph *perip break; } } while (1); + + /* Align length of the last range. */ + if ((softc->quirks & DA_Q_STRICT_UNMAP) && softc->unmap_gran != 0 && + (c = lastcount % softc->unmap_gran) != 0) { + if (lastcount <= c) + ranges--; + else + scsi_ulto4b(lastcount - c, d[ranges - 1].length); + } + scsi_ulto2b(ranges * 16 + 6, &buf[0]); scsi_ulto2b(ranges * 16, &buf[2]); @@ -4454,6 +4496,10 @@ dadone(struct cam_periph *periph, union block_limits->max_unmap_lba_cnt); uint32_t max_unmap_blk_cnt = scsi_4btoul( block_limits->max_unmap_blk_cnt); + uint32_t unmap_gran = scsi_4btoul( + block_limits->opt_unmap_grain); + uint32_t unmap_gran_align = scsi_4btoul( + block_limits->unmap_grain_align); uint64_t ws_max_blks = scsi_8btou64( block_limits->max_write_same_length); @@ -4471,6 +4517,14 @@ dadone(struct cam_periph *periph, union softc->unmap_max_lba = max_unmap_lba_cnt; softc->unmap_max_ranges = min(max_unmap_blk_cnt, UNMAP_MAX_RANGES); + if (unmap_gran > 1) { + softc->unmap_gran = unmap_gran; + if (unmap_gran_align & 0x80000000) { + softc->unmap_gran_align = + unmap_gran_align & + 0x7fffffff; + } + } } else { /* * Unexpected UNMAP limits which means the @@ -5380,6 +5434,10 @@ dasetgeom(struct cam_periph *periph, uin } else if (softc->quirks & DA_Q_4K) { dp->stripesize = 4096; dp->stripeoffset = 0; + } else if (softc->unmap_gran != 0) { + dp->stripesize = block_len * softc->unmap_gran; + dp->stripeoffset = (dp->stripesize - block_len * + softc->unmap_gran_align) % dp->stripesize; } else { dp->stripesize = 0; dp->stripeoffset = 0;