From owner-dev-commits-src-main@freebsd.org Sat Feb 27 15:40:30 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 2823054A2D7; Sat, 27 Feb 2021 15:40:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4DnrML0fFPz3Gl8; Sat, 27 Feb 2021 15:40:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 049742040A; Sat, 27 Feb 2021 15:40:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 11RFeTYw068094; Sat, 27 Feb 2021 15:40:29 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 11RFeTN6068093; Sat, 27 Feb 2021 15:40:29 GMT (envelope-from git) Date: Sat, 27 Feb 2021 15:40:29 GMT Message-Id: <202102271540.11RFeTN6068093@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Alexander Motin Subject: git: 9d9fd8b79f0e - main - Micro-optimize OOA queue processing. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mav X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 9d9fd8b79f0ebe59f791c8225fa01ab59858b7b5 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 27 Feb 2021 15:40:30 -0000 The branch main has been updated by mav: URL: https://cgit.FreeBSD.org/src/commit/?id=9d9fd8b79f0ebe59f791c8225fa01ab59858b7b5 commit 9d9fd8b79f0ebe59f791c8225fa01ab59858b7b5 Author: Alexander Motin AuthorDate: 2021-02-27 15:14:05 +0000 Commit: Alexander Motin CommitDate: 2021-02-27 15:40:24 +0000 Micro-optimize OOA queue processing. - Move ctl_get_cmd_entry() calls from every OOA traversal to when the requests first inserted, storing seridx in struct ctl_scsiio. - Move some checks out of the loop in ctl_check_ooa(). - Replace checks for errors that can not happen with asserts. - Transpose ctl_serialize_table, so that any OOA traversal accessed only one row (cache line). Compact it from enum to uint8_t. - Optimize static branch predictions in hottest places. Due to O(n) nature on deep LUN queues this can be the hottest code path in CTL, and additional 20% of IOPS I see in some 4KB I/O tests are good to have in reserve. About 50% of CPU time here according to the profiles is now spent in two memory accesses per traversed request in OOA. Sponsored by: iXsystems, Inc. MFC after: 2 weeks --- sys/cam/ctl/ctl.c | 238 ++++++++++++++++++++------------------------ sys/cam/ctl/ctl_io.h | 2 +- sys/cam/ctl/ctl_private.h | 18 ++-- sys/cam/ctl/ctl_ser_table.c | 41 ++++---- 4 files changed, 135 insertions(+), 164 deletions(-) diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 18a82ca72d76..cae6dd4aa101 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -500,9 +500,10 @@ static int ctl_inquiry_std(struct ctl_scsiio *ctsio); static int ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len); static ctl_action ctl_extent_check(union ctl_io *io1, union ctl_io *io2, bool seq); -static ctl_action ctl_extent_check_seq(union ctl_io *io1, union ctl_io *io2); +static ctl_action ctl_seq_check(union ctl_io *io1, union ctl_io *io2); static ctl_action ctl_check_for_blockage(struct ctl_lun *lun, - union ctl_io *pending_io, union ctl_io *ooa_io); + union ctl_io *pending_io, const uint8_t *serialize_row, + union ctl_io *ooa_io); static ctl_action ctl_check_ooa(struct ctl_lun *lun, union ctl_io *pending_io, union ctl_io **starting_io); static void ctl_try_unblock_io(struct ctl_lun *lun, union ctl_io *io, @@ -2313,6 +2314,7 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) } entry = ctl_get_cmd_entry(ctsio, NULL); + ctsio->seridx = entry->seridx; if (ctl_scsiio_lun_check(lun, entry, ctsio) != 0) { mtx_unlock(&lun->lun_lock); goto badjuju; @@ -2333,12 +2335,6 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) bio = (union ctl_io *)LIST_NEXT(&ctsio->io_hdr, ooa_links); switch (ctl_check_ooa(lun, (union ctl_io *)ctsio, &bio)) { - case CTL_ACTION_BLOCK: - ctsio->io_hdr.blocker = bio; - TAILQ_INSERT_TAIL(&bio->io_hdr.blocked_queue, &ctsio->io_hdr, - blocked_links); - mtx_unlock(&lun->lun_lock); - break; case CTL_ACTION_PASS: case CTL_ACTION_SKIP: if (softc->ha_mode == CTL_HA_MODE_XFER) { @@ -2357,6 +2353,12 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) sizeof(msg_info.hdr), M_WAITOK); } break; + case CTL_ACTION_BLOCK: + ctsio->io_hdr.blocker = bio; + TAILQ_INSERT_TAIL(&bio->io_hdr.blocked_queue, &ctsio->io_hdr, + blocked_links); + mtx_unlock(&lun->lun_lock); + break; case CTL_ACTION_OVERLAP: LIST_REMOVE(&ctsio->io_hdr, ooa_links); mtx_unlock(&lun->lun_lock); @@ -2366,14 +2368,6 @@ ctl_serialize_other_sc_cmd(struct ctl_scsiio *ctsio) LIST_REMOVE(&ctsio->io_hdr, ooa_links); mtx_unlock(&lun->lun_lock); ctl_set_overlapped_tag(ctsio, ctsio->tag_num); - goto badjuju; - case CTL_ACTION_ERROR: - default: - LIST_REMOVE(&ctsio->io_hdr, ooa_links); - mtx_unlock(&lun->lun_lock); - - ctl_set_internal_failure(ctsio, /*sks_valid*/ 0, - /*retry_count*/ 0); badjuju: ctl_copy_sense_data_back((union ctl_io *)ctsio, &msg_info); msg_info.hdr.original_sc = ctsio->io_hdr.remote_io; @@ -2383,6 +2377,8 @@ badjuju: sizeof(msg_info.scsi), M_WAITOK); ctl_free_io((union ctl_io *)ctsio); break; + default: + __assert_unreachable(); } } @@ -10819,8 +10815,9 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len) break; } default: + *lba = 0; + *len = UINT64_MAX; return (1); - break; /* NOTREACHED */ } return (0); @@ -10854,7 +10851,7 @@ ctl_extent_check_unmap(union ctl_io *io, uint64_t lba2, uint64_t len2) /* If not UNMAP -- go other way. */ if (io->scsiio.cdb[0] != UNMAP) - return (CTL_ACTION_ERROR); + return (CTL_ACTION_SKIP); /* If UNMAP without data -- block and wait for data. */ ptrlen = (struct ctl_ptr_len_flags *) @@ -10882,33 +10879,34 @@ ctl_extent_check(union ctl_io *io1, union ctl_io *io2, bool seq) uint64_t len1, len2; int retval; - if (ctl_get_lba_len(io2, &lba2, &len2) != 0) - return (CTL_ACTION_ERROR); + retval = ctl_get_lba_len(io2, &lba2, &len2); + KASSERT(retval == 0, ("ctl_get_lba_len() error")); retval = ctl_extent_check_unmap(io1, lba2, len2); - if (retval != CTL_ACTION_ERROR) + if (retval != CTL_ACTION_SKIP) return (retval); - if (ctl_get_lba_len(io1, &lba1, &len1) != 0) - return (CTL_ACTION_ERROR); + retval = ctl_get_lba_len(io1, &lba1, &len1); + KASSERT(retval == 0, ("ctl_get_lba_len() error")); - if (io1->io_hdr.flags & CTL_FLAG_SERSEQ_DONE) + if (seq && (io1->io_hdr.flags & CTL_FLAG_SERSEQ_DONE)) seq = FALSE; return (ctl_extent_check_lba(lba1, len1, lba2, len2, seq)); } static ctl_action -ctl_extent_check_seq(union ctl_io *io1, union ctl_io *io2) +ctl_seq_check(union ctl_io *io1, union ctl_io *io2) { uint64_t lba1, lba2; uint64_t len1, len2; + int retval; if (io1->io_hdr.flags & CTL_FLAG_SERSEQ_DONE) return (CTL_ACTION_PASS); - if (ctl_get_lba_len(io1, &lba1, &len1) != 0) - return (CTL_ACTION_ERROR); - if (ctl_get_lba_len(io2, &lba2, &len2) != 0) - return (CTL_ACTION_ERROR); + retval = ctl_get_lba_len(io1, &lba1, &len1); + KASSERT(retval == 0, ("ctl_get_lba_len() error")); + retval = ctl_get_lba_len(io2, &lba2, &len2); + KASSERT(retval == 0, ("ctl_get_lba_len() error")); if (lba1 + len1 == lba2) return (CTL_ACTION_BLOCK); @@ -10917,25 +10915,15 @@ ctl_extent_check_seq(union ctl_io *io1, union ctl_io *io2) static ctl_action ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, - union ctl_io *ooa_io) + const uint8_t *serialize_row, union ctl_io *ooa_io) { - const struct ctl_cmd_entry *pending_entry, *ooa_entry; - const ctl_serialize_action *serialize_row; - - /* - * Aborted commands are not going to be executed and may even - * not report completion, so we don't care about their order. - * Let them complete ASAP to clean the OOA queue. - */ - if (pending_io->io_hdr.flags & CTL_FLAG_ABORT) - return (CTL_ACTION_SKIP); /* * The initiator attempted multiple untagged commands at the same * time. Can't do that. */ - if ((pending_io->scsiio.tag_type == CTL_TAG_UNTAGGED) - && (ooa_io->scsiio.tag_type == CTL_TAG_UNTAGGED) + if (__predict_false(pending_io->scsiio.tag_type == CTL_TAG_UNTAGGED) + && __predict_false(ooa_io->scsiio.tag_type == CTL_TAG_UNTAGGED) && ((pending_io->io_hdr.nexus.targ_port == ooa_io->io_hdr.nexus.targ_port) && (pending_io->io_hdr.nexus.initid == @@ -10955,9 +10943,9 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, * command with the same tag number as long as the previous * instance of this tag number has been aborted somehow. */ - if ((pending_io->scsiio.tag_type != CTL_TAG_UNTAGGED) - && (ooa_io->scsiio.tag_type != CTL_TAG_UNTAGGED) - && (pending_io->scsiio.tag_num == ooa_io->scsiio.tag_num) + if (__predict_true(pending_io->scsiio.tag_type != CTL_TAG_UNTAGGED) + && __predict_true(ooa_io->scsiio.tag_type != CTL_TAG_UNTAGGED) + && __predict_false(pending_io->scsiio.tag_num == ooa_io->scsiio.tag_num) && ((pending_io->io_hdr.nexus.targ_port == ooa_io->io_hdr.nexus.targ_port) && (pending_io->io_hdr.nexus.initid == @@ -10980,75 +10968,47 @@ ctl_check_for_blockage(struct ctl_lun *lun, union ctl_io *pending_io, * * XXX KDM check for other types of blockage first?? */ - if (pending_io->scsiio.tag_type == CTL_TAG_HEAD_OF_QUEUE) + if (__predict_false(pending_io->scsiio.tag_type == CTL_TAG_HEAD_OF_QUEUE)) return (CTL_ACTION_PASS); - /* - * Ordered tags have to block until all items ahead of them - * have completed. If we get called with an ordered tag, we always - * block, if something else is ahead of us in the queue. - */ - if (pending_io->scsiio.tag_type == CTL_TAG_ORDERED) - return (CTL_ACTION_BLOCK); - /* * Simple tags get blocked until all head of queue and ordered tags * ahead of them have completed. I'm lumping untagged commands in * with simple tags here. XXX KDM is that the right thing to do? */ - if (((pending_io->scsiio.tag_type == CTL_TAG_UNTAGGED) - || (pending_io->scsiio.tag_type == CTL_TAG_SIMPLE)) - && ((ooa_io->scsiio.tag_type == CTL_TAG_HEAD_OF_QUEUE) - || (ooa_io->scsiio.tag_type == CTL_TAG_ORDERED))) + if (__predict_false(ooa_io->scsiio.tag_type == CTL_TAG_ORDERED) || + __predict_false(ooa_io->scsiio.tag_type == CTL_TAG_HEAD_OF_QUEUE)) return (CTL_ACTION_BLOCK); - pending_entry = ctl_get_cmd_entry(&pending_io->scsiio, NULL); - KASSERT(pending_entry->seridx < CTL_SERIDX_COUNT, - ("%s: Invalid seridx %d for pending CDB %02x %02x @ %p", - __func__, pending_entry->seridx, pending_io->scsiio.cdb[0], - pending_io->scsiio.cdb[1], pending_io)); - ooa_entry = ctl_get_cmd_entry(&ooa_io->scsiio, NULL); - if (ooa_entry->seridx == CTL_SERIDX_INVLD) - return (CTL_ACTION_PASS); /* Unsupported command in OOA queue */ - KASSERT(ooa_entry->seridx < CTL_SERIDX_COUNT, - ("%s: Invalid seridx %d for ooa CDB %02x %02x @ %p", - __func__, ooa_entry->seridx, ooa_io->scsiio.cdb[0], - ooa_io->scsiio.cdb[1], ooa_io)); - - serialize_row = ctl_serialize_table[ooa_entry->seridx]; - - switch (serialize_row[pending_entry->seridx]) { - case CTL_SER_BLOCK: - return (CTL_ACTION_BLOCK); - case CTL_SER_EXTENT: - return (ctl_extent_check(ooa_io, pending_io, - (lun->be_lun->serseq == CTL_LUN_SERSEQ_ON))); - case CTL_SER_EXTENTOPT: - if ((lun->MODE_CTRL.queue_flags & SCP_QUEUE_ALG_MASK) != - SCP_QUEUE_ALG_UNRESTRICTED) - return (ctl_extent_check(ooa_io, pending_io, - (lun->be_lun->serseq == CTL_LUN_SERSEQ_ON))); + /* Unsupported command in OOA queue. */ + if (__predict_false(ooa_io->scsiio.seridx == CTL_SERIDX_INVLD)) return (CTL_ACTION_PASS); - case CTL_SER_EXTENTSEQ: + + switch (serialize_row[ooa_io->scsiio.seridx]) { + case CTL_SER_SEQ: if (lun->be_lun->serseq != CTL_LUN_SERSEQ_OFF) - return (ctl_extent_check_seq(ooa_io, pending_io)); - return (CTL_ACTION_PASS); + return (ctl_seq_check(ooa_io, pending_io)); + /* FALLTHROUGH */ case CTL_SER_PASS: return (CTL_ACTION_PASS); + case CTL_SER_EXTENTOPT: + if ((lun->MODE_CTRL.queue_flags & SCP_QUEUE_ALG_MASK) == + SCP_QUEUE_ALG_UNRESTRICTED) + return (CTL_ACTION_PASS); + /* FALLTHROUGH */ + case CTL_SER_EXTENT: + return (ctl_extent_check(ooa_io, pending_io, + (lun->be_lun->serseq == CTL_LUN_SERSEQ_ON))); case CTL_SER_BLOCKOPT: - if ((lun->MODE_CTRL.queue_flags & SCP_QUEUE_ALG_MASK) != + if ((lun->MODE_CTRL.queue_flags & SCP_QUEUE_ALG_MASK) == SCP_QUEUE_ALG_UNRESTRICTED) - return (CTL_ACTION_BLOCK); - return (CTL_ACTION_PASS); - case CTL_SER_SKIP: - return (CTL_ACTION_SKIP); + return (CTL_ACTION_PASS); + /* FALLTHROUGH */ + case CTL_SER_BLOCK: + return (CTL_ACTION_BLOCK); default: - panic("%s: Invalid serialization value %d for %d => %d", - __func__, serialize_row[pending_entry->seridx], - pending_entry->seridx, ooa_entry->seridx); + __assert_unreachable(); } - - return (CTL_ACTION_ERROR); } /* @@ -11061,20 +11021,41 @@ static ctl_action ctl_check_ooa(struct ctl_lun *lun, union ctl_io *pending_io, union ctl_io **starting_io) { - union ctl_io *ooa_io; + union ctl_io *ooa_io = *starting_io; + const uint8_t *serialize_row; ctl_action action; mtx_assert(&lun->lun_lock, MA_OWNED); + /* + * Aborted commands are not going to be executed and may even + * not report completion, so we don't care about their order. + * Let them complete ASAP to clean the OOA queue. + */ + if (__predict_false(pending_io->io_hdr.flags & CTL_FLAG_ABORT)) + return (CTL_ACTION_SKIP); + + /* + * Ordered tags have to block until all items ahead of them have + * completed. If we get called with an ordered tag, we always + * block, if something else is ahead of us in the queue. + */ + if ((pending_io->scsiio.tag_type == CTL_TAG_ORDERED) && + (ooa_io != NULL)) + return (CTL_ACTION_BLOCK); + + serialize_row = ctl_serialize_table[pending_io->scsiio.seridx]; + /* * Run back along the OOA queue, starting with the current * blocked I/O and going through every I/O before it on the * queue. If starting_io is NULL, we'll just end up returning * CTL_ACTION_PASS. */ - for (ooa_io = *starting_io; ooa_io != NULL; + for (; ooa_io != NULL; ooa_io = (union ctl_io *)LIST_NEXT(&ooa_io->io_hdr, ooa_links)) { - action = ctl_check_for_blockage(lun, pending_io, ooa_io); + action = ctl_check_for_blockage(lun, pending_io, serialize_row, + ooa_io); if (action != CTL_ACTION_PASS) { *starting_io = ooa_io; return (action); @@ -11127,13 +11108,6 @@ ctl_try_unblock_io(struct ctl_lun *lun, union ctl_io *io, bool skip) io->io_hdr.blocker = NULL; switch (action) { - case CTL_ACTION_OVERLAP: - ctl_set_overlapped_cmd(&io->scsiio); - goto error; - case CTL_ACTION_OVERLAP_TAG: - ctl_set_overlapped_tag(&io->scsiio, - io->scsiio.tag_num & 0xff); - goto error; case CTL_ACTION_PASS: case CTL_ACTION_SKIP: @@ -11163,12 +11137,14 @@ ctl_try_unblock_io(struct ctl_lun *lun, union ctl_io *io, bool skip) io->io_hdr.flags |= CTL_FLAG_IS_WAS_ON_RTR; ctl_enqueue_rtr(io); break; - case CTL_ACTION_ERROR: default: - ctl_set_internal_failure(&io->scsiio, - /*sks_valid*/ 0, - /*retry_count*/ 0); - + __assert_unreachable(); + case CTL_ACTION_OVERLAP: + ctl_set_overlapped_cmd(&io->scsiio); + goto error; + case CTL_ACTION_OVERLAP_TAG: + ctl_set_overlapped_tag(&io->scsiio, + io->scsiio.tag_num & 0xff); error: /* Serializing commands from the other SC are done here. */ if ((io->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC) && @@ -11380,8 +11356,8 @@ ctl_failover_lun(union ctl_io *rio) /* We are master */ if (io->flags & CTL_FLAG_FROM_OTHER_SC) { if (io->flags & CTL_FLAG_IO_ACTIVE) { - io->flags |= CTL_FLAG_ABORT; - io->flags |= CTL_FLAG_FAILOVER; + io->flags |= CTL_FLAG_ABORT | + CTL_FLAG_FAILOVER; ctl_try_unblock_io(lun, (union ctl_io *)io, FALSE); } else { /* This can be only due to DATAMOVE */ @@ -11615,18 +11591,18 @@ ctl_scsiio_precheck(struct ctl_scsiio *ctsio) bio = (union ctl_io *)LIST_NEXT(&ctsio->io_hdr, ooa_links); switch (ctl_check_ooa(lun, (union ctl_io *)ctsio, &bio)) { - case CTL_ACTION_BLOCK: - ctsio->io_hdr.blocker = bio; - TAILQ_INSERT_TAIL(&bio->io_hdr.blocked_queue, &ctsio->io_hdr, - blocked_links); - mtx_unlock(&lun->lun_lock); - break; case CTL_ACTION_PASS: case CTL_ACTION_SKIP: ctsio->io_hdr.flags |= CTL_FLAG_IS_WAS_ON_RTR; mtx_unlock(&lun->lun_lock); ctl_enqueue_rtr((union ctl_io *)ctsio); break; + case CTL_ACTION_BLOCK: + ctsio->io_hdr.blocker = bio; + TAILQ_INSERT_TAIL(&bio->io_hdr.blocked_queue, &ctsio->io_hdr, + blocked_links); + mtx_unlock(&lun->lun_lock); + break; case CTL_ACTION_OVERLAP: mtx_unlock(&lun->lun_lock); ctl_set_overlapped_cmd(ctsio); @@ -11637,14 +11613,8 @@ ctl_scsiio_precheck(struct ctl_scsiio *ctsio) ctl_set_overlapped_tag(ctsio, ctsio->tag_num & 0xff); ctl_done((union ctl_io *)ctsio); break; - case CTL_ACTION_ERROR: default: - mtx_unlock(&lun->lun_lock); - ctl_set_internal_failure(ctsio, - /*sks_valid*/ 0, - /*retry_count*/ 0); - ctl_done((union ctl_io *)ctsio); - break; + __assert_unreachable(); } } @@ -11673,6 +11643,7 @@ ctl_validate_command(struct ctl_scsiio *ctsio) uint8_t diff; entry = ctl_get_cmd_entry(ctsio, &sa); + ctsio->seridx = entry->seridx; if (entry->execute == NULL) { if (sa) ctl_set_invalid_field(ctsio, @@ -13303,10 +13274,15 @@ ctl_serseq_done(union ctl_io *io) if (lun->be_lun->serseq == CTL_LUN_SERSEQ_OFF) return; - mtx_lock(&lun->lun_lock); - io->io_hdr.flags |= CTL_FLAG_SERSEQ_DONE; - ctl_try_unblock_others(lun, io, FALSE); - mtx_unlock(&lun->lun_lock); + + /* This is racy, but should not be a problem. */ + if (!TAILQ_EMPTY(&io->io_hdr.blocked_queue)) { + mtx_lock(&lun->lun_lock); + io->io_hdr.flags |= CTL_FLAG_SERSEQ_DONE; + ctl_try_unblock_others(lun, io, FALSE); + mtx_unlock(&lun->lun_lock); + } else + io->io_hdr.flags |= CTL_FLAG_SERSEQ_DONE; } void diff --git a/sys/cam/ctl/ctl_io.h b/sys/cam/ctl/ctl_io.h index 349cb02820d9..de312608da8e 100644 --- a/sys/cam/ctl/ctl_io.h +++ b/sys/cam/ctl/ctl_io.h @@ -326,7 +326,7 @@ struct ctl_scsiio { struct scsi_sense_data sense_data; /* sense data */ uint8_t sense_len; /* Returned sense length */ uint8_t scsi_status; /* SCSI status byte */ - uint8_t sense_residual; /* Unused. */ + uint8_t seridx; /* Serialization index. */ uint8_t priority; /* Command priority */ uint32_t residual; /* Unused */ uint32_t tag_num; /* tag number */ diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h index 8940babd4904..a891041e8f50 100644 --- a/sys/cam/ctl/ctl_private.h +++ b/sys/cam/ctl/ctl_private.h @@ -65,22 +65,20 @@ struct ctl_io_pool { }; typedef enum { - CTL_SER_BLOCK, - CTL_SER_BLOCKOPT, - CTL_SER_EXTENT, - CTL_SER_EXTENTOPT, - CTL_SER_EXTENTSEQ, + CTL_SER_SEQ, CTL_SER_PASS, - CTL_SER_SKIP + CTL_SER_EXTENTOPT, + CTL_SER_EXTENT, + CTL_SER_BLOCKOPT, + CTL_SER_BLOCK, } ctl_serialize_action; typedef enum { - CTL_ACTION_BLOCK, - CTL_ACTION_OVERLAP, - CTL_ACTION_OVERLAP_TAG, CTL_ACTION_PASS, CTL_ACTION_SKIP, - CTL_ACTION_ERROR + CTL_ACTION_BLOCK, + CTL_ACTION_OVERLAP, + CTL_ACTION_OVERLAP_TAG } ctl_action; /* diff --git a/sys/cam/ctl/ctl_ser_table.c b/sys/cam/ctl/ctl_ser_table.c index 5499e63534fa..be9ca6b34631 100644 --- a/sys/cam/ctl/ctl_ser_table.c +++ b/sys/cam/ctl/ctl_ser_table.c @@ -43,11 +43,8 @@ /* TABLE ctlSerTbl */ /* */ /* The matrix which drives the serialization algorithm. The major index */ -/* (the first) into this table is the command being checked and the minor */ -/* index is the command against which the first command is being checked. */ -/* i.e., the major index (row) command is ahead of the minor index command */ -/* (column) in the queue. This allows the code to optimize by capturing */ -/* the result of the first indexing operation into a pointer. */ +/* (the first, row) into this table is the new command. The minor index */ +/* (column) is the older, possibly already running, command. */ /* */ /* Whenever a new value is added to the IDX_T type, this matrix must be */ /* expanded by one row AND one column -- Because of this, some effort */ @@ -55,29 +52,29 @@ /* */ /****************************************************************************/ -#define sK CTL_SER_SKIP /* Skip */ #define pS CTL_SER_PASS /* Pass */ #define bK CTL_SER_BLOCK /* Blocked */ #define bO CTL_SER_BLOCKOPT /* Optional block */ #define xT CTL_SER_EXTENT /* Extent check */ #define xO CTL_SER_EXTENTOPT /* Optional extent check */ -#define xS CTL_SER_EXTENTSEQ /* Sequential extent check */ +#define xS CTL_SER_SEQ /* Sequential check */ -const static ctl_serialize_action +const static uint8_t ctl_serialize_table[CTL_SERIDX_COUNT][CTL_SERIDX_COUNT] = { /**>IDX_ :: 2nd:TUR RD WRT UNM SYN MDSN MDSL RQSN INQ RDCP RES LSNS FMT STR*/ -/*TUR */{ pS, pS, pS, pS, pS, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*READ */{ pS, xS, xT, bO, pS, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*WRITE */{ pS, xT, xT, bO, bO, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*UNMAP */{ pS, xO, xO, pS, pS, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*SYNC */{ pS, pS, pS, pS, pS, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*MD_SNS */{ bK, bK, bK, bK, bK, pS, bK, bK, pS, pS, bK, pS, bK, bK}, -/*MD_SEL */{ bK, bK, bK, bK, bK, bK, bK, bK, pS, pS, bK, pS, bK, bK}, -/*RQ_SNS */{ pS, pS, pS, pS, pS, pS, pS, bK, pS, pS, bK, pS, bK, bK}, -/*INQ */{ pS, pS, pS, pS, pS, pS, pS, bK, pS, pS, pS, pS, bK, bK}, -/*RD_CAP */{ pS, pS, pS, pS, pS, pS, pS, bK, pS, pS, pS, pS, bK, pS}, -/*RES */{ bK, bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK}, -/*LOG_SNS */{ pS, pS, pS, pS, pS, pS, bK, bK, pS, pS, bK, pS, bK, bK}, -/*FORMAT */{ pS, bK, bK, bK, bK, bK, bK, pS, pS, bK, bK, bK, bK, bK}, -/*START */{ bK, bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK, bK}, +/*TUR */{ pS, pS, pS, pS, pS, bK, bK, pS, pS, pS, bK, pS, pS, bK}, +/*READ */{ pS, xS, xT, xO, pS, bK, bK, pS, pS, pS, bK, pS, bK, bK}, +/*WRITE */{ pS, xT, xT, xO, pS, bK, bK, pS, pS, pS, bK, pS, bK, bK}, +/*UNMAP */{ pS, bO, bO, pS, pS, bK, bK, pS, pS, pS, bK, pS, bK, bK}, +/*SYNC */{ pS, pS, bO, pS, pS, bK, bK, pS, pS, pS, bK, pS, bK, bK}, +/*MD_SNS */{ bK, bK, bK, bK, bK, pS, bK, pS, pS, pS, bK, pS, bK, bK}, +/*MD_SEL */{ bK, bK, bK, bK, bK, bK, bK, pS, pS, pS, bK, bK, bK, bK}, +/*RQ_SNS */{ bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, pS, bK}, +/*INQ */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, pS}, +/*RD_CAP */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, bK, pS, bK, bK}, +/*RES */{ bK, bK, bK, bK, bK, bK, bK, bK, pS, pS, bK, bK, bK, bK}, +/*LOG_SNS */{ pS, pS, pS, pS, pS, pS, pS, pS, pS, pS, bK, pS, bK, bK}, +/*FORMAT */{ bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK, bK}, +/*START */{ bK, bK, bK, bK, bK, bK, bK, bK, bK, pS, bK, bK, bK, bK}, }; +