1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun * This file contains main functions related to the iSCSI Target Core Driver.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (c) Copyright 2007-2013 Datera, Inc.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun ******************************************************************************/
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <crypto/hash.h>
12*4882a593Smuzhiyun #include <linux/string.h>
13*4882a593Smuzhiyun #include <linux/kthread.h>
14*4882a593Smuzhiyun #include <linux/completion.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/vmalloc.h>
17*4882a593Smuzhiyun #include <linux/idr.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/sched/signal.h>
20*4882a593Smuzhiyun #include <asm/unaligned.h>
21*4882a593Smuzhiyun #include <linux/inet.h>
22*4882a593Smuzhiyun #include <net/ipv6.h>
23*4882a593Smuzhiyun #include <scsi/scsi_proto.h>
24*4882a593Smuzhiyun #include <scsi/iscsi_proto.h>
25*4882a593Smuzhiyun #include <scsi/scsi_tcq.h>
26*4882a593Smuzhiyun #include <target/target_core_base.h>
27*4882a593Smuzhiyun #include <target/target_core_fabric.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include <target/iscsi/iscsi_target_core.h>
30*4882a593Smuzhiyun #include "iscsi_target_parameters.h"
31*4882a593Smuzhiyun #include "iscsi_target_seq_pdu_list.h"
32*4882a593Smuzhiyun #include "iscsi_target_datain_values.h"
33*4882a593Smuzhiyun #include "iscsi_target_erl0.h"
34*4882a593Smuzhiyun #include "iscsi_target_erl1.h"
35*4882a593Smuzhiyun #include "iscsi_target_erl2.h"
36*4882a593Smuzhiyun #include "iscsi_target_login.h"
37*4882a593Smuzhiyun #include "iscsi_target_tmr.h"
38*4882a593Smuzhiyun #include "iscsi_target_tpg.h"
39*4882a593Smuzhiyun #include "iscsi_target_util.h"
40*4882a593Smuzhiyun #include "iscsi_target.h"
41*4882a593Smuzhiyun #include "iscsi_target_device.h"
42*4882a593Smuzhiyun #include <target/iscsi/iscsi_target_stat.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include <target/iscsi/iscsi_transport.h>
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static LIST_HEAD(g_tiqn_list);
47*4882a593Smuzhiyun static LIST_HEAD(g_np_list);
48*4882a593Smuzhiyun static DEFINE_SPINLOCK(tiqn_lock);
49*4882a593Smuzhiyun static DEFINE_MUTEX(np_lock);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun static struct idr tiqn_idr;
52*4882a593Smuzhiyun DEFINE_IDA(sess_ida);
53*4882a593Smuzhiyun struct mutex auth_id_lock;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct iscsit_global *iscsit_global;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun struct kmem_cache *lio_qr_cache;
58*4882a593Smuzhiyun struct kmem_cache *lio_dr_cache;
59*4882a593Smuzhiyun struct kmem_cache *lio_ooo_cache;
60*4882a593Smuzhiyun struct kmem_cache *lio_r2t_cache;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static int iscsit_handle_immediate_data(struct iscsi_cmd *,
63*4882a593Smuzhiyun struct iscsi_scsi_req *, u32);
64*4882a593Smuzhiyun
iscsit_get_tiqn_for_login(unsigned char * buf)65*4882a593Smuzhiyun struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct iscsi_tiqn *tiqn = NULL;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun spin_lock(&tiqn_lock);
70*4882a593Smuzhiyun list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
71*4882a593Smuzhiyun if (!strcmp(tiqn->tiqn, buf)) {
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_state_lock);
74*4882a593Smuzhiyun if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) {
75*4882a593Smuzhiyun tiqn->tiqn_access_count++;
76*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
77*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
78*4882a593Smuzhiyun return tiqn;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return NULL;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
iscsit_set_tiqn_shutdown(struct iscsi_tiqn * tiqn)88*4882a593Smuzhiyun static int iscsit_set_tiqn_shutdown(struct iscsi_tiqn *tiqn)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_state_lock);
91*4882a593Smuzhiyun if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) {
92*4882a593Smuzhiyun tiqn->tiqn_state = TIQN_STATE_SHUTDOWN;
93*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun return -1;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
iscsit_put_tiqn_for_login(struct iscsi_tiqn * tiqn)101*4882a593Smuzhiyun void iscsit_put_tiqn_for_login(struct iscsi_tiqn *tiqn)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_state_lock);
104*4882a593Smuzhiyun tiqn->tiqn_access_count--;
105*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * Note that IQN formatting is expected to be done in userspace, and
110*4882a593Smuzhiyun * no explict IQN format checks are done here.
111*4882a593Smuzhiyun */
iscsit_add_tiqn(unsigned char * buf)112*4882a593Smuzhiyun struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun struct iscsi_tiqn *tiqn = NULL;
115*4882a593Smuzhiyun int ret;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (strlen(buf) >= ISCSI_IQN_LEN) {
118*4882a593Smuzhiyun pr_err("Target IQN exceeds %d bytes\n",
119*4882a593Smuzhiyun ISCSI_IQN_LEN);
120*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun tiqn = kzalloc(sizeof(*tiqn), GFP_KERNEL);
124*4882a593Smuzhiyun if (!tiqn)
125*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun sprintf(tiqn->tiqn, "%s", buf);
128*4882a593Smuzhiyun INIT_LIST_HEAD(&tiqn->tiqn_list);
129*4882a593Smuzhiyun INIT_LIST_HEAD(&tiqn->tiqn_tpg_list);
130*4882a593Smuzhiyun spin_lock_init(&tiqn->tiqn_state_lock);
131*4882a593Smuzhiyun spin_lock_init(&tiqn->tiqn_tpg_lock);
132*4882a593Smuzhiyun spin_lock_init(&tiqn->sess_err_stats.lock);
133*4882a593Smuzhiyun spin_lock_init(&tiqn->login_stats.lock);
134*4882a593Smuzhiyun spin_lock_init(&tiqn->logout_stats.lock);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun tiqn->tiqn_state = TIQN_STATE_ACTIVE;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun idr_preload(GFP_KERNEL);
139*4882a593Smuzhiyun spin_lock(&tiqn_lock);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun ret = idr_alloc(&tiqn_idr, NULL, 0, 0, GFP_NOWAIT);
142*4882a593Smuzhiyun if (ret < 0) {
143*4882a593Smuzhiyun pr_err("idr_alloc() failed for tiqn->tiqn_index\n");
144*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
145*4882a593Smuzhiyun idr_preload_end();
146*4882a593Smuzhiyun kfree(tiqn);
147*4882a593Smuzhiyun return ERR_PTR(ret);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun tiqn->tiqn_index = ret;
150*4882a593Smuzhiyun list_add_tail(&tiqn->tiqn_list, &g_tiqn_list);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
153*4882a593Smuzhiyun idr_preload_end();
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun pr_debug("CORE[0] - Added iSCSI Target IQN: %s\n", tiqn->tiqn);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return tiqn;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
iscsit_wait_for_tiqn(struct iscsi_tiqn * tiqn)161*4882a593Smuzhiyun static void iscsit_wait_for_tiqn(struct iscsi_tiqn *tiqn)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun * Wait for accesses to said struct iscsi_tiqn to end.
165*4882a593Smuzhiyun */
166*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_state_lock);
167*4882a593Smuzhiyun while (tiqn->tiqn_access_count != 0) {
168*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
169*4882a593Smuzhiyun msleep(10);
170*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_state_lock);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_state_lock);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
iscsit_del_tiqn(struct iscsi_tiqn * tiqn)175*4882a593Smuzhiyun void iscsit_del_tiqn(struct iscsi_tiqn *tiqn)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * iscsit_set_tiqn_shutdown sets tiqn->tiqn_state = TIQN_STATE_SHUTDOWN
179*4882a593Smuzhiyun * while holding tiqn->tiqn_state_lock. This means that all subsequent
180*4882a593Smuzhiyun * attempts to access this struct iscsi_tiqn will fail from both transport
181*4882a593Smuzhiyun * fabric and control code paths.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun if (iscsit_set_tiqn_shutdown(tiqn) < 0) {
184*4882a593Smuzhiyun pr_err("iscsit_set_tiqn_shutdown() failed\n");
185*4882a593Smuzhiyun return;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun iscsit_wait_for_tiqn(tiqn);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun spin_lock(&tiqn_lock);
191*4882a593Smuzhiyun list_del(&tiqn->tiqn_list);
192*4882a593Smuzhiyun idr_remove(&tiqn_idr, tiqn->tiqn_index);
193*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun pr_debug("CORE[0] - Deleted iSCSI Target IQN: %s\n",
196*4882a593Smuzhiyun tiqn->tiqn);
197*4882a593Smuzhiyun kfree(tiqn);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
iscsit_access_np(struct iscsi_np * np,struct iscsi_portal_group * tpg)200*4882a593Smuzhiyun int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int ret;
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * Determine if the network portal is accepting storage traffic.
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun spin_lock_bh(&np->np_thread_lock);
207*4882a593Smuzhiyun if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
208*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
209*4882a593Smuzhiyun return -1;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
212*4882a593Smuzhiyun /*
213*4882a593Smuzhiyun * Determine if the portal group is accepting storage traffic.
214*4882a593Smuzhiyun */
215*4882a593Smuzhiyun spin_lock_bh(&tpg->tpg_state_lock);
216*4882a593Smuzhiyun if (tpg->tpg_state != TPG_STATE_ACTIVE) {
217*4882a593Smuzhiyun spin_unlock_bh(&tpg->tpg_state_lock);
218*4882a593Smuzhiyun return -1;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun spin_unlock_bh(&tpg->tpg_state_lock);
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun * Here we serialize access across the TIQN+TPG Tuple.
224*4882a593Smuzhiyun */
225*4882a593Smuzhiyun ret = down_interruptible(&tpg->np_login_sem);
226*4882a593Smuzhiyun if (ret != 0)
227*4882a593Smuzhiyun return -1;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun spin_lock_bh(&tpg->tpg_state_lock);
230*4882a593Smuzhiyun if (tpg->tpg_state != TPG_STATE_ACTIVE) {
231*4882a593Smuzhiyun spin_unlock_bh(&tpg->tpg_state_lock);
232*4882a593Smuzhiyun up(&tpg->np_login_sem);
233*4882a593Smuzhiyun return -1;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun spin_unlock_bh(&tpg->tpg_state_lock);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return 0;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
iscsit_login_kref_put(struct kref * kref)240*4882a593Smuzhiyun void iscsit_login_kref_put(struct kref *kref)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun struct iscsi_tpg_np *tpg_np = container_of(kref,
243*4882a593Smuzhiyun struct iscsi_tpg_np, tpg_np_kref);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun complete(&tpg_np->tpg_np_comp);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
iscsit_deaccess_np(struct iscsi_np * np,struct iscsi_portal_group * tpg,struct iscsi_tpg_np * tpg_np)248*4882a593Smuzhiyun int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg,
249*4882a593Smuzhiyun struct iscsi_tpg_np *tpg_np)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun up(&tpg->np_login_sem);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun if (tpg_np)
256*4882a593Smuzhiyun kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (tiqn)
259*4882a593Smuzhiyun iscsit_put_tiqn_for_login(tiqn);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun return 0;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
iscsit_check_np_match(struct sockaddr_storage * sockaddr,struct iscsi_np * np,int network_transport)264*4882a593Smuzhiyun bool iscsit_check_np_match(
265*4882a593Smuzhiyun struct sockaddr_storage *sockaddr,
266*4882a593Smuzhiyun struct iscsi_np *np,
267*4882a593Smuzhiyun int network_transport)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun struct sockaddr_in *sock_in, *sock_in_e;
270*4882a593Smuzhiyun struct sockaddr_in6 *sock_in6, *sock_in6_e;
271*4882a593Smuzhiyun bool ip_match = false;
272*4882a593Smuzhiyun u16 port, port_e;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (sockaddr->ss_family == AF_INET6) {
275*4882a593Smuzhiyun sock_in6 = (struct sockaddr_in6 *)sockaddr;
276*4882a593Smuzhiyun sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (!memcmp(&sock_in6->sin6_addr.in6_u,
279*4882a593Smuzhiyun &sock_in6_e->sin6_addr.in6_u,
280*4882a593Smuzhiyun sizeof(struct in6_addr)))
281*4882a593Smuzhiyun ip_match = true;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun port = ntohs(sock_in6->sin6_port);
284*4882a593Smuzhiyun port_e = ntohs(sock_in6_e->sin6_port);
285*4882a593Smuzhiyun } else {
286*4882a593Smuzhiyun sock_in = (struct sockaddr_in *)sockaddr;
287*4882a593Smuzhiyun sock_in_e = (struct sockaddr_in *)&np->np_sockaddr;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (sock_in->sin_addr.s_addr == sock_in_e->sin_addr.s_addr)
290*4882a593Smuzhiyun ip_match = true;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun port = ntohs(sock_in->sin_port);
293*4882a593Smuzhiyun port_e = ntohs(sock_in_e->sin_port);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (ip_match && (port_e == port) &&
297*4882a593Smuzhiyun (np->np_network_transport == network_transport))
298*4882a593Smuzhiyun return true;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun return false;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
iscsit_get_np(struct sockaddr_storage * sockaddr,int network_transport)303*4882a593Smuzhiyun static struct iscsi_np *iscsit_get_np(
304*4882a593Smuzhiyun struct sockaddr_storage *sockaddr,
305*4882a593Smuzhiyun int network_transport)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun struct iscsi_np *np;
308*4882a593Smuzhiyun bool match;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun lockdep_assert_held(&np_lock);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun list_for_each_entry(np, &g_np_list, np_list) {
313*4882a593Smuzhiyun spin_lock_bh(&np->np_thread_lock);
314*4882a593Smuzhiyun if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
315*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
316*4882a593Smuzhiyun continue;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun match = iscsit_check_np_match(sockaddr, np, network_transport);
320*4882a593Smuzhiyun if (match) {
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * Increment the np_exports reference count now to
323*4882a593Smuzhiyun * prevent iscsit_del_np() below from being called
324*4882a593Smuzhiyun * while iscsi_tpg_add_network_portal() is called.
325*4882a593Smuzhiyun */
326*4882a593Smuzhiyun np->np_exports++;
327*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
328*4882a593Smuzhiyun return np;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun return NULL;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
iscsit_add_np(struct sockaddr_storage * sockaddr,int network_transport)336*4882a593Smuzhiyun struct iscsi_np *iscsit_add_np(
337*4882a593Smuzhiyun struct sockaddr_storage *sockaddr,
338*4882a593Smuzhiyun int network_transport)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct iscsi_np *np;
341*4882a593Smuzhiyun int ret;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun mutex_lock(&np_lock);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /*
346*4882a593Smuzhiyun * Locate the existing struct iscsi_np if already active..
347*4882a593Smuzhiyun */
348*4882a593Smuzhiyun np = iscsit_get_np(sockaddr, network_transport);
349*4882a593Smuzhiyun if (np) {
350*4882a593Smuzhiyun mutex_unlock(&np_lock);
351*4882a593Smuzhiyun return np;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun np = kzalloc(sizeof(*np), GFP_KERNEL);
355*4882a593Smuzhiyun if (!np) {
356*4882a593Smuzhiyun mutex_unlock(&np_lock);
357*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun np->np_flags |= NPF_IP_NETWORK;
361*4882a593Smuzhiyun np->np_network_transport = network_transport;
362*4882a593Smuzhiyun spin_lock_init(&np->np_thread_lock);
363*4882a593Smuzhiyun init_completion(&np->np_restart_comp);
364*4882a593Smuzhiyun INIT_LIST_HEAD(&np->np_list);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun timer_setup(&np->np_login_timer, iscsi_handle_login_thread_timeout, 0);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = iscsi_target_setup_login_socket(np, sockaddr);
369*4882a593Smuzhiyun if (ret != 0) {
370*4882a593Smuzhiyun kfree(np);
371*4882a593Smuzhiyun mutex_unlock(&np_lock);
372*4882a593Smuzhiyun return ERR_PTR(ret);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun np->np_thread = kthread_run(iscsi_target_login_thread, np, "iscsi_np");
376*4882a593Smuzhiyun if (IS_ERR(np->np_thread)) {
377*4882a593Smuzhiyun pr_err("Unable to create kthread: iscsi_np\n");
378*4882a593Smuzhiyun ret = PTR_ERR(np->np_thread);
379*4882a593Smuzhiyun kfree(np);
380*4882a593Smuzhiyun mutex_unlock(&np_lock);
381*4882a593Smuzhiyun return ERR_PTR(ret);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun /*
384*4882a593Smuzhiyun * Increment the np_exports reference count now to prevent
385*4882a593Smuzhiyun * iscsit_del_np() below from being run while a new call to
386*4882a593Smuzhiyun * iscsi_tpg_add_network_portal() for a matching iscsi_np is
387*4882a593Smuzhiyun * active. We don't need to hold np->np_thread_lock at this
388*4882a593Smuzhiyun * point because iscsi_np has not been added to g_np_list yet.
389*4882a593Smuzhiyun */
390*4882a593Smuzhiyun np->np_exports = 1;
391*4882a593Smuzhiyun np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun list_add_tail(&np->np_list, &g_np_list);
394*4882a593Smuzhiyun mutex_unlock(&np_lock);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun pr_debug("CORE[0] - Added Network Portal: %pISpc on %s\n",
397*4882a593Smuzhiyun &np->np_sockaddr, np->np_transport->name);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun return np;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
iscsit_reset_np_thread(struct iscsi_np * np,struct iscsi_tpg_np * tpg_np,struct iscsi_portal_group * tpg,bool shutdown)402*4882a593Smuzhiyun int iscsit_reset_np_thread(
403*4882a593Smuzhiyun struct iscsi_np *np,
404*4882a593Smuzhiyun struct iscsi_tpg_np *tpg_np,
405*4882a593Smuzhiyun struct iscsi_portal_group *tpg,
406*4882a593Smuzhiyun bool shutdown)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun spin_lock_bh(&np->np_thread_lock);
409*4882a593Smuzhiyun if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) {
410*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun np->np_thread_state = ISCSI_NP_THREAD_RESET;
414*4882a593Smuzhiyun atomic_inc(&np->np_reset_count);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun if (np->np_thread) {
417*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
418*4882a593Smuzhiyun send_sig(SIGINT, np->np_thread, 1);
419*4882a593Smuzhiyun wait_for_completion(&np->np_restart_comp);
420*4882a593Smuzhiyun spin_lock_bh(&np->np_thread_lock);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun if (tpg_np && shutdown) {
425*4882a593Smuzhiyun kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun wait_for_completion(&tpg_np->tpg_np_comp);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun return 0;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
iscsit_free_np(struct iscsi_np * np)433*4882a593Smuzhiyun static void iscsit_free_np(struct iscsi_np *np)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun if (np->np_socket)
436*4882a593Smuzhiyun sock_release(np->np_socket);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun
iscsit_del_np(struct iscsi_np * np)439*4882a593Smuzhiyun int iscsit_del_np(struct iscsi_np *np)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun spin_lock_bh(&np->np_thread_lock);
442*4882a593Smuzhiyun np->np_exports--;
443*4882a593Smuzhiyun if (np->np_exports) {
444*4882a593Smuzhiyun np->enabled = true;
445*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
446*4882a593Smuzhiyun return 0;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun np->np_thread_state = ISCSI_NP_THREAD_SHUTDOWN;
449*4882a593Smuzhiyun spin_unlock_bh(&np->np_thread_lock);
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun if (np->np_thread) {
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * We need to send the signal to wakeup Linux/Net
454*4882a593Smuzhiyun * which may be sleeping in sock_accept()..
455*4882a593Smuzhiyun */
456*4882a593Smuzhiyun send_sig(SIGINT, np->np_thread, 1);
457*4882a593Smuzhiyun kthread_stop(np->np_thread);
458*4882a593Smuzhiyun np->np_thread = NULL;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun np->np_transport->iscsit_free_np(np);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun mutex_lock(&np_lock);
464*4882a593Smuzhiyun list_del(&np->np_list);
465*4882a593Smuzhiyun mutex_unlock(&np_lock);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun pr_debug("CORE[0] - Removed Network Portal: %pISpc on %s\n",
468*4882a593Smuzhiyun &np->np_sockaddr, np->np_transport->name);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun iscsit_put_transport(np->np_transport);
471*4882a593Smuzhiyun kfree(np);
472*4882a593Smuzhiyun return 0;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun static void iscsit_get_rx_pdu(struct iscsi_conn *);
476*4882a593Smuzhiyun
iscsit_queue_rsp(struct iscsi_conn * conn,struct iscsi_cmd * cmd)477*4882a593Smuzhiyun int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun return iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_queue_rsp);
482*4882a593Smuzhiyun
iscsit_aborted_task(struct iscsi_conn * conn,struct iscsi_cmd * cmd)483*4882a593Smuzhiyun void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
486*4882a593Smuzhiyun if (!list_empty(&cmd->i_conn_node))
487*4882a593Smuzhiyun list_del_init(&cmd->i_conn_node);
488*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun __iscsit_free_cmd(cmd, true);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_aborted_task);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun static void iscsit_do_crypto_hash_buf(struct ahash_request *, const void *,
495*4882a593Smuzhiyun u32, u32, const void *, void *);
496*4882a593Smuzhiyun static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun static int
iscsit_xmit_nondatain_pdu(struct iscsi_conn * conn,struct iscsi_cmd * cmd,const void * data_buf,u32 data_buf_len)499*4882a593Smuzhiyun iscsit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
500*4882a593Smuzhiyun const void *data_buf, u32 data_buf_len)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun struct iscsi_hdr *hdr = (struct iscsi_hdr *)cmd->pdu;
503*4882a593Smuzhiyun struct kvec *iov;
504*4882a593Smuzhiyun u32 niov = 0, tx_size = ISCSI_HDR_LEN;
505*4882a593Smuzhiyun int ret;
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun iov = &cmd->iov_misc[0];
508*4882a593Smuzhiyun iov[niov].iov_base = cmd->pdu;
509*4882a593Smuzhiyun iov[niov++].iov_len = ISCSI_HDR_LEN;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun if (conn->conn_ops->HeaderDigest) {
512*4882a593Smuzhiyun u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_tx_hash, hdr,
515*4882a593Smuzhiyun ISCSI_HDR_LEN, 0, NULL,
516*4882a593Smuzhiyun header_digest);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun iov[0].iov_len += ISCSI_CRC_LEN;
519*4882a593Smuzhiyun tx_size += ISCSI_CRC_LEN;
520*4882a593Smuzhiyun pr_debug("Attaching CRC32C HeaderDigest"
521*4882a593Smuzhiyun " to opcode 0x%x 0x%08x\n",
522*4882a593Smuzhiyun hdr->opcode, *header_digest);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (data_buf_len) {
526*4882a593Smuzhiyun u32 padding = ((-data_buf_len) & 3);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun iov[niov].iov_base = (void *)data_buf;
529*4882a593Smuzhiyun iov[niov++].iov_len = data_buf_len;
530*4882a593Smuzhiyun tx_size += data_buf_len;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun if (padding != 0) {
533*4882a593Smuzhiyun iov[niov].iov_base = &cmd->pad_bytes;
534*4882a593Smuzhiyun iov[niov++].iov_len = padding;
535*4882a593Smuzhiyun tx_size += padding;
536*4882a593Smuzhiyun pr_debug("Attaching %u additional"
537*4882a593Smuzhiyun " padding bytes.\n", padding);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
541*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_tx_hash,
542*4882a593Smuzhiyun data_buf, data_buf_len,
543*4882a593Smuzhiyun padding, &cmd->pad_bytes,
544*4882a593Smuzhiyun &cmd->data_crc);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun iov[niov].iov_base = &cmd->data_crc;
547*4882a593Smuzhiyun iov[niov++].iov_len = ISCSI_CRC_LEN;
548*4882a593Smuzhiyun tx_size += ISCSI_CRC_LEN;
549*4882a593Smuzhiyun pr_debug("Attached DataDigest for %u"
550*4882a593Smuzhiyun " bytes opcode 0x%x, CRC 0x%08x\n",
551*4882a593Smuzhiyun data_buf_len, hdr->opcode, cmd->data_crc);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun cmd->iov_misc_count = niov;
556*4882a593Smuzhiyun cmd->tx_size = tx_size;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun ret = iscsit_send_tx_data(cmd, conn, 1);
559*4882a593Smuzhiyun if (ret < 0) {
560*4882a593Smuzhiyun iscsit_tx_thread_wait_for_tcp(conn);
561*4882a593Smuzhiyun return ret;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun return 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun static int iscsit_map_iovec(struct iscsi_cmd *cmd, struct kvec *iov, int nvec,
568*4882a593Smuzhiyun u32 data_offset, u32 data_length);
569*4882a593Smuzhiyun static void iscsit_unmap_iovec(struct iscsi_cmd *);
570*4882a593Smuzhiyun static u32 iscsit_do_crypto_hash_sg(struct ahash_request *, struct iscsi_cmd *,
571*4882a593Smuzhiyun u32, u32, u32, u8 *);
572*4882a593Smuzhiyun static int
iscsit_xmit_datain_pdu(struct iscsi_conn * conn,struct iscsi_cmd * cmd,const struct iscsi_datain * datain)573*4882a593Smuzhiyun iscsit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
574*4882a593Smuzhiyun const struct iscsi_datain *datain)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun struct kvec *iov;
577*4882a593Smuzhiyun u32 iov_count = 0, tx_size = 0;
578*4882a593Smuzhiyun int ret, iov_ret;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun iov = &cmd->iov_data[0];
581*4882a593Smuzhiyun iov[iov_count].iov_base = cmd->pdu;
582*4882a593Smuzhiyun iov[iov_count++].iov_len = ISCSI_HDR_LEN;
583*4882a593Smuzhiyun tx_size += ISCSI_HDR_LEN;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (conn->conn_ops->HeaderDigest) {
586*4882a593Smuzhiyun u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_tx_hash, cmd->pdu,
589*4882a593Smuzhiyun ISCSI_HDR_LEN, 0, NULL,
590*4882a593Smuzhiyun header_digest);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun iov[0].iov_len += ISCSI_CRC_LEN;
593*4882a593Smuzhiyun tx_size += ISCSI_CRC_LEN;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun pr_debug("Attaching CRC32 HeaderDigest for DataIN PDU 0x%08x\n",
596*4882a593Smuzhiyun *header_digest);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[iov_count],
600*4882a593Smuzhiyun cmd->orig_iov_data_count - (iov_count + 2),
601*4882a593Smuzhiyun datain->offset, datain->length);
602*4882a593Smuzhiyun if (iov_ret < 0)
603*4882a593Smuzhiyun return -1;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun iov_count += iov_ret;
606*4882a593Smuzhiyun tx_size += datain->length;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun cmd->padding = ((-datain->length) & 3);
609*4882a593Smuzhiyun if (cmd->padding) {
610*4882a593Smuzhiyun iov[iov_count].iov_base = cmd->pad_bytes;
611*4882a593Smuzhiyun iov[iov_count++].iov_len = cmd->padding;
612*4882a593Smuzhiyun tx_size += cmd->padding;
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun pr_debug("Attaching %u padding bytes\n", cmd->padding);
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
618*4882a593Smuzhiyun cmd->data_crc = iscsit_do_crypto_hash_sg(conn->conn_tx_hash,
619*4882a593Smuzhiyun cmd, datain->offset,
620*4882a593Smuzhiyun datain->length,
621*4882a593Smuzhiyun cmd->padding,
622*4882a593Smuzhiyun cmd->pad_bytes);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun iov[iov_count].iov_base = &cmd->data_crc;
625*4882a593Smuzhiyun iov[iov_count++].iov_len = ISCSI_CRC_LEN;
626*4882a593Smuzhiyun tx_size += ISCSI_CRC_LEN;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun pr_debug("Attached CRC32C DataDigest %d bytes, crc 0x%08x\n",
629*4882a593Smuzhiyun datain->length + cmd->padding, cmd->data_crc);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun cmd->iov_data_count = iov_count;
633*4882a593Smuzhiyun cmd->tx_size = tx_size;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun ret = iscsit_fe_sendpage_sg(cmd, conn);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun iscsit_unmap_iovec(cmd);
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun if (ret < 0) {
640*4882a593Smuzhiyun iscsit_tx_thread_wait_for_tcp(conn);
641*4882a593Smuzhiyun return ret;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun return 0;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
iscsit_xmit_pdu(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_datain_req * dr,const void * buf,u32 buf_len)647*4882a593Smuzhiyun static int iscsit_xmit_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
648*4882a593Smuzhiyun struct iscsi_datain_req *dr, const void *buf,
649*4882a593Smuzhiyun u32 buf_len)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun if (dr)
652*4882a593Smuzhiyun return iscsit_xmit_datain_pdu(conn, cmd, buf);
653*4882a593Smuzhiyun else
654*4882a593Smuzhiyun return iscsit_xmit_nondatain_pdu(conn, cmd, buf, buf_len);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
iscsit_get_sup_prot_ops(struct iscsi_conn * conn)657*4882a593Smuzhiyun static enum target_prot_op iscsit_get_sup_prot_ops(struct iscsi_conn *conn)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun return TARGET_PROT_NORMAL;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun static struct iscsit_transport iscsi_target_transport = {
663*4882a593Smuzhiyun .name = "iSCSI/TCP",
664*4882a593Smuzhiyun .transport_type = ISCSI_TCP,
665*4882a593Smuzhiyun .rdma_shutdown = false,
666*4882a593Smuzhiyun .owner = NULL,
667*4882a593Smuzhiyun .iscsit_setup_np = iscsit_setup_np,
668*4882a593Smuzhiyun .iscsit_accept_np = iscsit_accept_np,
669*4882a593Smuzhiyun .iscsit_free_np = iscsit_free_np,
670*4882a593Smuzhiyun .iscsit_get_login_rx = iscsit_get_login_rx,
671*4882a593Smuzhiyun .iscsit_put_login_tx = iscsit_put_login_tx,
672*4882a593Smuzhiyun .iscsit_get_dataout = iscsit_build_r2ts_for_cmd,
673*4882a593Smuzhiyun .iscsit_immediate_queue = iscsit_immediate_queue,
674*4882a593Smuzhiyun .iscsit_response_queue = iscsit_response_queue,
675*4882a593Smuzhiyun .iscsit_queue_data_in = iscsit_queue_rsp,
676*4882a593Smuzhiyun .iscsit_queue_status = iscsit_queue_rsp,
677*4882a593Smuzhiyun .iscsit_aborted_task = iscsit_aborted_task,
678*4882a593Smuzhiyun .iscsit_xmit_pdu = iscsit_xmit_pdu,
679*4882a593Smuzhiyun .iscsit_get_rx_pdu = iscsit_get_rx_pdu,
680*4882a593Smuzhiyun .iscsit_get_sup_prot_ops = iscsit_get_sup_prot_ops,
681*4882a593Smuzhiyun };
682*4882a593Smuzhiyun
iscsi_target_init_module(void)683*4882a593Smuzhiyun static int __init iscsi_target_init_module(void)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun int ret = 0, size;
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun pr_debug("iSCSI-Target "ISCSIT_VERSION"\n");
688*4882a593Smuzhiyun iscsit_global = kzalloc(sizeof(*iscsit_global), GFP_KERNEL);
689*4882a593Smuzhiyun if (!iscsit_global)
690*4882a593Smuzhiyun return -1;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun spin_lock_init(&iscsit_global->ts_bitmap_lock);
693*4882a593Smuzhiyun mutex_init(&auth_id_lock);
694*4882a593Smuzhiyun idr_init(&tiqn_idr);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun ret = target_register_template(&iscsi_ops);
697*4882a593Smuzhiyun if (ret)
698*4882a593Smuzhiyun goto out;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun size = BITS_TO_LONGS(ISCSIT_BITMAP_BITS) * sizeof(long);
701*4882a593Smuzhiyun iscsit_global->ts_bitmap = vzalloc(size);
702*4882a593Smuzhiyun if (!iscsit_global->ts_bitmap)
703*4882a593Smuzhiyun goto configfs_out;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun lio_qr_cache = kmem_cache_create("lio_qr_cache",
706*4882a593Smuzhiyun sizeof(struct iscsi_queue_req),
707*4882a593Smuzhiyun __alignof__(struct iscsi_queue_req), 0, NULL);
708*4882a593Smuzhiyun if (!lio_qr_cache) {
709*4882a593Smuzhiyun pr_err("Unable to kmem_cache_create() for"
710*4882a593Smuzhiyun " lio_qr_cache\n");
711*4882a593Smuzhiyun goto bitmap_out;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun lio_dr_cache = kmem_cache_create("lio_dr_cache",
715*4882a593Smuzhiyun sizeof(struct iscsi_datain_req),
716*4882a593Smuzhiyun __alignof__(struct iscsi_datain_req), 0, NULL);
717*4882a593Smuzhiyun if (!lio_dr_cache) {
718*4882a593Smuzhiyun pr_err("Unable to kmem_cache_create() for"
719*4882a593Smuzhiyun " lio_dr_cache\n");
720*4882a593Smuzhiyun goto qr_out;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun lio_ooo_cache = kmem_cache_create("lio_ooo_cache",
724*4882a593Smuzhiyun sizeof(struct iscsi_ooo_cmdsn),
725*4882a593Smuzhiyun __alignof__(struct iscsi_ooo_cmdsn), 0, NULL);
726*4882a593Smuzhiyun if (!lio_ooo_cache) {
727*4882a593Smuzhiyun pr_err("Unable to kmem_cache_create() for"
728*4882a593Smuzhiyun " lio_ooo_cache\n");
729*4882a593Smuzhiyun goto dr_out;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun lio_r2t_cache = kmem_cache_create("lio_r2t_cache",
733*4882a593Smuzhiyun sizeof(struct iscsi_r2t), __alignof__(struct iscsi_r2t),
734*4882a593Smuzhiyun 0, NULL);
735*4882a593Smuzhiyun if (!lio_r2t_cache) {
736*4882a593Smuzhiyun pr_err("Unable to kmem_cache_create() for"
737*4882a593Smuzhiyun " lio_r2t_cache\n");
738*4882a593Smuzhiyun goto ooo_out;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun iscsit_register_transport(&iscsi_target_transport);
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (iscsit_load_discovery_tpg() < 0)
744*4882a593Smuzhiyun goto r2t_out;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun return ret;
747*4882a593Smuzhiyun r2t_out:
748*4882a593Smuzhiyun iscsit_unregister_transport(&iscsi_target_transport);
749*4882a593Smuzhiyun kmem_cache_destroy(lio_r2t_cache);
750*4882a593Smuzhiyun ooo_out:
751*4882a593Smuzhiyun kmem_cache_destroy(lio_ooo_cache);
752*4882a593Smuzhiyun dr_out:
753*4882a593Smuzhiyun kmem_cache_destroy(lio_dr_cache);
754*4882a593Smuzhiyun qr_out:
755*4882a593Smuzhiyun kmem_cache_destroy(lio_qr_cache);
756*4882a593Smuzhiyun bitmap_out:
757*4882a593Smuzhiyun vfree(iscsit_global->ts_bitmap);
758*4882a593Smuzhiyun configfs_out:
759*4882a593Smuzhiyun /* XXX: this probably wants it to be it's own unwind step.. */
760*4882a593Smuzhiyun if (iscsit_global->discovery_tpg)
761*4882a593Smuzhiyun iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
762*4882a593Smuzhiyun target_unregister_template(&iscsi_ops);
763*4882a593Smuzhiyun out:
764*4882a593Smuzhiyun kfree(iscsit_global);
765*4882a593Smuzhiyun return -ENOMEM;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
iscsi_target_cleanup_module(void)768*4882a593Smuzhiyun static void __exit iscsi_target_cleanup_module(void)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun iscsit_release_discovery_tpg();
771*4882a593Smuzhiyun iscsit_unregister_transport(&iscsi_target_transport);
772*4882a593Smuzhiyun kmem_cache_destroy(lio_qr_cache);
773*4882a593Smuzhiyun kmem_cache_destroy(lio_dr_cache);
774*4882a593Smuzhiyun kmem_cache_destroy(lio_ooo_cache);
775*4882a593Smuzhiyun kmem_cache_destroy(lio_r2t_cache);
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun /*
778*4882a593Smuzhiyun * Shutdown discovery sessions and disable discovery TPG
779*4882a593Smuzhiyun */
780*4882a593Smuzhiyun if (iscsit_global->discovery_tpg)
781*4882a593Smuzhiyun iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun target_unregister_template(&iscsi_ops);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun vfree(iscsit_global->ts_bitmap);
786*4882a593Smuzhiyun kfree(iscsit_global);
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
iscsit_add_reject(struct iscsi_conn * conn,u8 reason,unsigned char * buf)789*4882a593Smuzhiyun int iscsit_add_reject(
790*4882a593Smuzhiyun struct iscsi_conn *conn,
791*4882a593Smuzhiyun u8 reason,
792*4882a593Smuzhiyun unsigned char *buf)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun struct iscsi_cmd *cmd;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
797*4882a593Smuzhiyun if (!cmd)
798*4882a593Smuzhiyun return -1;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_REJECT;
801*4882a593Smuzhiyun cmd->reject_reason = reason;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
804*4882a593Smuzhiyun if (!cmd->buf_ptr) {
805*4882a593Smuzhiyun pr_err("Unable to allocate memory for cmd->buf_ptr\n");
806*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
807*4882a593Smuzhiyun return -1;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
811*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
812*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_REJECT;
815*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun return -1;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_add_reject);
820*4882a593Smuzhiyun
iscsit_add_reject_from_cmd(struct iscsi_cmd * cmd,u8 reason,bool add_to_conn,unsigned char * buf)821*4882a593Smuzhiyun static int iscsit_add_reject_from_cmd(
822*4882a593Smuzhiyun struct iscsi_cmd *cmd,
823*4882a593Smuzhiyun u8 reason,
824*4882a593Smuzhiyun bool add_to_conn,
825*4882a593Smuzhiyun unsigned char *buf)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun struct iscsi_conn *conn;
828*4882a593Smuzhiyun const bool do_put = cmd->se_cmd.se_tfo != NULL;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun if (!cmd->conn) {
831*4882a593Smuzhiyun pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
832*4882a593Smuzhiyun cmd->init_task_tag);
833*4882a593Smuzhiyun return -1;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun conn = cmd->conn;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_REJECT;
838*4882a593Smuzhiyun cmd->reject_reason = reason;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
841*4882a593Smuzhiyun if (!cmd->buf_ptr) {
842*4882a593Smuzhiyun pr_err("Unable to allocate memory for cmd->buf_ptr\n");
843*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
844*4882a593Smuzhiyun return -1;
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun if (add_to_conn) {
848*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
849*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
850*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_REJECT;
854*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
855*4882a593Smuzhiyun /*
856*4882a593Smuzhiyun * Perform the kref_put now if se_cmd has already been setup by
857*4882a593Smuzhiyun * scsit_setup_scsi_cmd()
858*4882a593Smuzhiyun */
859*4882a593Smuzhiyun if (do_put) {
860*4882a593Smuzhiyun pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
861*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun return -1;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun
iscsit_add_reject_cmd(struct iscsi_cmd * cmd,u8 reason,unsigned char * buf)866*4882a593Smuzhiyun static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason,
867*4882a593Smuzhiyun unsigned char *buf)
868*4882a593Smuzhiyun {
869*4882a593Smuzhiyun return iscsit_add_reject_from_cmd(cmd, reason, true, buf);
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
iscsit_reject_cmd(struct iscsi_cmd * cmd,u8 reason,unsigned char * buf)872*4882a593Smuzhiyun int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_reject_cmd);
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /*
879*4882a593Smuzhiyun * Map some portion of the allocated scatterlist to an iovec, suitable for
880*4882a593Smuzhiyun * kernel sockets to copy data in/out.
881*4882a593Smuzhiyun */
iscsit_map_iovec(struct iscsi_cmd * cmd,struct kvec * iov,int nvec,u32 data_offset,u32 data_length)882*4882a593Smuzhiyun static int iscsit_map_iovec(struct iscsi_cmd *cmd, struct kvec *iov, int nvec,
883*4882a593Smuzhiyun u32 data_offset, u32 data_length)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun u32 i = 0, orig_data_length = data_length;
886*4882a593Smuzhiyun struct scatterlist *sg;
887*4882a593Smuzhiyun unsigned int page_off;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun /*
890*4882a593Smuzhiyun * We know each entry in t_data_sg contains a page.
891*4882a593Smuzhiyun */
892*4882a593Smuzhiyun u32 ent = data_offset / PAGE_SIZE;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun if (!data_length)
895*4882a593Smuzhiyun return 0;
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun if (ent >= cmd->se_cmd.t_data_nents) {
898*4882a593Smuzhiyun pr_err("Initial page entry out-of-bounds\n");
899*4882a593Smuzhiyun goto overflow;
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun sg = &cmd->se_cmd.t_data_sg[ent];
903*4882a593Smuzhiyun page_off = (data_offset % PAGE_SIZE);
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun cmd->first_data_sg = sg;
906*4882a593Smuzhiyun cmd->first_data_sg_off = page_off;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun while (data_length) {
909*4882a593Smuzhiyun u32 cur_len;
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun if (WARN_ON_ONCE(!sg || i >= nvec))
912*4882a593Smuzhiyun goto overflow;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun cur_len = min_t(u32, data_length, sg->length - page_off);
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off;
917*4882a593Smuzhiyun iov[i].iov_len = cur_len;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun data_length -= cur_len;
920*4882a593Smuzhiyun page_off = 0;
921*4882a593Smuzhiyun sg = sg_next(sg);
922*4882a593Smuzhiyun i++;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun cmd->kmapped_nents = i;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun return i;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun overflow:
930*4882a593Smuzhiyun pr_err("offset %d + length %d overflow; %d/%d; sg-list:\n",
931*4882a593Smuzhiyun data_offset, orig_data_length, i, nvec);
932*4882a593Smuzhiyun for_each_sg(cmd->se_cmd.t_data_sg, sg,
933*4882a593Smuzhiyun cmd->se_cmd.t_data_nents, i) {
934*4882a593Smuzhiyun pr_err("[%d] off %d len %d\n",
935*4882a593Smuzhiyun i, sg->offset, sg->length);
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun return -1;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun
iscsit_unmap_iovec(struct iscsi_cmd * cmd)940*4882a593Smuzhiyun static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun u32 i;
943*4882a593Smuzhiyun struct scatterlist *sg;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun sg = cmd->first_data_sg;
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun for (i = 0; i < cmd->kmapped_nents; i++)
948*4882a593Smuzhiyun kunmap(sg_page(&sg[i]));
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
iscsit_ack_from_expstatsn(struct iscsi_conn * conn,u32 exp_statsn)951*4882a593Smuzhiyun static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
952*4882a593Smuzhiyun {
953*4882a593Smuzhiyun LIST_HEAD(ack_list);
954*4882a593Smuzhiyun struct iscsi_cmd *cmd, *cmd_p;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun conn->exp_statsn = exp_statsn;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun if (conn->sess->sess_ops->RDMAExtensions)
959*4882a593Smuzhiyun return;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
962*4882a593Smuzhiyun list_for_each_entry_safe(cmd, cmd_p, &conn->conn_cmd_list, i_conn_node) {
963*4882a593Smuzhiyun spin_lock(&cmd->istate_lock);
964*4882a593Smuzhiyun if ((cmd->i_state == ISTATE_SENT_STATUS) &&
965*4882a593Smuzhiyun iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {
966*4882a593Smuzhiyun cmd->i_state = ISTATE_REMOVE;
967*4882a593Smuzhiyun spin_unlock(&cmd->istate_lock);
968*4882a593Smuzhiyun list_move_tail(&cmd->i_conn_node, &ack_list);
969*4882a593Smuzhiyun continue;
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun spin_unlock(&cmd->istate_lock);
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
976*4882a593Smuzhiyun list_del_init(&cmd->i_conn_node);
977*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun
iscsit_allocate_iovecs(struct iscsi_cmd * cmd)981*4882a593Smuzhiyun static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun u32 iov_count = max(1UL, DIV_ROUND_UP(cmd->se_cmd.data_length, PAGE_SIZE));
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun iov_count += ISCSI_IOV_DATA_BUFFER;
986*4882a593Smuzhiyun cmd->iov_data = kcalloc(iov_count, sizeof(*cmd->iov_data), GFP_KERNEL);
987*4882a593Smuzhiyun if (!cmd->iov_data)
988*4882a593Smuzhiyun return -ENOMEM;
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun cmd->orig_iov_data_count = iov_count;
991*4882a593Smuzhiyun return 0;
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun
iscsit_setup_scsi_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)994*4882a593Smuzhiyun int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
995*4882a593Smuzhiyun unsigned char *buf)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun int data_direction, payload_length;
998*4882a593Smuzhiyun struct iscsi_scsi_req *hdr;
999*4882a593Smuzhiyun int iscsi_task_attr;
1000*4882a593Smuzhiyun int sam_task_attr;
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun atomic_long_inc(&conn->sess->cmd_pdus);
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun hdr = (struct iscsi_scsi_req *) buf;
1005*4882a593Smuzhiyun payload_length = ntoh24(hdr->dlength);
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun /* FIXME; Add checks for AdditionalHeaderSegment */
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun if (!(hdr->flags & ISCSI_FLAG_CMD_WRITE) &&
1010*4882a593Smuzhiyun !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
1011*4882a593Smuzhiyun pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
1012*4882a593Smuzhiyun " not set. Bad iSCSI Initiator.\n");
1013*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1014*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
1018*4882a593Smuzhiyun (hdr->flags & ISCSI_FLAG_CMD_WRITE)) && !hdr->data_length) {
1019*4882a593Smuzhiyun /*
1020*4882a593Smuzhiyun * From RFC-3720 Section 10.3.1:
1021*4882a593Smuzhiyun *
1022*4882a593Smuzhiyun * "Either or both of R and W MAY be 1 when either the
1023*4882a593Smuzhiyun * Expected Data Transfer Length and/or Bidirectional Read
1024*4882a593Smuzhiyun * Expected Data Transfer Length are 0"
1025*4882a593Smuzhiyun *
1026*4882a593Smuzhiyun * For this case, go ahead and clear the unnecssary bits
1027*4882a593Smuzhiyun * to avoid any confusion with ->data_direction.
1028*4882a593Smuzhiyun */
1029*4882a593Smuzhiyun hdr->flags &= ~ISCSI_FLAG_CMD_READ;
1030*4882a593Smuzhiyun hdr->flags &= ~ISCSI_FLAG_CMD_WRITE;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun pr_warn("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
1033*4882a593Smuzhiyun " set when Expected Data Transfer Length is 0 for"
1034*4882a593Smuzhiyun " CDB: 0x%02x, Fixing up flags\n", hdr->cdb[0]);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun if (!(hdr->flags & ISCSI_FLAG_CMD_READ) &&
1038*4882a593Smuzhiyun !(hdr->flags & ISCSI_FLAG_CMD_WRITE) && (hdr->data_length != 0)) {
1039*4882a593Smuzhiyun pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
1040*4882a593Smuzhiyun " MUST be set if Expected Data Transfer Length is not 0."
1041*4882a593Smuzhiyun " Bad iSCSI Initiator\n");
1042*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1043*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
1047*4882a593Smuzhiyun (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
1048*4882a593Smuzhiyun pr_err("Bidirectional operations not supported!\n");
1049*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1050*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
1054*4882a593Smuzhiyun pr_err("Illegally set Immediate Bit in iSCSI Initiator"
1055*4882a593Smuzhiyun " Scsi Command PDU.\n");
1056*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1057*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun if (payload_length && !conn->sess->sess_ops->ImmediateData) {
1061*4882a593Smuzhiyun pr_err("ImmediateData=No but DataSegmentLength=%u,"
1062*4882a593Smuzhiyun " protocol error.\n", payload_length);
1063*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1064*4882a593Smuzhiyun ISCSI_REASON_PROTOCOL_ERROR, buf);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if ((be32_to_cpu(hdr->data_length) == payload_length) &&
1068*4882a593Smuzhiyun (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {
1069*4882a593Smuzhiyun pr_err("Expected Data Transfer Length and Length of"
1070*4882a593Smuzhiyun " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
1071*4882a593Smuzhiyun " bit is not set protocol error\n");
1072*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1073*4882a593Smuzhiyun ISCSI_REASON_PROTOCOL_ERROR, buf);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun if (payload_length > be32_to_cpu(hdr->data_length)) {
1077*4882a593Smuzhiyun pr_err("DataSegmentLength: %u is greater than"
1078*4882a593Smuzhiyun " EDTL: %u, protocol error.\n", payload_length,
1079*4882a593Smuzhiyun hdr->data_length);
1080*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1081*4882a593Smuzhiyun ISCSI_REASON_PROTOCOL_ERROR, buf);
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
1085*4882a593Smuzhiyun pr_err("DataSegmentLength: %u is greater than"
1086*4882a593Smuzhiyun " MaxXmitDataSegmentLength: %u, protocol error.\n",
1087*4882a593Smuzhiyun payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
1088*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1089*4882a593Smuzhiyun ISCSI_REASON_PROTOCOL_ERROR, buf);
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
1093*4882a593Smuzhiyun pr_err("DataSegmentLength: %u is greater than"
1094*4882a593Smuzhiyun " FirstBurstLength: %u, protocol error.\n",
1095*4882a593Smuzhiyun payload_length, conn->sess->sess_ops->FirstBurstLength);
1096*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1097*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
1101*4882a593Smuzhiyun (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
1102*4882a593Smuzhiyun DMA_NONE;
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun cmd->data_direction = data_direction;
1105*4882a593Smuzhiyun iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK;
1106*4882a593Smuzhiyun /*
1107*4882a593Smuzhiyun * Figure out the SAM Task Attribute for the incoming SCSI CDB
1108*4882a593Smuzhiyun */
1109*4882a593Smuzhiyun if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) ||
1110*4882a593Smuzhiyun (iscsi_task_attr == ISCSI_ATTR_SIMPLE))
1111*4882a593Smuzhiyun sam_task_attr = TCM_SIMPLE_TAG;
1112*4882a593Smuzhiyun else if (iscsi_task_attr == ISCSI_ATTR_ORDERED)
1113*4882a593Smuzhiyun sam_task_attr = TCM_ORDERED_TAG;
1114*4882a593Smuzhiyun else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE)
1115*4882a593Smuzhiyun sam_task_attr = TCM_HEAD_TAG;
1116*4882a593Smuzhiyun else if (iscsi_task_attr == ISCSI_ATTR_ACA)
1117*4882a593Smuzhiyun sam_task_attr = TCM_ACA_TAG;
1118*4882a593Smuzhiyun else {
1119*4882a593Smuzhiyun pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using"
1120*4882a593Smuzhiyun " TCM_SIMPLE_TAG\n", iscsi_task_attr);
1121*4882a593Smuzhiyun sam_task_attr = TCM_SIMPLE_TAG;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_SCSI_CMD;
1125*4882a593Smuzhiyun cmd->i_state = ISTATE_NEW_CMD;
1126*4882a593Smuzhiyun cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
1127*4882a593Smuzhiyun cmd->immediate_data = (payload_length) ? 1 : 0;
1128*4882a593Smuzhiyun cmd->unsolicited_data = ((!(hdr->flags & ISCSI_FLAG_CMD_FINAL) &&
1129*4882a593Smuzhiyun (hdr->flags & ISCSI_FLAG_CMD_WRITE)) ? 1 : 0);
1130*4882a593Smuzhiyun if (cmd->unsolicited_data)
1131*4882a593Smuzhiyun cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA;
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
1134*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_CMD_READ)
1135*4882a593Smuzhiyun cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
1136*4882a593Smuzhiyun else
1137*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
1138*4882a593Smuzhiyun cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
1139*4882a593Smuzhiyun cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
1140*4882a593Smuzhiyun cmd->first_burst_len = payload_length;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun if (!conn->sess->sess_ops->RDMAExtensions &&
1143*4882a593Smuzhiyun cmd->data_direction == DMA_FROM_DEVICE) {
1144*4882a593Smuzhiyun struct iscsi_datain_req *dr;
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun dr = iscsit_allocate_datain_req();
1147*4882a593Smuzhiyun if (!dr)
1148*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1149*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun iscsit_attach_datain_req(cmd, dr);
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun /*
1155*4882a593Smuzhiyun * Initialize struct se_cmd descriptor from target_core_mod infrastructure
1156*4882a593Smuzhiyun */
1157*4882a593Smuzhiyun transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
1158*4882a593Smuzhiyun conn->sess->se_sess, be32_to_cpu(hdr->data_length),
1159*4882a593Smuzhiyun cmd->data_direction, sam_task_attr,
1160*4882a593Smuzhiyun cmd->sense_buffer + 2, scsilun_to_int(&hdr->lun));
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
1163*4882a593Smuzhiyun " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
1164*4882a593Smuzhiyun hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
1165*4882a593Smuzhiyun conn->cid);
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun target_get_sess_cmd(&cmd->se_cmd, true);
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun cmd->se_cmd.tag = (__force u32)cmd->init_task_tag;
1170*4882a593Smuzhiyun cmd->sense_reason = target_cmd_init_cdb(&cmd->se_cmd, hdr->cdb);
1171*4882a593Smuzhiyun if (cmd->sense_reason) {
1172*4882a593Smuzhiyun if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
1173*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1174*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun goto attach_cmd;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd);
1181*4882a593Smuzhiyun if (cmd->sense_reason)
1182*4882a593Smuzhiyun goto attach_cmd;
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun cmd->sense_reason = target_cmd_parse_cdb(&cmd->se_cmd);
1185*4882a593Smuzhiyun if (cmd->sense_reason)
1186*4882a593Smuzhiyun goto attach_cmd;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) {
1189*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
1190*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun attach_cmd:
1194*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
1195*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
1196*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
1197*4882a593Smuzhiyun /*
1198*4882a593Smuzhiyun * Check if we need to delay processing because of ALUA
1199*4882a593Smuzhiyun * Active/NonOptimized primary access state..
1200*4882a593Smuzhiyun */
1201*4882a593Smuzhiyun core_alua_check_nonop_delay(&cmd->se_cmd);
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun return 0;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_setup_scsi_cmd);
1206*4882a593Smuzhiyun
iscsit_set_unsolicited_dataout(struct iscsi_cmd * cmd)1207*4882a593Smuzhiyun void iscsit_set_unsolicited_dataout(struct iscsi_cmd *cmd)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun iscsit_set_dataout_sequence_values(cmd);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun spin_lock_bh(&cmd->dataout_timeout_lock);
1212*4882a593Smuzhiyun iscsit_start_dataout_timer(cmd, cmd->conn);
1213*4882a593Smuzhiyun spin_unlock_bh(&cmd->dataout_timeout_lock);
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_set_unsolicited_dataout);
1216*4882a593Smuzhiyun
iscsit_process_scsi_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_scsi_req * hdr)1217*4882a593Smuzhiyun int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1218*4882a593Smuzhiyun struct iscsi_scsi_req *hdr)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun int cmdsn_ret = 0;
1221*4882a593Smuzhiyun /*
1222*4882a593Smuzhiyun * Check the CmdSN against ExpCmdSN/MaxCmdSN here if
1223*4882a593Smuzhiyun * the Immediate Bit is not set, and no Immediate
1224*4882a593Smuzhiyun * Data is attached.
1225*4882a593Smuzhiyun *
1226*4882a593Smuzhiyun * A PDU/CmdSN carrying Immediate Data can only
1227*4882a593Smuzhiyun * be processed after the DataCRC has passed.
1228*4882a593Smuzhiyun * If the DataCRC fails, the CmdSN MUST NOT
1229*4882a593Smuzhiyun * be acknowledged. (See below)
1230*4882a593Smuzhiyun */
1231*4882a593Smuzhiyun if (!cmd->immediate_data) {
1232*4882a593Smuzhiyun cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
1233*4882a593Smuzhiyun (unsigned char *)hdr, hdr->cmdsn);
1234*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
1235*4882a593Smuzhiyun return -1;
1236*4882a593Smuzhiyun else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
1237*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
1238*4882a593Smuzhiyun return 0;
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun /*
1245*4882a593Smuzhiyun * If no Immediate Data is attached, it's OK to return now.
1246*4882a593Smuzhiyun */
1247*4882a593Smuzhiyun if (!cmd->immediate_data) {
1248*4882a593Smuzhiyun if (!cmd->sense_reason && cmd->unsolicited_data)
1249*4882a593Smuzhiyun iscsit_set_unsolicited_dataout(cmd);
1250*4882a593Smuzhiyun if (!cmd->sense_reason)
1251*4882a593Smuzhiyun return 0;
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
1254*4882a593Smuzhiyun return 0;
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun /*
1258*4882a593Smuzhiyun * Early CHECK_CONDITIONs with ImmediateData never make it to command
1259*4882a593Smuzhiyun * execution. These exceptions are processed in CmdSN order using
1260*4882a593Smuzhiyun * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
1261*4882a593Smuzhiyun */
1262*4882a593Smuzhiyun if (cmd->sense_reason)
1263*4882a593Smuzhiyun return 1;
1264*4882a593Smuzhiyun /*
1265*4882a593Smuzhiyun * Call directly into transport_generic_new_cmd() to perform
1266*4882a593Smuzhiyun * the backend memory allocation.
1267*4882a593Smuzhiyun */
1268*4882a593Smuzhiyun cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
1269*4882a593Smuzhiyun if (cmd->sense_reason)
1270*4882a593Smuzhiyun return 1;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun return 0;
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_process_scsi_cmd);
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun static int
iscsit_get_immediate_data(struct iscsi_cmd * cmd,struct iscsi_scsi_req * hdr,bool dump_payload)1277*4882a593Smuzhiyun iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
1278*4882a593Smuzhiyun bool dump_payload)
1279*4882a593Smuzhiyun {
1280*4882a593Smuzhiyun int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
1281*4882a593Smuzhiyun int rc;
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun /*
1284*4882a593Smuzhiyun * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
1285*4882a593Smuzhiyun */
1286*4882a593Smuzhiyun if (dump_payload) {
1287*4882a593Smuzhiyun u32 length = min(cmd->se_cmd.data_length - cmd->write_data_done,
1288*4882a593Smuzhiyun cmd->first_burst_len);
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun pr_debug("Dumping min(%d - %d, %d) = %d bytes of immediate data\n",
1291*4882a593Smuzhiyun cmd->se_cmd.data_length, cmd->write_data_done,
1292*4882a593Smuzhiyun cmd->first_burst_len, length);
1293*4882a593Smuzhiyun rc = iscsit_dump_data_payload(cmd->conn, length, 1);
1294*4882a593Smuzhiyun pr_debug("Finished dumping immediate data\n");
1295*4882a593Smuzhiyun if (rc < 0)
1296*4882a593Smuzhiyun immed_ret = IMMEDIATE_DATA_CANNOT_RECOVER;
1297*4882a593Smuzhiyun } else {
1298*4882a593Smuzhiyun immed_ret = iscsit_handle_immediate_data(cmd, hdr,
1299*4882a593Smuzhiyun cmd->first_burst_len);
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
1303*4882a593Smuzhiyun /*
1304*4882a593Smuzhiyun * A PDU/CmdSN carrying Immediate Data passed
1305*4882a593Smuzhiyun * DataCRC, check against ExpCmdSN/MaxCmdSN if
1306*4882a593Smuzhiyun * Immediate Bit is not set.
1307*4882a593Smuzhiyun */
1308*4882a593Smuzhiyun cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
1309*4882a593Smuzhiyun (unsigned char *)hdr, hdr->cmdsn);
1310*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
1311*4882a593Smuzhiyun return -1;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
1314*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun return 0;
1317*4882a593Smuzhiyun } else if (cmd->unsolicited_data)
1318*4882a593Smuzhiyun iscsit_set_unsolicited_dataout(cmd);
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
1321*4882a593Smuzhiyun /*
1322*4882a593Smuzhiyun * Immediate Data failed DataCRC and ERL>=1,
1323*4882a593Smuzhiyun * silently drop this PDU and let the initiator
1324*4882a593Smuzhiyun * plug the CmdSN gap.
1325*4882a593Smuzhiyun *
1326*4882a593Smuzhiyun * FIXME: Send Unsolicited NOPIN with reserved
1327*4882a593Smuzhiyun * TTT here to help the initiator figure out
1328*4882a593Smuzhiyun * the missing CmdSN, although they should be
1329*4882a593Smuzhiyun * intelligent enough to determine the missing
1330*4882a593Smuzhiyun * CmdSN and issue a retry to plug the sequence.
1331*4882a593Smuzhiyun */
1332*4882a593Smuzhiyun cmd->i_state = ISTATE_REMOVE;
1333*4882a593Smuzhiyun iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, cmd->i_state);
1334*4882a593Smuzhiyun } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
1335*4882a593Smuzhiyun return -1;
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun return 0;
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun static int
iscsit_handle_scsi_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)1341*4882a593Smuzhiyun iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1342*4882a593Smuzhiyun unsigned char *buf)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
1345*4882a593Smuzhiyun int rc, immed_data;
1346*4882a593Smuzhiyun bool dump_payload = false;
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
1349*4882a593Smuzhiyun if (rc < 0)
1350*4882a593Smuzhiyun return 0;
1351*4882a593Smuzhiyun /*
1352*4882a593Smuzhiyun * Allocation iovecs needed for struct socket operations for
1353*4882a593Smuzhiyun * traditional iSCSI block I/O.
1354*4882a593Smuzhiyun */
1355*4882a593Smuzhiyun if (iscsit_allocate_iovecs(cmd) < 0) {
1356*4882a593Smuzhiyun return iscsit_reject_cmd(cmd,
1357*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun immed_data = cmd->immediate_data;
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
1362*4882a593Smuzhiyun if (rc < 0)
1363*4882a593Smuzhiyun return rc;
1364*4882a593Smuzhiyun else if (rc > 0)
1365*4882a593Smuzhiyun dump_payload = true;
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun if (!immed_data)
1368*4882a593Smuzhiyun return 0;
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun return iscsit_get_immediate_data(cmd, hdr, dump_payload);
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun
iscsit_do_crypto_hash_sg(struct ahash_request * hash,struct iscsi_cmd * cmd,u32 data_offset,u32 data_length,u32 padding,u8 * pad_bytes)1373*4882a593Smuzhiyun static u32 iscsit_do_crypto_hash_sg(
1374*4882a593Smuzhiyun struct ahash_request *hash,
1375*4882a593Smuzhiyun struct iscsi_cmd *cmd,
1376*4882a593Smuzhiyun u32 data_offset,
1377*4882a593Smuzhiyun u32 data_length,
1378*4882a593Smuzhiyun u32 padding,
1379*4882a593Smuzhiyun u8 *pad_bytes)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun u32 data_crc;
1382*4882a593Smuzhiyun struct scatterlist *sg;
1383*4882a593Smuzhiyun unsigned int page_off;
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun crypto_ahash_init(hash);
1386*4882a593Smuzhiyun
1387*4882a593Smuzhiyun sg = cmd->first_data_sg;
1388*4882a593Smuzhiyun page_off = cmd->first_data_sg_off;
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun if (data_length && page_off) {
1391*4882a593Smuzhiyun struct scatterlist first_sg;
1392*4882a593Smuzhiyun u32 len = min_t(u32, data_length, sg->length - page_off);
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun sg_init_table(&first_sg, 1);
1395*4882a593Smuzhiyun sg_set_page(&first_sg, sg_page(sg), len, sg->offset + page_off);
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun ahash_request_set_crypt(hash, &first_sg, NULL, len);
1398*4882a593Smuzhiyun crypto_ahash_update(hash);
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun data_length -= len;
1401*4882a593Smuzhiyun sg = sg_next(sg);
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun while (data_length) {
1405*4882a593Smuzhiyun u32 cur_len = min_t(u32, data_length, sg->length);
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun ahash_request_set_crypt(hash, sg, NULL, cur_len);
1408*4882a593Smuzhiyun crypto_ahash_update(hash);
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun data_length -= cur_len;
1411*4882a593Smuzhiyun /* iscsit_map_iovec has already checked for invalid sg pointers */
1412*4882a593Smuzhiyun sg = sg_next(sg);
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun
1415*4882a593Smuzhiyun if (padding) {
1416*4882a593Smuzhiyun struct scatterlist pad_sg;
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun sg_init_one(&pad_sg, pad_bytes, padding);
1419*4882a593Smuzhiyun ahash_request_set_crypt(hash, &pad_sg, (u8 *)&data_crc,
1420*4882a593Smuzhiyun padding);
1421*4882a593Smuzhiyun crypto_ahash_finup(hash);
1422*4882a593Smuzhiyun } else {
1423*4882a593Smuzhiyun ahash_request_set_crypt(hash, NULL, (u8 *)&data_crc, 0);
1424*4882a593Smuzhiyun crypto_ahash_final(hash);
1425*4882a593Smuzhiyun }
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun return data_crc;
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun
iscsit_do_crypto_hash_buf(struct ahash_request * hash,const void * buf,u32 payload_length,u32 padding,const void * pad_bytes,void * data_crc)1430*4882a593Smuzhiyun static void iscsit_do_crypto_hash_buf(struct ahash_request *hash,
1431*4882a593Smuzhiyun const void *buf, u32 payload_length, u32 padding,
1432*4882a593Smuzhiyun const void *pad_bytes, void *data_crc)
1433*4882a593Smuzhiyun {
1434*4882a593Smuzhiyun struct scatterlist sg[2];
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun sg_init_table(sg, ARRAY_SIZE(sg));
1437*4882a593Smuzhiyun sg_set_buf(sg, buf, payload_length);
1438*4882a593Smuzhiyun if (padding)
1439*4882a593Smuzhiyun sg_set_buf(sg + 1, pad_bytes, padding);
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding);
1442*4882a593Smuzhiyun
1443*4882a593Smuzhiyun crypto_ahash_digest(hash);
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun int
__iscsit_check_dataout_hdr(struct iscsi_conn * conn,void * buf,struct iscsi_cmd * cmd,u32 payload_length,bool * success)1447*4882a593Smuzhiyun __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf,
1448*4882a593Smuzhiyun struct iscsi_cmd *cmd, u32 payload_length,
1449*4882a593Smuzhiyun bool *success)
1450*4882a593Smuzhiyun {
1451*4882a593Smuzhiyun struct iscsi_data *hdr = buf;
1452*4882a593Smuzhiyun struct se_cmd *se_cmd;
1453*4882a593Smuzhiyun int rc;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun /* iSCSI write */
1456*4882a593Smuzhiyun atomic_long_add(payload_length, &conn->sess->rx_data_octets);
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x,"
1459*4882a593Smuzhiyun " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
1460*4882a593Smuzhiyun hdr->itt, hdr->ttt, hdr->datasn, ntohl(hdr->offset),
1461*4882a593Smuzhiyun payload_length, conn->cid);
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
1464*4882a593Smuzhiyun pr_err("Command ITT: 0x%08x received DataOUT after"
1465*4882a593Smuzhiyun " last DataOUT received, dumping payload\n",
1466*4882a593Smuzhiyun cmd->init_task_tag);
1467*4882a593Smuzhiyun return iscsit_dump_data_payload(conn, payload_length, 1);
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun
1470*4882a593Smuzhiyun if (cmd->data_direction != DMA_TO_DEVICE) {
1471*4882a593Smuzhiyun pr_err("Command ITT: 0x%08x received DataOUT for a"
1472*4882a593Smuzhiyun " NON-WRITE command.\n", cmd->init_task_tag);
1473*4882a593Smuzhiyun return iscsit_dump_data_payload(conn, payload_length, 1);
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun se_cmd = &cmd->se_cmd;
1476*4882a593Smuzhiyun iscsit_mod_dataout_timer(cmd);
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun if ((be32_to_cpu(hdr->offset) + payload_length) > cmd->se_cmd.data_length) {
1479*4882a593Smuzhiyun pr_err("DataOut Offset: %u, Length %u greater than iSCSI Command EDTL %u, protocol error.\n",
1480*4882a593Smuzhiyun be32_to_cpu(hdr->offset), payload_length,
1481*4882a593Smuzhiyun cmd->se_cmd.data_length);
1482*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun
1485*4882a593Smuzhiyun if (cmd->unsolicited_data) {
1486*4882a593Smuzhiyun int dump_unsolicited_data = 0;
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun if (conn->sess->sess_ops->InitialR2T) {
1489*4882a593Smuzhiyun pr_err("Received unexpected unsolicited data"
1490*4882a593Smuzhiyun " while InitialR2T=Yes, protocol error.\n");
1491*4882a593Smuzhiyun transport_send_check_condition_and_sense(&cmd->se_cmd,
1492*4882a593Smuzhiyun TCM_UNEXPECTED_UNSOLICITED_DATA, 0);
1493*4882a593Smuzhiyun return -1;
1494*4882a593Smuzhiyun }
1495*4882a593Smuzhiyun /*
1496*4882a593Smuzhiyun * Special case for dealing with Unsolicited DataOUT
1497*4882a593Smuzhiyun * and Unsupported SAM WRITE Opcodes and SE resource allocation
1498*4882a593Smuzhiyun * failures;
1499*4882a593Smuzhiyun */
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun /* Something's amiss if we're not in WRITE_PENDING state... */
1502*4882a593Smuzhiyun WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING);
1503*4882a593Smuzhiyun if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE))
1504*4882a593Smuzhiyun dump_unsolicited_data = 1;
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun if (dump_unsolicited_data) {
1507*4882a593Smuzhiyun /*
1508*4882a593Smuzhiyun * Check if a delayed TASK_ABORTED status needs to
1509*4882a593Smuzhiyun * be sent now if the ISCSI_FLAG_CMD_FINAL has been
1510*4882a593Smuzhiyun * received with the unsolicited data out.
1511*4882a593Smuzhiyun */
1512*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
1513*4882a593Smuzhiyun iscsit_stop_dataout_timer(cmd);
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun return iscsit_dump_data_payload(conn, payload_length, 1);
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun } else {
1518*4882a593Smuzhiyun /*
1519*4882a593Smuzhiyun * For the normal solicited data path:
1520*4882a593Smuzhiyun *
1521*4882a593Smuzhiyun * Check for a delayed TASK_ABORTED status and dump any
1522*4882a593Smuzhiyun * incoming data out payload if one exists. Also, when the
1523*4882a593Smuzhiyun * ISCSI_FLAG_CMD_FINAL is set to denote the end of the current
1524*4882a593Smuzhiyun * data out sequence, we decrement outstanding_r2ts. Once
1525*4882a593Smuzhiyun * outstanding_r2ts reaches zero, go ahead and send the delayed
1526*4882a593Smuzhiyun * TASK_ABORTED status.
1527*4882a593Smuzhiyun */
1528*4882a593Smuzhiyun if (se_cmd->transport_state & CMD_T_ABORTED) {
1529*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_CMD_FINAL &&
1530*4882a593Smuzhiyun --cmd->outstanding_r2ts < 1)
1531*4882a593Smuzhiyun iscsit_stop_dataout_timer(cmd);
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun return iscsit_dump_data_payload(conn, payload_length, 1);
1534*4882a593Smuzhiyun }
1535*4882a593Smuzhiyun }
1536*4882a593Smuzhiyun /*
1537*4882a593Smuzhiyun * Perform DataSN, DataSequenceInOrder, DataPDUInOrder, and
1538*4882a593Smuzhiyun * within-command recovery checks before receiving the payload.
1539*4882a593Smuzhiyun */
1540*4882a593Smuzhiyun rc = iscsit_check_pre_dataout(cmd, buf);
1541*4882a593Smuzhiyun if (rc == DATAOUT_WITHIN_COMMAND_RECOVERY)
1542*4882a593Smuzhiyun return 0;
1543*4882a593Smuzhiyun else if (rc == DATAOUT_CANNOT_RECOVER)
1544*4882a593Smuzhiyun return -1;
1545*4882a593Smuzhiyun *success = true;
1546*4882a593Smuzhiyun return 0;
1547*4882a593Smuzhiyun }
1548*4882a593Smuzhiyun EXPORT_SYMBOL(__iscsit_check_dataout_hdr);
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun int
iscsit_check_dataout_hdr(struct iscsi_conn * conn,void * buf,struct iscsi_cmd ** out_cmd)1551*4882a593Smuzhiyun iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf,
1552*4882a593Smuzhiyun struct iscsi_cmd **out_cmd)
1553*4882a593Smuzhiyun {
1554*4882a593Smuzhiyun struct iscsi_data *hdr = buf;
1555*4882a593Smuzhiyun struct iscsi_cmd *cmd;
1556*4882a593Smuzhiyun u32 payload_length = ntoh24(hdr->dlength);
1557*4882a593Smuzhiyun int rc;
1558*4882a593Smuzhiyun bool success = false;
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun if (!payload_length) {
1561*4882a593Smuzhiyun pr_warn_ratelimited("DataOUT payload is ZERO, ignoring.\n");
1562*4882a593Smuzhiyun return 0;
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
1566*4882a593Smuzhiyun pr_err_ratelimited("DataSegmentLength: %u is greater than"
1567*4882a593Smuzhiyun " MaxXmitDataSegmentLength: %u\n", payload_length,
1568*4882a593Smuzhiyun conn->conn_ops->MaxXmitDataSegmentLength);
1569*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, buf);
1570*4882a593Smuzhiyun }
1571*4882a593Smuzhiyun
1572*4882a593Smuzhiyun cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, payload_length);
1573*4882a593Smuzhiyun if (!cmd)
1574*4882a593Smuzhiyun return 0;
1575*4882a593Smuzhiyun
1576*4882a593Smuzhiyun rc = __iscsit_check_dataout_hdr(conn, buf, cmd, payload_length, &success);
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun if (success)
1579*4882a593Smuzhiyun *out_cmd = cmd;
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun return rc;
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_check_dataout_hdr);
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun static int
iscsit_get_dataout(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_data * hdr)1586*4882a593Smuzhiyun iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1587*4882a593Smuzhiyun struct iscsi_data *hdr)
1588*4882a593Smuzhiyun {
1589*4882a593Smuzhiyun struct kvec *iov;
1590*4882a593Smuzhiyun u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0;
1591*4882a593Smuzhiyun u32 payload_length;
1592*4882a593Smuzhiyun int iov_ret, data_crc_failed = 0;
1593*4882a593Smuzhiyun
1594*4882a593Smuzhiyun payload_length = min_t(u32, cmd->se_cmd.data_length,
1595*4882a593Smuzhiyun ntoh24(hdr->dlength));
1596*4882a593Smuzhiyun rx_size += payload_length;
1597*4882a593Smuzhiyun iov = &cmd->iov_data[0];
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun iov_ret = iscsit_map_iovec(cmd, iov, cmd->orig_iov_data_count - 2,
1600*4882a593Smuzhiyun be32_to_cpu(hdr->offset), payload_length);
1601*4882a593Smuzhiyun if (iov_ret < 0)
1602*4882a593Smuzhiyun return -1;
1603*4882a593Smuzhiyun
1604*4882a593Smuzhiyun iov_count += iov_ret;
1605*4882a593Smuzhiyun
1606*4882a593Smuzhiyun padding = ((-payload_length) & 3);
1607*4882a593Smuzhiyun if (padding != 0) {
1608*4882a593Smuzhiyun iov[iov_count].iov_base = cmd->pad_bytes;
1609*4882a593Smuzhiyun iov[iov_count++].iov_len = padding;
1610*4882a593Smuzhiyun rx_size += padding;
1611*4882a593Smuzhiyun pr_debug("Receiving %u padding bytes.\n", padding);
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun
1614*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
1615*4882a593Smuzhiyun iov[iov_count].iov_base = &checksum;
1616*4882a593Smuzhiyun iov[iov_count++].iov_len = ISCSI_CRC_LEN;
1617*4882a593Smuzhiyun rx_size += ISCSI_CRC_LEN;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun WARN_ON_ONCE(iov_count > cmd->orig_iov_data_count);
1621*4882a593Smuzhiyun rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size);
1622*4882a593Smuzhiyun
1623*4882a593Smuzhiyun iscsit_unmap_iovec(cmd);
1624*4882a593Smuzhiyun
1625*4882a593Smuzhiyun if (rx_got != rx_size)
1626*4882a593Smuzhiyun return -1;
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
1629*4882a593Smuzhiyun u32 data_crc;
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
1632*4882a593Smuzhiyun be32_to_cpu(hdr->offset),
1633*4882a593Smuzhiyun payload_length, padding,
1634*4882a593Smuzhiyun cmd->pad_bytes);
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun if (checksum != data_crc) {
1637*4882a593Smuzhiyun pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
1638*4882a593Smuzhiyun " DataSN: 0x%08x, CRC32C DataDigest 0x%08x"
1639*4882a593Smuzhiyun " does not match computed 0x%08x\n",
1640*4882a593Smuzhiyun hdr->itt, hdr->offset, payload_length,
1641*4882a593Smuzhiyun hdr->datasn, checksum, data_crc);
1642*4882a593Smuzhiyun data_crc_failed = 1;
1643*4882a593Smuzhiyun } else {
1644*4882a593Smuzhiyun pr_debug("Got CRC32C DataDigest 0x%08x for"
1645*4882a593Smuzhiyun " %u bytes of Data Out\n", checksum,
1646*4882a593Smuzhiyun payload_length);
1647*4882a593Smuzhiyun }
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun return data_crc_failed;
1651*4882a593Smuzhiyun }
1652*4882a593Smuzhiyun
1653*4882a593Smuzhiyun int
iscsit_check_dataout_payload(struct iscsi_cmd * cmd,struct iscsi_data * hdr,bool data_crc_failed)1654*4882a593Smuzhiyun iscsit_check_dataout_payload(struct iscsi_cmd *cmd, struct iscsi_data *hdr,
1655*4882a593Smuzhiyun bool data_crc_failed)
1656*4882a593Smuzhiyun {
1657*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
1658*4882a593Smuzhiyun int rc, ooo_cmdsn;
1659*4882a593Smuzhiyun /*
1660*4882a593Smuzhiyun * Increment post receive data and CRC values or perform
1661*4882a593Smuzhiyun * within-command recovery.
1662*4882a593Smuzhiyun */
1663*4882a593Smuzhiyun rc = iscsit_check_post_dataout(cmd, (unsigned char *)hdr, data_crc_failed);
1664*4882a593Smuzhiyun if ((rc == DATAOUT_NORMAL) || (rc == DATAOUT_WITHIN_COMMAND_RECOVERY))
1665*4882a593Smuzhiyun return 0;
1666*4882a593Smuzhiyun else if (rc == DATAOUT_SEND_R2T) {
1667*4882a593Smuzhiyun iscsit_set_dataout_sequence_values(cmd);
1668*4882a593Smuzhiyun conn->conn_transport->iscsit_get_dataout(conn, cmd, false);
1669*4882a593Smuzhiyun } else if (rc == DATAOUT_SEND_TO_TRANSPORT) {
1670*4882a593Smuzhiyun /*
1671*4882a593Smuzhiyun * Handle extra special case for out of order
1672*4882a593Smuzhiyun * Unsolicited Data Out.
1673*4882a593Smuzhiyun */
1674*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
1675*4882a593Smuzhiyun ooo_cmdsn = (cmd->cmd_flags & ICF_OOO_CMDSN);
1676*4882a593Smuzhiyun cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
1677*4882a593Smuzhiyun cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
1678*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun iscsit_stop_dataout_timer(cmd);
1681*4882a593Smuzhiyun if (ooo_cmdsn)
1682*4882a593Smuzhiyun return 0;
1683*4882a593Smuzhiyun target_execute_cmd(&cmd->se_cmd);
1684*4882a593Smuzhiyun return 0;
1685*4882a593Smuzhiyun } else /* DATAOUT_CANNOT_RECOVER */
1686*4882a593Smuzhiyun return -1;
1687*4882a593Smuzhiyun
1688*4882a593Smuzhiyun return 0;
1689*4882a593Smuzhiyun }
1690*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_check_dataout_payload);
1691*4882a593Smuzhiyun
iscsit_handle_data_out(struct iscsi_conn * conn,unsigned char * buf)1692*4882a593Smuzhiyun static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun struct iscsi_cmd *cmd = NULL;
1695*4882a593Smuzhiyun struct iscsi_data *hdr = (struct iscsi_data *)buf;
1696*4882a593Smuzhiyun int rc;
1697*4882a593Smuzhiyun bool data_crc_failed = false;
1698*4882a593Smuzhiyun
1699*4882a593Smuzhiyun rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
1700*4882a593Smuzhiyun if (rc < 0)
1701*4882a593Smuzhiyun return 0;
1702*4882a593Smuzhiyun else if (!cmd)
1703*4882a593Smuzhiyun return 0;
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun rc = iscsit_get_dataout(conn, cmd, hdr);
1706*4882a593Smuzhiyun if (rc < 0)
1707*4882a593Smuzhiyun return rc;
1708*4882a593Smuzhiyun else if (rc > 0)
1709*4882a593Smuzhiyun data_crc_failed = true;
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun
iscsit_setup_nop_out(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_nopout * hdr)1714*4882a593Smuzhiyun int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1715*4882a593Smuzhiyun struct iscsi_nopout *hdr)
1716*4882a593Smuzhiyun {
1717*4882a593Smuzhiyun u32 payload_length = ntoh24(hdr->dlength);
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
1720*4882a593Smuzhiyun pr_err("NopOUT Flag's, Left Most Bit not set, protocol error.\n");
1721*4882a593Smuzhiyun if (!cmd)
1722*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
1723*4882a593Smuzhiyun (unsigned char *)hdr);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
1726*4882a593Smuzhiyun (unsigned char *)hdr);
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
1730*4882a593Smuzhiyun pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
1731*4882a593Smuzhiyun " not set, protocol error.\n");
1732*4882a593Smuzhiyun if (!cmd)
1733*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
1734*4882a593Smuzhiyun (unsigned char *)hdr);
1735*4882a593Smuzhiyun
1736*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
1737*4882a593Smuzhiyun (unsigned char *)hdr);
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
1741*4882a593Smuzhiyun pr_err("NOPOUT Ping Data DataSegmentLength: %u is"
1742*4882a593Smuzhiyun " greater than MaxXmitDataSegmentLength: %u, protocol"
1743*4882a593Smuzhiyun " error.\n", payload_length,
1744*4882a593Smuzhiyun conn->conn_ops->MaxXmitDataSegmentLength);
1745*4882a593Smuzhiyun if (!cmd)
1746*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
1747*4882a593Smuzhiyun (unsigned char *)hdr);
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
1750*4882a593Smuzhiyun (unsigned char *)hdr);
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
1754*4882a593Smuzhiyun " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
1755*4882a593Smuzhiyun hdr->itt == RESERVED_ITT ? "Response" : "Request",
1756*4882a593Smuzhiyun hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
1757*4882a593Smuzhiyun payload_length);
1758*4882a593Smuzhiyun /*
1759*4882a593Smuzhiyun * This is not a response to a Unsolicited NopIN, which means
1760*4882a593Smuzhiyun * it can either be a NOPOUT ping request (with a valid ITT),
1761*4882a593Smuzhiyun * or a NOPOUT not requesting a NOPIN (with a reserved ITT).
1762*4882a593Smuzhiyun * Either way, make sure we allocate an struct iscsi_cmd, as both
1763*4882a593Smuzhiyun * can contain ping data.
1764*4882a593Smuzhiyun */
1765*4882a593Smuzhiyun if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
1766*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT;
1767*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_NOPIN;
1768*4882a593Smuzhiyun cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ?
1769*4882a593Smuzhiyun 1 : 0);
1770*4882a593Smuzhiyun conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
1771*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
1772*4882a593Smuzhiyun cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
1773*4882a593Smuzhiyun cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
1774*4882a593Smuzhiyun cmd->data_direction = DMA_NONE;
1775*4882a593Smuzhiyun }
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun return 0;
1778*4882a593Smuzhiyun }
1779*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_setup_nop_out);
1780*4882a593Smuzhiyun
iscsit_process_nop_out(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_nopout * hdr)1781*4882a593Smuzhiyun int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1782*4882a593Smuzhiyun struct iscsi_nopout *hdr)
1783*4882a593Smuzhiyun {
1784*4882a593Smuzhiyun struct iscsi_cmd *cmd_p = NULL;
1785*4882a593Smuzhiyun int cmdsn_ret = 0;
1786*4882a593Smuzhiyun /*
1787*4882a593Smuzhiyun * Initiator is expecting a NopIN ping reply..
1788*4882a593Smuzhiyun */
1789*4882a593Smuzhiyun if (hdr->itt != RESERVED_ITT) {
1790*4882a593Smuzhiyun if (!cmd)
1791*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
1792*4882a593Smuzhiyun (unsigned char *)hdr);
1793*4882a593Smuzhiyun
1794*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
1795*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
1796*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
1799*4882a593Smuzhiyun
1800*4882a593Smuzhiyun if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
1801*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn,
1802*4882a593Smuzhiyun cmd->i_state);
1803*4882a593Smuzhiyun return 0;
1804*4882a593Smuzhiyun }
1805*4882a593Smuzhiyun
1806*4882a593Smuzhiyun cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
1807*4882a593Smuzhiyun (unsigned char *)hdr, hdr->cmdsn);
1808*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
1809*4882a593Smuzhiyun return 0;
1810*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
1811*4882a593Smuzhiyun return -1;
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun return 0;
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun /*
1816*4882a593Smuzhiyun * This was a response to a unsolicited NOPIN ping.
1817*4882a593Smuzhiyun */
1818*4882a593Smuzhiyun if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
1819*4882a593Smuzhiyun cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
1820*4882a593Smuzhiyun if (!cmd_p)
1821*4882a593Smuzhiyun return -EINVAL;
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun iscsit_stop_nopin_response_timer(conn);
1824*4882a593Smuzhiyun
1825*4882a593Smuzhiyun cmd_p->i_state = ISTATE_REMOVE;
1826*4882a593Smuzhiyun iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
1827*4882a593Smuzhiyun
1828*4882a593Smuzhiyun iscsit_start_nopin_timer(conn);
1829*4882a593Smuzhiyun return 0;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun /*
1832*4882a593Smuzhiyun * Otherwise, initiator is not expecting a NOPIN is response.
1833*4882a593Smuzhiyun * Just ignore for now.
1834*4882a593Smuzhiyun */
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun if (cmd)
1837*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun return 0;
1840*4882a593Smuzhiyun }
1841*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_process_nop_out);
1842*4882a593Smuzhiyun
iscsit_handle_nop_out(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)1843*4882a593Smuzhiyun static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1844*4882a593Smuzhiyun unsigned char *buf)
1845*4882a593Smuzhiyun {
1846*4882a593Smuzhiyun unsigned char *ping_data = NULL;
1847*4882a593Smuzhiyun struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
1848*4882a593Smuzhiyun struct kvec *iov = NULL;
1849*4882a593Smuzhiyun u32 payload_length = ntoh24(hdr->dlength);
1850*4882a593Smuzhiyun int ret;
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun ret = iscsit_setup_nop_out(conn, cmd, hdr);
1853*4882a593Smuzhiyun if (ret < 0)
1854*4882a593Smuzhiyun return 0;
1855*4882a593Smuzhiyun /*
1856*4882a593Smuzhiyun * Handle NOP-OUT payload for traditional iSCSI sockets
1857*4882a593Smuzhiyun */
1858*4882a593Smuzhiyun if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
1859*4882a593Smuzhiyun u32 checksum, data_crc, padding = 0;
1860*4882a593Smuzhiyun int niov = 0, rx_got, rx_size = payload_length;
1861*4882a593Smuzhiyun
1862*4882a593Smuzhiyun ping_data = kzalloc(payload_length + 1, GFP_KERNEL);
1863*4882a593Smuzhiyun if (!ping_data) {
1864*4882a593Smuzhiyun ret = -1;
1865*4882a593Smuzhiyun goto out;
1866*4882a593Smuzhiyun }
1867*4882a593Smuzhiyun
1868*4882a593Smuzhiyun iov = &cmd->iov_misc[0];
1869*4882a593Smuzhiyun iov[niov].iov_base = ping_data;
1870*4882a593Smuzhiyun iov[niov++].iov_len = payload_length;
1871*4882a593Smuzhiyun
1872*4882a593Smuzhiyun padding = ((-payload_length) & 3);
1873*4882a593Smuzhiyun if (padding != 0) {
1874*4882a593Smuzhiyun pr_debug("Receiving %u additional bytes"
1875*4882a593Smuzhiyun " for padding.\n", padding);
1876*4882a593Smuzhiyun iov[niov].iov_base = &cmd->pad_bytes;
1877*4882a593Smuzhiyun iov[niov++].iov_len = padding;
1878*4882a593Smuzhiyun rx_size += padding;
1879*4882a593Smuzhiyun }
1880*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
1881*4882a593Smuzhiyun iov[niov].iov_base = &checksum;
1882*4882a593Smuzhiyun iov[niov++].iov_len = ISCSI_CRC_LEN;
1883*4882a593Smuzhiyun rx_size += ISCSI_CRC_LEN;
1884*4882a593Smuzhiyun }
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun WARN_ON_ONCE(niov > ARRAY_SIZE(cmd->iov_misc));
1887*4882a593Smuzhiyun rx_got = rx_data(conn, &cmd->iov_misc[0], niov, rx_size);
1888*4882a593Smuzhiyun if (rx_got != rx_size) {
1889*4882a593Smuzhiyun ret = -1;
1890*4882a593Smuzhiyun goto out;
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
1894*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_rx_hash, ping_data,
1895*4882a593Smuzhiyun payload_length, padding,
1896*4882a593Smuzhiyun cmd->pad_bytes, &data_crc);
1897*4882a593Smuzhiyun
1898*4882a593Smuzhiyun if (checksum != data_crc) {
1899*4882a593Smuzhiyun pr_err("Ping data CRC32C DataDigest"
1900*4882a593Smuzhiyun " 0x%08x does not match computed 0x%08x\n",
1901*4882a593Smuzhiyun checksum, data_crc);
1902*4882a593Smuzhiyun if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
1903*4882a593Smuzhiyun pr_err("Unable to recover from"
1904*4882a593Smuzhiyun " NOPOUT Ping DataCRC failure while in"
1905*4882a593Smuzhiyun " ERL=0.\n");
1906*4882a593Smuzhiyun ret = -1;
1907*4882a593Smuzhiyun goto out;
1908*4882a593Smuzhiyun } else {
1909*4882a593Smuzhiyun /*
1910*4882a593Smuzhiyun * Silently drop this PDU and let the
1911*4882a593Smuzhiyun * initiator plug the CmdSN gap.
1912*4882a593Smuzhiyun */
1913*4882a593Smuzhiyun pr_debug("Dropping NOPOUT"
1914*4882a593Smuzhiyun " Command CmdSN: 0x%08x due to"
1915*4882a593Smuzhiyun " DataCRC error.\n", hdr->cmdsn);
1916*4882a593Smuzhiyun ret = 0;
1917*4882a593Smuzhiyun goto out;
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun } else {
1920*4882a593Smuzhiyun pr_debug("Got CRC32C DataDigest"
1921*4882a593Smuzhiyun " 0x%08x for %u bytes of ping data.\n",
1922*4882a593Smuzhiyun checksum, payload_length);
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun ping_data[payload_length] = '\0';
1927*4882a593Smuzhiyun /*
1928*4882a593Smuzhiyun * Attach ping data to struct iscsi_cmd->buf_ptr.
1929*4882a593Smuzhiyun */
1930*4882a593Smuzhiyun cmd->buf_ptr = ping_data;
1931*4882a593Smuzhiyun cmd->buf_ptr_size = payload_length;
1932*4882a593Smuzhiyun
1933*4882a593Smuzhiyun pr_debug("Got %u bytes of NOPOUT ping"
1934*4882a593Smuzhiyun " data.\n", payload_length);
1935*4882a593Smuzhiyun pr_debug("Ping Data: \"%s\"\n", ping_data);
1936*4882a593Smuzhiyun }
1937*4882a593Smuzhiyun
1938*4882a593Smuzhiyun return iscsit_process_nop_out(conn, cmd, hdr);
1939*4882a593Smuzhiyun out:
1940*4882a593Smuzhiyun if (cmd)
1941*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun kfree(ping_data);
1944*4882a593Smuzhiyun return ret;
1945*4882a593Smuzhiyun }
1946*4882a593Smuzhiyun
iscsit_convert_tmf(u8 iscsi_tmf)1947*4882a593Smuzhiyun static enum tcm_tmreq_table iscsit_convert_tmf(u8 iscsi_tmf)
1948*4882a593Smuzhiyun {
1949*4882a593Smuzhiyun switch (iscsi_tmf) {
1950*4882a593Smuzhiyun case ISCSI_TM_FUNC_ABORT_TASK:
1951*4882a593Smuzhiyun return TMR_ABORT_TASK;
1952*4882a593Smuzhiyun case ISCSI_TM_FUNC_ABORT_TASK_SET:
1953*4882a593Smuzhiyun return TMR_ABORT_TASK_SET;
1954*4882a593Smuzhiyun case ISCSI_TM_FUNC_CLEAR_ACA:
1955*4882a593Smuzhiyun return TMR_CLEAR_ACA;
1956*4882a593Smuzhiyun case ISCSI_TM_FUNC_CLEAR_TASK_SET:
1957*4882a593Smuzhiyun return TMR_CLEAR_TASK_SET;
1958*4882a593Smuzhiyun case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
1959*4882a593Smuzhiyun return TMR_LUN_RESET;
1960*4882a593Smuzhiyun case ISCSI_TM_FUNC_TARGET_WARM_RESET:
1961*4882a593Smuzhiyun return TMR_TARGET_WARM_RESET;
1962*4882a593Smuzhiyun case ISCSI_TM_FUNC_TARGET_COLD_RESET:
1963*4882a593Smuzhiyun return TMR_TARGET_COLD_RESET;
1964*4882a593Smuzhiyun default:
1965*4882a593Smuzhiyun return TMR_UNKNOWN;
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun int
iscsit_handle_task_mgt_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)1970*4882a593Smuzhiyun iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
1971*4882a593Smuzhiyun unsigned char *buf)
1972*4882a593Smuzhiyun {
1973*4882a593Smuzhiyun struct se_tmr_req *se_tmr;
1974*4882a593Smuzhiyun struct iscsi_tmr_req *tmr_req;
1975*4882a593Smuzhiyun struct iscsi_tm *hdr;
1976*4882a593Smuzhiyun int out_of_order_cmdsn = 0, ret;
1977*4882a593Smuzhiyun u8 function, tcm_function = TMR_UNKNOWN;
1978*4882a593Smuzhiyun
1979*4882a593Smuzhiyun hdr = (struct iscsi_tm *) buf;
1980*4882a593Smuzhiyun hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
1981*4882a593Smuzhiyun function = hdr->flags;
1982*4882a593Smuzhiyun
1983*4882a593Smuzhiyun pr_debug("Got Task Management Request ITT: 0x%08x, CmdSN:"
1984*4882a593Smuzhiyun " 0x%08x, Function: 0x%02x, RefTaskTag: 0x%08x, RefCmdSN:"
1985*4882a593Smuzhiyun " 0x%08x, CID: %hu\n", hdr->itt, hdr->cmdsn, function,
1986*4882a593Smuzhiyun hdr->rtt, hdr->refcmdsn, conn->cid);
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
1989*4882a593Smuzhiyun ((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
1990*4882a593Smuzhiyun hdr->rtt != RESERVED_ITT)) {
1991*4882a593Smuzhiyun pr_err("RefTaskTag should be set to 0xFFFFFFFF.\n");
1992*4882a593Smuzhiyun hdr->rtt = RESERVED_ITT;
1993*4882a593Smuzhiyun }
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun if ((function == ISCSI_TM_FUNC_TASK_REASSIGN) &&
1996*4882a593Smuzhiyun !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
1997*4882a593Smuzhiyun pr_err("Task Management Request TASK_REASSIGN not"
1998*4882a593Smuzhiyun " issued as immediate command, bad iSCSI Initiator"
1999*4882a593Smuzhiyun "implementation\n");
2000*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
2001*4882a593Smuzhiyun ISCSI_REASON_PROTOCOL_ERROR, buf);
2002*4882a593Smuzhiyun }
2003*4882a593Smuzhiyun if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
2004*4882a593Smuzhiyun be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
2005*4882a593Smuzhiyun hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun cmd->data_direction = DMA_NONE;
2008*4882a593Smuzhiyun cmd->tmr_req = kzalloc(sizeof(*cmd->tmr_req), GFP_KERNEL);
2009*4882a593Smuzhiyun if (!cmd->tmr_req) {
2010*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
2011*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES,
2012*4882a593Smuzhiyun buf);
2013*4882a593Smuzhiyun }
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun transport_init_se_cmd(&cmd->se_cmd, &iscsi_ops,
2016*4882a593Smuzhiyun conn->sess->se_sess, 0, DMA_NONE,
2017*4882a593Smuzhiyun TCM_SIMPLE_TAG, cmd->sense_buffer + 2,
2018*4882a593Smuzhiyun scsilun_to_int(&hdr->lun));
2019*4882a593Smuzhiyun
2020*4882a593Smuzhiyun target_get_sess_cmd(&cmd->se_cmd, true);
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun /*
2023*4882a593Smuzhiyun * TASK_REASSIGN for ERL=2 / connection stays inside of
2024*4882a593Smuzhiyun * LIO-Target $FABRIC_MOD
2025*4882a593Smuzhiyun */
2026*4882a593Smuzhiyun if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
2027*4882a593Smuzhiyun tcm_function = iscsit_convert_tmf(function);
2028*4882a593Smuzhiyun if (tcm_function == TMR_UNKNOWN) {
2029*4882a593Smuzhiyun pr_err("Unknown iSCSI TMR Function:"
2030*4882a593Smuzhiyun " 0x%02x\n", function);
2031*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
2032*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
2033*4882a593Smuzhiyun }
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req, tcm_function,
2036*4882a593Smuzhiyun GFP_KERNEL);
2037*4882a593Smuzhiyun if (ret < 0)
2038*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
2039*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_SCSI_TMFUNC;
2044*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_TASKMGTRSP;
2045*4882a593Smuzhiyun cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
2046*4882a593Smuzhiyun cmd->init_task_tag = hdr->itt;
2047*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
2048*4882a593Smuzhiyun cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
2049*4882a593Smuzhiyun cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
2050*4882a593Smuzhiyun se_tmr = cmd->se_cmd.se_tmr_req;
2051*4882a593Smuzhiyun tmr_req = cmd->tmr_req;
2052*4882a593Smuzhiyun /*
2053*4882a593Smuzhiyun * Locate the struct se_lun for all TMRs not related to ERL=2 TASK_REASSIGN
2054*4882a593Smuzhiyun */
2055*4882a593Smuzhiyun if (function != ISCSI_TM_FUNC_TASK_REASSIGN) {
2056*4882a593Smuzhiyun ret = transport_lookup_tmr_lun(&cmd->se_cmd);
2057*4882a593Smuzhiyun if (ret < 0) {
2058*4882a593Smuzhiyun se_tmr->response = ISCSI_TMF_RSP_NO_LUN;
2059*4882a593Smuzhiyun goto attach;
2060*4882a593Smuzhiyun }
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun
2063*4882a593Smuzhiyun switch (function) {
2064*4882a593Smuzhiyun case ISCSI_TM_FUNC_ABORT_TASK:
2065*4882a593Smuzhiyun se_tmr->response = iscsit_tmr_abort_task(cmd, buf);
2066*4882a593Smuzhiyun if (se_tmr->response)
2067*4882a593Smuzhiyun goto attach;
2068*4882a593Smuzhiyun break;
2069*4882a593Smuzhiyun case ISCSI_TM_FUNC_ABORT_TASK_SET:
2070*4882a593Smuzhiyun case ISCSI_TM_FUNC_CLEAR_ACA:
2071*4882a593Smuzhiyun case ISCSI_TM_FUNC_CLEAR_TASK_SET:
2072*4882a593Smuzhiyun case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET:
2073*4882a593Smuzhiyun break;
2074*4882a593Smuzhiyun case ISCSI_TM_FUNC_TARGET_WARM_RESET:
2075*4882a593Smuzhiyun if (iscsit_tmr_task_warm_reset(conn, tmr_req, buf) < 0) {
2076*4882a593Smuzhiyun se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;
2077*4882a593Smuzhiyun goto attach;
2078*4882a593Smuzhiyun }
2079*4882a593Smuzhiyun break;
2080*4882a593Smuzhiyun case ISCSI_TM_FUNC_TARGET_COLD_RESET:
2081*4882a593Smuzhiyun if (iscsit_tmr_task_cold_reset(conn, tmr_req, buf) < 0) {
2082*4882a593Smuzhiyun se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED;
2083*4882a593Smuzhiyun goto attach;
2084*4882a593Smuzhiyun }
2085*4882a593Smuzhiyun break;
2086*4882a593Smuzhiyun case ISCSI_TM_FUNC_TASK_REASSIGN:
2087*4882a593Smuzhiyun se_tmr->response = iscsit_tmr_task_reassign(cmd, buf);
2088*4882a593Smuzhiyun /*
2089*4882a593Smuzhiyun * Perform sanity checks on the ExpDataSN only if the
2090*4882a593Smuzhiyun * TASK_REASSIGN was successful.
2091*4882a593Smuzhiyun */
2092*4882a593Smuzhiyun if (se_tmr->response)
2093*4882a593Smuzhiyun break;
2094*4882a593Smuzhiyun
2095*4882a593Smuzhiyun if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
2096*4882a593Smuzhiyun return iscsit_add_reject_cmd(cmd,
2097*4882a593Smuzhiyun ISCSI_REASON_BOOKMARK_INVALID, buf);
2098*4882a593Smuzhiyun break;
2099*4882a593Smuzhiyun default:
2100*4882a593Smuzhiyun pr_err("Unknown TMR function: 0x%02x, protocol"
2101*4882a593Smuzhiyun " error.\n", function);
2102*4882a593Smuzhiyun se_tmr->response = ISCSI_TMF_RSP_NOT_SUPPORTED;
2103*4882a593Smuzhiyun goto attach;
2104*4882a593Smuzhiyun }
2105*4882a593Smuzhiyun
2106*4882a593Smuzhiyun if ((function != ISCSI_TM_FUNC_TASK_REASSIGN) &&
2107*4882a593Smuzhiyun (se_tmr->response == ISCSI_TMF_RSP_COMPLETE))
2108*4882a593Smuzhiyun se_tmr->call_transport = 1;
2109*4882a593Smuzhiyun attach:
2110*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
2111*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
2112*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
2113*4882a593Smuzhiyun
2114*4882a593Smuzhiyun if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
2115*4882a593Smuzhiyun int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
2116*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) {
2117*4882a593Smuzhiyun out_of_order_cmdsn = 1;
2118*4882a593Smuzhiyun } else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
2119*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
2120*4882a593Smuzhiyun return 0;
2121*4882a593Smuzhiyun } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
2122*4882a593Smuzhiyun return -1;
2123*4882a593Smuzhiyun }
2124*4882a593Smuzhiyun }
2125*4882a593Smuzhiyun iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
2126*4882a593Smuzhiyun
2127*4882a593Smuzhiyun if (out_of_order_cmdsn || !(hdr->opcode & ISCSI_OP_IMMEDIATE))
2128*4882a593Smuzhiyun return 0;
2129*4882a593Smuzhiyun /*
2130*4882a593Smuzhiyun * Found the referenced task, send to transport for processing.
2131*4882a593Smuzhiyun */
2132*4882a593Smuzhiyun if (se_tmr->call_transport)
2133*4882a593Smuzhiyun return transport_generic_handle_tmr(&cmd->se_cmd);
2134*4882a593Smuzhiyun
2135*4882a593Smuzhiyun /*
2136*4882a593Smuzhiyun * Could not find the referenced LUN, task, or Task Management
2137*4882a593Smuzhiyun * command not authorized or supported. Change state and
2138*4882a593Smuzhiyun * let the tx_thread send the response.
2139*4882a593Smuzhiyun *
2140*4882a593Smuzhiyun * For connection recovery, this is also the default action for
2141*4882a593Smuzhiyun * TMR TASK_REASSIGN.
2142*4882a593Smuzhiyun */
2143*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2144*4882a593Smuzhiyun target_put_sess_cmd(&cmd->se_cmd);
2145*4882a593Smuzhiyun return 0;
2146*4882a593Smuzhiyun }
2147*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
2148*4882a593Smuzhiyun
2149*4882a593Smuzhiyun /* #warning FIXME: Support Text Command parameters besides SendTargets */
2150*4882a593Smuzhiyun int
iscsit_setup_text_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_text * hdr)2151*4882a593Smuzhiyun iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
2152*4882a593Smuzhiyun struct iscsi_text *hdr)
2153*4882a593Smuzhiyun {
2154*4882a593Smuzhiyun u32 payload_length = ntoh24(hdr->dlength);
2155*4882a593Smuzhiyun
2156*4882a593Smuzhiyun if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
2157*4882a593Smuzhiyun pr_err("Unable to accept text parameter length: %u"
2158*4882a593Smuzhiyun "greater than MaxXmitDataSegmentLength %u.\n",
2159*4882a593Smuzhiyun payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
2160*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
2161*4882a593Smuzhiyun (unsigned char *)hdr);
2162*4882a593Smuzhiyun }
2163*4882a593Smuzhiyun
2164*4882a593Smuzhiyun if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL) ||
2165*4882a593Smuzhiyun (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)) {
2166*4882a593Smuzhiyun pr_err("Multi sequence text commands currently not supported\n");
2167*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_CMD_NOT_SUPPORTED,
2168*4882a593Smuzhiyun (unsigned char *)hdr);
2169*4882a593Smuzhiyun }
2170*4882a593Smuzhiyun
2171*4882a593Smuzhiyun pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
2172*4882a593Smuzhiyun " ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,
2173*4882a593Smuzhiyun hdr->exp_statsn, payload_length);
2174*4882a593Smuzhiyun
2175*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_TEXT;
2176*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_TEXTRSP;
2177*4882a593Smuzhiyun cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
2178*4882a593Smuzhiyun conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
2179*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
2180*4882a593Smuzhiyun cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
2181*4882a593Smuzhiyun cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
2182*4882a593Smuzhiyun cmd->data_direction = DMA_NONE;
2183*4882a593Smuzhiyun kfree(cmd->text_in_ptr);
2184*4882a593Smuzhiyun cmd->text_in_ptr = NULL;
2185*4882a593Smuzhiyun
2186*4882a593Smuzhiyun return 0;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_setup_text_cmd);
2189*4882a593Smuzhiyun
2190*4882a593Smuzhiyun int
iscsit_process_text_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,struct iscsi_text * hdr)2191*4882a593Smuzhiyun iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
2192*4882a593Smuzhiyun struct iscsi_text *hdr)
2193*4882a593Smuzhiyun {
2194*4882a593Smuzhiyun unsigned char *text_in = cmd->text_in_ptr, *text_ptr;
2195*4882a593Smuzhiyun int cmdsn_ret;
2196*4882a593Smuzhiyun
2197*4882a593Smuzhiyun if (!text_in) {
2198*4882a593Smuzhiyun cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt);
2199*4882a593Smuzhiyun if (cmd->targ_xfer_tag == 0xFFFFFFFF) {
2200*4882a593Smuzhiyun pr_err("Unable to locate text_in buffer for sendtargets"
2201*4882a593Smuzhiyun " discovery\n");
2202*4882a593Smuzhiyun goto reject;
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun goto empty_sendtargets;
2205*4882a593Smuzhiyun }
2206*4882a593Smuzhiyun if (strncmp("SendTargets=", text_in, 12) != 0) {
2207*4882a593Smuzhiyun pr_err("Received Text Data that is not"
2208*4882a593Smuzhiyun " SendTargets, cannot continue.\n");
2209*4882a593Smuzhiyun goto reject;
2210*4882a593Smuzhiyun }
2211*4882a593Smuzhiyun /* '=' confirmed in strncmp */
2212*4882a593Smuzhiyun text_ptr = strchr(text_in, '=');
2213*4882a593Smuzhiyun BUG_ON(!text_ptr);
2214*4882a593Smuzhiyun if (!strncmp("=All", text_ptr, 5)) {
2215*4882a593Smuzhiyun cmd->cmd_flags |= ICF_SENDTARGETS_ALL;
2216*4882a593Smuzhiyun } else if (!strncmp("=iqn.", text_ptr, 5) ||
2217*4882a593Smuzhiyun !strncmp("=eui.", text_ptr, 5)) {
2218*4882a593Smuzhiyun cmd->cmd_flags |= ICF_SENDTARGETS_SINGLE;
2219*4882a593Smuzhiyun } else {
2220*4882a593Smuzhiyun pr_err("Unable to locate valid SendTargets%s value\n",
2221*4882a593Smuzhiyun text_ptr);
2222*4882a593Smuzhiyun goto reject;
2223*4882a593Smuzhiyun }
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
2226*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
2227*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
2228*4882a593Smuzhiyun
2229*4882a593Smuzhiyun empty_sendtargets:
2230*4882a593Smuzhiyun iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
2231*4882a593Smuzhiyun
2232*4882a593Smuzhiyun if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
2233*4882a593Smuzhiyun cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
2234*4882a593Smuzhiyun (unsigned char *)hdr, hdr->cmdsn);
2235*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
2236*4882a593Smuzhiyun return -1;
2237*4882a593Smuzhiyun
2238*4882a593Smuzhiyun return 0;
2239*4882a593Smuzhiyun }
2240*4882a593Smuzhiyun
2241*4882a593Smuzhiyun return iscsit_execute_cmd(cmd, 0);
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun reject:
2244*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
2245*4882a593Smuzhiyun (unsigned char *)hdr);
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_process_text_cmd);
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun static int
iscsit_handle_text_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)2250*4882a593Smuzhiyun iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
2251*4882a593Smuzhiyun unsigned char *buf)
2252*4882a593Smuzhiyun {
2253*4882a593Smuzhiyun struct iscsi_text *hdr = (struct iscsi_text *)buf;
2254*4882a593Smuzhiyun char *text_in = NULL;
2255*4882a593Smuzhiyun u32 payload_length = ntoh24(hdr->dlength);
2256*4882a593Smuzhiyun int rx_size, rc;
2257*4882a593Smuzhiyun
2258*4882a593Smuzhiyun rc = iscsit_setup_text_cmd(conn, cmd, hdr);
2259*4882a593Smuzhiyun if (rc < 0)
2260*4882a593Smuzhiyun return 0;
2261*4882a593Smuzhiyun
2262*4882a593Smuzhiyun rx_size = payload_length;
2263*4882a593Smuzhiyun if (payload_length) {
2264*4882a593Smuzhiyun u32 checksum = 0, data_crc = 0;
2265*4882a593Smuzhiyun u32 padding = 0;
2266*4882a593Smuzhiyun int niov = 0, rx_got;
2267*4882a593Smuzhiyun struct kvec iov[2];
2268*4882a593Smuzhiyun
2269*4882a593Smuzhiyun rx_size = ALIGN(payload_length, 4);
2270*4882a593Smuzhiyun text_in = kzalloc(rx_size, GFP_KERNEL);
2271*4882a593Smuzhiyun if (!text_in)
2272*4882a593Smuzhiyun goto reject;
2273*4882a593Smuzhiyun
2274*4882a593Smuzhiyun cmd->text_in_ptr = text_in;
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun memset(iov, 0, sizeof(iov));
2277*4882a593Smuzhiyun iov[niov].iov_base = text_in;
2278*4882a593Smuzhiyun iov[niov++].iov_len = rx_size;
2279*4882a593Smuzhiyun
2280*4882a593Smuzhiyun padding = rx_size - payload_length;
2281*4882a593Smuzhiyun if (padding)
2282*4882a593Smuzhiyun pr_debug("Receiving %u additional bytes"
2283*4882a593Smuzhiyun " for padding.\n", padding);
2284*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
2285*4882a593Smuzhiyun iov[niov].iov_base = &checksum;
2286*4882a593Smuzhiyun iov[niov++].iov_len = ISCSI_CRC_LEN;
2287*4882a593Smuzhiyun rx_size += ISCSI_CRC_LEN;
2288*4882a593Smuzhiyun }
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun WARN_ON_ONCE(niov > ARRAY_SIZE(iov));
2291*4882a593Smuzhiyun rx_got = rx_data(conn, &iov[0], niov, rx_size);
2292*4882a593Smuzhiyun if (rx_got != rx_size)
2293*4882a593Smuzhiyun goto reject;
2294*4882a593Smuzhiyun
2295*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
2296*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
2297*4882a593Smuzhiyun text_in, rx_size, 0, NULL,
2298*4882a593Smuzhiyun &data_crc);
2299*4882a593Smuzhiyun
2300*4882a593Smuzhiyun if (checksum != data_crc) {
2301*4882a593Smuzhiyun pr_err("Text data CRC32C DataDigest"
2302*4882a593Smuzhiyun " 0x%08x does not match computed"
2303*4882a593Smuzhiyun " 0x%08x\n", checksum, data_crc);
2304*4882a593Smuzhiyun if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
2305*4882a593Smuzhiyun pr_err("Unable to recover from"
2306*4882a593Smuzhiyun " Text Data digest failure while in"
2307*4882a593Smuzhiyun " ERL=0.\n");
2308*4882a593Smuzhiyun goto reject;
2309*4882a593Smuzhiyun } else {
2310*4882a593Smuzhiyun /*
2311*4882a593Smuzhiyun * Silently drop this PDU and let the
2312*4882a593Smuzhiyun * initiator plug the CmdSN gap.
2313*4882a593Smuzhiyun */
2314*4882a593Smuzhiyun pr_debug("Dropping Text"
2315*4882a593Smuzhiyun " Command CmdSN: 0x%08x due to"
2316*4882a593Smuzhiyun " DataCRC error.\n", hdr->cmdsn);
2317*4882a593Smuzhiyun kfree(text_in);
2318*4882a593Smuzhiyun return 0;
2319*4882a593Smuzhiyun }
2320*4882a593Smuzhiyun } else {
2321*4882a593Smuzhiyun pr_debug("Got CRC32C DataDigest"
2322*4882a593Smuzhiyun " 0x%08x for %u bytes of text data.\n",
2323*4882a593Smuzhiyun checksum, payload_length);
2324*4882a593Smuzhiyun }
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun text_in[payload_length - 1] = '\0';
2327*4882a593Smuzhiyun pr_debug("Successfully read %d bytes of text"
2328*4882a593Smuzhiyun " data.\n", payload_length);
2329*4882a593Smuzhiyun }
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun return iscsit_process_text_cmd(conn, cmd, hdr);
2332*4882a593Smuzhiyun
2333*4882a593Smuzhiyun reject:
2334*4882a593Smuzhiyun kfree(cmd->text_in_ptr);
2335*4882a593Smuzhiyun cmd->text_in_ptr = NULL;
2336*4882a593Smuzhiyun return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
2337*4882a593Smuzhiyun }
2338*4882a593Smuzhiyun
iscsit_logout_closesession(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2339*4882a593Smuzhiyun int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
2340*4882a593Smuzhiyun {
2341*4882a593Smuzhiyun struct iscsi_conn *conn_p;
2342*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
2343*4882a593Smuzhiyun
2344*4882a593Smuzhiyun pr_debug("Received logout request CLOSESESSION on CID: %hu"
2345*4882a593Smuzhiyun " for SID: %u.\n", conn->cid, conn->sess->sid);
2346*4882a593Smuzhiyun
2347*4882a593Smuzhiyun atomic_set(&sess->session_logout, 1);
2348*4882a593Smuzhiyun atomic_set(&conn->conn_logout_remove, 1);
2349*4882a593Smuzhiyun conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_SESSION;
2350*4882a593Smuzhiyun
2351*4882a593Smuzhiyun iscsit_inc_conn_usage_count(conn);
2352*4882a593Smuzhiyun iscsit_inc_session_usage_count(sess);
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
2355*4882a593Smuzhiyun list_for_each_entry(conn_p, &sess->sess_conn_list, conn_list) {
2356*4882a593Smuzhiyun if (conn_p->conn_state != TARG_CONN_STATE_LOGGED_IN)
2357*4882a593Smuzhiyun continue;
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
2360*4882a593Smuzhiyun conn_p->conn_state = TARG_CONN_STATE_IN_LOGOUT;
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
2363*4882a593Smuzhiyun
2364*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2365*4882a593Smuzhiyun
2366*4882a593Smuzhiyun return 0;
2367*4882a593Smuzhiyun }
2368*4882a593Smuzhiyun
iscsit_logout_closeconnection(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2369*4882a593Smuzhiyun int iscsit_logout_closeconnection(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
2370*4882a593Smuzhiyun {
2371*4882a593Smuzhiyun struct iscsi_conn *l_conn;
2372*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
2373*4882a593Smuzhiyun
2374*4882a593Smuzhiyun pr_debug("Received logout request CLOSECONNECTION for CID:"
2375*4882a593Smuzhiyun " %hu on CID: %hu.\n", cmd->logout_cid, conn->cid);
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun /*
2378*4882a593Smuzhiyun * A Logout Request with a CLOSECONNECTION reason code for a CID
2379*4882a593Smuzhiyun * can arrive on a connection with a differing CID.
2380*4882a593Smuzhiyun */
2381*4882a593Smuzhiyun if (conn->cid == cmd->logout_cid) {
2382*4882a593Smuzhiyun spin_lock_bh(&conn->state_lock);
2383*4882a593Smuzhiyun pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
2384*4882a593Smuzhiyun conn->conn_state = TARG_CONN_STATE_IN_LOGOUT;
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun atomic_set(&conn->conn_logout_remove, 1);
2387*4882a593Smuzhiyun conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_CONNECTION;
2388*4882a593Smuzhiyun iscsit_inc_conn_usage_count(conn);
2389*4882a593Smuzhiyun
2390*4882a593Smuzhiyun spin_unlock_bh(&conn->state_lock);
2391*4882a593Smuzhiyun } else {
2392*4882a593Smuzhiyun /*
2393*4882a593Smuzhiyun * Handle all different cid CLOSECONNECTION requests in
2394*4882a593Smuzhiyun * iscsit_logout_post_handler_diffcid() as to give enough
2395*4882a593Smuzhiyun * time for any non immediate command's CmdSN to be
2396*4882a593Smuzhiyun * acknowledged on the connection in question.
2397*4882a593Smuzhiyun *
2398*4882a593Smuzhiyun * Here we simply make sure the CID is still around.
2399*4882a593Smuzhiyun */
2400*4882a593Smuzhiyun l_conn = iscsit_get_conn_from_cid(sess,
2401*4882a593Smuzhiyun cmd->logout_cid);
2402*4882a593Smuzhiyun if (!l_conn) {
2403*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND;
2404*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn,
2405*4882a593Smuzhiyun cmd->i_state);
2406*4882a593Smuzhiyun return 0;
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun
2409*4882a593Smuzhiyun iscsit_dec_conn_usage_count(l_conn);
2410*4882a593Smuzhiyun }
2411*4882a593Smuzhiyun
2412*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2413*4882a593Smuzhiyun
2414*4882a593Smuzhiyun return 0;
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun
iscsit_logout_removeconnforrecovery(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2417*4882a593Smuzhiyun int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
2418*4882a593Smuzhiyun {
2419*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
2420*4882a593Smuzhiyun
2421*4882a593Smuzhiyun pr_debug("Received explicit REMOVECONNFORRECOVERY logout for"
2422*4882a593Smuzhiyun " CID: %hu on CID: %hu.\n", cmd->logout_cid, conn->cid);
2423*4882a593Smuzhiyun
2424*4882a593Smuzhiyun if (sess->sess_ops->ErrorRecoveryLevel != 2) {
2425*4882a593Smuzhiyun pr_err("Received Logout Request REMOVECONNFORRECOVERY"
2426*4882a593Smuzhiyun " while ERL!=2.\n");
2427*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_RECOVERY_UNSUPPORTED;
2428*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2429*4882a593Smuzhiyun return 0;
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun if (conn->cid == cmd->logout_cid) {
2433*4882a593Smuzhiyun pr_err("Received Logout Request REMOVECONNFORRECOVERY"
2434*4882a593Smuzhiyun " with CID: %hu on CID: %hu, implementation error.\n",
2435*4882a593Smuzhiyun cmd->logout_cid, conn->cid);
2436*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_CLEANUP_FAILED;
2437*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2438*4882a593Smuzhiyun return 0;
2439*4882a593Smuzhiyun }
2440*4882a593Smuzhiyun
2441*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
2442*4882a593Smuzhiyun
2443*4882a593Smuzhiyun return 0;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun
2446*4882a593Smuzhiyun int
iscsit_handle_logout_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,unsigned char * buf)2447*4882a593Smuzhiyun iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
2448*4882a593Smuzhiyun unsigned char *buf)
2449*4882a593Smuzhiyun {
2450*4882a593Smuzhiyun int cmdsn_ret, logout_remove = 0;
2451*4882a593Smuzhiyun u8 reason_code = 0;
2452*4882a593Smuzhiyun struct iscsi_logout *hdr;
2453*4882a593Smuzhiyun struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn);
2454*4882a593Smuzhiyun
2455*4882a593Smuzhiyun hdr = (struct iscsi_logout *) buf;
2456*4882a593Smuzhiyun reason_code = (hdr->flags & 0x7f);
2457*4882a593Smuzhiyun
2458*4882a593Smuzhiyun if (tiqn) {
2459*4882a593Smuzhiyun spin_lock(&tiqn->logout_stats.lock);
2460*4882a593Smuzhiyun if (reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION)
2461*4882a593Smuzhiyun tiqn->logout_stats.normal_logouts++;
2462*4882a593Smuzhiyun else
2463*4882a593Smuzhiyun tiqn->logout_stats.abnormal_logouts++;
2464*4882a593Smuzhiyun spin_unlock(&tiqn->logout_stats.lock);
2465*4882a593Smuzhiyun }
2466*4882a593Smuzhiyun
2467*4882a593Smuzhiyun pr_debug("Got Logout Request ITT: 0x%08x CmdSN: 0x%08x"
2468*4882a593Smuzhiyun " ExpStatSN: 0x%08x Reason: 0x%02x CID: %hu on CID: %hu\n",
2469*4882a593Smuzhiyun hdr->itt, hdr->cmdsn, hdr->exp_statsn, reason_code,
2470*4882a593Smuzhiyun hdr->cid, conn->cid);
2471*4882a593Smuzhiyun
2472*4882a593Smuzhiyun if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
2473*4882a593Smuzhiyun pr_err("Received logout request on connection that"
2474*4882a593Smuzhiyun " is not in logged in state, ignoring request.\n");
2475*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
2476*4882a593Smuzhiyun return 0;
2477*4882a593Smuzhiyun }
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_LOGOUT;
2480*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_LOGOUTRSP;
2481*4882a593Smuzhiyun cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
2482*4882a593Smuzhiyun conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
2483*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
2484*4882a593Smuzhiyun cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
2485*4882a593Smuzhiyun cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
2486*4882a593Smuzhiyun cmd->logout_cid = be16_to_cpu(hdr->cid);
2487*4882a593Smuzhiyun cmd->logout_reason = reason_code;
2488*4882a593Smuzhiyun cmd->data_direction = DMA_NONE;
2489*4882a593Smuzhiyun
2490*4882a593Smuzhiyun /*
2491*4882a593Smuzhiyun * We need to sleep in these cases (by returning 1) until the Logout
2492*4882a593Smuzhiyun * Response gets sent in the tx thread.
2493*4882a593Smuzhiyun */
2494*4882a593Smuzhiyun if ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) ||
2495*4882a593Smuzhiyun ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) &&
2496*4882a593Smuzhiyun be16_to_cpu(hdr->cid) == conn->cid))
2497*4882a593Smuzhiyun logout_remove = 1;
2498*4882a593Smuzhiyun
2499*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
2500*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
2501*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
2502*4882a593Smuzhiyun
2503*4882a593Smuzhiyun if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY)
2504*4882a593Smuzhiyun iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun /*
2507*4882a593Smuzhiyun * Immediate commands are executed, well, immediately.
2508*4882a593Smuzhiyun * Non-Immediate Logout Commands are executed in CmdSN order.
2509*4882a593Smuzhiyun */
2510*4882a593Smuzhiyun if (cmd->immediate_cmd) {
2511*4882a593Smuzhiyun int ret = iscsit_execute_cmd(cmd, 0);
2512*4882a593Smuzhiyun
2513*4882a593Smuzhiyun if (ret < 0)
2514*4882a593Smuzhiyun return ret;
2515*4882a593Smuzhiyun } else {
2516*4882a593Smuzhiyun cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
2517*4882a593Smuzhiyun if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
2518*4882a593Smuzhiyun logout_remove = 0;
2519*4882a593Smuzhiyun else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
2520*4882a593Smuzhiyun return -1;
2521*4882a593Smuzhiyun }
2522*4882a593Smuzhiyun
2523*4882a593Smuzhiyun return logout_remove;
2524*4882a593Smuzhiyun }
2525*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_handle_logout_cmd);
2526*4882a593Smuzhiyun
iscsit_handle_snack(struct iscsi_conn * conn,unsigned char * buf)2527*4882a593Smuzhiyun int iscsit_handle_snack(
2528*4882a593Smuzhiyun struct iscsi_conn *conn,
2529*4882a593Smuzhiyun unsigned char *buf)
2530*4882a593Smuzhiyun {
2531*4882a593Smuzhiyun struct iscsi_snack *hdr;
2532*4882a593Smuzhiyun
2533*4882a593Smuzhiyun hdr = (struct iscsi_snack *) buf;
2534*4882a593Smuzhiyun hdr->flags &= ~ISCSI_FLAG_CMD_FINAL;
2535*4882a593Smuzhiyun
2536*4882a593Smuzhiyun pr_debug("Got ISCSI_INIT_SNACK, ITT: 0x%08x, ExpStatSN:"
2537*4882a593Smuzhiyun " 0x%08x, Type: 0x%02x, BegRun: 0x%08x, RunLength: 0x%08x,"
2538*4882a593Smuzhiyun " CID: %hu\n", hdr->itt, hdr->exp_statsn, hdr->flags,
2539*4882a593Smuzhiyun hdr->begrun, hdr->runlength, conn->cid);
2540*4882a593Smuzhiyun
2541*4882a593Smuzhiyun if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
2542*4882a593Smuzhiyun pr_err("Initiator sent SNACK request while in"
2543*4882a593Smuzhiyun " ErrorRecoveryLevel=0.\n");
2544*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
2545*4882a593Smuzhiyun buf);
2546*4882a593Smuzhiyun }
2547*4882a593Smuzhiyun /*
2548*4882a593Smuzhiyun * SNACK_DATA and SNACK_R2T are both 0, so check which function to
2549*4882a593Smuzhiyun * call from inside iscsi_send_recovery_datain_or_r2t().
2550*4882a593Smuzhiyun */
2551*4882a593Smuzhiyun switch (hdr->flags & ISCSI_FLAG_SNACK_TYPE_MASK) {
2552*4882a593Smuzhiyun case 0:
2553*4882a593Smuzhiyun return iscsit_handle_recovery_datain_or_r2t(conn, buf,
2554*4882a593Smuzhiyun hdr->itt,
2555*4882a593Smuzhiyun be32_to_cpu(hdr->ttt),
2556*4882a593Smuzhiyun be32_to_cpu(hdr->begrun),
2557*4882a593Smuzhiyun be32_to_cpu(hdr->runlength));
2558*4882a593Smuzhiyun case ISCSI_FLAG_SNACK_TYPE_STATUS:
2559*4882a593Smuzhiyun return iscsit_handle_status_snack(conn, hdr->itt,
2560*4882a593Smuzhiyun be32_to_cpu(hdr->ttt),
2561*4882a593Smuzhiyun be32_to_cpu(hdr->begrun), be32_to_cpu(hdr->runlength));
2562*4882a593Smuzhiyun case ISCSI_FLAG_SNACK_TYPE_DATA_ACK:
2563*4882a593Smuzhiyun return iscsit_handle_data_ack(conn, be32_to_cpu(hdr->ttt),
2564*4882a593Smuzhiyun be32_to_cpu(hdr->begrun),
2565*4882a593Smuzhiyun be32_to_cpu(hdr->runlength));
2566*4882a593Smuzhiyun case ISCSI_FLAG_SNACK_TYPE_RDATA:
2567*4882a593Smuzhiyun /* FIXME: Support R-Data SNACK */
2568*4882a593Smuzhiyun pr_err("R-Data SNACK Not Supported.\n");
2569*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
2570*4882a593Smuzhiyun buf);
2571*4882a593Smuzhiyun default:
2572*4882a593Smuzhiyun pr_err("Unknown SNACK type 0x%02x, protocol"
2573*4882a593Smuzhiyun " error.\n", hdr->flags & 0x0f);
2574*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
2575*4882a593Smuzhiyun buf);
2576*4882a593Smuzhiyun }
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun return 0;
2579*4882a593Smuzhiyun }
2580*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_handle_snack);
2581*4882a593Smuzhiyun
iscsit_rx_thread_wait_for_tcp(struct iscsi_conn * conn)2582*4882a593Smuzhiyun static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
2585*4882a593Smuzhiyun (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
2586*4882a593Smuzhiyun wait_for_completion_interruptible_timeout(
2587*4882a593Smuzhiyun &conn->rx_half_close_comp,
2588*4882a593Smuzhiyun ISCSI_RX_THREAD_TCP_TIMEOUT * HZ);
2589*4882a593Smuzhiyun }
2590*4882a593Smuzhiyun }
2591*4882a593Smuzhiyun
iscsit_handle_immediate_data(struct iscsi_cmd * cmd,struct iscsi_scsi_req * hdr,u32 length)2592*4882a593Smuzhiyun static int iscsit_handle_immediate_data(
2593*4882a593Smuzhiyun struct iscsi_cmd *cmd,
2594*4882a593Smuzhiyun struct iscsi_scsi_req *hdr,
2595*4882a593Smuzhiyun u32 length)
2596*4882a593Smuzhiyun {
2597*4882a593Smuzhiyun int iov_ret, rx_got = 0, rx_size = 0;
2598*4882a593Smuzhiyun u32 checksum, iov_count = 0, padding = 0;
2599*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
2600*4882a593Smuzhiyun struct kvec *iov;
2601*4882a593Smuzhiyun void *overflow_buf = NULL;
2602*4882a593Smuzhiyun
2603*4882a593Smuzhiyun BUG_ON(cmd->write_data_done > cmd->se_cmd.data_length);
2604*4882a593Smuzhiyun rx_size = min(cmd->se_cmd.data_length - cmd->write_data_done, length);
2605*4882a593Smuzhiyun iov_ret = iscsit_map_iovec(cmd, cmd->iov_data,
2606*4882a593Smuzhiyun cmd->orig_iov_data_count - 2,
2607*4882a593Smuzhiyun cmd->write_data_done, rx_size);
2608*4882a593Smuzhiyun if (iov_ret < 0)
2609*4882a593Smuzhiyun return IMMEDIATE_DATA_CANNOT_RECOVER;
2610*4882a593Smuzhiyun
2611*4882a593Smuzhiyun iov_count = iov_ret;
2612*4882a593Smuzhiyun iov = &cmd->iov_data[0];
2613*4882a593Smuzhiyun if (rx_size < length) {
2614*4882a593Smuzhiyun /*
2615*4882a593Smuzhiyun * Special case: length of immediate data exceeds the data
2616*4882a593Smuzhiyun * buffer size derived from the CDB.
2617*4882a593Smuzhiyun */
2618*4882a593Smuzhiyun overflow_buf = kmalloc(length - rx_size, GFP_KERNEL);
2619*4882a593Smuzhiyun if (!overflow_buf) {
2620*4882a593Smuzhiyun iscsit_unmap_iovec(cmd);
2621*4882a593Smuzhiyun return IMMEDIATE_DATA_CANNOT_RECOVER;
2622*4882a593Smuzhiyun }
2623*4882a593Smuzhiyun cmd->overflow_buf = overflow_buf;
2624*4882a593Smuzhiyun iov[iov_count].iov_base = overflow_buf;
2625*4882a593Smuzhiyun iov[iov_count].iov_len = length - rx_size;
2626*4882a593Smuzhiyun iov_count++;
2627*4882a593Smuzhiyun rx_size = length;
2628*4882a593Smuzhiyun }
2629*4882a593Smuzhiyun
2630*4882a593Smuzhiyun padding = ((-length) & 3);
2631*4882a593Smuzhiyun if (padding != 0) {
2632*4882a593Smuzhiyun iov[iov_count].iov_base = cmd->pad_bytes;
2633*4882a593Smuzhiyun iov[iov_count++].iov_len = padding;
2634*4882a593Smuzhiyun rx_size += padding;
2635*4882a593Smuzhiyun }
2636*4882a593Smuzhiyun
2637*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
2638*4882a593Smuzhiyun iov[iov_count].iov_base = &checksum;
2639*4882a593Smuzhiyun iov[iov_count++].iov_len = ISCSI_CRC_LEN;
2640*4882a593Smuzhiyun rx_size += ISCSI_CRC_LEN;
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun
2643*4882a593Smuzhiyun WARN_ON_ONCE(iov_count > cmd->orig_iov_data_count);
2644*4882a593Smuzhiyun rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size);
2645*4882a593Smuzhiyun
2646*4882a593Smuzhiyun iscsit_unmap_iovec(cmd);
2647*4882a593Smuzhiyun
2648*4882a593Smuzhiyun if (rx_got != rx_size) {
2649*4882a593Smuzhiyun iscsit_rx_thread_wait_for_tcp(conn);
2650*4882a593Smuzhiyun return IMMEDIATE_DATA_CANNOT_RECOVER;
2651*4882a593Smuzhiyun }
2652*4882a593Smuzhiyun
2653*4882a593Smuzhiyun if (conn->conn_ops->DataDigest) {
2654*4882a593Smuzhiyun u32 data_crc;
2655*4882a593Smuzhiyun
2656*4882a593Smuzhiyun data_crc = iscsit_do_crypto_hash_sg(conn->conn_rx_hash, cmd,
2657*4882a593Smuzhiyun cmd->write_data_done, length, padding,
2658*4882a593Smuzhiyun cmd->pad_bytes);
2659*4882a593Smuzhiyun
2660*4882a593Smuzhiyun if (checksum != data_crc) {
2661*4882a593Smuzhiyun pr_err("ImmediateData CRC32C DataDigest 0x%08x"
2662*4882a593Smuzhiyun " does not match computed 0x%08x\n", checksum,
2663*4882a593Smuzhiyun data_crc);
2664*4882a593Smuzhiyun
2665*4882a593Smuzhiyun if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
2666*4882a593Smuzhiyun pr_err("Unable to recover from"
2667*4882a593Smuzhiyun " Immediate Data digest failure while"
2668*4882a593Smuzhiyun " in ERL=0.\n");
2669*4882a593Smuzhiyun iscsit_reject_cmd(cmd,
2670*4882a593Smuzhiyun ISCSI_REASON_DATA_DIGEST_ERROR,
2671*4882a593Smuzhiyun (unsigned char *)hdr);
2672*4882a593Smuzhiyun return IMMEDIATE_DATA_CANNOT_RECOVER;
2673*4882a593Smuzhiyun } else {
2674*4882a593Smuzhiyun iscsit_reject_cmd(cmd,
2675*4882a593Smuzhiyun ISCSI_REASON_DATA_DIGEST_ERROR,
2676*4882a593Smuzhiyun (unsigned char *)hdr);
2677*4882a593Smuzhiyun return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
2678*4882a593Smuzhiyun }
2679*4882a593Smuzhiyun } else {
2680*4882a593Smuzhiyun pr_debug("Got CRC32C DataDigest 0x%08x for"
2681*4882a593Smuzhiyun " %u bytes of Immediate Data\n", checksum,
2682*4882a593Smuzhiyun length);
2683*4882a593Smuzhiyun }
2684*4882a593Smuzhiyun }
2685*4882a593Smuzhiyun
2686*4882a593Smuzhiyun cmd->write_data_done += length;
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun if (cmd->write_data_done == cmd->se_cmd.data_length) {
2689*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
2690*4882a593Smuzhiyun cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
2691*4882a593Smuzhiyun cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
2692*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
2693*4882a593Smuzhiyun }
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun return IMMEDIATE_DATA_NORMAL_OPERATION;
2696*4882a593Smuzhiyun }
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun /* #warning iscsi_build_conn_drop_async_message() only sends out on connections
2699*4882a593Smuzhiyun with active network interface */
iscsit_build_conn_drop_async_message(struct iscsi_conn * conn)2700*4882a593Smuzhiyun static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
2701*4882a593Smuzhiyun {
2702*4882a593Smuzhiyun struct iscsi_cmd *cmd;
2703*4882a593Smuzhiyun struct iscsi_conn *conn_p;
2704*4882a593Smuzhiyun bool found = false;
2705*4882a593Smuzhiyun
2706*4882a593Smuzhiyun lockdep_assert_held(&conn->sess->conn_lock);
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun /*
2709*4882a593Smuzhiyun * Only send a Asynchronous Message on connections whos network
2710*4882a593Smuzhiyun * interface is still functional.
2711*4882a593Smuzhiyun */
2712*4882a593Smuzhiyun list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) {
2713*4882a593Smuzhiyun if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) {
2714*4882a593Smuzhiyun iscsit_inc_conn_usage_count(conn_p);
2715*4882a593Smuzhiyun found = true;
2716*4882a593Smuzhiyun break;
2717*4882a593Smuzhiyun }
2718*4882a593Smuzhiyun }
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun if (!found)
2721*4882a593Smuzhiyun return;
2722*4882a593Smuzhiyun
2723*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn_p, TASK_RUNNING);
2724*4882a593Smuzhiyun if (!cmd) {
2725*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn_p);
2726*4882a593Smuzhiyun return;
2727*4882a593Smuzhiyun }
2728*4882a593Smuzhiyun
2729*4882a593Smuzhiyun cmd->logout_cid = conn->cid;
2730*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
2731*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_ASYNCMSG;
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun spin_lock_bh(&conn_p->cmd_lock);
2734*4882a593Smuzhiyun list_add_tail(&cmd->i_conn_node, &conn_p->conn_cmd_list);
2735*4882a593Smuzhiyun spin_unlock_bh(&conn_p->cmd_lock);
2736*4882a593Smuzhiyun
2737*4882a593Smuzhiyun iscsit_add_cmd_to_response_queue(cmd, conn_p, cmd->i_state);
2738*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn_p);
2739*4882a593Smuzhiyun }
2740*4882a593Smuzhiyun
iscsit_send_conn_drop_async_message(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2741*4882a593Smuzhiyun static int iscsit_send_conn_drop_async_message(
2742*4882a593Smuzhiyun struct iscsi_cmd *cmd,
2743*4882a593Smuzhiyun struct iscsi_conn *conn)
2744*4882a593Smuzhiyun {
2745*4882a593Smuzhiyun struct iscsi_async *hdr;
2746*4882a593Smuzhiyun
2747*4882a593Smuzhiyun cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT;
2748*4882a593Smuzhiyun
2749*4882a593Smuzhiyun hdr = (struct iscsi_async *) cmd->pdu;
2750*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_ASYNC_EVENT;
2751*4882a593Smuzhiyun hdr->flags = ISCSI_FLAG_CMD_FINAL;
2752*4882a593Smuzhiyun cmd->init_task_tag = RESERVED_ITT;
2753*4882a593Smuzhiyun cmd->targ_xfer_tag = 0xFFFFFFFF;
2754*4882a593Smuzhiyun put_unaligned_be64(0xFFFFFFFFFFFFFFFFULL, &hdr->rsvd4[0]);
2755*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
2756*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
2757*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
2758*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
2759*4882a593Smuzhiyun hdr->async_event = ISCSI_ASYNC_MSG_DROPPING_CONNECTION;
2760*4882a593Smuzhiyun hdr->param1 = cpu_to_be16(cmd->logout_cid);
2761*4882a593Smuzhiyun hdr->param2 = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait);
2762*4882a593Smuzhiyun hdr->param3 = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Retain);
2763*4882a593Smuzhiyun
2764*4882a593Smuzhiyun pr_debug("Sending Connection Dropped Async Message StatSN:"
2765*4882a593Smuzhiyun " 0x%08x, for CID: %hu on CID: %hu\n", cmd->stat_sn,
2766*4882a593Smuzhiyun cmd->logout_cid, conn->cid);
2767*4882a593Smuzhiyun
2768*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, NULL, 0);
2769*4882a593Smuzhiyun }
2770*4882a593Smuzhiyun
iscsit_tx_thread_wait_for_tcp(struct iscsi_conn * conn)2771*4882a593Smuzhiyun static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
2772*4882a593Smuzhiyun {
2773*4882a593Smuzhiyun if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
2774*4882a593Smuzhiyun (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
2775*4882a593Smuzhiyun wait_for_completion_interruptible_timeout(
2776*4882a593Smuzhiyun &conn->tx_half_close_comp,
2777*4882a593Smuzhiyun ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
2778*4882a593Smuzhiyun }
2779*4882a593Smuzhiyun }
2780*4882a593Smuzhiyun
2781*4882a593Smuzhiyun void
iscsit_build_datain_pdu(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_datain * datain,struct iscsi_data_rsp * hdr,bool set_statsn)2782*4882a593Smuzhiyun iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
2783*4882a593Smuzhiyun struct iscsi_datain *datain, struct iscsi_data_rsp *hdr,
2784*4882a593Smuzhiyun bool set_statsn)
2785*4882a593Smuzhiyun {
2786*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_SCSI_DATA_IN;
2787*4882a593Smuzhiyun hdr->flags = datain->flags;
2788*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
2789*4882a593Smuzhiyun if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
2790*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
2791*4882a593Smuzhiyun hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
2792*4882a593Smuzhiyun } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
2793*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
2794*4882a593Smuzhiyun hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
2795*4882a593Smuzhiyun }
2796*4882a593Smuzhiyun }
2797*4882a593Smuzhiyun hton24(hdr->dlength, datain->length);
2798*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_DATA_ACK)
2799*4882a593Smuzhiyun int_to_scsilun(cmd->se_cmd.orig_fe_lun,
2800*4882a593Smuzhiyun (struct scsi_lun *)&hdr->lun);
2801*4882a593Smuzhiyun else
2802*4882a593Smuzhiyun put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
2803*4882a593Smuzhiyun
2804*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
2805*4882a593Smuzhiyun
2806*4882a593Smuzhiyun if (hdr->flags & ISCSI_FLAG_DATA_ACK)
2807*4882a593Smuzhiyun hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
2808*4882a593Smuzhiyun else
2809*4882a593Smuzhiyun hdr->ttt = cpu_to_be32(0xFFFFFFFF);
2810*4882a593Smuzhiyun if (set_statsn)
2811*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
2812*4882a593Smuzhiyun else
2813*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(0xFFFFFFFF);
2814*4882a593Smuzhiyun
2815*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
2816*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
2817*4882a593Smuzhiyun hdr->datasn = cpu_to_be32(datain->data_sn);
2818*4882a593Smuzhiyun hdr->offset = cpu_to_be32(datain->offset);
2819*4882a593Smuzhiyun
2820*4882a593Smuzhiyun pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
2821*4882a593Smuzhiyun " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
2822*4882a593Smuzhiyun cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
2823*4882a593Smuzhiyun ntohl(hdr->offset), datain->length, conn->cid);
2824*4882a593Smuzhiyun }
2825*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_datain_pdu);
2826*4882a593Smuzhiyun
iscsit_send_datain(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2827*4882a593Smuzhiyun static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
2828*4882a593Smuzhiyun {
2829*4882a593Smuzhiyun struct iscsi_data_rsp *hdr = (struct iscsi_data_rsp *)&cmd->pdu[0];
2830*4882a593Smuzhiyun struct iscsi_datain datain;
2831*4882a593Smuzhiyun struct iscsi_datain_req *dr;
2832*4882a593Smuzhiyun int eodr = 0, ret;
2833*4882a593Smuzhiyun bool set_statsn = false;
2834*4882a593Smuzhiyun
2835*4882a593Smuzhiyun memset(&datain, 0, sizeof(struct iscsi_datain));
2836*4882a593Smuzhiyun dr = iscsit_get_datain_values(cmd, &datain);
2837*4882a593Smuzhiyun if (!dr) {
2838*4882a593Smuzhiyun pr_err("iscsit_get_datain_values failed for ITT: 0x%08x\n",
2839*4882a593Smuzhiyun cmd->init_task_tag);
2840*4882a593Smuzhiyun return -1;
2841*4882a593Smuzhiyun }
2842*4882a593Smuzhiyun /*
2843*4882a593Smuzhiyun * Be paranoid and double check the logic for now.
2844*4882a593Smuzhiyun */
2845*4882a593Smuzhiyun if ((datain.offset + datain.length) > cmd->se_cmd.data_length) {
2846*4882a593Smuzhiyun pr_err("Command ITT: 0x%08x, datain.offset: %u and"
2847*4882a593Smuzhiyun " datain.length: %u exceeds cmd->data_length: %u\n",
2848*4882a593Smuzhiyun cmd->init_task_tag, datain.offset, datain.length,
2849*4882a593Smuzhiyun cmd->se_cmd.data_length);
2850*4882a593Smuzhiyun return -1;
2851*4882a593Smuzhiyun }
2852*4882a593Smuzhiyun
2853*4882a593Smuzhiyun atomic_long_add(datain.length, &conn->sess->tx_data_octets);
2854*4882a593Smuzhiyun /*
2855*4882a593Smuzhiyun * Special case for successfully execution w/ both DATAIN
2856*4882a593Smuzhiyun * and Sense Data.
2857*4882a593Smuzhiyun */
2858*4882a593Smuzhiyun if ((datain.flags & ISCSI_FLAG_DATA_STATUS) &&
2859*4882a593Smuzhiyun (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE))
2860*4882a593Smuzhiyun datain.flags &= ~ISCSI_FLAG_DATA_STATUS;
2861*4882a593Smuzhiyun else {
2862*4882a593Smuzhiyun if ((dr->dr_complete == DATAIN_COMPLETE_NORMAL) ||
2863*4882a593Smuzhiyun (dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) {
2864*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
2865*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
2866*4882a593Smuzhiyun set_statsn = true;
2867*4882a593Smuzhiyun } else if (dr->dr_complete ==
2868*4882a593Smuzhiyun DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
2869*4882a593Smuzhiyun set_statsn = true;
2870*4882a593Smuzhiyun }
2871*4882a593Smuzhiyun
2872*4882a593Smuzhiyun iscsit_build_datain_pdu(cmd, conn, &datain, hdr, set_statsn);
2873*4882a593Smuzhiyun
2874*4882a593Smuzhiyun ret = conn->conn_transport->iscsit_xmit_pdu(conn, cmd, dr, &datain, 0);
2875*4882a593Smuzhiyun if (ret < 0)
2876*4882a593Smuzhiyun return ret;
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun if (dr->dr_complete) {
2879*4882a593Smuzhiyun eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
2880*4882a593Smuzhiyun 2 : 1;
2881*4882a593Smuzhiyun iscsit_free_datain_req(cmd, dr);
2882*4882a593Smuzhiyun }
2883*4882a593Smuzhiyun
2884*4882a593Smuzhiyun return eodr;
2885*4882a593Smuzhiyun }
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun int
iscsit_build_logout_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_logout_rsp * hdr)2888*4882a593Smuzhiyun iscsit_build_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
2889*4882a593Smuzhiyun struct iscsi_logout_rsp *hdr)
2890*4882a593Smuzhiyun {
2891*4882a593Smuzhiyun struct iscsi_conn *logout_conn = NULL;
2892*4882a593Smuzhiyun struct iscsi_conn_recovery *cr = NULL;
2893*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
2894*4882a593Smuzhiyun /*
2895*4882a593Smuzhiyun * The actual shutting down of Sessions and/or Connections
2896*4882a593Smuzhiyun * for CLOSESESSION and CLOSECONNECTION Logout Requests
2897*4882a593Smuzhiyun * is done in scsi_logout_post_handler().
2898*4882a593Smuzhiyun */
2899*4882a593Smuzhiyun switch (cmd->logout_reason) {
2900*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_CLOSE_SESSION:
2901*4882a593Smuzhiyun pr_debug("iSCSI session logout successful, setting"
2902*4882a593Smuzhiyun " logout response to ISCSI_LOGOUT_SUCCESS.\n");
2903*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
2904*4882a593Smuzhiyun break;
2905*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION:
2906*4882a593Smuzhiyun if (cmd->logout_response == ISCSI_LOGOUT_CID_NOT_FOUND)
2907*4882a593Smuzhiyun break;
2908*4882a593Smuzhiyun /*
2909*4882a593Smuzhiyun * For CLOSECONNECTION logout requests carrying
2910*4882a593Smuzhiyun * a matching logout CID -> local CID, the reference
2911*4882a593Smuzhiyun * for the local CID will have been incremented in
2912*4882a593Smuzhiyun * iscsi_logout_closeconnection().
2913*4882a593Smuzhiyun *
2914*4882a593Smuzhiyun * For CLOSECONNECTION logout requests carrying
2915*4882a593Smuzhiyun * a different CID than the connection it arrived
2916*4882a593Smuzhiyun * on, the connection responding to cmd->logout_cid
2917*4882a593Smuzhiyun * is stopped in iscsit_logout_post_handler_diffcid().
2918*4882a593Smuzhiyun */
2919*4882a593Smuzhiyun
2920*4882a593Smuzhiyun pr_debug("iSCSI CID: %hu logout on CID: %hu"
2921*4882a593Smuzhiyun " successful.\n", cmd->logout_cid, conn->cid);
2922*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
2923*4882a593Smuzhiyun break;
2924*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_RECOVERY:
2925*4882a593Smuzhiyun if ((cmd->logout_response == ISCSI_LOGOUT_RECOVERY_UNSUPPORTED) ||
2926*4882a593Smuzhiyun (cmd->logout_response == ISCSI_LOGOUT_CLEANUP_FAILED))
2927*4882a593Smuzhiyun break;
2928*4882a593Smuzhiyun /*
2929*4882a593Smuzhiyun * If the connection is still active from our point of view
2930*4882a593Smuzhiyun * force connection recovery to occur.
2931*4882a593Smuzhiyun */
2932*4882a593Smuzhiyun logout_conn = iscsit_get_conn_from_cid_rcfr(sess,
2933*4882a593Smuzhiyun cmd->logout_cid);
2934*4882a593Smuzhiyun if (logout_conn) {
2935*4882a593Smuzhiyun iscsit_connection_reinstatement_rcfr(logout_conn);
2936*4882a593Smuzhiyun iscsit_dec_conn_usage_count(logout_conn);
2937*4882a593Smuzhiyun }
2938*4882a593Smuzhiyun
2939*4882a593Smuzhiyun cr = iscsit_get_inactive_connection_recovery_entry(
2940*4882a593Smuzhiyun conn->sess, cmd->logout_cid);
2941*4882a593Smuzhiyun if (!cr) {
2942*4882a593Smuzhiyun pr_err("Unable to locate CID: %hu for"
2943*4882a593Smuzhiyun " REMOVECONNFORRECOVERY Logout Request.\n",
2944*4882a593Smuzhiyun cmd->logout_cid);
2945*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND;
2946*4882a593Smuzhiyun break;
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun
2949*4882a593Smuzhiyun iscsit_discard_cr_cmds_by_expstatsn(cr, cmd->exp_stat_sn);
2950*4882a593Smuzhiyun
2951*4882a593Smuzhiyun pr_debug("iSCSI REMOVECONNFORRECOVERY logout"
2952*4882a593Smuzhiyun " for recovery for CID: %hu on CID: %hu successful.\n",
2953*4882a593Smuzhiyun cmd->logout_cid, conn->cid);
2954*4882a593Smuzhiyun cmd->logout_response = ISCSI_LOGOUT_SUCCESS;
2955*4882a593Smuzhiyun break;
2956*4882a593Smuzhiyun default:
2957*4882a593Smuzhiyun pr_err("Unknown cmd->logout_reason: 0x%02x\n",
2958*4882a593Smuzhiyun cmd->logout_reason);
2959*4882a593Smuzhiyun return -1;
2960*4882a593Smuzhiyun }
2961*4882a593Smuzhiyun
2962*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_LOGOUT_RSP;
2963*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_FINAL;
2964*4882a593Smuzhiyun hdr->response = cmd->logout_response;
2965*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
2966*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
2967*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
2968*4882a593Smuzhiyun
2969*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
2970*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
2971*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
2972*4882a593Smuzhiyun
2973*4882a593Smuzhiyun pr_debug("Built Logout Response ITT: 0x%08x StatSN:"
2974*4882a593Smuzhiyun " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
2975*4882a593Smuzhiyun cmd->init_task_tag, cmd->stat_sn, hdr->response,
2976*4882a593Smuzhiyun cmd->logout_cid, conn->cid);
2977*4882a593Smuzhiyun
2978*4882a593Smuzhiyun return 0;
2979*4882a593Smuzhiyun }
2980*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_logout_rsp);
2981*4882a593Smuzhiyun
2982*4882a593Smuzhiyun static int
iscsit_send_logout(struct iscsi_cmd * cmd,struct iscsi_conn * conn)2983*4882a593Smuzhiyun iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
2984*4882a593Smuzhiyun {
2985*4882a593Smuzhiyun int rc;
2986*4882a593Smuzhiyun
2987*4882a593Smuzhiyun rc = iscsit_build_logout_rsp(cmd, conn,
2988*4882a593Smuzhiyun (struct iscsi_logout_rsp *)&cmd->pdu[0]);
2989*4882a593Smuzhiyun if (rc < 0)
2990*4882a593Smuzhiyun return rc;
2991*4882a593Smuzhiyun
2992*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, NULL, 0);
2993*4882a593Smuzhiyun }
2994*4882a593Smuzhiyun
2995*4882a593Smuzhiyun void
iscsit_build_nopin_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_nopin * hdr,bool nopout_response)2996*4882a593Smuzhiyun iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
2997*4882a593Smuzhiyun struct iscsi_nopin *hdr, bool nopout_response)
2998*4882a593Smuzhiyun {
2999*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_NOOP_IN;
3000*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3001*4882a593Smuzhiyun hton24(hdr->dlength, cmd->buf_ptr_size);
3002*4882a593Smuzhiyun if (nopout_response)
3003*4882a593Smuzhiyun put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
3004*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
3005*4882a593Smuzhiyun hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
3006*4882a593Smuzhiyun cmd->stat_sn = (nopout_response) ? conn->stat_sn++ :
3007*4882a593Smuzhiyun conn->stat_sn;
3008*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
3009*4882a593Smuzhiyun
3010*4882a593Smuzhiyun if (nopout_response)
3011*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
3012*4882a593Smuzhiyun
3013*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3014*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3015*4882a593Smuzhiyun
3016*4882a593Smuzhiyun pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
3017*4882a593Smuzhiyun " StatSN: 0x%08x, Length %u\n", (nopout_response) ?
3018*4882a593Smuzhiyun "Solicited" : "Unsolicited", cmd->init_task_tag,
3019*4882a593Smuzhiyun cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
3020*4882a593Smuzhiyun }
3021*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_nopin_rsp);
3022*4882a593Smuzhiyun
3023*4882a593Smuzhiyun /*
3024*4882a593Smuzhiyun * Unsolicited NOPIN, either requesting a response or not.
3025*4882a593Smuzhiyun */
iscsit_send_unsolicited_nopin(struct iscsi_cmd * cmd,struct iscsi_conn * conn,int want_response)3026*4882a593Smuzhiyun static int iscsit_send_unsolicited_nopin(
3027*4882a593Smuzhiyun struct iscsi_cmd *cmd,
3028*4882a593Smuzhiyun struct iscsi_conn *conn,
3029*4882a593Smuzhiyun int want_response)
3030*4882a593Smuzhiyun {
3031*4882a593Smuzhiyun struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
3032*4882a593Smuzhiyun int ret;
3033*4882a593Smuzhiyun
3034*4882a593Smuzhiyun iscsit_build_nopin_rsp(cmd, conn, hdr, false);
3035*4882a593Smuzhiyun
3036*4882a593Smuzhiyun pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:"
3037*4882a593Smuzhiyun " 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid);
3038*4882a593Smuzhiyun
3039*4882a593Smuzhiyun ret = conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, NULL, 0);
3040*4882a593Smuzhiyun if (ret < 0)
3041*4882a593Smuzhiyun return ret;
3042*4882a593Smuzhiyun
3043*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
3044*4882a593Smuzhiyun cmd->i_state = want_response ?
3045*4882a593Smuzhiyun ISTATE_SENT_NOPIN_WANT_RESPONSE : ISTATE_SENT_STATUS;
3046*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
3047*4882a593Smuzhiyun
3048*4882a593Smuzhiyun return 0;
3049*4882a593Smuzhiyun }
3050*4882a593Smuzhiyun
3051*4882a593Smuzhiyun static int
iscsit_send_nopin(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3052*4882a593Smuzhiyun iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
3053*4882a593Smuzhiyun {
3054*4882a593Smuzhiyun struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
3055*4882a593Smuzhiyun
3056*4882a593Smuzhiyun iscsit_build_nopin_rsp(cmd, conn, hdr, true);
3057*4882a593Smuzhiyun
3058*4882a593Smuzhiyun /*
3059*4882a593Smuzhiyun * NOPOUT Ping Data is attached to struct iscsi_cmd->buf_ptr.
3060*4882a593Smuzhiyun * NOPOUT DataSegmentLength is at struct iscsi_cmd->buf_ptr_size.
3061*4882a593Smuzhiyun */
3062*4882a593Smuzhiyun pr_debug("Echoing back %u bytes of ping data.\n", cmd->buf_ptr_size);
3063*4882a593Smuzhiyun
3064*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL,
3065*4882a593Smuzhiyun cmd->buf_ptr,
3066*4882a593Smuzhiyun cmd->buf_ptr_size);
3067*4882a593Smuzhiyun }
3068*4882a593Smuzhiyun
iscsit_send_r2t(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3069*4882a593Smuzhiyun static int iscsit_send_r2t(
3070*4882a593Smuzhiyun struct iscsi_cmd *cmd,
3071*4882a593Smuzhiyun struct iscsi_conn *conn)
3072*4882a593Smuzhiyun {
3073*4882a593Smuzhiyun struct iscsi_r2t *r2t;
3074*4882a593Smuzhiyun struct iscsi_r2t_rsp *hdr;
3075*4882a593Smuzhiyun int ret;
3076*4882a593Smuzhiyun
3077*4882a593Smuzhiyun r2t = iscsit_get_r2t_from_list(cmd);
3078*4882a593Smuzhiyun if (!r2t)
3079*4882a593Smuzhiyun return -1;
3080*4882a593Smuzhiyun
3081*4882a593Smuzhiyun hdr = (struct iscsi_r2t_rsp *) cmd->pdu;
3082*4882a593Smuzhiyun memset(hdr, 0, ISCSI_HDR_LEN);
3083*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_R2T;
3084*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3085*4882a593Smuzhiyun int_to_scsilun(cmd->se_cmd.orig_fe_lun,
3086*4882a593Smuzhiyun (struct scsi_lun *)&hdr->lun);
3087*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
3088*4882a593Smuzhiyun if (conn->conn_transport->iscsit_get_r2t_ttt)
3089*4882a593Smuzhiyun conn->conn_transport->iscsit_get_r2t_ttt(conn, cmd, r2t);
3090*4882a593Smuzhiyun else
3091*4882a593Smuzhiyun r2t->targ_xfer_tag = session_get_next_ttt(conn->sess);
3092*4882a593Smuzhiyun hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag);
3093*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(conn->stat_sn);
3094*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3095*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3096*4882a593Smuzhiyun hdr->r2tsn = cpu_to_be32(r2t->r2t_sn);
3097*4882a593Smuzhiyun hdr->data_offset = cpu_to_be32(r2t->offset);
3098*4882a593Smuzhiyun hdr->data_length = cpu_to_be32(r2t->xfer_len);
3099*4882a593Smuzhiyun
3100*4882a593Smuzhiyun pr_debug("Built %sR2T, ITT: 0x%08x, TTT: 0x%08x, StatSN:"
3101*4882a593Smuzhiyun " 0x%08x, R2TSN: 0x%08x, Offset: %u, DDTL: %u, CID: %hu\n",
3102*4882a593Smuzhiyun (!r2t->recovery_r2t) ? "" : "Recovery ", cmd->init_task_tag,
3103*4882a593Smuzhiyun r2t->targ_xfer_tag, ntohl(hdr->statsn), r2t->r2t_sn,
3104*4882a593Smuzhiyun r2t->offset, r2t->xfer_len, conn->cid);
3105*4882a593Smuzhiyun
3106*4882a593Smuzhiyun spin_lock_bh(&cmd->r2t_lock);
3107*4882a593Smuzhiyun r2t->sent_r2t = 1;
3108*4882a593Smuzhiyun spin_unlock_bh(&cmd->r2t_lock);
3109*4882a593Smuzhiyun
3110*4882a593Smuzhiyun ret = conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, NULL, 0);
3111*4882a593Smuzhiyun if (ret < 0) {
3112*4882a593Smuzhiyun return ret;
3113*4882a593Smuzhiyun }
3114*4882a593Smuzhiyun
3115*4882a593Smuzhiyun spin_lock_bh(&cmd->dataout_timeout_lock);
3116*4882a593Smuzhiyun iscsit_start_dataout_timer(cmd, conn);
3117*4882a593Smuzhiyun spin_unlock_bh(&cmd->dataout_timeout_lock);
3118*4882a593Smuzhiyun
3119*4882a593Smuzhiyun return 0;
3120*4882a593Smuzhiyun }
3121*4882a593Smuzhiyun
3122*4882a593Smuzhiyun /*
3123*4882a593Smuzhiyun * @recovery: If called from iscsi_task_reassign_complete_write() for
3124*4882a593Smuzhiyun * connection recovery.
3125*4882a593Smuzhiyun */
iscsit_build_r2ts_for_cmd(struct iscsi_conn * conn,struct iscsi_cmd * cmd,bool recovery)3126*4882a593Smuzhiyun int iscsit_build_r2ts_for_cmd(
3127*4882a593Smuzhiyun struct iscsi_conn *conn,
3128*4882a593Smuzhiyun struct iscsi_cmd *cmd,
3129*4882a593Smuzhiyun bool recovery)
3130*4882a593Smuzhiyun {
3131*4882a593Smuzhiyun int first_r2t = 1;
3132*4882a593Smuzhiyun u32 offset = 0, xfer_len = 0;
3133*4882a593Smuzhiyun
3134*4882a593Smuzhiyun spin_lock_bh(&cmd->r2t_lock);
3135*4882a593Smuzhiyun if (cmd->cmd_flags & ICF_SENT_LAST_R2T) {
3136*4882a593Smuzhiyun spin_unlock_bh(&cmd->r2t_lock);
3137*4882a593Smuzhiyun return 0;
3138*4882a593Smuzhiyun }
3139*4882a593Smuzhiyun
3140*4882a593Smuzhiyun if (conn->sess->sess_ops->DataSequenceInOrder &&
3141*4882a593Smuzhiyun !recovery)
3142*4882a593Smuzhiyun cmd->r2t_offset = max(cmd->r2t_offset, cmd->write_data_done);
3143*4882a593Smuzhiyun
3144*4882a593Smuzhiyun while (cmd->outstanding_r2ts < conn->sess->sess_ops->MaxOutstandingR2T) {
3145*4882a593Smuzhiyun if (conn->sess->sess_ops->DataSequenceInOrder) {
3146*4882a593Smuzhiyun offset = cmd->r2t_offset;
3147*4882a593Smuzhiyun
3148*4882a593Smuzhiyun if (first_r2t && recovery) {
3149*4882a593Smuzhiyun int new_data_end = offset +
3150*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength -
3151*4882a593Smuzhiyun cmd->next_burst_len;
3152*4882a593Smuzhiyun
3153*4882a593Smuzhiyun if (new_data_end > cmd->se_cmd.data_length)
3154*4882a593Smuzhiyun xfer_len = cmd->se_cmd.data_length - offset;
3155*4882a593Smuzhiyun else
3156*4882a593Smuzhiyun xfer_len =
3157*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength -
3158*4882a593Smuzhiyun cmd->next_burst_len;
3159*4882a593Smuzhiyun } else {
3160*4882a593Smuzhiyun int new_data_end = offset +
3161*4882a593Smuzhiyun conn->sess->sess_ops->MaxBurstLength;
3162*4882a593Smuzhiyun
3163*4882a593Smuzhiyun if (new_data_end > cmd->se_cmd.data_length)
3164*4882a593Smuzhiyun xfer_len = cmd->se_cmd.data_length - offset;
3165*4882a593Smuzhiyun else
3166*4882a593Smuzhiyun xfer_len = conn->sess->sess_ops->MaxBurstLength;
3167*4882a593Smuzhiyun }
3168*4882a593Smuzhiyun
3169*4882a593Smuzhiyun if ((s32)xfer_len < 0) {
3170*4882a593Smuzhiyun cmd->cmd_flags |= ICF_SENT_LAST_R2T;
3171*4882a593Smuzhiyun break;
3172*4882a593Smuzhiyun }
3173*4882a593Smuzhiyun
3174*4882a593Smuzhiyun cmd->r2t_offset += xfer_len;
3175*4882a593Smuzhiyun
3176*4882a593Smuzhiyun if (cmd->r2t_offset == cmd->se_cmd.data_length)
3177*4882a593Smuzhiyun cmd->cmd_flags |= ICF_SENT_LAST_R2T;
3178*4882a593Smuzhiyun } else {
3179*4882a593Smuzhiyun struct iscsi_seq *seq;
3180*4882a593Smuzhiyun
3181*4882a593Smuzhiyun seq = iscsit_get_seq_holder_for_r2t(cmd);
3182*4882a593Smuzhiyun if (!seq) {
3183*4882a593Smuzhiyun spin_unlock_bh(&cmd->r2t_lock);
3184*4882a593Smuzhiyun return -1;
3185*4882a593Smuzhiyun }
3186*4882a593Smuzhiyun
3187*4882a593Smuzhiyun offset = seq->offset;
3188*4882a593Smuzhiyun xfer_len = seq->xfer_len;
3189*4882a593Smuzhiyun
3190*4882a593Smuzhiyun if (cmd->seq_send_order == cmd->seq_count)
3191*4882a593Smuzhiyun cmd->cmd_flags |= ICF_SENT_LAST_R2T;
3192*4882a593Smuzhiyun }
3193*4882a593Smuzhiyun cmd->outstanding_r2ts++;
3194*4882a593Smuzhiyun first_r2t = 0;
3195*4882a593Smuzhiyun
3196*4882a593Smuzhiyun if (iscsit_add_r2t_to_list(cmd, offset, xfer_len, 0, 0) < 0) {
3197*4882a593Smuzhiyun spin_unlock_bh(&cmd->r2t_lock);
3198*4882a593Smuzhiyun return -1;
3199*4882a593Smuzhiyun }
3200*4882a593Smuzhiyun
3201*4882a593Smuzhiyun if (cmd->cmd_flags & ICF_SENT_LAST_R2T)
3202*4882a593Smuzhiyun break;
3203*4882a593Smuzhiyun }
3204*4882a593Smuzhiyun spin_unlock_bh(&cmd->r2t_lock);
3205*4882a593Smuzhiyun
3206*4882a593Smuzhiyun return 0;
3207*4882a593Smuzhiyun }
3208*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_r2ts_for_cmd);
3209*4882a593Smuzhiyun
iscsit_build_rsp_pdu(struct iscsi_cmd * cmd,struct iscsi_conn * conn,bool inc_stat_sn,struct iscsi_scsi_rsp * hdr)3210*4882a593Smuzhiyun void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
3211*4882a593Smuzhiyun bool inc_stat_sn, struct iscsi_scsi_rsp *hdr)
3212*4882a593Smuzhiyun {
3213*4882a593Smuzhiyun if (inc_stat_sn)
3214*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
3215*4882a593Smuzhiyun
3216*4882a593Smuzhiyun atomic_long_inc(&conn->sess->rsp_pdus);
3217*4882a593Smuzhiyun
3218*4882a593Smuzhiyun memset(hdr, 0, ISCSI_HDR_LEN);
3219*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_SCSI_CMD_RSP;
3220*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3221*4882a593Smuzhiyun if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
3222*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW;
3223*4882a593Smuzhiyun hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
3224*4882a593Smuzhiyun } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
3225*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW;
3226*4882a593Smuzhiyun hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
3227*4882a593Smuzhiyun }
3228*4882a593Smuzhiyun hdr->response = cmd->iscsi_response;
3229*4882a593Smuzhiyun hdr->cmd_status = cmd->se_cmd.scsi_status;
3230*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
3231*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
3232*4882a593Smuzhiyun
3233*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
3234*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3235*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3236*4882a593Smuzhiyun
3237*4882a593Smuzhiyun pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
3238*4882a593Smuzhiyun " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
3239*4882a593Smuzhiyun cmd->init_task_tag, cmd->stat_sn, cmd->se_cmd.scsi_status,
3240*4882a593Smuzhiyun cmd->se_cmd.scsi_status, conn->cid);
3241*4882a593Smuzhiyun }
3242*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_rsp_pdu);
3243*4882a593Smuzhiyun
iscsit_send_response(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3244*4882a593Smuzhiyun static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
3245*4882a593Smuzhiyun {
3246*4882a593Smuzhiyun struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)&cmd->pdu[0];
3247*4882a593Smuzhiyun bool inc_stat_sn = (cmd->i_state == ISTATE_SEND_STATUS);
3248*4882a593Smuzhiyun void *data_buf = NULL;
3249*4882a593Smuzhiyun u32 padding = 0, data_buf_len = 0;
3250*4882a593Smuzhiyun
3251*4882a593Smuzhiyun iscsit_build_rsp_pdu(cmd, conn, inc_stat_sn, hdr);
3252*4882a593Smuzhiyun
3253*4882a593Smuzhiyun /*
3254*4882a593Smuzhiyun * Attach SENSE DATA payload to iSCSI Response PDU
3255*4882a593Smuzhiyun */
3256*4882a593Smuzhiyun if (cmd->se_cmd.sense_buffer &&
3257*4882a593Smuzhiyun ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
3258*4882a593Smuzhiyun (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
3259*4882a593Smuzhiyun put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer);
3260*4882a593Smuzhiyun cmd->se_cmd.scsi_sense_length += sizeof (__be16);
3261*4882a593Smuzhiyun
3262*4882a593Smuzhiyun padding = -(cmd->se_cmd.scsi_sense_length) & 3;
3263*4882a593Smuzhiyun hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
3264*4882a593Smuzhiyun data_buf = cmd->sense_buffer;
3265*4882a593Smuzhiyun data_buf_len = cmd->se_cmd.scsi_sense_length + padding;
3266*4882a593Smuzhiyun
3267*4882a593Smuzhiyun if (padding) {
3268*4882a593Smuzhiyun memset(cmd->sense_buffer +
3269*4882a593Smuzhiyun cmd->se_cmd.scsi_sense_length, 0, padding);
3270*4882a593Smuzhiyun pr_debug("Adding %u bytes of padding to"
3271*4882a593Smuzhiyun " SENSE.\n", padding);
3272*4882a593Smuzhiyun }
3273*4882a593Smuzhiyun
3274*4882a593Smuzhiyun pr_debug("Attaching SENSE DATA: %u bytes to iSCSI"
3275*4882a593Smuzhiyun " Response PDU\n",
3276*4882a593Smuzhiyun cmd->se_cmd.scsi_sense_length);
3277*4882a593Smuzhiyun }
3278*4882a593Smuzhiyun
3279*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, data_buf,
3280*4882a593Smuzhiyun data_buf_len);
3281*4882a593Smuzhiyun }
3282*4882a593Smuzhiyun
iscsit_convert_tcm_tmr_rsp(struct se_tmr_req * se_tmr)3283*4882a593Smuzhiyun static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
3284*4882a593Smuzhiyun {
3285*4882a593Smuzhiyun switch (se_tmr->response) {
3286*4882a593Smuzhiyun case TMR_FUNCTION_COMPLETE:
3287*4882a593Smuzhiyun return ISCSI_TMF_RSP_COMPLETE;
3288*4882a593Smuzhiyun case TMR_TASK_DOES_NOT_EXIST:
3289*4882a593Smuzhiyun return ISCSI_TMF_RSP_NO_TASK;
3290*4882a593Smuzhiyun case TMR_LUN_DOES_NOT_EXIST:
3291*4882a593Smuzhiyun return ISCSI_TMF_RSP_NO_LUN;
3292*4882a593Smuzhiyun case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
3293*4882a593Smuzhiyun return ISCSI_TMF_RSP_NOT_SUPPORTED;
3294*4882a593Smuzhiyun case TMR_FUNCTION_REJECTED:
3295*4882a593Smuzhiyun default:
3296*4882a593Smuzhiyun return ISCSI_TMF_RSP_REJECTED;
3297*4882a593Smuzhiyun }
3298*4882a593Smuzhiyun }
3299*4882a593Smuzhiyun
3300*4882a593Smuzhiyun void
iscsit_build_task_mgt_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_tm_rsp * hdr)3301*4882a593Smuzhiyun iscsit_build_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
3302*4882a593Smuzhiyun struct iscsi_tm_rsp *hdr)
3303*4882a593Smuzhiyun {
3304*4882a593Smuzhiyun struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
3305*4882a593Smuzhiyun
3306*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
3307*4882a593Smuzhiyun hdr->flags = ISCSI_FLAG_CMD_FINAL;
3308*4882a593Smuzhiyun hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr);
3309*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
3310*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
3311*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
3312*4882a593Smuzhiyun
3313*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
3314*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3315*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3316*4882a593Smuzhiyun
3317*4882a593Smuzhiyun pr_debug("Built Task Management Response ITT: 0x%08x,"
3318*4882a593Smuzhiyun " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
3319*4882a593Smuzhiyun cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
3320*4882a593Smuzhiyun }
3321*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_task_mgt_rsp);
3322*4882a593Smuzhiyun
3323*4882a593Smuzhiyun static int
iscsit_send_task_mgt_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3324*4882a593Smuzhiyun iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
3325*4882a593Smuzhiyun {
3326*4882a593Smuzhiyun struct iscsi_tm_rsp *hdr = (struct iscsi_tm_rsp *)&cmd->pdu[0];
3327*4882a593Smuzhiyun
3328*4882a593Smuzhiyun iscsit_build_task_mgt_rsp(cmd, conn, hdr);
3329*4882a593Smuzhiyun
3330*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL, NULL, 0);
3331*4882a593Smuzhiyun }
3332*4882a593Smuzhiyun
3333*4882a593Smuzhiyun #define SENDTARGETS_BUF_LIMIT 32768U
3334*4882a593Smuzhiyun
3335*4882a593Smuzhiyun static int
iscsit_build_sendtargets_response(struct iscsi_cmd * cmd,enum iscsit_transport_type network_transport,int skip_bytes,bool * completed)3336*4882a593Smuzhiyun iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
3337*4882a593Smuzhiyun enum iscsit_transport_type network_transport,
3338*4882a593Smuzhiyun int skip_bytes, bool *completed)
3339*4882a593Smuzhiyun {
3340*4882a593Smuzhiyun char *payload = NULL;
3341*4882a593Smuzhiyun struct iscsi_conn *conn = cmd->conn;
3342*4882a593Smuzhiyun struct iscsi_portal_group *tpg;
3343*4882a593Smuzhiyun struct iscsi_tiqn *tiqn;
3344*4882a593Smuzhiyun struct iscsi_tpg_np *tpg_np;
3345*4882a593Smuzhiyun int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;
3346*4882a593Smuzhiyun int target_name_printed;
3347*4882a593Smuzhiyun unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
3348*4882a593Smuzhiyun unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
3349*4882a593Smuzhiyun bool active;
3350*4882a593Smuzhiyun
3351*4882a593Smuzhiyun buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength,
3352*4882a593Smuzhiyun SENDTARGETS_BUF_LIMIT);
3353*4882a593Smuzhiyun
3354*4882a593Smuzhiyun payload = kzalloc(buffer_len, GFP_KERNEL);
3355*4882a593Smuzhiyun if (!payload)
3356*4882a593Smuzhiyun return -ENOMEM;
3357*4882a593Smuzhiyun
3358*4882a593Smuzhiyun /*
3359*4882a593Smuzhiyun * Locate pointer to iqn./eui. string for ICF_SENDTARGETS_SINGLE
3360*4882a593Smuzhiyun * explicit case..
3361*4882a593Smuzhiyun */
3362*4882a593Smuzhiyun if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE) {
3363*4882a593Smuzhiyun text_ptr = strchr(text_in, '=');
3364*4882a593Smuzhiyun if (!text_ptr) {
3365*4882a593Smuzhiyun pr_err("Unable to locate '=' string in text_in:"
3366*4882a593Smuzhiyun " %s\n", text_in);
3367*4882a593Smuzhiyun kfree(payload);
3368*4882a593Smuzhiyun return -EINVAL;
3369*4882a593Smuzhiyun }
3370*4882a593Smuzhiyun /*
3371*4882a593Smuzhiyun * Skip over '=' character..
3372*4882a593Smuzhiyun */
3373*4882a593Smuzhiyun text_ptr += 1;
3374*4882a593Smuzhiyun }
3375*4882a593Smuzhiyun
3376*4882a593Smuzhiyun spin_lock(&tiqn_lock);
3377*4882a593Smuzhiyun list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
3378*4882a593Smuzhiyun if ((cmd->cmd_flags & ICF_SENDTARGETS_SINGLE) &&
3379*4882a593Smuzhiyun strcmp(tiqn->tiqn, text_ptr)) {
3380*4882a593Smuzhiyun continue;
3381*4882a593Smuzhiyun }
3382*4882a593Smuzhiyun
3383*4882a593Smuzhiyun target_name_printed = 0;
3384*4882a593Smuzhiyun
3385*4882a593Smuzhiyun spin_lock(&tiqn->tiqn_tpg_lock);
3386*4882a593Smuzhiyun list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
3387*4882a593Smuzhiyun
3388*4882a593Smuzhiyun /* If demo_mode_discovery=0 and generate_node_acls=0
3389*4882a593Smuzhiyun * (demo mode dislabed) do not return
3390*4882a593Smuzhiyun * TargetName+TargetAddress unless a NodeACL exists.
3391*4882a593Smuzhiyun */
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun if ((tpg->tpg_attrib.generate_node_acls == 0) &&
3394*4882a593Smuzhiyun (tpg->tpg_attrib.demo_mode_discovery == 0) &&
3395*4882a593Smuzhiyun (!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
3396*4882a593Smuzhiyun cmd->conn->sess->sess_ops->InitiatorName))) {
3397*4882a593Smuzhiyun continue;
3398*4882a593Smuzhiyun }
3399*4882a593Smuzhiyun
3400*4882a593Smuzhiyun spin_lock(&tpg->tpg_state_lock);
3401*4882a593Smuzhiyun active = (tpg->tpg_state == TPG_STATE_ACTIVE);
3402*4882a593Smuzhiyun spin_unlock(&tpg->tpg_state_lock);
3403*4882a593Smuzhiyun
3404*4882a593Smuzhiyun if (!active && tpg->tpg_attrib.tpg_enabled_sendtargets)
3405*4882a593Smuzhiyun continue;
3406*4882a593Smuzhiyun
3407*4882a593Smuzhiyun spin_lock(&tpg->tpg_np_lock);
3408*4882a593Smuzhiyun list_for_each_entry(tpg_np, &tpg->tpg_gnp_list,
3409*4882a593Smuzhiyun tpg_np_list) {
3410*4882a593Smuzhiyun struct iscsi_np *np = tpg_np->tpg_np;
3411*4882a593Smuzhiyun struct sockaddr_storage *sockaddr;
3412*4882a593Smuzhiyun
3413*4882a593Smuzhiyun if (np->np_network_transport != network_transport)
3414*4882a593Smuzhiyun continue;
3415*4882a593Smuzhiyun
3416*4882a593Smuzhiyun if (!target_name_printed) {
3417*4882a593Smuzhiyun len = sprintf(buf, "TargetName=%s",
3418*4882a593Smuzhiyun tiqn->tiqn);
3419*4882a593Smuzhiyun len += 1;
3420*4882a593Smuzhiyun
3421*4882a593Smuzhiyun if ((len + payload_len) > buffer_len) {
3422*4882a593Smuzhiyun spin_unlock(&tpg->tpg_np_lock);
3423*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_tpg_lock);
3424*4882a593Smuzhiyun end_of_buf = 1;
3425*4882a593Smuzhiyun goto eob;
3426*4882a593Smuzhiyun }
3427*4882a593Smuzhiyun
3428*4882a593Smuzhiyun if (skip_bytes && len <= skip_bytes) {
3429*4882a593Smuzhiyun skip_bytes -= len;
3430*4882a593Smuzhiyun } else {
3431*4882a593Smuzhiyun memcpy(payload + payload_len, buf, len);
3432*4882a593Smuzhiyun payload_len += len;
3433*4882a593Smuzhiyun target_name_printed = 1;
3434*4882a593Smuzhiyun if (len > skip_bytes)
3435*4882a593Smuzhiyun skip_bytes = 0;
3436*4882a593Smuzhiyun }
3437*4882a593Smuzhiyun }
3438*4882a593Smuzhiyun
3439*4882a593Smuzhiyun if (inet_addr_is_any((struct sockaddr *)&np->np_sockaddr))
3440*4882a593Smuzhiyun sockaddr = &conn->local_sockaddr;
3441*4882a593Smuzhiyun else
3442*4882a593Smuzhiyun sockaddr = &np->np_sockaddr;
3443*4882a593Smuzhiyun
3444*4882a593Smuzhiyun len = sprintf(buf, "TargetAddress="
3445*4882a593Smuzhiyun "%pISpc,%hu",
3446*4882a593Smuzhiyun sockaddr,
3447*4882a593Smuzhiyun tpg->tpgt);
3448*4882a593Smuzhiyun len += 1;
3449*4882a593Smuzhiyun
3450*4882a593Smuzhiyun if ((len + payload_len) > buffer_len) {
3451*4882a593Smuzhiyun spin_unlock(&tpg->tpg_np_lock);
3452*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_tpg_lock);
3453*4882a593Smuzhiyun end_of_buf = 1;
3454*4882a593Smuzhiyun goto eob;
3455*4882a593Smuzhiyun }
3456*4882a593Smuzhiyun
3457*4882a593Smuzhiyun if (skip_bytes && len <= skip_bytes) {
3458*4882a593Smuzhiyun skip_bytes -= len;
3459*4882a593Smuzhiyun } else {
3460*4882a593Smuzhiyun memcpy(payload + payload_len, buf, len);
3461*4882a593Smuzhiyun payload_len += len;
3462*4882a593Smuzhiyun if (len > skip_bytes)
3463*4882a593Smuzhiyun skip_bytes = 0;
3464*4882a593Smuzhiyun }
3465*4882a593Smuzhiyun }
3466*4882a593Smuzhiyun spin_unlock(&tpg->tpg_np_lock);
3467*4882a593Smuzhiyun }
3468*4882a593Smuzhiyun spin_unlock(&tiqn->tiqn_tpg_lock);
3469*4882a593Smuzhiyun eob:
3470*4882a593Smuzhiyun if (end_of_buf) {
3471*4882a593Smuzhiyun *completed = false;
3472*4882a593Smuzhiyun break;
3473*4882a593Smuzhiyun }
3474*4882a593Smuzhiyun
3475*4882a593Smuzhiyun if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE)
3476*4882a593Smuzhiyun break;
3477*4882a593Smuzhiyun }
3478*4882a593Smuzhiyun spin_unlock(&tiqn_lock);
3479*4882a593Smuzhiyun
3480*4882a593Smuzhiyun cmd->buf_ptr = payload;
3481*4882a593Smuzhiyun
3482*4882a593Smuzhiyun return payload_len;
3483*4882a593Smuzhiyun }
3484*4882a593Smuzhiyun
3485*4882a593Smuzhiyun int
iscsit_build_text_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_text_rsp * hdr,enum iscsit_transport_type network_transport)3486*4882a593Smuzhiyun iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
3487*4882a593Smuzhiyun struct iscsi_text_rsp *hdr,
3488*4882a593Smuzhiyun enum iscsit_transport_type network_transport)
3489*4882a593Smuzhiyun {
3490*4882a593Smuzhiyun int text_length, padding;
3491*4882a593Smuzhiyun bool completed = true;
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun text_length = iscsit_build_sendtargets_response(cmd, network_transport,
3494*4882a593Smuzhiyun cmd->read_data_done,
3495*4882a593Smuzhiyun &completed);
3496*4882a593Smuzhiyun if (text_length < 0)
3497*4882a593Smuzhiyun return text_length;
3498*4882a593Smuzhiyun
3499*4882a593Smuzhiyun if (completed) {
3500*4882a593Smuzhiyun hdr->flags = ISCSI_FLAG_CMD_FINAL;
3501*4882a593Smuzhiyun } else {
3502*4882a593Smuzhiyun hdr->flags = ISCSI_FLAG_TEXT_CONTINUE;
3503*4882a593Smuzhiyun cmd->read_data_done += text_length;
3504*4882a593Smuzhiyun if (cmd->targ_xfer_tag == 0xFFFFFFFF)
3505*4882a593Smuzhiyun cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
3506*4882a593Smuzhiyun }
3507*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_TEXT_RSP;
3508*4882a593Smuzhiyun padding = ((-text_length) & 3);
3509*4882a593Smuzhiyun hton24(hdr->dlength, text_length);
3510*4882a593Smuzhiyun hdr->itt = cmd->init_task_tag;
3511*4882a593Smuzhiyun hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
3512*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
3513*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
3514*4882a593Smuzhiyun
3515*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, conn->sess);
3516*4882a593Smuzhiyun /*
3517*4882a593Smuzhiyun * Reset maxcmdsn_inc in multi-part text payload exchanges to
3518*4882a593Smuzhiyun * correctly increment MaxCmdSN for each response answering a
3519*4882a593Smuzhiyun * non immediate text request with a valid CmdSN.
3520*4882a593Smuzhiyun */
3521*4882a593Smuzhiyun cmd->maxcmdsn_inc = 0;
3522*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3523*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3524*4882a593Smuzhiyun
3525*4882a593Smuzhiyun pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
3526*4882a593Smuzhiyun " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
3527*4882a593Smuzhiyun cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid,
3528*4882a593Smuzhiyun !!(hdr->flags & ISCSI_FLAG_CMD_FINAL),
3529*4882a593Smuzhiyun !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE));
3530*4882a593Smuzhiyun
3531*4882a593Smuzhiyun return text_length + padding;
3532*4882a593Smuzhiyun }
3533*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_text_rsp);
3534*4882a593Smuzhiyun
iscsit_send_text_rsp(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3535*4882a593Smuzhiyun static int iscsit_send_text_rsp(
3536*4882a593Smuzhiyun struct iscsi_cmd *cmd,
3537*4882a593Smuzhiyun struct iscsi_conn *conn)
3538*4882a593Smuzhiyun {
3539*4882a593Smuzhiyun struct iscsi_text_rsp *hdr = (struct iscsi_text_rsp *)cmd->pdu;
3540*4882a593Smuzhiyun int text_length;
3541*4882a593Smuzhiyun
3542*4882a593Smuzhiyun text_length = iscsit_build_text_rsp(cmd, conn, hdr,
3543*4882a593Smuzhiyun conn->conn_transport->transport_type);
3544*4882a593Smuzhiyun if (text_length < 0)
3545*4882a593Smuzhiyun return text_length;
3546*4882a593Smuzhiyun
3547*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL,
3548*4882a593Smuzhiyun cmd->buf_ptr,
3549*4882a593Smuzhiyun text_length);
3550*4882a593Smuzhiyun }
3551*4882a593Smuzhiyun
3552*4882a593Smuzhiyun void
iscsit_build_reject(struct iscsi_cmd * cmd,struct iscsi_conn * conn,struct iscsi_reject * hdr)3553*4882a593Smuzhiyun iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
3554*4882a593Smuzhiyun struct iscsi_reject *hdr)
3555*4882a593Smuzhiyun {
3556*4882a593Smuzhiyun hdr->opcode = ISCSI_OP_REJECT;
3557*4882a593Smuzhiyun hdr->reason = cmd->reject_reason;
3558*4882a593Smuzhiyun hdr->flags |= ISCSI_FLAG_CMD_FINAL;
3559*4882a593Smuzhiyun hton24(hdr->dlength, ISCSI_HDR_LEN);
3560*4882a593Smuzhiyun hdr->ffffffff = cpu_to_be32(0xffffffff);
3561*4882a593Smuzhiyun cmd->stat_sn = conn->stat_sn++;
3562*4882a593Smuzhiyun hdr->statsn = cpu_to_be32(cmd->stat_sn);
3563*4882a593Smuzhiyun hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
3564*4882a593Smuzhiyun hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn));
3565*4882a593Smuzhiyun
3566*4882a593Smuzhiyun }
3567*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_build_reject);
3568*4882a593Smuzhiyun
iscsit_send_reject(struct iscsi_cmd * cmd,struct iscsi_conn * conn)3569*4882a593Smuzhiyun static int iscsit_send_reject(
3570*4882a593Smuzhiyun struct iscsi_cmd *cmd,
3571*4882a593Smuzhiyun struct iscsi_conn *conn)
3572*4882a593Smuzhiyun {
3573*4882a593Smuzhiyun struct iscsi_reject *hdr = (struct iscsi_reject *)&cmd->pdu[0];
3574*4882a593Smuzhiyun
3575*4882a593Smuzhiyun iscsit_build_reject(cmd, conn, hdr);
3576*4882a593Smuzhiyun
3577*4882a593Smuzhiyun pr_debug("Built Reject PDU StatSN: 0x%08x, Reason: 0x%02x,"
3578*4882a593Smuzhiyun " CID: %hu\n", ntohl(hdr->statsn), hdr->reason, conn->cid);
3579*4882a593Smuzhiyun
3580*4882a593Smuzhiyun return conn->conn_transport->iscsit_xmit_pdu(conn, cmd, NULL,
3581*4882a593Smuzhiyun cmd->buf_ptr,
3582*4882a593Smuzhiyun ISCSI_HDR_LEN);
3583*4882a593Smuzhiyun }
3584*4882a593Smuzhiyun
iscsit_thread_get_cpumask(struct iscsi_conn * conn)3585*4882a593Smuzhiyun void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
3586*4882a593Smuzhiyun {
3587*4882a593Smuzhiyun int ord, cpu;
3588*4882a593Smuzhiyun /*
3589*4882a593Smuzhiyun * bitmap_id is assigned from iscsit_global->ts_bitmap from
3590*4882a593Smuzhiyun * within iscsit_start_kthreads()
3591*4882a593Smuzhiyun *
3592*4882a593Smuzhiyun * Here we use bitmap_id to determine which CPU that this
3593*4882a593Smuzhiyun * iSCSI connection's RX/TX threads will be scheduled to
3594*4882a593Smuzhiyun * execute upon.
3595*4882a593Smuzhiyun */
3596*4882a593Smuzhiyun ord = conn->bitmap_id % cpumask_weight(cpu_online_mask);
3597*4882a593Smuzhiyun for_each_online_cpu(cpu) {
3598*4882a593Smuzhiyun if (ord-- == 0) {
3599*4882a593Smuzhiyun cpumask_set_cpu(cpu, conn->conn_cpumask);
3600*4882a593Smuzhiyun return;
3601*4882a593Smuzhiyun }
3602*4882a593Smuzhiyun }
3603*4882a593Smuzhiyun /*
3604*4882a593Smuzhiyun * This should never be reached..
3605*4882a593Smuzhiyun */
3606*4882a593Smuzhiyun dump_stack();
3607*4882a593Smuzhiyun cpumask_setall(conn->conn_cpumask);
3608*4882a593Smuzhiyun }
3609*4882a593Smuzhiyun
3610*4882a593Smuzhiyun int
iscsit_immediate_queue(struct iscsi_conn * conn,struct iscsi_cmd * cmd,int state)3611*4882a593Smuzhiyun iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
3612*4882a593Smuzhiyun {
3613*4882a593Smuzhiyun int ret;
3614*4882a593Smuzhiyun
3615*4882a593Smuzhiyun switch (state) {
3616*4882a593Smuzhiyun case ISTATE_SEND_R2T:
3617*4882a593Smuzhiyun ret = iscsit_send_r2t(cmd, conn);
3618*4882a593Smuzhiyun if (ret < 0)
3619*4882a593Smuzhiyun goto err;
3620*4882a593Smuzhiyun break;
3621*4882a593Smuzhiyun case ISTATE_REMOVE:
3622*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
3623*4882a593Smuzhiyun list_del_init(&cmd->i_conn_node);
3624*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
3625*4882a593Smuzhiyun
3626*4882a593Smuzhiyun iscsit_free_cmd(cmd, false);
3627*4882a593Smuzhiyun break;
3628*4882a593Smuzhiyun case ISTATE_SEND_NOPIN_WANT_RESPONSE:
3629*4882a593Smuzhiyun iscsit_mod_nopin_response_timer(conn);
3630*4882a593Smuzhiyun ret = iscsit_send_unsolicited_nopin(cmd, conn, 1);
3631*4882a593Smuzhiyun if (ret < 0)
3632*4882a593Smuzhiyun goto err;
3633*4882a593Smuzhiyun break;
3634*4882a593Smuzhiyun case ISTATE_SEND_NOPIN_NO_RESPONSE:
3635*4882a593Smuzhiyun ret = iscsit_send_unsolicited_nopin(cmd, conn, 0);
3636*4882a593Smuzhiyun if (ret < 0)
3637*4882a593Smuzhiyun goto err;
3638*4882a593Smuzhiyun break;
3639*4882a593Smuzhiyun default:
3640*4882a593Smuzhiyun pr_err("Unknown Opcode: 0x%02x ITT:"
3641*4882a593Smuzhiyun " 0x%08x, i_state: %d on CID: %hu\n",
3642*4882a593Smuzhiyun cmd->iscsi_opcode, cmd->init_task_tag, state,
3643*4882a593Smuzhiyun conn->cid);
3644*4882a593Smuzhiyun goto err;
3645*4882a593Smuzhiyun }
3646*4882a593Smuzhiyun
3647*4882a593Smuzhiyun return 0;
3648*4882a593Smuzhiyun
3649*4882a593Smuzhiyun err:
3650*4882a593Smuzhiyun return -1;
3651*4882a593Smuzhiyun }
3652*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_immediate_queue);
3653*4882a593Smuzhiyun
3654*4882a593Smuzhiyun static int
iscsit_handle_immediate_queue(struct iscsi_conn * conn)3655*4882a593Smuzhiyun iscsit_handle_immediate_queue(struct iscsi_conn *conn)
3656*4882a593Smuzhiyun {
3657*4882a593Smuzhiyun struct iscsit_transport *t = conn->conn_transport;
3658*4882a593Smuzhiyun struct iscsi_queue_req *qr;
3659*4882a593Smuzhiyun struct iscsi_cmd *cmd;
3660*4882a593Smuzhiyun u8 state;
3661*4882a593Smuzhiyun int ret;
3662*4882a593Smuzhiyun
3663*4882a593Smuzhiyun while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
3664*4882a593Smuzhiyun atomic_set(&conn->check_immediate_queue, 0);
3665*4882a593Smuzhiyun cmd = qr->cmd;
3666*4882a593Smuzhiyun state = qr->state;
3667*4882a593Smuzhiyun kmem_cache_free(lio_qr_cache, qr);
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun ret = t->iscsit_immediate_queue(conn, cmd, state);
3670*4882a593Smuzhiyun if (ret < 0)
3671*4882a593Smuzhiyun return ret;
3672*4882a593Smuzhiyun }
3673*4882a593Smuzhiyun
3674*4882a593Smuzhiyun return 0;
3675*4882a593Smuzhiyun }
3676*4882a593Smuzhiyun
3677*4882a593Smuzhiyun int
iscsit_response_queue(struct iscsi_conn * conn,struct iscsi_cmd * cmd,int state)3678*4882a593Smuzhiyun iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
3679*4882a593Smuzhiyun {
3680*4882a593Smuzhiyun int ret;
3681*4882a593Smuzhiyun
3682*4882a593Smuzhiyun check_rsp_state:
3683*4882a593Smuzhiyun switch (state) {
3684*4882a593Smuzhiyun case ISTATE_SEND_DATAIN:
3685*4882a593Smuzhiyun ret = iscsit_send_datain(cmd, conn);
3686*4882a593Smuzhiyun if (ret < 0)
3687*4882a593Smuzhiyun goto err;
3688*4882a593Smuzhiyun else if (!ret)
3689*4882a593Smuzhiyun /* more drs */
3690*4882a593Smuzhiyun goto check_rsp_state;
3691*4882a593Smuzhiyun else if (ret == 1) {
3692*4882a593Smuzhiyun /* all done */
3693*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
3694*4882a593Smuzhiyun cmd->i_state = ISTATE_SENT_STATUS;
3695*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
3696*4882a593Smuzhiyun
3697*4882a593Smuzhiyun if (atomic_read(&conn->check_immediate_queue))
3698*4882a593Smuzhiyun return 1;
3699*4882a593Smuzhiyun
3700*4882a593Smuzhiyun return 0;
3701*4882a593Smuzhiyun } else if (ret == 2) {
3702*4882a593Smuzhiyun /* Still must send status,
3703*4882a593Smuzhiyun SCF_TRANSPORT_TASK_SENSE was set */
3704*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
3705*4882a593Smuzhiyun cmd->i_state = ISTATE_SEND_STATUS;
3706*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
3707*4882a593Smuzhiyun state = ISTATE_SEND_STATUS;
3708*4882a593Smuzhiyun goto check_rsp_state;
3709*4882a593Smuzhiyun }
3710*4882a593Smuzhiyun
3711*4882a593Smuzhiyun break;
3712*4882a593Smuzhiyun case ISTATE_SEND_STATUS:
3713*4882a593Smuzhiyun case ISTATE_SEND_STATUS_RECOVERY:
3714*4882a593Smuzhiyun ret = iscsit_send_response(cmd, conn);
3715*4882a593Smuzhiyun break;
3716*4882a593Smuzhiyun case ISTATE_SEND_LOGOUTRSP:
3717*4882a593Smuzhiyun ret = iscsit_send_logout(cmd, conn);
3718*4882a593Smuzhiyun break;
3719*4882a593Smuzhiyun case ISTATE_SEND_ASYNCMSG:
3720*4882a593Smuzhiyun ret = iscsit_send_conn_drop_async_message(
3721*4882a593Smuzhiyun cmd, conn);
3722*4882a593Smuzhiyun break;
3723*4882a593Smuzhiyun case ISTATE_SEND_NOPIN:
3724*4882a593Smuzhiyun ret = iscsit_send_nopin(cmd, conn);
3725*4882a593Smuzhiyun break;
3726*4882a593Smuzhiyun case ISTATE_SEND_REJECT:
3727*4882a593Smuzhiyun ret = iscsit_send_reject(cmd, conn);
3728*4882a593Smuzhiyun break;
3729*4882a593Smuzhiyun case ISTATE_SEND_TASKMGTRSP:
3730*4882a593Smuzhiyun ret = iscsit_send_task_mgt_rsp(cmd, conn);
3731*4882a593Smuzhiyun if (ret != 0)
3732*4882a593Smuzhiyun break;
3733*4882a593Smuzhiyun ret = iscsit_tmr_post_handler(cmd, conn);
3734*4882a593Smuzhiyun if (ret != 0)
3735*4882a593Smuzhiyun iscsit_fall_back_to_erl0(conn->sess);
3736*4882a593Smuzhiyun break;
3737*4882a593Smuzhiyun case ISTATE_SEND_TEXTRSP:
3738*4882a593Smuzhiyun ret = iscsit_send_text_rsp(cmd, conn);
3739*4882a593Smuzhiyun break;
3740*4882a593Smuzhiyun default:
3741*4882a593Smuzhiyun pr_err("Unknown Opcode: 0x%02x ITT:"
3742*4882a593Smuzhiyun " 0x%08x, i_state: %d on CID: %hu\n",
3743*4882a593Smuzhiyun cmd->iscsi_opcode, cmd->init_task_tag,
3744*4882a593Smuzhiyun state, conn->cid);
3745*4882a593Smuzhiyun goto err;
3746*4882a593Smuzhiyun }
3747*4882a593Smuzhiyun if (ret < 0)
3748*4882a593Smuzhiyun goto err;
3749*4882a593Smuzhiyun
3750*4882a593Smuzhiyun switch (state) {
3751*4882a593Smuzhiyun case ISTATE_SEND_LOGOUTRSP:
3752*4882a593Smuzhiyun if (!iscsit_logout_post_handler(cmd, conn))
3753*4882a593Smuzhiyun return -ECONNRESET;
3754*4882a593Smuzhiyun fallthrough;
3755*4882a593Smuzhiyun case ISTATE_SEND_STATUS:
3756*4882a593Smuzhiyun case ISTATE_SEND_ASYNCMSG:
3757*4882a593Smuzhiyun case ISTATE_SEND_NOPIN:
3758*4882a593Smuzhiyun case ISTATE_SEND_STATUS_RECOVERY:
3759*4882a593Smuzhiyun case ISTATE_SEND_TEXTRSP:
3760*4882a593Smuzhiyun case ISTATE_SEND_TASKMGTRSP:
3761*4882a593Smuzhiyun case ISTATE_SEND_REJECT:
3762*4882a593Smuzhiyun spin_lock_bh(&cmd->istate_lock);
3763*4882a593Smuzhiyun cmd->i_state = ISTATE_SENT_STATUS;
3764*4882a593Smuzhiyun spin_unlock_bh(&cmd->istate_lock);
3765*4882a593Smuzhiyun break;
3766*4882a593Smuzhiyun default:
3767*4882a593Smuzhiyun pr_err("Unknown Opcode: 0x%02x ITT:"
3768*4882a593Smuzhiyun " 0x%08x, i_state: %d on CID: %hu\n",
3769*4882a593Smuzhiyun cmd->iscsi_opcode, cmd->init_task_tag,
3770*4882a593Smuzhiyun cmd->i_state, conn->cid);
3771*4882a593Smuzhiyun goto err;
3772*4882a593Smuzhiyun }
3773*4882a593Smuzhiyun
3774*4882a593Smuzhiyun if (atomic_read(&conn->check_immediate_queue))
3775*4882a593Smuzhiyun return 1;
3776*4882a593Smuzhiyun
3777*4882a593Smuzhiyun return 0;
3778*4882a593Smuzhiyun
3779*4882a593Smuzhiyun err:
3780*4882a593Smuzhiyun return -1;
3781*4882a593Smuzhiyun }
3782*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_response_queue);
3783*4882a593Smuzhiyun
iscsit_handle_response_queue(struct iscsi_conn * conn)3784*4882a593Smuzhiyun static int iscsit_handle_response_queue(struct iscsi_conn *conn)
3785*4882a593Smuzhiyun {
3786*4882a593Smuzhiyun struct iscsit_transport *t = conn->conn_transport;
3787*4882a593Smuzhiyun struct iscsi_queue_req *qr;
3788*4882a593Smuzhiyun struct iscsi_cmd *cmd;
3789*4882a593Smuzhiyun u8 state;
3790*4882a593Smuzhiyun int ret;
3791*4882a593Smuzhiyun
3792*4882a593Smuzhiyun while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
3793*4882a593Smuzhiyun cmd = qr->cmd;
3794*4882a593Smuzhiyun state = qr->state;
3795*4882a593Smuzhiyun kmem_cache_free(lio_qr_cache, qr);
3796*4882a593Smuzhiyun
3797*4882a593Smuzhiyun ret = t->iscsit_response_queue(conn, cmd, state);
3798*4882a593Smuzhiyun if (ret == 1 || ret < 0)
3799*4882a593Smuzhiyun return ret;
3800*4882a593Smuzhiyun }
3801*4882a593Smuzhiyun
3802*4882a593Smuzhiyun return 0;
3803*4882a593Smuzhiyun }
3804*4882a593Smuzhiyun
iscsi_target_tx_thread(void * arg)3805*4882a593Smuzhiyun int iscsi_target_tx_thread(void *arg)
3806*4882a593Smuzhiyun {
3807*4882a593Smuzhiyun int ret = 0;
3808*4882a593Smuzhiyun struct iscsi_conn *conn = arg;
3809*4882a593Smuzhiyun bool conn_freed = false;
3810*4882a593Smuzhiyun
3811*4882a593Smuzhiyun /*
3812*4882a593Smuzhiyun * Allow ourselves to be interrupted by SIGINT so that a
3813*4882a593Smuzhiyun * connection recovery / failure event can be triggered externally.
3814*4882a593Smuzhiyun */
3815*4882a593Smuzhiyun allow_signal(SIGINT);
3816*4882a593Smuzhiyun
3817*4882a593Smuzhiyun while (!kthread_should_stop()) {
3818*4882a593Smuzhiyun /*
3819*4882a593Smuzhiyun * Ensure that both TX and RX per connection kthreads
3820*4882a593Smuzhiyun * are scheduled to run on the same CPU.
3821*4882a593Smuzhiyun */
3822*4882a593Smuzhiyun iscsit_thread_check_cpumask(conn, current, 1);
3823*4882a593Smuzhiyun
3824*4882a593Smuzhiyun wait_event_interruptible(conn->queues_wq,
3825*4882a593Smuzhiyun !iscsit_conn_all_queues_empty(conn));
3826*4882a593Smuzhiyun
3827*4882a593Smuzhiyun if (signal_pending(current))
3828*4882a593Smuzhiyun goto transport_err;
3829*4882a593Smuzhiyun
3830*4882a593Smuzhiyun get_immediate:
3831*4882a593Smuzhiyun ret = iscsit_handle_immediate_queue(conn);
3832*4882a593Smuzhiyun if (ret < 0)
3833*4882a593Smuzhiyun goto transport_err;
3834*4882a593Smuzhiyun
3835*4882a593Smuzhiyun ret = iscsit_handle_response_queue(conn);
3836*4882a593Smuzhiyun if (ret == 1) {
3837*4882a593Smuzhiyun goto get_immediate;
3838*4882a593Smuzhiyun } else if (ret == -ECONNRESET) {
3839*4882a593Smuzhiyun conn_freed = true;
3840*4882a593Smuzhiyun goto out;
3841*4882a593Smuzhiyun } else if (ret < 0) {
3842*4882a593Smuzhiyun goto transport_err;
3843*4882a593Smuzhiyun }
3844*4882a593Smuzhiyun }
3845*4882a593Smuzhiyun
3846*4882a593Smuzhiyun transport_err:
3847*4882a593Smuzhiyun /*
3848*4882a593Smuzhiyun * Avoid the normal connection failure code-path if this connection
3849*4882a593Smuzhiyun * is still within LOGIN mode, and iscsi_np process context is
3850*4882a593Smuzhiyun * responsible for cleaning up the early connection failure.
3851*4882a593Smuzhiyun */
3852*4882a593Smuzhiyun if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
3853*4882a593Smuzhiyun iscsit_take_action_for_connection_exit(conn, &conn_freed);
3854*4882a593Smuzhiyun out:
3855*4882a593Smuzhiyun if (!conn_freed) {
3856*4882a593Smuzhiyun while (!kthread_should_stop()) {
3857*4882a593Smuzhiyun msleep(100);
3858*4882a593Smuzhiyun }
3859*4882a593Smuzhiyun }
3860*4882a593Smuzhiyun return 0;
3861*4882a593Smuzhiyun }
3862*4882a593Smuzhiyun
iscsi_target_rx_opcode(struct iscsi_conn * conn,unsigned char * buf)3863*4882a593Smuzhiyun static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
3864*4882a593Smuzhiyun {
3865*4882a593Smuzhiyun struct iscsi_hdr *hdr = (struct iscsi_hdr *)buf;
3866*4882a593Smuzhiyun struct iscsi_cmd *cmd;
3867*4882a593Smuzhiyun int ret = 0;
3868*4882a593Smuzhiyun
3869*4882a593Smuzhiyun switch (hdr->opcode & ISCSI_OPCODE_MASK) {
3870*4882a593Smuzhiyun case ISCSI_OP_SCSI_CMD:
3871*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
3872*4882a593Smuzhiyun if (!cmd)
3873*4882a593Smuzhiyun goto reject;
3874*4882a593Smuzhiyun
3875*4882a593Smuzhiyun ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
3876*4882a593Smuzhiyun break;
3877*4882a593Smuzhiyun case ISCSI_OP_SCSI_DATA_OUT:
3878*4882a593Smuzhiyun ret = iscsit_handle_data_out(conn, buf);
3879*4882a593Smuzhiyun break;
3880*4882a593Smuzhiyun case ISCSI_OP_NOOP_OUT:
3881*4882a593Smuzhiyun cmd = NULL;
3882*4882a593Smuzhiyun if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
3883*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
3884*4882a593Smuzhiyun if (!cmd)
3885*4882a593Smuzhiyun goto reject;
3886*4882a593Smuzhiyun }
3887*4882a593Smuzhiyun ret = iscsit_handle_nop_out(conn, cmd, buf);
3888*4882a593Smuzhiyun break;
3889*4882a593Smuzhiyun case ISCSI_OP_SCSI_TMFUNC:
3890*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
3891*4882a593Smuzhiyun if (!cmd)
3892*4882a593Smuzhiyun goto reject;
3893*4882a593Smuzhiyun
3894*4882a593Smuzhiyun ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
3895*4882a593Smuzhiyun break;
3896*4882a593Smuzhiyun case ISCSI_OP_TEXT:
3897*4882a593Smuzhiyun if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
3898*4882a593Smuzhiyun cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
3899*4882a593Smuzhiyun if (!cmd)
3900*4882a593Smuzhiyun goto reject;
3901*4882a593Smuzhiyun } else {
3902*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
3903*4882a593Smuzhiyun if (!cmd)
3904*4882a593Smuzhiyun goto reject;
3905*4882a593Smuzhiyun }
3906*4882a593Smuzhiyun
3907*4882a593Smuzhiyun ret = iscsit_handle_text_cmd(conn, cmd, buf);
3908*4882a593Smuzhiyun break;
3909*4882a593Smuzhiyun case ISCSI_OP_LOGOUT:
3910*4882a593Smuzhiyun cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
3911*4882a593Smuzhiyun if (!cmd)
3912*4882a593Smuzhiyun goto reject;
3913*4882a593Smuzhiyun
3914*4882a593Smuzhiyun ret = iscsit_handle_logout_cmd(conn, cmd, buf);
3915*4882a593Smuzhiyun if (ret > 0)
3916*4882a593Smuzhiyun wait_for_completion_timeout(&conn->conn_logout_comp,
3917*4882a593Smuzhiyun SECONDS_FOR_LOGOUT_COMP * HZ);
3918*4882a593Smuzhiyun break;
3919*4882a593Smuzhiyun case ISCSI_OP_SNACK:
3920*4882a593Smuzhiyun ret = iscsit_handle_snack(conn, buf);
3921*4882a593Smuzhiyun break;
3922*4882a593Smuzhiyun default:
3923*4882a593Smuzhiyun pr_err("Got unknown iSCSI OpCode: 0x%02x\n", hdr->opcode);
3924*4882a593Smuzhiyun if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
3925*4882a593Smuzhiyun pr_err("Cannot recover from unknown"
3926*4882a593Smuzhiyun " opcode while ERL=0, closing iSCSI connection.\n");
3927*4882a593Smuzhiyun return -1;
3928*4882a593Smuzhiyun }
3929*4882a593Smuzhiyun pr_err("Unable to recover from unknown opcode while OFMarker=No,"
3930*4882a593Smuzhiyun " closing iSCSI connection.\n");
3931*4882a593Smuzhiyun ret = -1;
3932*4882a593Smuzhiyun break;
3933*4882a593Smuzhiyun }
3934*4882a593Smuzhiyun
3935*4882a593Smuzhiyun return ret;
3936*4882a593Smuzhiyun reject:
3937*4882a593Smuzhiyun return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
3938*4882a593Smuzhiyun }
3939*4882a593Smuzhiyun
iscsi_target_check_conn_state(struct iscsi_conn * conn)3940*4882a593Smuzhiyun static bool iscsi_target_check_conn_state(struct iscsi_conn *conn)
3941*4882a593Smuzhiyun {
3942*4882a593Smuzhiyun bool ret;
3943*4882a593Smuzhiyun
3944*4882a593Smuzhiyun spin_lock_bh(&conn->state_lock);
3945*4882a593Smuzhiyun ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN);
3946*4882a593Smuzhiyun spin_unlock_bh(&conn->state_lock);
3947*4882a593Smuzhiyun
3948*4882a593Smuzhiyun return ret;
3949*4882a593Smuzhiyun }
3950*4882a593Smuzhiyun
iscsit_get_rx_pdu(struct iscsi_conn * conn)3951*4882a593Smuzhiyun static void iscsit_get_rx_pdu(struct iscsi_conn *conn)
3952*4882a593Smuzhiyun {
3953*4882a593Smuzhiyun int ret;
3954*4882a593Smuzhiyun u8 *buffer, opcode;
3955*4882a593Smuzhiyun u32 checksum = 0, digest = 0;
3956*4882a593Smuzhiyun struct kvec iov;
3957*4882a593Smuzhiyun
3958*4882a593Smuzhiyun buffer = kcalloc(ISCSI_HDR_LEN, sizeof(*buffer), GFP_KERNEL);
3959*4882a593Smuzhiyun if (!buffer)
3960*4882a593Smuzhiyun return;
3961*4882a593Smuzhiyun
3962*4882a593Smuzhiyun while (!kthread_should_stop()) {
3963*4882a593Smuzhiyun /*
3964*4882a593Smuzhiyun * Ensure that both TX and RX per connection kthreads
3965*4882a593Smuzhiyun * are scheduled to run on the same CPU.
3966*4882a593Smuzhiyun */
3967*4882a593Smuzhiyun iscsit_thread_check_cpumask(conn, current, 0);
3968*4882a593Smuzhiyun
3969*4882a593Smuzhiyun memset(&iov, 0, sizeof(struct kvec));
3970*4882a593Smuzhiyun
3971*4882a593Smuzhiyun iov.iov_base = buffer;
3972*4882a593Smuzhiyun iov.iov_len = ISCSI_HDR_LEN;
3973*4882a593Smuzhiyun
3974*4882a593Smuzhiyun ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN);
3975*4882a593Smuzhiyun if (ret != ISCSI_HDR_LEN) {
3976*4882a593Smuzhiyun iscsit_rx_thread_wait_for_tcp(conn);
3977*4882a593Smuzhiyun break;
3978*4882a593Smuzhiyun }
3979*4882a593Smuzhiyun
3980*4882a593Smuzhiyun if (conn->conn_ops->HeaderDigest) {
3981*4882a593Smuzhiyun iov.iov_base = &digest;
3982*4882a593Smuzhiyun iov.iov_len = ISCSI_CRC_LEN;
3983*4882a593Smuzhiyun
3984*4882a593Smuzhiyun ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN);
3985*4882a593Smuzhiyun if (ret != ISCSI_CRC_LEN) {
3986*4882a593Smuzhiyun iscsit_rx_thread_wait_for_tcp(conn);
3987*4882a593Smuzhiyun break;
3988*4882a593Smuzhiyun }
3989*4882a593Smuzhiyun
3990*4882a593Smuzhiyun iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer,
3991*4882a593Smuzhiyun ISCSI_HDR_LEN, 0, NULL,
3992*4882a593Smuzhiyun &checksum);
3993*4882a593Smuzhiyun
3994*4882a593Smuzhiyun if (digest != checksum) {
3995*4882a593Smuzhiyun pr_err("HeaderDigest CRC32C failed,"
3996*4882a593Smuzhiyun " received 0x%08x, computed 0x%08x\n",
3997*4882a593Smuzhiyun digest, checksum);
3998*4882a593Smuzhiyun /*
3999*4882a593Smuzhiyun * Set the PDU to 0xff so it will intentionally
4000*4882a593Smuzhiyun * hit default in the switch below.
4001*4882a593Smuzhiyun */
4002*4882a593Smuzhiyun memset(buffer, 0xff, ISCSI_HDR_LEN);
4003*4882a593Smuzhiyun atomic_long_inc(&conn->sess->conn_digest_errors);
4004*4882a593Smuzhiyun } else {
4005*4882a593Smuzhiyun pr_debug("Got HeaderDigest CRC32C"
4006*4882a593Smuzhiyun " 0x%08x\n", checksum);
4007*4882a593Smuzhiyun }
4008*4882a593Smuzhiyun }
4009*4882a593Smuzhiyun
4010*4882a593Smuzhiyun if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT)
4011*4882a593Smuzhiyun break;
4012*4882a593Smuzhiyun
4013*4882a593Smuzhiyun opcode = buffer[0] & ISCSI_OPCODE_MASK;
4014*4882a593Smuzhiyun
4015*4882a593Smuzhiyun if (conn->sess->sess_ops->SessionType &&
4016*4882a593Smuzhiyun ((!(opcode & ISCSI_OP_TEXT)) ||
4017*4882a593Smuzhiyun (!(opcode & ISCSI_OP_LOGOUT)))) {
4018*4882a593Smuzhiyun pr_err("Received illegal iSCSI Opcode: 0x%02x"
4019*4882a593Smuzhiyun " while in Discovery Session, rejecting.\n", opcode);
4020*4882a593Smuzhiyun iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
4021*4882a593Smuzhiyun buffer);
4022*4882a593Smuzhiyun break;
4023*4882a593Smuzhiyun }
4024*4882a593Smuzhiyun
4025*4882a593Smuzhiyun ret = iscsi_target_rx_opcode(conn, buffer);
4026*4882a593Smuzhiyun if (ret < 0)
4027*4882a593Smuzhiyun break;
4028*4882a593Smuzhiyun }
4029*4882a593Smuzhiyun
4030*4882a593Smuzhiyun kfree(buffer);
4031*4882a593Smuzhiyun }
4032*4882a593Smuzhiyun
iscsi_target_rx_thread(void * arg)4033*4882a593Smuzhiyun int iscsi_target_rx_thread(void *arg)
4034*4882a593Smuzhiyun {
4035*4882a593Smuzhiyun int rc;
4036*4882a593Smuzhiyun struct iscsi_conn *conn = arg;
4037*4882a593Smuzhiyun bool conn_freed = false;
4038*4882a593Smuzhiyun
4039*4882a593Smuzhiyun /*
4040*4882a593Smuzhiyun * Allow ourselves to be interrupted by SIGINT so that a
4041*4882a593Smuzhiyun * connection recovery / failure event can be triggered externally.
4042*4882a593Smuzhiyun */
4043*4882a593Smuzhiyun allow_signal(SIGINT);
4044*4882a593Smuzhiyun /*
4045*4882a593Smuzhiyun * Wait for iscsi_post_login_handler() to complete before allowing
4046*4882a593Smuzhiyun * incoming iscsi/tcp socket I/O, and/or failing the connection.
4047*4882a593Smuzhiyun */
4048*4882a593Smuzhiyun rc = wait_for_completion_interruptible(&conn->rx_login_comp);
4049*4882a593Smuzhiyun if (rc < 0 || iscsi_target_check_conn_state(conn))
4050*4882a593Smuzhiyun goto out;
4051*4882a593Smuzhiyun
4052*4882a593Smuzhiyun if (!conn->conn_transport->iscsit_get_rx_pdu)
4053*4882a593Smuzhiyun return 0;
4054*4882a593Smuzhiyun
4055*4882a593Smuzhiyun conn->conn_transport->iscsit_get_rx_pdu(conn);
4056*4882a593Smuzhiyun
4057*4882a593Smuzhiyun if (!signal_pending(current))
4058*4882a593Smuzhiyun atomic_set(&conn->transport_failed, 1);
4059*4882a593Smuzhiyun iscsit_take_action_for_connection_exit(conn, &conn_freed);
4060*4882a593Smuzhiyun
4061*4882a593Smuzhiyun out:
4062*4882a593Smuzhiyun if (!conn_freed) {
4063*4882a593Smuzhiyun while (!kthread_should_stop()) {
4064*4882a593Smuzhiyun msleep(100);
4065*4882a593Smuzhiyun }
4066*4882a593Smuzhiyun }
4067*4882a593Smuzhiyun
4068*4882a593Smuzhiyun return 0;
4069*4882a593Smuzhiyun }
4070*4882a593Smuzhiyun
iscsit_release_commands_from_conn(struct iscsi_conn * conn)4071*4882a593Smuzhiyun static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
4072*4882a593Smuzhiyun {
4073*4882a593Smuzhiyun LIST_HEAD(tmp_list);
4074*4882a593Smuzhiyun struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL;
4075*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
4076*4882a593Smuzhiyun /*
4077*4882a593Smuzhiyun * We expect this function to only ever be called from either RX or TX
4078*4882a593Smuzhiyun * thread context via iscsit_close_connection() once the other context
4079*4882a593Smuzhiyun * has been reset -> returned sleeping pre-handler state.
4080*4882a593Smuzhiyun */
4081*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
4082*4882a593Smuzhiyun list_splice_init(&conn->conn_cmd_list, &tmp_list);
4083*4882a593Smuzhiyun
4084*4882a593Smuzhiyun list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
4085*4882a593Smuzhiyun struct se_cmd *se_cmd = &cmd->se_cmd;
4086*4882a593Smuzhiyun
4087*4882a593Smuzhiyun if (se_cmd->se_tfo != NULL) {
4088*4882a593Smuzhiyun spin_lock_irq(&se_cmd->t_state_lock);
4089*4882a593Smuzhiyun if (se_cmd->transport_state & CMD_T_ABORTED) {
4090*4882a593Smuzhiyun /*
4091*4882a593Smuzhiyun * LIO's abort path owns the cleanup for this,
4092*4882a593Smuzhiyun * so put it back on the list and let
4093*4882a593Smuzhiyun * aborted_task handle it.
4094*4882a593Smuzhiyun */
4095*4882a593Smuzhiyun list_move_tail(&cmd->i_conn_node,
4096*4882a593Smuzhiyun &conn->conn_cmd_list);
4097*4882a593Smuzhiyun } else {
4098*4882a593Smuzhiyun se_cmd->transport_state |= CMD_T_FABRIC_STOP;
4099*4882a593Smuzhiyun }
4100*4882a593Smuzhiyun spin_unlock_irq(&se_cmd->t_state_lock);
4101*4882a593Smuzhiyun }
4102*4882a593Smuzhiyun }
4103*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
4104*4882a593Smuzhiyun
4105*4882a593Smuzhiyun list_for_each_entry_safe(cmd, cmd_tmp, &tmp_list, i_conn_node) {
4106*4882a593Smuzhiyun list_del_init(&cmd->i_conn_node);
4107*4882a593Smuzhiyun
4108*4882a593Smuzhiyun iscsit_increment_maxcmdsn(cmd, sess);
4109*4882a593Smuzhiyun iscsit_free_cmd(cmd, true);
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun }
4112*4882a593Smuzhiyun }
4113*4882a593Smuzhiyun
iscsit_stop_timers_for_cmds(struct iscsi_conn * conn)4114*4882a593Smuzhiyun static void iscsit_stop_timers_for_cmds(
4115*4882a593Smuzhiyun struct iscsi_conn *conn)
4116*4882a593Smuzhiyun {
4117*4882a593Smuzhiyun struct iscsi_cmd *cmd;
4118*4882a593Smuzhiyun
4119*4882a593Smuzhiyun spin_lock_bh(&conn->cmd_lock);
4120*4882a593Smuzhiyun list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
4121*4882a593Smuzhiyun if (cmd->data_direction == DMA_TO_DEVICE)
4122*4882a593Smuzhiyun iscsit_stop_dataout_timer(cmd);
4123*4882a593Smuzhiyun }
4124*4882a593Smuzhiyun spin_unlock_bh(&conn->cmd_lock);
4125*4882a593Smuzhiyun }
4126*4882a593Smuzhiyun
iscsit_close_connection(struct iscsi_conn * conn)4127*4882a593Smuzhiyun int iscsit_close_connection(
4128*4882a593Smuzhiyun struct iscsi_conn *conn)
4129*4882a593Smuzhiyun {
4130*4882a593Smuzhiyun int conn_logout = (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT);
4131*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
4132*4882a593Smuzhiyun
4133*4882a593Smuzhiyun pr_debug("Closing iSCSI connection CID %hu on SID:"
4134*4882a593Smuzhiyun " %u\n", conn->cid, sess->sid);
4135*4882a593Smuzhiyun /*
4136*4882a593Smuzhiyun * Always up conn_logout_comp for the traditional TCP and HW_OFFLOAD
4137*4882a593Smuzhiyun * case just in case the RX Thread in iscsi_target_rx_opcode() is
4138*4882a593Smuzhiyun * sleeping and the logout response never got sent because the
4139*4882a593Smuzhiyun * connection failed.
4140*4882a593Smuzhiyun *
4141*4882a593Smuzhiyun * However for iser-target, isert_wait4logout() is using conn_logout_comp
4142*4882a593Smuzhiyun * to signal logout response TX interrupt completion. Go ahead and skip
4143*4882a593Smuzhiyun * this for iser since isert_rx_opcode() does not wait on logout failure,
4144*4882a593Smuzhiyun * and to avoid iscsi_conn pointer dereference in iser-target code.
4145*4882a593Smuzhiyun */
4146*4882a593Smuzhiyun if (!conn->conn_transport->rdma_shutdown)
4147*4882a593Smuzhiyun complete(&conn->conn_logout_comp);
4148*4882a593Smuzhiyun
4149*4882a593Smuzhiyun if (!strcmp(current->comm, ISCSI_RX_THREAD_NAME)) {
4150*4882a593Smuzhiyun if (conn->tx_thread &&
4151*4882a593Smuzhiyun cmpxchg(&conn->tx_thread_active, true, false)) {
4152*4882a593Smuzhiyun send_sig(SIGINT, conn->tx_thread, 1);
4153*4882a593Smuzhiyun kthread_stop(conn->tx_thread);
4154*4882a593Smuzhiyun }
4155*4882a593Smuzhiyun } else if (!strcmp(current->comm, ISCSI_TX_THREAD_NAME)) {
4156*4882a593Smuzhiyun if (conn->rx_thread &&
4157*4882a593Smuzhiyun cmpxchg(&conn->rx_thread_active, true, false)) {
4158*4882a593Smuzhiyun send_sig(SIGINT, conn->rx_thread, 1);
4159*4882a593Smuzhiyun kthread_stop(conn->rx_thread);
4160*4882a593Smuzhiyun }
4161*4882a593Smuzhiyun }
4162*4882a593Smuzhiyun
4163*4882a593Smuzhiyun spin_lock(&iscsit_global->ts_bitmap_lock);
4164*4882a593Smuzhiyun bitmap_release_region(iscsit_global->ts_bitmap, conn->bitmap_id,
4165*4882a593Smuzhiyun get_order(1));
4166*4882a593Smuzhiyun spin_unlock(&iscsit_global->ts_bitmap_lock);
4167*4882a593Smuzhiyun
4168*4882a593Smuzhiyun iscsit_stop_timers_for_cmds(conn);
4169*4882a593Smuzhiyun iscsit_stop_nopin_response_timer(conn);
4170*4882a593Smuzhiyun iscsit_stop_nopin_timer(conn);
4171*4882a593Smuzhiyun
4172*4882a593Smuzhiyun if (conn->conn_transport->iscsit_wait_conn)
4173*4882a593Smuzhiyun conn->conn_transport->iscsit_wait_conn(conn);
4174*4882a593Smuzhiyun
4175*4882a593Smuzhiyun /*
4176*4882a593Smuzhiyun * During Connection recovery drop unacknowledged out of order
4177*4882a593Smuzhiyun * commands for this connection, and prepare the other commands
4178*4882a593Smuzhiyun * for reallegiance.
4179*4882a593Smuzhiyun *
4180*4882a593Smuzhiyun * During normal operation clear the out of order commands (but
4181*4882a593Smuzhiyun * do not free the struct iscsi_ooo_cmdsn's) and release all
4182*4882a593Smuzhiyun * struct iscsi_cmds.
4183*4882a593Smuzhiyun */
4184*4882a593Smuzhiyun if (atomic_read(&conn->connection_recovery)) {
4185*4882a593Smuzhiyun iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(conn);
4186*4882a593Smuzhiyun iscsit_prepare_cmds_for_reallegiance(conn);
4187*4882a593Smuzhiyun } else {
4188*4882a593Smuzhiyun iscsit_clear_ooo_cmdsns_for_conn(conn);
4189*4882a593Smuzhiyun iscsit_release_commands_from_conn(conn);
4190*4882a593Smuzhiyun }
4191*4882a593Smuzhiyun iscsit_free_queue_reqs_for_conn(conn);
4192*4882a593Smuzhiyun
4193*4882a593Smuzhiyun /*
4194*4882a593Smuzhiyun * Handle decrementing session or connection usage count if
4195*4882a593Smuzhiyun * a logout response was not able to be sent because the
4196*4882a593Smuzhiyun * connection failed. Fall back to Session Recovery here.
4197*4882a593Smuzhiyun */
4198*4882a593Smuzhiyun if (atomic_read(&conn->conn_logout_remove)) {
4199*4882a593Smuzhiyun if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) {
4200*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn);
4201*4882a593Smuzhiyun iscsit_dec_session_usage_count(sess);
4202*4882a593Smuzhiyun }
4203*4882a593Smuzhiyun if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION)
4204*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn);
4205*4882a593Smuzhiyun
4206*4882a593Smuzhiyun atomic_set(&conn->conn_logout_remove, 0);
4207*4882a593Smuzhiyun atomic_set(&sess->session_reinstatement, 0);
4208*4882a593Smuzhiyun atomic_set(&sess->session_fall_back_to_erl0, 1);
4209*4882a593Smuzhiyun }
4210*4882a593Smuzhiyun
4211*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4212*4882a593Smuzhiyun list_del(&conn->conn_list);
4213*4882a593Smuzhiyun
4214*4882a593Smuzhiyun /*
4215*4882a593Smuzhiyun * Attempt to let the Initiator know this connection failed by
4216*4882a593Smuzhiyun * sending an Connection Dropped Async Message on another
4217*4882a593Smuzhiyun * active connection.
4218*4882a593Smuzhiyun */
4219*4882a593Smuzhiyun if (atomic_read(&conn->connection_recovery))
4220*4882a593Smuzhiyun iscsit_build_conn_drop_async_message(conn);
4221*4882a593Smuzhiyun
4222*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4223*4882a593Smuzhiyun
4224*4882a593Smuzhiyun /*
4225*4882a593Smuzhiyun * If connection reinstatement is being performed on this connection,
4226*4882a593Smuzhiyun * up the connection reinstatement semaphore that is being blocked on
4227*4882a593Smuzhiyun * in iscsit_cause_connection_reinstatement().
4228*4882a593Smuzhiyun */
4229*4882a593Smuzhiyun spin_lock_bh(&conn->state_lock);
4230*4882a593Smuzhiyun if (atomic_read(&conn->sleep_on_conn_wait_comp)) {
4231*4882a593Smuzhiyun spin_unlock_bh(&conn->state_lock);
4232*4882a593Smuzhiyun complete(&conn->conn_wait_comp);
4233*4882a593Smuzhiyun wait_for_completion(&conn->conn_post_wait_comp);
4234*4882a593Smuzhiyun spin_lock_bh(&conn->state_lock);
4235*4882a593Smuzhiyun }
4236*4882a593Smuzhiyun
4237*4882a593Smuzhiyun /*
4238*4882a593Smuzhiyun * If connection reinstatement is being performed on this connection
4239*4882a593Smuzhiyun * by receiving a REMOVECONNFORRECOVERY logout request, up the
4240*4882a593Smuzhiyun * connection wait rcfr semaphore that is being blocked on
4241*4882a593Smuzhiyun * an iscsit_connection_reinstatement_rcfr().
4242*4882a593Smuzhiyun */
4243*4882a593Smuzhiyun if (atomic_read(&conn->connection_wait_rcfr)) {
4244*4882a593Smuzhiyun spin_unlock_bh(&conn->state_lock);
4245*4882a593Smuzhiyun complete(&conn->conn_wait_rcfr_comp);
4246*4882a593Smuzhiyun wait_for_completion(&conn->conn_post_wait_comp);
4247*4882a593Smuzhiyun spin_lock_bh(&conn->state_lock);
4248*4882a593Smuzhiyun }
4249*4882a593Smuzhiyun atomic_set(&conn->connection_reinstatement, 1);
4250*4882a593Smuzhiyun spin_unlock_bh(&conn->state_lock);
4251*4882a593Smuzhiyun
4252*4882a593Smuzhiyun /*
4253*4882a593Smuzhiyun * If any other processes are accessing this connection pointer we
4254*4882a593Smuzhiyun * must wait until they have completed.
4255*4882a593Smuzhiyun */
4256*4882a593Smuzhiyun iscsit_check_conn_usage_count(conn);
4257*4882a593Smuzhiyun
4258*4882a593Smuzhiyun ahash_request_free(conn->conn_tx_hash);
4259*4882a593Smuzhiyun if (conn->conn_rx_hash) {
4260*4882a593Smuzhiyun struct crypto_ahash *tfm;
4261*4882a593Smuzhiyun
4262*4882a593Smuzhiyun tfm = crypto_ahash_reqtfm(conn->conn_rx_hash);
4263*4882a593Smuzhiyun ahash_request_free(conn->conn_rx_hash);
4264*4882a593Smuzhiyun crypto_free_ahash(tfm);
4265*4882a593Smuzhiyun }
4266*4882a593Smuzhiyun
4267*4882a593Smuzhiyun if (conn->sock)
4268*4882a593Smuzhiyun sock_release(conn->sock);
4269*4882a593Smuzhiyun
4270*4882a593Smuzhiyun if (conn->conn_transport->iscsit_free_conn)
4271*4882a593Smuzhiyun conn->conn_transport->iscsit_free_conn(conn);
4272*4882a593Smuzhiyun
4273*4882a593Smuzhiyun pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
4274*4882a593Smuzhiyun conn->conn_state = TARG_CONN_STATE_FREE;
4275*4882a593Smuzhiyun iscsit_free_conn(conn);
4276*4882a593Smuzhiyun
4277*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4278*4882a593Smuzhiyun atomic_dec(&sess->nconn);
4279*4882a593Smuzhiyun pr_debug("Decremented iSCSI connection count to %hu from node:"
4280*4882a593Smuzhiyun " %s\n", atomic_read(&sess->nconn),
4281*4882a593Smuzhiyun sess->sess_ops->InitiatorName);
4282*4882a593Smuzhiyun /*
4283*4882a593Smuzhiyun * Make sure that if one connection fails in an non ERL=2 iSCSI
4284*4882a593Smuzhiyun * Session that they all fail.
4285*4882a593Smuzhiyun */
4286*4882a593Smuzhiyun if ((sess->sess_ops->ErrorRecoveryLevel != 2) && !conn_logout &&
4287*4882a593Smuzhiyun !atomic_read(&sess->session_logout))
4288*4882a593Smuzhiyun atomic_set(&sess->session_fall_back_to_erl0, 1);
4289*4882a593Smuzhiyun
4290*4882a593Smuzhiyun /*
4291*4882a593Smuzhiyun * If this was not the last connection in the session, and we are
4292*4882a593Smuzhiyun * performing session reinstatement or falling back to ERL=0, call
4293*4882a593Smuzhiyun * iscsit_stop_session() without sleeping to shutdown the other
4294*4882a593Smuzhiyun * active connections.
4295*4882a593Smuzhiyun */
4296*4882a593Smuzhiyun if (atomic_read(&sess->nconn)) {
4297*4882a593Smuzhiyun if (!atomic_read(&sess->session_reinstatement) &&
4298*4882a593Smuzhiyun !atomic_read(&sess->session_fall_back_to_erl0)) {
4299*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4300*4882a593Smuzhiyun return 0;
4301*4882a593Smuzhiyun }
4302*4882a593Smuzhiyun if (!atomic_read(&sess->session_stop_active)) {
4303*4882a593Smuzhiyun atomic_set(&sess->session_stop_active, 1);
4304*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4305*4882a593Smuzhiyun iscsit_stop_session(sess, 0, 0);
4306*4882a593Smuzhiyun return 0;
4307*4882a593Smuzhiyun }
4308*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4309*4882a593Smuzhiyun return 0;
4310*4882a593Smuzhiyun }
4311*4882a593Smuzhiyun
4312*4882a593Smuzhiyun /*
4313*4882a593Smuzhiyun * If this was the last connection in the session and one of the
4314*4882a593Smuzhiyun * following is occurring:
4315*4882a593Smuzhiyun *
4316*4882a593Smuzhiyun * Session Reinstatement is not being performed, and are falling back
4317*4882a593Smuzhiyun * to ERL=0 call iscsit_close_session().
4318*4882a593Smuzhiyun *
4319*4882a593Smuzhiyun * Session Logout was requested. iscsit_close_session() will be called
4320*4882a593Smuzhiyun * elsewhere.
4321*4882a593Smuzhiyun *
4322*4882a593Smuzhiyun * Session Continuation is not being performed, start the Time2Retain
4323*4882a593Smuzhiyun * handler and check if sleep_on_sess_wait_sem is active.
4324*4882a593Smuzhiyun */
4325*4882a593Smuzhiyun if (!atomic_read(&sess->session_reinstatement) &&
4326*4882a593Smuzhiyun atomic_read(&sess->session_fall_back_to_erl0)) {
4327*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4328*4882a593Smuzhiyun complete_all(&sess->session_wait_comp);
4329*4882a593Smuzhiyun iscsit_close_session(sess);
4330*4882a593Smuzhiyun
4331*4882a593Smuzhiyun return 0;
4332*4882a593Smuzhiyun } else if (atomic_read(&sess->session_logout)) {
4333*4882a593Smuzhiyun pr_debug("Moving to TARG_SESS_STATE_FREE.\n");
4334*4882a593Smuzhiyun sess->session_state = TARG_SESS_STATE_FREE;
4335*4882a593Smuzhiyun
4336*4882a593Smuzhiyun if (atomic_read(&sess->session_close)) {
4337*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4338*4882a593Smuzhiyun complete_all(&sess->session_wait_comp);
4339*4882a593Smuzhiyun iscsit_close_session(sess);
4340*4882a593Smuzhiyun } else {
4341*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4342*4882a593Smuzhiyun }
4343*4882a593Smuzhiyun
4344*4882a593Smuzhiyun return 0;
4345*4882a593Smuzhiyun } else {
4346*4882a593Smuzhiyun pr_debug("Moving to TARG_SESS_STATE_FAILED.\n");
4347*4882a593Smuzhiyun sess->session_state = TARG_SESS_STATE_FAILED;
4348*4882a593Smuzhiyun
4349*4882a593Smuzhiyun if (!atomic_read(&sess->session_continuation))
4350*4882a593Smuzhiyun iscsit_start_time2retain_handler(sess);
4351*4882a593Smuzhiyun
4352*4882a593Smuzhiyun if (atomic_read(&sess->session_close)) {
4353*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4354*4882a593Smuzhiyun complete_all(&sess->session_wait_comp);
4355*4882a593Smuzhiyun iscsit_close_session(sess);
4356*4882a593Smuzhiyun } else {
4357*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4358*4882a593Smuzhiyun }
4359*4882a593Smuzhiyun
4360*4882a593Smuzhiyun return 0;
4361*4882a593Smuzhiyun }
4362*4882a593Smuzhiyun }
4363*4882a593Smuzhiyun
4364*4882a593Smuzhiyun /*
4365*4882a593Smuzhiyun * If the iSCSI Session for the iSCSI Initiator Node exists,
4366*4882a593Smuzhiyun * forcefully shutdown the iSCSI NEXUS.
4367*4882a593Smuzhiyun */
iscsit_close_session(struct iscsi_session * sess)4368*4882a593Smuzhiyun int iscsit_close_session(struct iscsi_session *sess)
4369*4882a593Smuzhiyun {
4370*4882a593Smuzhiyun struct iscsi_portal_group *tpg = sess->tpg;
4371*4882a593Smuzhiyun struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
4372*4882a593Smuzhiyun
4373*4882a593Smuzhiyun if (atomic_read(&sess->nconn)) {
4374*4882a593Smuzhiyun pr_err("%d connection(s) still exist for iSCSI session"
4375*4882a593Smuzhiyun " to %s\n", atomic_read(&sess->nconn),
4376*4882a593Smuzhiyun sess->sess_ops->InitiatorName);
4377*4882a593Smuzhiyun BUG();
4378*4882a593Smuzhiyun }
4379*4882a593Smuzhiyun
4380*4882a593Smuzhiyun spin_lock_bh(&se_tpg->session_lock);
4381*4882a593Smuzhiyun atomic_set(&sess->session_logout, 1);
4382*4882a593Smuzhiyun atomic_set(&sess->session_reinstatement, 1);
4383*4882a593Smuzhiyun iscsit_stop_time2retain_timer(sess);
4384*4882a593Smuzhiyun spin_unlock_bh(&se_tpg->session_lock);
4385*4882a593Smuzhiyun
4386*4882a593Smuzhiyun /*
4387*4882a593Smuzhiyun * transport_deregister_session_configfs() will clear the
4388*4882a593Smuzhiyun * struct se_node_acl->nacl_sess pointer now as a iscsi_np process context
4389*4882a593Smuzhiyun * can be setting it again with __transport_register_session() in
4390*4882a593Smuzhiyun * iscsi_post_login_handler() again after the iscsit_stop_session()
4391*4882a593Smuzhiyun * completes in iscsi_np context.
4392*4882a593Smuzhiyun */
4393*4882a593Smuzhiyun transport_deregister_session_configfs(sess->se_sess);
4394*4882a593Smuzhiyun
4395*4882a593Smuzhiyun /*
4396*4882a593Smuzhiyun * If any other processes are accessing this session pointer we must
4397*4882a593Smuzhiyun * wait until they have completed. If we are in an interrupt (the
4398*4882a593Smuzhiyun * time2retain handler) and contain and active session usage count we
4399*4882a593Smuzhiyun * restart the timer and exit.
4400*4882a593Smuzhiyun */
4401*4882a593Smuzhiyun if (!in_interrupt()) {
4402*4882a593Smuzhiyun iscsit_check_session_usage_count(sess);
4403*4882a593Smuzhiyun } else {
4404*4882a593Smuzhiyun if (iscsit_check_session_usage_count(sess) == 2) {
4405*4882a593Smuzhiyun atomic_set(&sess->session_logout, 0);
4406*4882a593Smuzhiyun iscsit_start_time2retain_handler(sess);
4407*4882a593Smuzhiyun return 0;
4408*4882a593Smuzhiyun }
4409*4882a593Smuzhiyun }
4410*4882a593Smuzhiyun
4411*4882a593Smuzhiyun transport_deregister_session(sess->se_sess);
4412*4882a593Smuzhiyun
4413*4882a593Smuzhiyun if (sess->sess_ops->ErrorRecoveryLevel == 2)
4414*4882a593Smuzhiyun iscsit_free_connection_recovery_entries(sess);
4415*4882a593Smuzhiyun
4416*4882a593Smuzhiyun iscsit_free_all_ooo_cmdsns(sess);
4417*4882a593Smuzhiyun
4418*4882a593Smuzhiyun spin_lock_bh(&se_tpg->session_lock);
4419*4882a593Smuzhiyun pr_debug("Moving to TARG_SESS_STATE_FREE.\n");
4420*4882a593Smuzhiyun sess->session_state = TARG_SESS_STATE_FREE;
4421*4882a593Smuzhiyun pr_debug("Released iSCSI session from node: %s\n",
4422*4882a593Smuzhiyun sess->sess_ops->InitiatorName);
4423*4882a593Smuzhiyun tpg->nsessions--;
4424*4882a593Smuzhiyun if (tpg->tpg_tiqn)
4425*4882a593Smuzhiyun tpg->tpg_tiqn->tiqn_nsessions--;
4426*4882a593Smuzhiyun
4427*4882a593Smuzhiyun pr_debug("Decremented number of active iSCSI Sessions on"
4428*4882a593Smuzhiyun " iSCSI TPG: %hu to %u\n", tpg->tpgt, tpg->nsessions);
4429*4882a593Smuzhiyun
4430*4882a593Smuzhiyun ida_free(&sess_ida, sess->session_index);
4431*4882a593Smuzhiyun kfree(sess->sess_ops);
4432*4882a593Smuzhiyun sess->sess_ops = NULL;
4433*4882a593Smuzhiyun spin_unlock_bh(&se_tpg->session_lock);
4434*4882a593Smuzhiyun
4435*4882a593Smuzhiyun kfree(sess);
4436*4882a593Smuzhiyun return 0;
4437*4882a593Smuzhiyun }
4438*4882a593Smuzhiyun
iscsit_logout_post_handler_closesession(struct iscsi_conn * conn)4439*4882a593Smuzhiyun static void iscsit_logout_post_handler_closesession(
4440*4882a593Smuzhiyun struct iscsi_conn *conn)
4441*4882a593Smuzhiyun {
4442*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
4443*4882a593Smuzhiyun int sleep = 1;
4444*4882a593Smuzhiyun /*
4445*4882a593Smuzhiyun * Traditional iscsi/tcp will invoke this logic from TX thread
4446*4882a593Smuzhiyun * context during session logout, so clear tx_thread_active and
4447*4882a593Smuzhiyun * sleep if iscsit_close_connection() has not already occured.
4448*4882a593Smuzhiyun *
4449*4882a593Smuzhiyun * Since iser-target invokes this logic from it's own workqueue,
4450*4882a593Smuzhiyun * always sleep waiting for RX/TX thread shutdown to complete
4451*4882a593Smuzhiyun * within iscsit_close_connection().
4452*4882a593Smuzhiyun */
4453*4882a593Smuzhiyun if (!conn->conn_transport->rdma_shutdown) {
4454*4882a593Smuzhiyun sleep = cmpxchg(&conn->tx_thread_active, true, false);
4455*4882a593Smuzhiyun if (!sleep)
4456*4882a593Smuzhiyun return;
4457*4882a593Smuzhiyun }
4458*4882a593Smuzhiyun
4459*4882a593Smuzhiyun atomic_set(&conn->conn_logout_remove, 0);
4460*4882a593Smuzhiyun complete(&conn->conn_logout_comp);
4461*4882a593Smuzhiyun
4462*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn);
4463*4882a593Smuzhiyun atomic_set(&sess->session_close, 1);
4464*4882a593Smuzhiyun iscsit_stop_session(sess, sleep, sleep);
4465*4882a593Smuzhiyun iscsit_dec_session_usage_count(sess);
4466*4882a593Smuzhiyun }
4467*4882a593Smuzhiyun
iscsit_logout_post_handler_samecid(struct iscsi_conn * conn)4468*4882a593Smuzhiyun static void iscsit_logout_post_handler_samecid(
4469*4882a593Smuzhiyun struct iscsi_conn *conn)
4470*4882a593Smuzhiyun {
4471*4882a593Smuzhiyun int sleep = 1;
4472*4882a593Smuzhiyun
4473*4882a593Smuzhiyun if (!conn->conn_transport->rdma_shutdown) {
4474*4882a593Smuzhiyun sleep = cmpxchg(&conn->tx_thread_active, true, false);
4475*4882a593Smuzhiyun if (!sleep)
4476*4882a593Smuzhiyun return;
4477*4882a593Smuzhiyun }
4478*4882a593Smuzhiyun
4479*4882a593Smuzhiyun atomic_set(&conn->conn_logout_remove, 0);
4480*4882a593Smuzhiyun complete(&conn->conn_logout_comp);
4481*4882a593Smuzhiyun
4482*4882a593Smuzhiyun iscsit_cause_connection_reinstatement(conn, sleep);
4483*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn);
4484*4882a593Smuzhiyun }
4485*4882a593Smuzhiyun
iscsit_logout_post_handler_diffcid(struct iscsi_conn * conn,u16 cid)4486*4882a593Smuzhiyun static void iscsit_logout_post_handler_diffcid(
4487*4882a593Smuzhiyun struct iscsi_conn *conn,
4488*4882a593Smuzhiyun u16 cid)
4489*4882a593Smuzhiyun {
4490*4882a593Smuzhiyun struct iscsi_conn *l_conn;
4491*4882a593Smuzhiyun struct iscsi_session *sess = conn->sess;
4492*4882a593Smuzhiyun bool conn_found = false;
4493*4882a593Smuzhiyun
4494*4882a593Smuzhiyun if (!sess)
4495*4882a593Smuzhiyun return;
4496*4882a593Smuzhiyun
4497*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4498*4882a593Smuzhiyun list_for_each_entry(l_conn, &sess->sess_conn_list, conn_list) {
4499*4882a593Smuzhiyun if (l_conn->cid == cid) {
4500*4882a593Smuzhiyun iscsit_inc_conn_usage_count(l_conn);
4501*4882a593Smuzhiyun conn_found = true;
4502*4882a593Smuzhiyun break;
4503*4882a593Smuzhiyun }
4504*4882a593Smuzhiyun }
4505*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4506*4882a593Smuzhiyun
4507*4882a593Smuzhiyun if (!conn_found)
4508*4882a593Smuzhiyun return;
4509*4882a593Smuzhiyun
4510*4882a593Smuzhiyun if (l_conn->sock)
4511*4882a593Smuzhiyun l_conn->sock->ops->shutdown(l_conn->sock, RCV_SHUTDOWN);
4512*4882a593Smuzhiyun
4513*4882a593Smuzhiyun spin_lock_bh(&l_conn->state_lock);
4514*4882a593Smuzhiyun pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n");
4515*4882a593Smuzhiyun l_conn->conn_state = TARG_CONN_STATE_IN_LOGOUT;
4516*4882a593Smuzhiyun spin_unlock_bh(&l_conn->state_lock);
4517*4882a593Smuzhiyun
4518*4882a593Smuzhiyun iscsit_cause_connection_reinstatement(l_conn, 1);
4519*4882a593Smuzhiyun iscsit_dec_conn_usage_count(l_conn);
4520*4882a593Smuzhiyun }
4521*4882a593Smuzhiyun
4522*4882a593Smuzhiyun /*
4523*4882a593Smuzhiyun * Return of 0 causes the TX thread to restart.
4524*4882a593Smuzhiyun */
iscsit_logout_post_handler(struct iscsi_cmd * cmd,struct iscsi_conn * conn)4525*4882a593Smuzhiyun int iscsit_logout_post_handler(
4526*4882a593Smuzhiyun struct iscsi_cmd *cmd,
4527*4882a593Smuzhiyun struct iscsi_conn *conn)
4528*4882a593Smuzhiyun {
4529*4882a593Smuzhiyun int ret = 0;
4530*4882a593Smuzhiyun
4531*4882a593Smuzhiyun switch (cmd->logout_reason) {
4532*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_CLOSE_SESSION:
4533*4882a593Smuzhiyun switch (cmd->logout_response) {
4534*4882a593Smuzhiyun case ISCSI_LOGOUT_SUCCESS:
4535*4882a593Smuzhiyun case ISCSI_LOGOUT_CLEANUP_FAILED:
4536*4882a593Smuzhiyun default:
4537*4882a593Smuzhiyun iscsit_logout_post_handler_closesession(conn);
4538*4882a593Smuzhiyun break;
4539*4882a593Smuzhiyun }
4540*4882a593Smuzhiyun break;
4541*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION:
4542*4882a593Smuzhiyun if (conn->cid == cmd->logout_cid) {
4543*4882a593Smuzhiyun switch (cmd->logout_response) {
4544*4882a593Smuzhiyun case ISCSI_LOGOUT_SUCCESS:
4545*4882a593Smuzhiyun case ISCSI_LOGOUT_CLEANUP_FAILED:
4546*4882a593Smuzhiyun default:
4547*4882a593Smuzhiyun iscsit_logout_post_handler_samecid(conn);
4548*4882a593Smuzhiyun break;
4549*4882a593Smuzhiyun }
4550*4882a593Smuzhiyun } else {
4551*4882a593Smuzhiyun switch (cmd->logout_response) {
4552*4882a593Smuzhiyun case ISCSI_LOGOUT_SUCCESS:
4553*4882a593Smuzhiyun iscsit_logout_post_handler_diffcid(conn,
4554*4882a593Smuzhiyun cmd->logout_cid);
4555*4882a593Smuzhiyun break;
4556*4882a593Smuzhiyun case ISCSI_LOGOUT_CID_NOT_FOUND:
4557*4882a593Smuzhiyun case ISCSI_LOGOUT_CLEANUP_FAILED:
4558*4882a593Smuzhiyun default:
4559*4882a593Smuzhiyun break;
4560*4882a593Smuzhiyun }
4561*4882a593Smuzhiyun ret = 1;
4562*4882a593Smuzhiyun }
4563*4882a593Smuzhiyun break;
4564*4882a593Smuzhiyun case ISCSI_LOGOUT_REASON_RECOVERY:
4565*4882a593Smuzhiyun switch (cmd->logout_response) {
4566*4882a593Smuzhiyun case ISCSI_LOGOUT_SUCCESS:
4567*4882a593Smuzhiyun case ISCSI_LOGOUT_CID_NOT_FOUND:
4568*4882a593Smuzhiyun case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED:
4569*4882a593Smuzhiyun case ISCSI_LOGOUT_CLEANUP_FAILED:
4570*4882a593Smuzhiyun default:
4571*4882a593Smuzhiyun break;
4572*4882a593Smuzhiyun }
4573*4882a593Smuzhiyun ret = 1;
4574*4882a593Smuzhiyun break;
4575*4882a593Smuzhiyun default:
4576*4882a593Smuzhiyun break;
4577*4882a593Smuzhiyun
4578*4882a593Smuzhiyun }
4579*4882a593Smuzhiyun return ret;
4580*4882a593Smuzhiyun }
4581*4882a593Smuzhiyun EXPORT_SYMBOL(iscsit_logout_post_handler);
4582*4882a593Smuzhiyun
iscsit_fail_session(struct iscsi_session * sess)4583*4882a593Smuzhiyun void iscsit_fail_session(struct iscsi_session *sess)
4584*4882a593Smuzhiyun {
4585*4882a593Smuzhiyun struct iscsi_conn *conn;
4586*4882a593Smuzhiyun
4587*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4588*4882a593Smuzhiyun list_for_each_entry(conn, &sess->sess_conn_list, conn_list) {
4589*4882a593Smuzhiyun pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n");
4590*4882a593Smuzhiyun conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT;
4591*4882a593Smuzhiyun }
4592*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4593*4882a593Smuzhiyun
4594*4882a593Smuzhiyun pr_debug("Moving to TARG_SESS_STATE_FAILED.\n");
4595*4882a593Smuzhiyun sess->session_state = TARG_SESS_STATE_FAILED;
4596*4882a593Smuzhiyun }
4597*4882a593Smuzhiyun
iscsit_stop_session(struct iscsi_session * sess,int session_sleep,int connection_sleep)4598*4882a593Smuzhiyun void iscsit_stop_session(
4599*4882a593Smuzhiyun struct iscsi_session *sess,
4600*4882a593Smuzhiyun int session_sleep,
4601*4882a593Smuzhiyun int connection_sleep)
4602*4882a593Smuzhiyun {
4603*4882a593Smuzhiyun u16 conn_count = atomic_read(&sess->nconn);
4604*4882a593Smuzhiyun struct iscsi_conn *conn, *conn_tmp = NULL;
4605*4882a593Smuzhiyun int is_last;
4606*4882a593Smuzhiyun
4607*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4608*4882a593Smuzhiyun
4609*4882a593Smuzhiyun if (connection_sleep) {
4610*4882a593Smuzhiyun list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list,
4611*4882a593Smuzhiyun conn_list) {
4612*4882a593Smuzhiyun if (conn_count == 0)
4613*4882a593Smuzhiyun break;
4614*4882a593Smuzhiyun
4615*4882a593Smuzhiyun if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) {
4616*4882a593Smuzhiyun is_last = 1;
4617*4882a593Smuzhiyun } else {
4618*4882a593Smuzhiyun iscsit_inc_conn_usage_count(conn_tmp);
4619*4882a593Smuzhiyun is_last = 0;
4620*4882a593Smuzhiyun }
4621*4882a593Smuzhiyun iscsit_inc_conn_usage_count(conn);
4622*4882a593Smuzhiyun
4623*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4624*4882a593Smuzhiyun iscsit_cause_connection_reinstatement(conn, 1);
4625*4882a593Smuzhiyun spin_lock_bh(&sess->conn_lock);
4626*4882a593Smuzhiyun
4627*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn);
4628*4882a593Smuzhiyun if (is_last == 0)
4629*4882a593Smuzhiyun iscsit_dec_conn_usage_count(conn_tmp);
4630*4882a593Smuzhiyun conn_count--;
4631*4882a593Smuzhiyun }
4632*4882a593Smuzhiyun } else {
4633*4882a593Smuzhiyun list_for_each_entry(conn, &sess->sess_conn_list, conn_list)
4634*4882a593Smuzhiyun iscsit_cause_connection_reinstatement(conn, 0);
4635*4882a593Smuzhiyun }
4636*4882a593Smuzhiyun
4637*4882a593Smuzhiyun if (session_sleep && atomic_read(&sess->nconn)) {
4638*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4639*4882a593Smuzhiyun wait_for_completion(&sess->session_wait_comp);
4640*4882a593Smuzhiyun } else
4641*4882a593Smuzhiyun spin_unlock_bh(&sess->conn_lock);
4642*4882a593Smuzhiyun }
4643*4882a593Smuzhiyun
iscsit_release_sessions_for_tpg(struct iscsi_portal_group * tpg,int force)4644*4882a593Smuzhiyun int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
4645*4882a593Smuzhiyun {
4646*4882a593Smuzhiyun struct iscsi_session *sess;
4647*4882a593Smuzhiyun struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
4648*4882a593Smuzhiyun struct se_session *se_sess, *se_sess_tmp;
4649*4882a593Smuzhiyun LIST_HEAD(free_list);
4650*4882a593Smuzhiyun int session_count = 0;
4651*4882a593Smuzhiyun
4652*4882a593Smuzhiyun spin_lock_bh(&se_tpg->session_lock);
4653*4882a593Smuzhiyun if (tpg->nsessions && !force) {
4654*4882a593Smuzhiyun spin_unlock_bh(&se_tpg->session_lock);
4655*4882a593Smuzhiyun return -1;
4656*4882a593Smuzhiyun }
4657*4882a593Smuzhiyun
4658*4882a593Smuzhiyun list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
4659*4882a593Smuzhiyun sess_list) {
4660*4882a593Smuzhiyun sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
4661*4882a593Smuzhiyun
4662*4882a593Smuzhiyun spin_lock(&sess->conn_lock);
4663*4882a593Smuzhiyun if (atomic_read(&sess->session_fall_back_to_erl0) ||
4664*4882a593Smuzhiyun atomic_read(&sess->session_logout) ||
4665*4882a593Smuzhiyun atomic_read(&sess->session_close) ||
4666*4882a593Smuzhiyun (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
4667*4882a593Smuzhiyun spin_unlock(&sess->conn_lock);
4668*4882a593Smuzhiyun continue;
4669*4882a593Smuzhiyun }
4670*4882a593Smuzhiyun iscsit_inc_session_usage_count(sess);
4671*4882a593Smuzhiyun atomic_set(&sess->session_reinstatement, 1);
4672*4882a593Smuzhiyun atomic_set(&sess->session_fall_back_to_erl0, 1);
4673*4882a593Smuzhiyun atomic_set(&sess->session_close, 1);
4674*4882a593Smuzhiyun spin_unlock(&sess->conn_lock);
4675*4882a593Smuzhiyun
4676*4882a593Smuzhiyun list_move_tail(&se_sess->sess_list, &free_list);
4677*4882a593Smuzhiyun }
4678*4882a593Smuzhiyun spin_unlock_bh(&se_tpg->session_lock);
4679*4882a593Smuzhiyun
4680*4882a593Smuzhiyun list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
4681*4882a593Smuzhiyun sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
4682*4882a593Smuzhiyun
4683*4882a593Smuzhiyun list_del_init(&se_sess->sess_list);
4684*4882a593Smuzhiyun iscsit_stop_session(sess, 1, 1);
4685*4882a593Smuzhiyun iscsit_dec_session_usage_count(sess);
4686*4882a593Smuzhiyun session_count++;
4687*4882a593Smuzhiyun }
4688*4882a593Smuzhiyun
4689*4882a593Smuzhiyun pr_debug("Released %d iSCSI Session(s) from Target Portal"
4690*4882a593Smuzhiyun " Group: %hu\n", session_count, tpg->tpgt);
4691*4882a593Smuzhiyun return 0;
4692*4882a593Smuzhiyun }
4693*4882a593Smuzhiyun
4694*4882a593Smuzhiyun MODULE_DESCRIPTION("iSCSI-Target Driver for mainline target infrastructure");
4695*4882a593Smuzhiyun MODULE_VERSION("4.1.x");
4696*4882a593Smuzhiyun MODULE_AUTHOR("nab@Linux-iSCSI.org");
4697*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4698*4882a593Smuzhiyun
4699*4882a593Smuzhiyun module_init(iscsi_target_init_module);
4700*4882a593Smuzhiyun module_exit(iscsi_target_cleanup_module);
4701