Walking thru a Task Management Request on the UNH target.

State
-----
There are 2 components to the state of a command at any time, written as:
	[iscsi-state, target-msg-state]
where iscsi-state names start with ISCSI_xxx and represents the state seen
	by the rx_thread and tx_thread in iscsi_target.c,
and target-msg-state names the state seen
	by the target_thread in scsi_target.c.


State Transitions
-----------------
State at the end of each step in the diagrams that follow.
0.	[<null>, <null>]
1.	[ISCSI_DEQUEUE, <null>]
2.	[ISCSI_MGT_FN_DONE, <null>]
3.	[ISCSI_DEQUEUE, <null>]
4.	[<null>, <null>]


Thread Interactions
-------------------
	rx_thread	tx_thread	target_thread	midlevel
	|		|		|		|
	1 ---------------------------->
			  <------------ 2
			3
			4


Overview
--------
0.		[<null>, <null>]

1. rx_thread	gets new TASK MANAGEMENT pdu from initiator, allocates iscsi
		command for it and adds this to iscsi queue,
		then calls-back rx_task_mgmt_fn in
		target to allocate target msg, add it to target msg queue,
		and then wake up target_thread.
		[ISCSI_NEW_CMND, ABORT_TASK]

2. target_thread finds and removes msg in msg queue
		searches for matching command and sets its abort_code
		calls back device's task_mgmt_fn_done() entry
		to set state = ISCSI_MGT_FN_DONE and wake up tx_thread
		[ISCSI_MGT_FN_DONE, <null>]

3. tx_thread	creates and sends TM Response pdu
		finds related command and sets its state to ISCSI_DEQUEUE
		[ISCSI_DEQUEUE, <null>]

4. tx_thread	removes command from iscsi queue
		[<null>, <null>]

Details
-------
1. rx_thread in iscsi_target.c
	-> main loop in iscsi_rx_thread()
		read TASK MANAGEMENT Request Header (opcode 0x02)
		read and check header crc if header digest is on
		dispatch on opcode to case ISCSI_INIT_TASK_MGMT_CMND
		which calls handle_task_mgt_command()
	-> handle_task_mgt_command()
		convert big-endian to host pdu fields IN PLACE
		call get_new_cmnd() to allocate clean struct iscsi_cmnd *cmnd
		cmnd->state = ISCSI_NEW_CMND
		fill in fields in cmnd from pdu
		fill in default response = FUNCTION_COMPLETE
		call check_cmd_sn() to check CmdSN of pdu for in-order cmnd
		if cmnd is out-of-order,
			cmnd->state = ISCSI_QUEUE_CMND
		else
			call do_task_mgt()
	-----------------> do_task_mgt() in iscsi_target.c
				if function == ABORT_TASK
					search for command refered to by RTT
					if found
						call-back rx_task_mgmt_fn()
						if this fails
							set cmnd->response to
							FUNCTION_REJECTED
							cmnd->state
							    = ISCSI_MGT_FN_DONE
					else
						call get_abort_response() to set
							cmnd->response to
							TASK_DOES_NOT_EXIST or
							FUNCTION_COMPLETE, as
							appropriate
						cmnd->state = ISCSI_MGT_FN_DONE
				else
					we don't support this TM function yet!
					set cmnd->response to
					  TASK_MANAGEMENT_FUNCTION_NOT_SUPPORTED
					cmnd->state = ISCSI_MGT_FN_DONE
		<--------
		call ack_sent_cmnds() to add this cmnd to session->cmnd_list
	<--------

		-> rx_task_mgmt_fn in scsi_target.c
			allocate Target_Scsi_Message
			fill in fields in msg
			add msg to end of target_data.msgq
			up target_data.target_sem to wake up target thread

	At this point:	cmnd (state=ISCSI_NEW_CMND) is in session->cmnd_list,
			command (message=ABORT_TASK) is in target_data.msgq
			target must act next

2. target_thread in scsi_target.c
	-> main loop in scsi_target_process_thread()
		wake up after blocking on target_data.target_sem
		look at each msg in target_data.msgq
		remove msg from msgq
		dispatch on msg->message == ABORT_TASK
			search target_data.cmd_queue for command with matching
				id and lun
			if found
				set command's abort_code = CMND_ABORTED
				call abort_notify()
		free msg
	<--------

		-> abort_notify() in scsi_target.c
			search target_data.st_device_list to find device
				with id that matches cmnd->dev_id
			if found
				call-back device's task_mgmt_fn_done() entry
					(which is iscsi_task_mgt_fn_done)

		-> iscsi_task_mgt_fn_done() in iscsi_target.c
			call search_task_mgt_command() to find related command
			if found
				state = ISCSI_MGT_FN_DONE
				up conn->tx_sem

	At this point:	cmnd (state=ISCSI_MGT_FN_DONE) is in session->cmnd_list,
			msg is free and is NOT in target_data.msgq
			tx_thread must act next

3. tx_thread in iscsi_target.c
	-> main loop in iscsi_tx_thread()
		wake up after blocking on conn->tx_sem
		look at each command in session->cmnd_list
			dispatch on state to case ISCSI_MGT_FN_DONE
			which calls handle_iscsi_mgt_fn_done()
			repeat loop

	-> handle_iscsi_mgt_fn_done()
		fill in fields in TASK MANAGEMENT Response pdu
		cmnd->state = ISCSI_DEQUEUE
		call send_hdr_only() to send TASK MANAGEMENT Response pdu
		call search_tags() to find aborted command
		if found
			set its state = ISCSI_DEQUEUE
		up on conn->tx_sem to wake tx_thread


	At this point:	cmnd (state=ISCSI_DEQUEUE) is in session->cmnd_list,
			msg is free and is NOT in target_data.msgq
			tx_thread must act next

4. tx_thread in iscsi_target.c
	-> main loop in iscsi_tx_thread()
		wake up after blocking on conn->tx_sem
		look at each command in session->cmnd_list
			dispatch on state to case ISCSI_DEQUEUE
			which removes command from list & calls iscsi_dequeue()
			then restarts loop

	-> iscsi_dequeue()
		if pointer to SCSI cmnd is not NULL
			call-back scsi_target_done() in scsi_target.c
	----------------> scsi_target_done()
				state = ST_DEQUEUE
				up target_data.target_sem
		if this was connection's text_in_progess command, mark it freed
		free up structures pointed to by command
		free up command structure itself

	At this point:	cmnd is free and is NOT in session->cmnd_list,
			msg is free and is NOT in target_data.msgq
			no more action needed on target side
