// File: CMU-SAFARI[P]MQSim/src/ssd/Host_Interface_NVMe.cpp
// Function: SSD_Components::Input_Stream_Manager_NVMe::Handle_serviced_request(SSD_Components::User_Request*)
inline void Input_Stream_Manager_NVMe::Handle_serviced_request(User_Request *request)
{
	stream_id_type stream_id = request->Stream_id;
	((Input_Stream_NVMe *)input_streams[request->Stream_id])->Waiting_user_requests.remove(request);
	((Input_Stream_NVMe *)input_streams[stream_id])->On_the_fly_requests--;

	DEBUG("** Host Interface: Request #" << request->ID << " from stream #" << request->Stream_id << " is finished")

	//If this is a read request, then the read data should be written to host memory
	if (request->Type == UserRequestType::READ)
	{
		((Host_Interface_NVMe *)host_interface)->request_fetch_unit->Send_read_data(request);
	}

	//there are waiting requests in the submission queue but have not been fetched, due to Queue_fetch_size limit
	if (((Input_Stream_NVMe *)input_streams[stream_id])->Submission_head != ((Input_Stream_NVMe *)input_streams[stream_id])->Submission_tail)
	{
		((Host_Interface_NVMe *)host_interface)->request_fetch_unit->Fetch_next_request(stream_id);
		((Input_Stream_NVMe *)input_streams[stream_id])->On_the_fly_requests++;
		((Input_Stream_NVMe *)input_streams[stream_id])->Submission_head++; //Update submission queue head after starting fetch request
		if (((Input_Stream_NVMe *)input_streams[stream_id])->Submission_head == ((Input_Stream_NVMe *)input_streams[stream_id])->Submission_queue_size)
		{ //Circular queue implementation
			((Input_Stream_NVMe *)input_streams[stream_id])->Submission_head = 0;
		}
	}

	//Check if completion queue is full
	if (((Input_Stream_NVMe *)input_streams[stream_id])->Completion_head > ((Input_Stream_NVMe *)input_streams[stream_id])->Completion_tail)
	{
		//completion queue is full
		if (((Input_Stream_NVMe *)input_streams[stream_id])->Completion_tail + 1 == ((Input_Stream_NVMe *)input_streams[stream_id])->Completion_head)
		{
			((Input_Stream_NVMe *)input_streams[stream_id])->Completed_user_requests.push_back(request); //Wait while the completion queue is full
			return;
		}
	}
	else if (((Input_Stream_NVMe *)input_streams[stream_id])->Completion_tail - ((Input_Stream_NVMe *)input_streams[stream_id])->Completion_head == ((Input_Stream_NVMe *)input_streams[stream_id])->Completion_queue_size - 1)
	{
		((Input_Stream_NVMe *)input_streams[stream_id])->Completed_user_requests.push_back(request); //Wait while the completion queue is full
		return;
	}

	inform_host_request_completed(stream_id, request); //Completion queue is not full, so the device can DMA the completion queue entry to the host
	DELETE_REQUEST_NVME(request);
}

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x50(%rsp)
movq %rsi, 0x48(%rsp)
movq 0x50(%rsp), %rdi
movq %rdi, 0x38(%rsp)
movq 0x48(%rsp), %rax
movw 0x68(%rax), %ax
movw %ax, 0x46(%rsp)
addq $0x10, %rdi
movq 0x48(%rsp), %rax
movzwl 0x68(%rax), %eax
movl %eax, %esi
callq 0x85300
movq (%rax), %rdi
addq $0x88, %rdi
leaq 0x48(%rsp), %rsi
callq 0x709e0
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq (%rax), %rax
movw 0xd0(%rax), %cx
addw $-0x1, %cx
movw %cx, 0xd0(%rax)
movq 0x48(%rsp), %rax
cmpl $0x0, 0x64(%rax)
jne 0x8846b
movq 0x38(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x58(%rax), %rdi
movq 0x48(%rsp), %rsi
movq (%rdi), %rax
callq *0x20(%rax)
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movzwl 0x7a(%rax), %eax
movl %eax, 0x34(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq %rax, %rcx
movl 0x34(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x7e(%rcx), %ecx
cmpl %ecx, %eax
je 0x88586
movq 0x38(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x58(%rax), %rdi
movw 0x46(%rsp), %cx
movq (%rdi), %rax
movzwl %cx, %esi
callq *0x10(%rax)
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movw 0xd0(%rax), %cx
addw $0x1, %cx
movw %cx, 0xd0(%rax)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movw 0x7a(%rax), %cx
addw $0x1, %cx
movw %cx, 0x7a(%rax)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movzwl 0x7a(%rax), %eax
movl %eax, 0x30(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq %rax, %rcx
movl 0x30(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x68(%rcx), %ecx
cmpl %ecx, %eax
jne 0x88584
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq (%rax), %rax
movw $0x0, 0x7a(%rax)
jmp 0x88586
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movzwl 0x80(%rax), %eax
movl %eax, 0x2c(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq %rax, %rcx
movl 0x2c(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x82(%rcx), %ecx
cmpl %ecx, %eax
jle 0x8865a
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movzwl 0x82(%rax), %eax
addl $0x1, %eax
movl %eax, 0x28(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq %rax, %rcx
movl 0x28(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x80(%rcx), %ecx
cmpl %ecx, %eax
jne 0x88655
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq (%rax), %rdi
addq $0xa0, %rdi
leaq 0x48(%rsp), %rsi
callq 0x6c210
jmp 0x887fc
jmp 0x88703
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq (%rax), %rax
movzwl 0x82(%rax), %eax
movl %eax, 0x20(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq 0x38(%rsp), %rdi
movq %rax, %rcx
movl 0x20(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x80(%rcx), %ecx
subl %ecx, %eax
movl %eax, 0x24(%rsp)
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq %rax, %rcx
movl 0x24(%rsp), %eax
movq (%rcx), %rcx
movzwl 0x78(%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jne 0x88701
movq 0x38(%rsp), %rdi
addq $0x10, %rdi
movzwl 0x46(%rsp), %eax
movl %eax, %esi
callq 0x85300
movq (%rax), %rdi
addq $0xa0, %rdi
leaq 0x48(%rsp), %rsi
callq 0x6c210
jmp 0x887fc
jmp 0x88703
movq 0x38(%rsp), %rdi
movw 0x46(%rsp), %ax
movq 0x48(%rsp), %rdx
movzwl %ax, %esi
callq 0x888f0
movq 0x48(%rsp), %rax
movq 0x70(%rax), %rax
movq %rax, 0x18(%rsp)
cmpq $0x0, %rax
je 0x88738
movq 0x18(%rsp), %rdi
callq 0x8410
callq 0x46500
movq %rax, %rdi
callq 0x46d20
testb $0x1, %al
jne 0x8874b
jmp 0x88779
movq 0x48(%rsp), %rax
cmpq $0x0, 0x78(%rax)
je 0x88777
movq 0x48(%rsp), %rax
movq 0x78(%rax), %rax
movq %rax, 0x10(%rsp)
cmpq $0x0, %rax
je 0x88775
movq 0x10(%rsp), %rdi
callq 0x8570
jmp 0x88777
jmp 0x88779
movq 0x48(%rsp), %rdi
addq $0x40, %rdi
callq 0x59910
cmpq $0x0, %rax
je 0x887d8
movq 0x5185c(%rip), %rdi     # 0xd9ff0
leaq 0x2214d(%rip), %rsi     # 0xaa8e8
callq 0x8440
movq 0x51849(%rip), %rdi     # 0xd9ff0
leaq 0x25c68(%rip), %rsi     # 0xae416
callq 0x8440
movq %rax, %rdi
movq 0x5179b(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x51807(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
movq 0x48(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x887fc
movq 0x8(%rsp), %rdi
callq 0x6c070
movq 0x8(%rsp), %rdi
callq 0x8410
addq $0x58, %rsp
retq
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)