FreeBSD/sys/cam/ctl/ctl.c
/*
 * Assumptions:
 * - An I/O has just completed, and has been removed from the per-LUN OOA
 *   queue, so some items on the blocked queue may now be unblocked.
 */
- An I/O has just completed, and has been removed from the per-LUN OOA
queue, so some items on the blocked queue may now be unblocked.
- An I / O has just completed and has been removed from the per - LUN OOA queue so some items on the blocked queue may now be unblocked .
static int
ctl_check_blocked(struct ctl_lun *lun)
{
	struct ctl_softc *softc = lun->ctl_softc;
	union ctl_io *cur_blocked, *next_blocked;
	mtx_assert(&lun->lun_lock, MA_OWNED);
	for (cur_blocked = (union ctl_io *)TAILQ_FIRST(&lun->blocked_queue);
	     cur_blocked != NULL; cur_blocked = next_blocked) {
		union ctl_io *prev_ooa;
		ctl_action action;
		next_blocked = (union ctl_io *)TAILQ_NEXT(&cur_blocked->io_hdr,
							  blocked_links);
		prev_ooa = (union ctl_io *)TAILQ_PREV(&cur_blocked->io_hdr,
						      ctl_ooaq, ooa_links);
		action = ctl_check_ooa(lun, cur_blocked, prev_ooa);
		switch (action) {
		case CTL_ACTION_BLOCK:
			break;
		case CTL_ACTION_OVERLAP:
		case CTL_ACTION_OVERLAP_TAG:
			break;
		case CTL_ACTION_PASS:
		case CTL_ACTION_SKIP: {
			const struct ctl_cmd_entry *entry;
			TAILQ_REMOVE(&lun->blocked_queue, &cur_blocked->io_hdr,
				     blocked_links);
			cur_blocked->io_hdr.flags &= ~CTL_FLAG_BLOCKED;
			if ((softc->ha_mode != CTL_HA_MODE_XFER) &&
			    (cur_blocked->io_hdr.flags & CTL_FLAG_FROM_OTHER_SC)){
				union ctl_ha_msg msg_info;
				cur_blocked->io_hdr.flags &= ~CTL_FLAG_IO_ACTIVE;
				msg_info.hdr.original_sc =
					cur_blocked->io_hdr.original_sc;
				msg_info.hdr.serializing_sc = cur_blocked;
				msg_info.hdr.msg_type = CTL_MSG_R2R;
				ctl_ha_msg_send(CTL_HA_CHAN_CTL, &msg_info,
				    sizeof(msg_info.hdr), M_NOWAIT);
				break;
			}
			entry = ctl_get_cmd_entry(&cur_blocked->scsiio, NULL);
			if (ctl_scsiio_lun_check(lun, entry,
						 &cur_blocked->scsiio) == 0) {
				cur_blocked->io_hdr.flags |=
				                      CTL_FLAG_IS_WAS_ON_RTR;
				ctl_enqueue_rtr(cur_blocked);
			} else
				ctl_done(cur_blocked);
			break;
		}
		default:
			break;
		}
	}
	return (CTL_RETVAL_COMPLETE);
}
static int ctl_check_blocked ( struct ctl_lun * lun ) { struct ctl_softc * softc = lun -> ctl_softc ; union ctl_io * cur_blocked , * next_blocked ; mtx_assert ( & lun -> lun_lock , MA_OWNED ) ; for ( cur_blocked = ( union ctl_io * ) TAILQ_FIRST ( & lun -> blocked_queue ) ; cur_blocked != NULL ; cur_blocked = next_blocked ) { union ctl_io * prev_ooa ; ctl_action action ; next_blocked = ( union ctl_io * ) TAILQ_NEXT ( & cur_blocked -> io_hdr , blocked_links ) ; prev_ooa = ( union ctl_io * ) TAILQ_PREV ( & cur_blocked -> io_hdr , ctl_ooaq , ooa_links ) ; action = ctl_check_ooa ( lun , cur_blocked , prev_ooa ) ; switch ( action ) { case CTL_ACTION_BLOCK : break ; case CTL_ACTION_OVERLAP : case CTL_ACTION_OVERLAP_TAG : break ; case CTL_ACTION_PASS : case CTL_ACTION_SKIP : { const struct ctl_cmd_entry * entry ; TAILQ_REMOVE ( & lun -> blocked_queue , & cur_blocked -> io_hdr , blocked_links ) ; cur_blocked -> io_hdr . flags &= ~ CTL_FLAG_BLOCKED ; if ( ( softc -> ha_mode != CTL_HA_MODE_XFER ) && ( cur_blocked -> io_hdr . flags & CTL_FLAG_FROM_OTHER_SC ) ) { union ctl_ha_msg msg_info ; cur_blocked -> io_hdr . flags &= ~ CTL_FLAG_IO_ACTIVE ; msg_info . hdr . original_sc = cur_blocked -> io_hdr . original_sc ; msg_info . hdr . serializing_sc = cur_blocked ; msg_info . hdr . msg_type = CTL_MSG_R2R ; ctl_ha_msg_send ( CTL_HA_CHAN_CTL , & msg_info , sizeof ( msg_info . hdr ) , M_NOWAIT ) ; break ; } entry = ctl_get_cmd_entry ( & cur_blocked -> scsiio , NULL ) ; if ( ctl_scsiio_lun_check ( lun , entry , & cur_blocked -> scsiio ) == 0 ) { cur_blocked -> io_hdr . flags |= CTL_FLAG_IS_WAS_ON_RTR ; ctl_enqueue_rtr ( cur_blocked ) ; } else ctl_done ( cur_blocked ) ; break ; } default : break ; } } return ( CTL_RETVAL_COMPLETE ) ; }
Assumptions:
 - An I/O has just completed, and has been removed from the per-LUN OOA
   queue, so some items on the blocked queue may now be unblocked.
Assumptions : - An I / O has just completed and has been removed from the per - LUN OOA queue so some items on the blocked queue may now be unblocked .
/*
	 * Run forward from the head of the blocked queue, checking each
	 * entry against the I/Os prior to it on the OOA queue to see if
	 * there is still any blockage.
	 *
	 * We cannot use the TAILQ_FOREACH() macro, because it can't deal
	 * with our removing a variable on it while it is traversing the
	 * list.
	 */ /*
		 * If cur_blocked happens to be the first item in the OOA
		 * queue now, prev_ooa will be NULL, and the action
		 * returned will just be CTL_ACTION_PASS.
		 */ /* Nothing to do here, still blocked */ /*
			 * This shouldn't happen!  In theory we've already
			 * checked this command for overlap...
			 */ /*
			 * The skip case shouldn't happen, this transaction
			 * should have never made it onto the blocked queue.
			 */ /*
			 * This I/O is no longer blocked, we can remove it
			 * from the blocked queue.  Since this is a TAILQ
			 * (doubly linked list), we can do O(1) removals
			 * from any place on the list.
			 */ /*
				 * Need to send IO back to original side to
				 * run
				 */ /*
			 * Check this I/O for LUN state changes that may
			 * have happened while this command was blocked.
			 * The LUN state may have been changed by a command
			 * ahead of us in the queue, so we need to re-check
			 * for any states that can be caused by SCSI
			 * commands.
			 */ /*
			 * This probably shouldn't happen -- we shouldn't
			 * get CTL_ACTION_ERROR, or anything else.
			 */