1 /*
2    Copyright (C) 2011 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 2.1 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
24 
25 #ifdef HAVE_ARPA_INET_H
26 #include <arpa/inet.h>
27 #endif
28 
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 #include <stdio.h>
34 #include "iscsi.h"
35 #include "iscsi-private.h"
36 #include "scsi-lowlevel.h"
37 
38 int
iscsi_task_mgmt_async(struct iscsi_context * iscsi,int lun,enum iscsi_task_mgmt_funcs function,uint32_t ritt,uint32_t rcmdsn,iscsi_command_cb cb,void * private_data)39 iscsi_task_mgmt_async(struct iscsi_context *iscsi,
40 		      int lun, enum iscsi_task_mgmt_funcs function,
41 		      uint32_t ritt, uint32_t rcmdsn,
42 		      iscsi_command_cb cb, void *private_data)
43 {
44 	struct iscsi_pdu *pdu;
45 
46 	if (iscsi->is_loggedin == 0) {
47 		iscsi_set_error(iscsi, "trying to send task-mgmt while not "
48 				"logged in");
49 		return -1;
50 	}
51 
52 	pdu = iscsi_allocate_pdu(iscsi,
53 				 ISCSI_PDU_SCSI_TASK_MANAGEMENT_REQUEST,
54 				 ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE,
55 				 iscsi_itt_post_increment(iscsi),
56 				 ISCSI_PDU_DROP_ON_RECONNECT);
57 	if (pdu == NULL) {
58 		iscsi_set_error(iscsi, "Failed to allocate task mgmt pdu");
59 		return -1;
60 	}
61 
62 	/* immediate flag */
63 	iscsi_pdu_set_immediate(pdu);
64 
65 	/* flags */
66 	iscsi_pdu_set_pduflags(pdu, 0x80 | function);
67 
68 	/* lun */
69 	iscsi_pdu_set_lun(pdu, lun);
70 
71 	/* ritt */
72 	iscsi_pdu_set_ritt(pdu, ritt);
73 
74 	/* cmdsn is not increased if Immediate delivery*/
75 	iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
76 
77 	/* rcmdsn */
78 	iscsi_pdu_set_rcmdsn(pdu, rcmdsn);
79 
80 	pdu->callback     = cb;
81 	pdu->private_data = private_data;
82 
83 	if (iscsi_queue_pdu(iscsi, pdu) != 0) {
84 		iscsi_set_error(iscsi, "failed to queue iscsi taskmgmt pdu");
85 		iscsi->drv->free_pdu(iscsi, pdu);
86 		return -1;
87 	}
88 
89 	return 0;
90 }
91 
92 int
iscsi_process_task_mgmt_reply(struct iscsi_context * iscsi,struct iscsi_pdu * pdu,struct iscsi_in_pdu * in)93 iscsi_process_task_mgmt_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
94 			    struct iscsi_in_pdu *in)
95 {
96 	uint32_t response = in->hdr[2];
97 
98 	if (pdu->callback) {
99 		pdu->callback(iscsi, SCSI_STATUS_GOOD, &response, pdu->private_data);
100 	}
101 	return 0;
102 }
103 
104 int
iscsi_task_mgmt_abort_task_async(struct iscsi_context * iscsi,struct scsi_task * task,iscsi_command_cb cb,void * private_data)105 iscsi_task_mgmt_abort_task_async(struct iscsi_context *iscsi,
106 		      struct scsi_task *task,
107 		      iscsi_command_cb cb, void *private_data)
108 {
109 	return iscsi_task_mgmt_async(iscsi,
110 		      task->lun, ISCSI_TM_ABORT_TASK,
111 		      task->itt, task->cmdsn,
112 		      cb, private_data);
113 }
114 
115 int
iscsi_task_mgmt_abort_task_set_async(struct iscsi_context * iscsi,uint32_t lun,iscsi_command_cb cb,void * private_data)116 iscsi_task_mgmt_abort_task_set_async(struct iscsi_context *iscsi,
117 		      uint32_t lun,
118 		      iscsi_command_cb cb, void *private_data)
119 {
120 	iscsi_scsi_cancel_all_tasks(iscsi);
121 
122 	return iscsi_task_mgmt_async(iscsi,
123 		      lun, ISCSI_TM_ABORT_TASK_SET,
124 		      0xffffffff, 0,
125 		      cb, private_data);
126 }
127 
128 int
iscsi_task_mgmt_lun_reset_async(struct iscsi_context * iscsi,uint32_t lun,iscsi_command_cb cb,void * private_data)129 iscsi_task_mgmt_lun_reset_async(struct iscsi_context *iscsi,
130 		      uint32_t lun,
131 		      iscsi_command_cb cb, void *private_data)
132 {
133 	iscsi_scsi_cancel_all_tasks(iscsi);
134 
135 	return iscsi_task_mgmt_async(iscsi,
136 		      lun, ISCSI_TM_LUN_RESET,
137 		      0xffffffff, 0,
138 		      cb, private_data);
139 }
140 
141 int
iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context * iscsi,iscsi_command_cb cb,void * private_data)142 iscsi_task_mgmt_target_warm_reset_async(struct iscsi_context *iscsi,
143 		      iscsi_command_cb cb, void *private_data)
144 {
145 	iscsi_scsi_cancel_all_tasks(iscsi);
146 
147 	return iscsi_task_mgmt_async(iscsi,
148 		      0, ISCSI_TM_TARGET_WARM_RESET,
149 		      0xffffffff, 0,
150 		      cb, private_data);
151 }
152 
153 
154 int
iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context * iscsi,iscsi_command_cb cb,void * private_data)155 iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi,
156 		      iscsi_command_cb cb, void *private_data)
157 {
158 	iscsi_scsi_cancel_all_tasks(iscsi);
159 
160 	return iscsi_task_mgmt_async(iscsi,
161 		      0, ISCSI_TM_TARGET_COLD_RESET,
162 		      0xffffffff, 0,
163 		      cb, private_data);
164 }
165 
166 
167