xref: /freebsd/sys/cam/ctl/ctl_tpc.c (revision 8cbf9eae6f129323eeb6b9e77e9baa4b6e17a828)
1984a2ea9SAlexander Motin /*-
2984a2ea9SAlexander Motin  * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
3984a2ea9SAlexander Motin  * All rights reserved.
4984a2ea9SAlexander Motin  *
5984a2ea9SAlexander Motin  * Redistribution and use in source and binary forms, with or without
6984a2ea9SAlexander Motin  * modification, are permitted provided that the following conditions
7984a2ea9SAlexander Motin  * are met:
8984a2ea9SAlexander Motin  * 1. Redistributions of source code must retain the above copyright
9984a2ea9SAlexander Motin  *    notice, this list of conditions and the following disclaimer,
10984a2ea9SAlexander Motin  *    without modification, immediately at the beginning of the file.
11984a2ea9SAlexander Motin  * 2. Redistributions in binary form must reproduce the above copyright
12984a2ea9SAlexander Motin  *    notice, this list of conditions and the following disclaimer in the
13984a2ea9SAlexander Motin  *    documentation and/or other materials provided with the distribution.
14984a2ea9SAlexander Motin  *
15984a2ea9SAlexander Motin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16984a2ea9SAlexander Motin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17984a2ea9SAlexander Motin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18984a2ea9SAlexander Motin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19984a2ea9SAlexander Motin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20984a2ea9SAlexander Motin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21984a2ea9SAlexander Motin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22984a2ea9SAlexander Motin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23984a2ea9SAlexander Motin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24984a2ea9SAlexander Motin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25984a2ea9SAlexander Motin  */
26984a2ea9SAlexander Motin 
27984a2ea9SAlexander Motin #include <sys/cdefs.h>
28984a2ea9SAlexander Motin __FBSDID("$FreeBSD$");
29984a2ea9SAlexander Motin 
30984a2ea9SAlexander Motin #include <sys/param.h>
31984a2ea9SAlexander Motin #include <sys/systm.h>
32984a2ea9SAlexander Motin #include <sys/kernel.h>
33984a2ea9SAlexander Motin #include <sys/types.h>
34984a2ea9SAlexander Motin #include <sys/lock.h>
35984a2ea9SAlexander Motin #include <sys/module.h>
36984a2ea9SAlexander Motin #include <sys/mutex.h>
37984a2ea9SAlexander Motin #include <sys/condvar.h>
38984a2ea9SAlexander Motin #include <sys/malloc.h>
39984a2ea9SAlexander Motin #include <sys/conf.h>
40984a2ea9SAlexander Motin #include <sys/queue.h>
41984a2ea9SAlexander Motin #include <sys/sysctl.h>
42984a2ea9SAlexander Motin #include <machine/atomic.h>
43984a2ea9SAlexander Motin 
44984a2ea9SAlexander Motin #include <cam/cam.h>
45984a2ea9SAlexander Motin #include <cam/scsi/scsi_all.h>
46984a2ea9SAlexander Motin #include <cam/scsi/scsi_da.h>
47984a2ea9SAlexander Motin #include <cam/ctl/ctl_io.h>
48984a2ea9SAlexander Motin #include <cam/ctl/ctl.h>
49984a2ea9SAlexander Motin #include <cam/ctl/ctl_frontend.h>
50984a2ea9SAlexander Motin #include <cam/ctl/ctl_frontend_internal.h>
51984a2ea9SAlexander Motin #include <cam/ctl/ctl_util.h>
52984a2ea9SAlexander Motin #include <cam/ctl/ctl_backend.h>
53984a2ea9SAlexander Motin #include <cam/ctl/ctl_ioctl.h>
54984a2ea9SAlexander Motin #include <cam/ctl/ctl_ha.h>
55984a2ea9SAlexander Motin #include <cam/ctl/ctl_private.h>
56984a2ea9SAlexander Motin #include <cam/ctl/ctl_debug.h>
57984a2ea9SAlexander Motin #include <cam/ctl/ctl_scsi_all.h>
58984a2ea9SAlexander Motin #include <cam/ctl/ctl_tpc.h>
59984a2ea9SAlexander Motin #include <cam/ctl/ctl_error.h>
60984a2ea9SAlexander Motin 
61984a2ea9SAlexander Motin #define	TPC_MAX_CSCDS	64
62984a2ea9SAlexander Motin #define	TPC_MAX_SEGS	64
63984a2ea9SAlexander Motin #define	TPC_MAX_SEG	0
64984a2ea9SAlexander Motin #define	TPC_MAX_LIST	8192
65984a2ea9SAlexander Motin #define	TPC_MAX_INLINE	0
66984a2ea9SAlexander Motin #define	TPC_MAX_LISTS	255
67984a2ea9SAlexander Motin #define	TPC_MAX_IO_SIZE	(1024 * 1024)
68984a2ea9SAlexander Motin 
69984a2ea9SAlexander Motin MALLOC_DEFINE(M_CTL_TPC, "ctltpc", "CTL TPC");
70984a2ea9SAlexander Motin 
71984a2ea9SAlexander Motin typedef enum {
72984a2ea9SAlexander Motin 	TPC_ERR_RETRY		= 0x000,
73984a2ea9SAlexander Motin 	TPC_ERR_FAIL		= 0x001,
74984a2ea9SAlexander Motin 	TPC_ERR_MASK		= 0x0ff,
75984a2ea9SAlexander Motin 	TPC_ERR_NO_DECREMENT	= 0x100
76984a2ea9SAlexander Motin } tpc_error_action;
77984a2ea9SAlexander Motin 
78984a2ea9SAlexander Motin struct tpc_list;
79984a2ea9SAlexander Motin TAILQ_HEAD(runl, tpc_io);
80984a2ea9SAlexander Motin struct tpc_io {
81984a2ea9SAlexander Motin 	union ctl_io		*io;
82984a2ea9SAlexander Motin 	uint64_t		 lun;
83984a2ea9SAlexander Motin 	struct tpc_list		*list;
84984a2ea9SAlexander Motin 	struct runl		 run;
85984a2ea9SAlexander Motin 	TAILQ_ENTRY(tpc_io)	 rlinks;
86984a2ea9SAlexander Motin 	TAILQ_ENTRY(tpc_io)	 links;
87984a2ea9SAlexander Motin };
88984a2ea9SAlexander Motin 
89984a2ea9SAlexander Motin struct tpc_list {
90984a2ea9SAlexander Motin 	uint8_t			 service_action;
91984a2ea9SAlexander Motin 	int			 init_port;
92*8cbf9eaeSAlexander Motin 	uint32_t		 init_idx;
93984a2ea9SAlexander Motin 	uint32_t		 list_id;
94984a2ea9SAlexander Motin 	uint8_t			 flags;
95984a2ea9SAlexander Motin 	uint8_t			*params;
96984a2ea9SAlexander Motin 	struct scsi_ec_cscd	*cscd;
97984a2ea9SAlexander Motin 	struct scsi_ec_segment	*seg[TPC_MAX_SEGS];
98984a2ea9SAlexander Motin 	uint8_t			*inl;
99984a2ea9SAlexander Motin 	int			 ncscd;
100984a2ea9SAlexander Motin 	int			 nseg;
101984a2ea9SAlexander Motin 	int			 leninl;
102984a2ea9SAlexander Motin 	int			 curseg;
103984a2ea9SAlexander Motin 	off_t			 curbytes;
104984a2ea9SAlexander Motin 	int			 curops;
105984a2ea9SAlexander Motin 	int			 stage;
106984a2ea9SAlexander Motin 	uint8_t			*buf;
107984a2ea9SAlexander Motin 	int			 segbytes;
108984a2ea9SAlexander Motin 	int			 tbdio;
109984a2ea9SAlexander Motin 	int			 error;
110984a2ea9SAlexander Motin 	int			 abort;
111984a2ea9SAlexander Motin 	int			 completed;
112984a2ea9SAlexander Motin 	TAILQ_HEAD(, tpc_io)	 allio;
113984a2ea9SAlexander Motin 	struct scsi_sense_data	 sense_data;
114984a2ea9SAlexander Motin 	uint8_t			 sense_len;
115984a2ea9SAlexander Motin 	uint8_t			 scsi_status;
116984a2ea9SAlexander Motin 	struct ctl_scsiio	*ctsio;
117984a2ea9SAlexander Motin 	struct ctl_lun		*lun;
118984a2ea9SAlexander Motin 	TAILQ_ENTRY(tpc_list)	 links;
119984a2ea9SAlexander Motin };
120984a2ea9SAlexander Motin 
121984a2ea9SAlexander Motin void
122984a2ea9SAlexander Motin ctl_tpc_init(struct ctl_lun *lun)
123984a2ea9SAlexander Motin {
124984a2ea9SAlexander Motin 
125984a2ea9SAlexander Motin 	TAILQ_INIT(&lun->tpc_lists);
126984a2ea9SAlexander Motin }
127984a2ea9SAlexander Motin 
128984a2ea9SAlexander Motin void
129984a2ea9SAlexander Motin ctl_tpc_shutdown(struct ctl_lun *lun)
130984a2ea9SAlexander Motin {
131984a2ea9SAlexander Motin 	struct tpc_list *list;
132984a2ea9SAlexander Motin 
133984a2ea9SAlexander Motin 	while ((list = TAILQ_FIRST(&lun->tpc_lists)) != NULL) {
134984a2ea9SAlexander Motin 		TAILQ_REMOVE(&lun->tpc_lists, list, links);
135984a2ea9SAlexander Motin 		KASSERT(list->completed,
136984a2ea9SAlexander Motin 		    ("Not completed TPC (%p) on shutdown", list));
137984a2ea9SAlexander Motin 		free(list, M_CTL);
138984a2ea9SAlexander Motin 	}
139984a2ea9SAlexander Motin }
140984a2ea9SAlexander Motin 
141984a2ea9SAlexander Motin int
142984a2ea9SAlexander Motin ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len)
143984a2ea9SAlexander Motin {
144984a2ea9SAlexander Motin 	struct scsi_vpd_tpc *tpc_ptr;
145984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor *d_ptr;
146984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_sc *sc_ptr;
147984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_sc_descr *scd_ptr;
148984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_pd *pd_ptr;
149984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_sd *sd_ptr;
150984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_sdid *sdid_ptr;
151984a2ea9SAlexander Motin 	struct scsi_vpd_tpc_descriptor_gco *gco_ptr;
152984a2ea9SAlexander Motin 	struct ctl_lun *lun;
153984a2ea9SAlexander Motin 	int data_len;
154984a2ea9SAlexander Motin 
155984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
156984a2ea9SAlexander Motin 
157984a2ea9SAlexander Motin 	data_len = sizeof(struct scsi_vpd_tpc) +
158984a2ea9SAlexander Motin 	    roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sc) +
159984a2ea9SAlexander Motin 	     2 * sizeof(struct scsi_vpd_tpc_descriptor_sc_descr) + 7, 4) +
160984a2ea9SAlexander Motin 	    sizeof(struct scsi_vpd_tpc_descriptor_pd) +
161984a2ea9SAlexander Motin 	    roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sd) + 4, 4) +
162984a2ea9SAlexander Motin 	    roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sdid) + 2, 4) +
163984a2ea9SAlexander Motin 	    sizeof(struct scsi_vpd_tpc_descriptor_gco);
164984a2ea9SAlexander Motin 
165984a2ea9SAlexander Motin 	ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO);
166984a2ea9SAlexander Motin 	tpc_ptr = (struct scsi_vpd_tpc *)ctsio->kern_data_ptr;
167984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
168984a2ea9SAlexander Motin 
169984a2ea9SAlexander Motin 	if (data_len < alloc_len) {
170984a2ea9SAlexander Motin 		ctsio->residual = alloc_len - data_len;
171984a2ea9SAlexander Motin 		ctsio->kern_data_len = data_len;
172984a2ea9SAlexander Motin 		ctsio->kern_total_len = data_len;
173984a2ea9SAlexander Motin 	} else {
174984a2ea9SAlexander Motin 		ctsio->residual = 0;
175984a2ea9SAlexander Motin 		ctsio->kern_data_len = alloc_len;
176984a2ea9SAlexander Motin 		ctsio->kern_total_len = alloc_len;
177984a2ea9SAlexander Motin 	}
178984a2ea9SAlexander Motin 	ctsio->kern_data_resid = 0;
179984a2ea9SAlexander Motin 	ctsio->kern_rel_offset = 0;
180984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
181984a2ea9SAlexander Motin 
182984a2ea9SAlexander Motin 	/*
183984a2ea9SAlexander Motin 	 * The control device is always connected.  The disk device, on the
184984a2ea9SAlexander Motin 	 * other hand, may not be online all the time.
185984a2ea9SAlexander Motin 	 */
186984a2ea9SAlexander Motin 	if (lun != NULL)
187984a2ea9SAlexander Motin 		tpc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) |
188984a2ea9SAlexander Motin 				     lun->be_lun->lun_type;
189984a2ea9SAlexander Motin 	else
190984a2ea9SAlexander Motin 		tpc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT;
191984a2ea9SAlexander Motin 	tpc_ptr->page_code = SVPD_SCSI_TPC;
192984a2ea9SAlexander Motin 	scsi_ulto2b(data_len - 4, tpc_ptr->page_length);
193984a2ea9SAlexander Motin 
194984a2ea9SAlexander Motin 	/* Supported commands */
195984a2ea9SAlexander Motin 	d_ptr = (struct scsi_vpd_tpc_descriptor *)&tpc_ptr->descr[0];
196984a2ea9SAlexander Motin 	sc_ptr = (struct scsi_vpd_tpc_descriptor_sc *)d_ptr;
197984a2ea9SAlexander Motin 	scsi_ulto2b(SVPD_TPC_SC, sc_ptr->desc_type);
198984a2ea9SAlexander Motin 	sc_ptr->list_length = 2 * sizeof(*scd_ptr) + 7;
199984a2ea9SAlexander Motin 	scsi_ulto2b(roundup2(1 + sc_ptr->list_length, 4), sc_ptr->desc_length);
200984a2ea9SAlexander Motin 	scd_ptr = &sc_ptr->descr[0];
201984a2ea9SAlexander Motin 	scd_ptr->opcode = EXTENDED_COPY;
202984a2ea9SAlexander Motin 	scd_ptr->sa_length = 3;
203984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[0] = EC_EC_LID1;
204984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[1] = EC_EC_LID4;
205984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[2] = EC_COA;
206984a2ea9SAlexander Motin 	scd_ptr = (struct scsi_vpd_tpc_descriptor_sc_descr *)
207984a2ea9SAlexander Motin 	    &scd_ptr->supported_service_actions[scd_ptr->sa_length];
208984a2ea9SAlexander Motin 	scd_ptr->opcode = RECEIVE_COPY_STATUS;
209984a2ea9SAlexander Motin 	scd_ptr->sa_length = 4;
210984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[0] = RCS_RCS_LID1;
211984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[1] = RCS_RCFD;
212984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[2] = RCS_RCS_LID4;
213984a2ea9SAlexander Motin 	scd_ptr->supported_service_actions[3] = RCS_RCOP;
214984a2ea9SAlexander Motin 
215984a2ea9SAlexander Motin 	/* Parameter data. */
216984a2ea9SAlexander Motin 	d_ptr = (struct scsi_vpd_tpc_descriptor *)
217984a2ea9SAlexander Motin 	    (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
218984a2ea9SAlexander Motin 	pd_ptr = (struct scsi_vpd_tpc_descriptor_pd *)d_ptr;
219984a2ea9SAlexander Motin 	scsi_ulto2b(SVPD_TPC_PD, pd_ptr->desc_type);
220984a2ea9SAlexander Motin 	scsi_ulto2b(sizeof(*pd_ptr) - 4, pd_ptr->desc_length);
221984a2ea9SAlexander Motin 	scsi_ulto2b(TPC_MAX_CSCDS, pd_ptr->maximum_cscd_descriptor_count);
222984a2ea9SAlexander Motin 	scsi_ulto2b(TPC_MAX_SEGS, pd_ptr->maximum_segment_descriptor_count);
223984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_LIST, pd_ptr->maximum_descriptor_list_length);
224984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_INLINE, pd_ptr->maximum_inline_data_length);
225984a2ea9SAlexander Motin 
226984a2ea9SAlexander Motin 	/* Supported Descriptors */
227984a2ea9SAlexander Motin 	d_ptr = (struct scsi_vpd_tpc_descriptor *)
228984a2ea9SAlexander Motin 	    (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
229984a2ea9SAlexander Motin 	sd_ptr = (struct scsi_vpd_tpc_descriptor_sd *)d_ptr;
230984a2ea9SAlexander Motin 	scsi_ulto2b(SVPD_TPC_SD, sd_ptr->desc_type);
231984a2ea9SAlexander Motin 	scsi_ulto2b(roundup2(sizeof(*sd_ptr) - 4 + 4, 4), sd_ptr->desc_length);
232984a2ea9SAlexander Motin 	sd_ptr->list_length = 4;
233984a2ea9SAlexander Motin 	sd_ptr->supported_descriptor_codes[0] = EC_SEG_B2B;
234984a2ea9SAlexander Motin 	sd_ptr->supported_descriptor_codes[1] = EC_SEG_VERIFY;
235984a2ea9SAlexander Motin 	sd_ptr->supported_descriptor_codes[2] = EC_SEG_REGISTER_KEY;
236984a2ea9SAlexander Motin 	sd_ptr->supported_descriptor_codes[3] = EC_CSCD_ID;
237984a2ea9SAlexander Motin 
238984a2ea9SAlexander Motin 	/* Supported CSCD Descriptor IDs */
239984a2ea9SAlexander Motin 	d_ptr = (struct scsi_vpd_tpc_descriptor *)
240984a2ea9SAlexander Motin 	    (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
241984a2ea9SAlexander Motin 	sdid_ptr = (struct scsi_vpd_tpc_descriptor_sdid *)d_ptr;
242984a2ea9SAlexander Motin 	scsi_ulto2b(SVPD_TPC_SDID, sdid_ptr->desc_type);
243984a2ea9SAlexander Motin 	scsi_ulto2b(roundup2(sizeof(*sdid_ptr) - 4 + 2, 4), sdid_ptr->desc_length);
244984a2ea9SAlexander Motin 	scsi_ulto2b(2, sdid_ptr->list_length);
245984a2ea9SAlexander Motin 	scsi_ulto2b(0xffff, &sdid_ptr->supported_descriptor_ids[0]);
246984a2ea9SAlexander Motin 
247984a2ea9SAlexander Motin 	/* General Copy Operations */
248984a2ea9SAlexander Motin 	d_ptr = (struct scsi_vpd_tpc_descriptor *)
249984a2ea9SAlexander Motin 	    (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length));
250984a2ea9SAlexander Motin 	gco_ptr = (struct scsi_vpd_tpc_descriptor_gco *)d_ptr;
251984a2ea9SAlexander Motin 	scsi_ulto2b(SVPD_TPC_GCO, gco_ptr->desc_type);
252984a2ea9SAlexander Motin 	scsi_ulto2b(sizeof(*gco_ptr) - 4, gco_ptr->desc_length);
253984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->total_concurrent_copies);
254984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->maximum_identified_concurrent_copies);
255984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_SEG, gco_ptr->maximum_segment_length);
256984a2ea9SAlexander Motin 	gco_ptr->data_segment_granularity = 0;
257984a2ea9SAlexander Motin 	gco_ptr->inline_data_granularity = 0;
258984a2ea9SAlexander Motin 
259984a2ea9SAlexander Motin 	ctsio->scsi_status = SCSI_STATUS_OK;
260984a2ea9SAlexander Motin 	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
261984a2ea9SAlexander Motin 	ctsio->be_move_done = ctl_config_move_done;
262984a2ea9SAlexander Motin 	ctl_datamove((union ctl_io *)ctsio);
263984a2ea9SAlexander Motin 
264984a2ea9SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
265984a2ea9SAlexander Motin }
266984a2ea9SAlexander Motin 
267984a2ea9SAlexander Motin int
268984a2ea9SAlexander Motin ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio)
269984a2ea9SAlexander Motin {
270984a2ea9SAlexander Motin 	struct ctl_lun *lun;
271984a2ea9SAlexander Motin 	struct scsi_receive_copy_operating_parameters *cdb;
272984a2ea9SAlexander Motin 	struct scsi_receive_copy_operating_parameters_data *data;
273984a2ea9SAlexander Motin 	int retval;
274984a2ea9SAlexander Motin 	int alloc_len, total_len;
275984a2ea9SAlexander Motin 
276984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_report_supported_tmf\n"));
277984a2ea9SAlexander Motin 
278984a2ea9SAlexander Motin 	cdb = (struct scsi_receive_copy_operating_parameters *)ctsio->cdb;
279984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
280984a2ea9SAlexander Motin 
281984a2ea9SAlexander Motin 	retval = CTL_RETVAL_COMPLETE;
282984a2ea9SAlexander Motin 
283984a2ea9SAlexander Motin 	total_len = sizeof(*data) + 4;
284984a2ea9SAlexander Motin 	alloc_len = scsi_4btoul(cdb->length);
285984a2ea9SAlexander Motin 
286984a2ea9SAlexander Motin 	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
287984a2ea9SAlexander Motin 
288984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
289984a2ea9SAlexander Motin 
290984a2ea9SAlexander Motin 	if (total_len < alloc_len) {
291984a2ea9SAlexander Motin 		ctsio->residual = alloc_len - total_len;
292984a2ea9SAlexander Motin 		ctsio->kern_data_len = total_len;
293984a2ea9SAlexander Motin 		ctsio->kern_total_len = total_len;
294984a2ea9SAlexander Motin 	} else {
295984a2ea9SAlexander Motin 		ctsio->residual = 0;
296984a2ea9SAlexander Motin 		ctsio->kern_data_len = alloc_len;
297984a2ea9SAlexander Motin 		ctsio->kern_total_len = alloc_len;
298984a2ea9SAlexander Motin 	}
299984a2ea9SAlexander Motin 	ctsio->kern_data_resid = 0;
300984a2ea9SAlexander Motin 	ctsio->kern_rel_offset = 0;
301984a2ea9SAlexander Motin 
302984a2ea9SAlexander Motin 	data = (struct scsi_receive_copy_operating_parameters_data *)ctsio->kern_data_ptr;
303984a2ea9SAlexander Motin 	scsi_ulto4b(sizeof(*data) - 4 + 4, data->length);
304984a2ea9SAlexander Motin 	data->snlid = RCOP_SNLID;
305984a2ea9SAlexander Motin 	scsi_ulto2b(TPC_MAX_CSCDS, data->maximum_cscd_descriptor_count);
306984a2ea9SAlexander Motin 	scsi_ulto2b(TPC_MAX_SEGS, data->maximum_segment_descriptor_count);
307984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_LIST, data->maximum_descriptor_list_length);
308984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_SEG, data->maximum_segment_length);
309984a2ea9SAlexander Motin 	scsi_ulto4b(TPC_MAX_INLINE, data->maximum_inline_data_length);
310984a2ea9SAlexander Motin 	scsi_ulto4b(0, data->held_data_limit);
311984a2ea9SAlexander Motin 	scsi_ulto4b(0, data->maximum_stream_device_transfer_size);
312984a2ea9SAlexander Motin 	scsi_ulto2b(TPC_MAX_LISTS, data->total_concurrent_copies);
313984a2ea9SAlexander Motin 	data->maximum_concurrent_copies = TPC_MAX_LISTS;
314984a2ea9SAlexander Motin 	data->data_segment_granularity = 0;
315984a2ea9SAlexander Motin 	data->inline_data_granularity = 0;
316984a2ea9SAlexander Motin 	data->held_data_granularity = 0;
317984a2ea9SAlexander Motin 	data->implemented_descriptor_list_length = 4;
318984a2ea9SAlexander Motin 	data->list_of_implemented_descriptor_type_codes[0] = EC_SEG_B2B;
319984a2ea9SAlexander Motin 	data->list_of_implemented_descriptor_type_codes[1] = EC_SEG_VERIFY;
320984a2ea9SAlexander Motin 	data->list_of_implemented_descriptor_type_codes[2] = EC_SEG_REGISTER_KEY;
321984a2ea9SAlexander Motin 	data->list_of_implemented_descriptor_type_codes[3] = EC_CSCD_ID;
322984a2ea9SAlexander Motin 
323984a2ea9SAlexander Motin 	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
324984a2ea9SAlexander Motin 	ctsio->be_move_done = ctl_config_move_done;
325984a2ea9SAlexander Motin 
326984a2ea9SAlexander Motin 	ctl_datamove((union ctl_io *)ctsio);
327984a2ea9SAlexander Motin 	return (retval);
328984a2ea9SAlexander Motin }
329984a2ea9SAlexander Motin 
330984a2ea9SAlexander Motin int
331984a2ea9SAlexander Motin ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio)
332984a2ea9SAlexander Motin {
333984a2ea9SAlexander Motin 	struct ctl_lun *lun;
334984a2ea9SAlexander Motin 	struct scsi_receive_copy_status_lid1 *cdb;
335984a2ea9SAlexander Motin 	struct scsi_receive_copy_status_lid1_data *data;
336984a2ea9SAlexander Motin 	struct tpc_list *list;
337984a2ea9SAlexander Motin 	struct tpc_list list_copy;
338984a2ea9SAlexander Motin 	int retval;
339984a2ea9SAlexander Motin 	int alloc_len, total_len;
340984a2ea9SAlexander Motin 	uint32_t list_id;
341984a2ea9SAlexander Motin 
342984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid1\n"));
343984a2ea9SAlexander Motin 
344984a2ea9SAlexander Motin 	cdb = (struct scsi_receive_copy_status_lid1 *)ctsio->cdb;
345984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
346984a2ea9SAlexander Motin 
347984a2ea9SAlexander Motin 	retval = CTL_RETVAL_COMPLETE;
348984a2ea9SAlexander Motin 
349984a2ea9SAlexander Motin 	list_id = cdb->list_identifier;
350984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
351984a2ea9SAlexander Motin 	TAILQ_FOREACH(list, &lun->tpc_lists, links) {
352984a2ea9SAlexander Motin 		if ((list->flags & EC_LIST_ID_USAGE_MASK) !=
353984a2ea9SAlexander Motin 		     EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
354984a2ea9SAlexander Motin 			break;
355984a2ea9SAlexander Motin 	}
356984a2ea9SAlexander Motin 	if (list == NULL) {
357984a2ea9SAlexander Motin 		mtx_unlock(&lun->lun_lock);
358984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
359984a2ea9SAlexander Motin 		    /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
360984a2ea9SAlexander Motin 		    /*bit*/ 0);
361984a2ea9SAlexander Motin 		ctl_done((union ctl_io *)ctsio);
362984a2ea9SAlexander Motin 		return (retval);
363984a2ea9SAlexander Motin 	}
364984a2ea9SAlexander Motin 	list_copy = *list;
365984a2ea9SAlexander Motin 	if (list->completed) {
366984a2ea9SAlexander Motin 		TAILQ_REMOVE(&lun->tpc_lists, list, links);
367984a2ea9SAlexander Motin 		free(list, M_CTL);
368984a2ea9SAlexander Motin 	}
369984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
370984a2ea9SAlexander Motin 
371984a2ea9SAlexander Motin 	total_len = sizeof(*data);
372984a2ea9SAlexander Motin 	alloc_len = scsi_4btoul(cdb->length);
373984a2ea9SAlexander Motin 
374984a2ea9SAlexander Motin 	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
375984a2ea9SAlexander Motin 
376984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
377984a2ea9SAlexander Motin 
378984a2ea9SAlexander Motin 	if (total_len < alloc_len) {
379984a2ea9SAlexander Motin 		ctsio->residual = alloc_len - total_len;
380984a2ea9SAlexander Motin 		ctsio->kern_data_len = total_len;
381984a2ea9SAlexander Motin 		ctsio->kern_total_len = total_len;
382984a2ea9SAlexander Motin 	} else {
383984a2ea9SAlexander Motin 		ctsio->residual = 0;
384984a2ea9SAlexander Motin 		ctsio->kern_data_len = alloc_len;
385984a2ea9SAlexander Motin 		ctsio->kern_total_len = alloc_len;
386984a2ea9SAlexander Motin 	}
387984a2ea9SAlexander Motin 	ctsio->kern_data_resid = 0;
388984a2ea9SAlexander Motin 	ctsio->kern_rel_offset = 0;
389984a2ea9SAlexander Motin 
390984a2ea9SAlexander Motin 	data = (struct scsi_receive_copy_status_lid1_data *)ctsio->kern_data_ptr;
391984a2ea9SAlexander Motin 	scsi_ulto4b(sizeof(*data) - 4, data->available_data);
392984a2ea9SAlexander Motin 	if (list_copy.completed) {
393984a2ea9SAlexander Motin 		if (list_copy.error || list_copy.abort)
394984a2ea9SAlexander Motin 			data->copy_command_status = RCS_CCS_ERROR;
395984a2ea9SAlexander Motin 		else
396984a2ea9SAlexander Motin 			data->copy_command_status = RCS_CCS_COMPLETED;
397984a2ea9SAlexander Motin 	} else
398984a2ea9SAlexander Motin 		data->copy_command_status = RCS_CCS_INPROG;
399984a2ea9SAlexander Motin 	scsi_ulto2b(list_copy.curseg, data->segments_processed);
400984a2ea9SAlexander Motin 	if (list_copy.curbytes <= UINT32_MAX) {
401984a2ea9SAlexander Motin 		data->transfer_count_units = RCS_TC_BYTES;
402984a2ea9SAlexander Motin 		scsi_ulto4b(list_copy.curbytes, data->transfer_count);
403984a2ea9SAlexander Motin 	} else {
404984a2ea9SAlexander Motin 		data->transfer_count_units = RCS_TC_MBYTES;
405984a2ea9SAlexander Motin 		scsi_ulto4b(list_copy.curbytes >> 20, data->transfer_count);
406984a2ea9SAlexander Motin 	}
407984a2ea9SAlexander Motin 
408984a2ea9SAlexander Motin 	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
409984a2ea9SAlexander Motin 	ctsio->be_move_done = ctl_config_move_done;
410984a2ea9SAlexander Motin 
411984a2ea9SAlexander Motin 	ctl_datamove((union ctl_io *)ctsio);
412984a2ea9SAlexander Motin 	return (retval);
413984a2ea9SAlexander Motin }
414984a2ea9SAlexander Motin 
415984a2ea9SAlexander Motin int
416984a2ea9SAlexander Motin ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio)
417984a2ea9SAlexander Motin {
418984a2ea9SAlexander Motin 	struct ctl_lun *lun;
419984a2ea9SAlexander Motin 	struct scsi_receive_copy_failure_details *cdb;
420984a2ea9SAlexander Motin 	struct scsi_receive_copy_failure_details_data *data;
421984a2ea9SAlexander Motin 	struct tpc_list *list;
422984a2ea9SAlexander Motin 	struct tpc_list list_copy;
423984a2ea9SAlexander Motin 	int retval;
424984a2ea9SAlexander Motin 	int alloc_len, total_len;
425984a2ea9SAlexander Motin 	uint32_t list_id;
426984a2ea9SAlexander Motin 
427984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_receive_copy_failure_details\n"));
428984a2ea9SAlexander Motin 
429984a2ea9SAlexander Motin 	cdb = (struct scsi_receive_copy_failure_details *)ctsio->cdb;
430984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
431984a2ea9SAlexander Motin 
432984a2ea9SAlexander Motin 	retval = CTL_RETVAL_COMPLETE;
433984a2ea9SAlexander Motin 
434984a2ea9SAlexander Motin 	list_id = cdb->list_identifier;
435984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
436984a2ea9SAlexander Motin 	TAILQ_FOREACH(list, &lun->tpc_lists, links) {
437984a2ea9SAlexander Motin 		if (list->completed && (list->flags & EC_LIST_ID_USAGE_MASK) !=
438984a2ea9SAlexander Motin 		     EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
439984a2ea9SAlexander Motin 			break;
440984a2ea9SAlexander Motin 	}
441984a2ea9SAlexander Motin 	if (list == NULL) {
442984a2ea9SAlexander Motin 		mtx_unlock(&lun->lun_lock);
443984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
444984a2ea9SAlexander Motin 		    /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
445984a2ea9SAlexander Motin 		    /*bit*/ 0);
446984a2ea9SAlexander Motin 		ctl_done((union ctl_io *)ctsio);
447984a2ea9SAlexander Motin 		return (retval);
448984a2ea9SAlexander Motin 	}
449984a2ea9SAlexander Motin 	list_copy = *list;
450984a2ea9SAlexander Motin 	TAILQ_REMOVE(&lun->tpc_lists, list, links);
451984a2ea9SAlexander Motin 	free(list, M_CTL);
452984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
453984a2ea9SAlexander Motin 
454984a2ea9SAlexander Motin 	total_len = sizeof(*data) + list_copy.sense_len;
455984a2ea9SAlexander Motin 	alloc_len = scsi_4btoul(cdb->length);
456984a2ea9SAlexander Motin 
457984a2ea9SAlexander Motin 	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
458984a2ea9SAlexander Motin 
459984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
460984a2ea9SAlexander Motin 
461984a2ea9SAlexander Motin 	if (total_len < alloc_len) {
462984a2ea9SAlexander Motin 		ctsio->residual = alloc_len - total_len;
463984a2ea9SAlexander Motin 		ctsio->kern_data_len = total_len;
464984a2ea9SAlexander Motin 		ctsio->kern_total_len = total_len;
465984a2ea9SAlexander Motin 	} else {
466984a2ea9SAlexander Motin 		ctsio->residual = 0;
467984a2ea9SAlexander Motin 		ctsio->kern_data_len = alloc_len;
468984a2ea9SAlexander Motin 		ctsio->kern_total_len = alloc_len;
469984a2ea9SAlexander Motin 	}
470984a2ea9SAlexander Motin 	ctsio->kern_data_resid = 0;
471984a2ea9SAlexander Motin 	ctsio->kern_rel_offset = 0;
472984a2ea9SAlexander Motin 
473984a2ea9SAlexander Motin 	data = (struct scsi_receive_copy_failure_details_data *)ctsio->kern_data_ptr;
474984a2ea9SAlexander Motin 	if (list_copy.completed && (list_copy.error || list_copy.abort)) {
475984a2ea9SAlexander Motin 		scsi_ulto4b(sizeof(*data) - 4, data->available_data);
476984a2ea9SAlexander Motin 		data->copy_command_status = RCS_CCS_ERROR;
477984a2ea9SAlexander Motin 	} else
478984a2ea9SAlexander Motin 		scsi_ulto4b(0, data->available_data);
479984a2ea9SAlexander Motin 	scsi_ulto2b(list_copy.sense_len, data->sense_data_length);
480984a2ea9SAlexander Motin 	memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len);
481984a2ea9SAlexander Motin 
482984a2ea9SAlexander Motin 	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
483984a2ea9SAlexander Motin 	ctsio->be_move_done = ctl_config_move_done;
484984a2ea9SAlexander Motin 
485984a2ea9SAlexander Motin 	ctl_datamove((union ctl_io *)ctsio);
486984a2ea9SAlexander Motin 	return (retval);
487984a2ea9SAlexander Motin }
488984a2ea9SAlexander Motin 
489984a2ea9SAlexander Motin int
490984a2ea9SAlexander Motin ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio)
491984a2ea9SAlexander Motin {
492984a2ea9SAlexander Motin 	struct ctl_lun *lun;
493984a2ea9SAlexander Motin 	struct scsi_receive_copy_status_lid4 *cdb;
494984a2ea9SAlexander Motin 	struct scsi_receive_copy_status_lid4_data *data;
495984a2ea9SAlexander Motin 	struct tpc_list *list;
496984a2ea9SAlexander Motin 	struct tpc_list list_copy;
497984a2ea9SAlexander Motin 	int retval;
498984a2ea9SAlexander Motin 	int alloc_len, total_len;
499984a2ea9SAlexander Motin 	uint32_t list_id;
500984a2ea9SAlexander Motin 
501984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid4\n"));
502984a2ea9SAlexander Motin 
503984a2ea9SAlexander Motin 	cdb = (struct scsi_receive_copy_status_lid4 *)ctsio->cdb;
504984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
505984a2ea9SAlexander Motin 
506984a2ea9SAlexander Motin 	retval = CTL_RETVAL_COMPLETE;
507984a2ea9SAlexander Motin 
508984a2ea9SAlexander Motin 	list_id = scsi_4btoul(cdb->list_identifier);
509984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
510984a2ea9SAlexander Motin 	TAILQ_FOREACH(list, &lun->tpc_lists, links) {
511984a2ea9SAlexander Motin 		if ((list->flags & EC_LIST_ID_USAGE_MASK) !=
512984a2ea9SAlexander Motin 		     EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
513984a2ea9SAlexander Motin 			break;
514984a2ea9SAlexander Motin 	}
515984a2ea9SAlexander Motin 	if (list == NULL) {
516984a2ea9SAlexander Motin 		mtx_unlock(&lun->lun_lock);
517984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
518984a2ea9SAlexander Motin 		    /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
519984a2ea9SAlexander Motin 		    /*bit*/ 0);
520984a2ea9SAlexander Motin 		ctl_done((union ctl_io *)ctsio);
521984a2ea9SAlexander Motin 		return (retval);
522984a2ea9SAlexander Motin 	}
523984a2ea9SAlexander Motin 	list_copy = *list;
524984a2ea9SAlexander Motin 	if (list->completed) {
525984a2ea9SAlexander Motin 		TAILQ_REMOVE(&lun->tpc_lists, list, links);
526984a2ea9SAlexander Motin 		free(list, M_CTL);
527984a2ea9SAlexander Motin 	}
528984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
529984a2ea9SAlexander Motin 
530984a2ea9SAlexander Motin 	total_len = sizeof(*data) + list_copy.sense_len;
531984a2ea9SAlexander Motin 	alloc_len = scsi_4btoul(cdb->length);
532984a2ea9SAlexander Motin 
533984a2ea9SAlexander Motin 	ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
534984a2ea9SAlexander Motin 
535984a2ea9SAlexander Motin 	ctsio->kern_sg_entries = 0;
536984a2ea9SAlexander Motin 
537984a2ea9SAlexander Motin 	if (total_len < alloc_len) {
538984a2ea9SAlexander Motin 		ctsio->residual = alloc_len - total_len;
539984a2ea9SAlexander Motin 		ctsio->kern_data_len = total_len;
540984a2ea9SAlexander Motin 		ctsio->kern_total_len = total_len;
541984a2ea9SAlexander Motin 	} else {
542984a2ea9SAlexander Motin 		ctsio->residual = 0;
543984a2ea9SAlexander Motin 		ctsio->kern_data_len = alloc_len;
544984a2ea9SAlexander Motin 		ctsio->kern_total_len = alloc_len;
545984a2ea9SAlexander Motin 	}
546984a2ea9SAlexander Motin 	ctsio->kern_data_resid = 0;
547984a2ea9SAlexander Motin 	ctsio->kern_rel_offset = 0;
548984a2ea9SAlexander Motin 
549984a2ea9SAlexander Motin 	data = (struct scsi_receive_copy_status_lid4_data *)ctsio->kern_data_ptr;
550984a2ea9SAlexander Motin 	scsi_ulto4b(sizeof(*data) - 4, data->available_data);
551984a2ea9SAlexander Motin 	data->response_to_service_action = list_copy.service_action;
552984a2ea9SAlexander Motin 	if (list_copy.completed) {
553984a2ea9SAlexander Motin 		if (list_copy.error)
554984a2ea9SAlexander Motin 			data->copy_command_status = RCS_CCS_ERROR;
555984a2ea9SAlexander Motin 		else if (list_copy.abort)
556984a2ea9SAlexander Motin 			data->copy_command_status = RCS_CCS_ABORTED;
557984a2ea9SAlexander Motin 		else
558984a2ea9SAlexander Motin 			data->copy_command_status = RCS_CCS_COMPLETED;
559984a2ea9SAlexander Motin 	} else
560984a2ea9SAlexander Motin 		data->copy_command_status = RCS_CCS_INPROG_FG;
561984a2ea9SAlexander Motin 	scsi_ulto2b(list_copy.curops, data->operation_counter);
562984a2ea9SAlexander Motin 	scsi_ulto4b(UINT32_MAX, data->estimated_status_update_delay);
563984a2ea9SAlexander Motin 	if (list_copy.curbytes <= UINT32_MAX) {
564984a2ea9SAlexander Motin 		data->transfer_count_units = RCS_TC_BYTES;
565984a2ea9SAlexander Motin 		scsi_ulto4b(list_copy.curbytes, data->transfer_count);
566984a2ea9SAlexander Motin 	} else {
567984a2ea9SAlexander Motin 		data->transfer_count_units = RCS_TC_MBYTES;
568984a2ea9SAlexander Motin 		scsi_ulto4b(list_copy.curbytes >> 20, data->transfer_count);
569984a2ea9SAlexander Motin 	}
570984a2ea9SAlexander Motin 	scsi_ulto2b(list_copy.curseg, data->segments_processed);
571984a2ea9SAlexander Motin 	data->sense_data_length = list_copy.sense_len;
572984a2ea9SAlexander Motin 	memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len);
573984a2ea9SAlexander Motin 
574984a2ea9SAlexander Motin 	ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
575984a2ea9SAlexander Motin 	ctsio->be_move_done = ctl_config_move_done;
576984a2ea9SAlexander Motin 
577984a2ea9SAlexander Motin 	ctl_datamove((union ctl_io *)ctsio);
578984a2ea9SAlexander Motin 	return (retval);
579984a2ea9SAlexander Motin }
580984a2ea9SAlexander Motin 
581984a2ea9SAlexander Motin int
582984a2ea9SAlexander Motin ctl_copy_operation_abort(struct ctl_scsiio *ctsio)
583984a2ea9SAlexander Motin {
584984a2ea9SAlexander Motin 	struct ctl_lun *lun;
585984a2ea9SAlexander Motin 	struct scsi_copy_operation_abort *cdb;
586984a2ea9SAlexander Motin 	struct tpc_list *list;
587984a2ea9SAlexander Motin 	int retval;
588984a2ea9SAlexander Motin 	uint32_t list_id;
589984a2ea9SAlexander Motin 
590984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_copy_operation_abort\n"));
591984a2ea9SAlexander Motin 
592984a2ea9SAlexander Motin 	cdb = (struct scsi_copy_operation_abort *)ctsio->cdb;
593984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
594984a2ea9SAlexander Motin 
595984a2ea9SAlexander Motin 	retval = CTL_RETVAL_COMPLETE;
596984a2ea9SAlexander Motin 
597984a2ea9SAlexander Motin 	list_id = scsi_4btoul(cdb->list_identifier);
598984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
599984a2ea9SAlexander Motin 	TAILQ_FOREACH(list, &lun->tpc_lists, links) {
600984a2ea9SAlexander Motin 		if ((list->flags & EC_LIST_ID_USAGE_MASK) !=
601984a2ea9SAlexander Motin 		     EC_LIST_ID_USAGE_NONE && list->list_id == list_id)
602984a2ea9SAlexander Motin 			break;
603984a2ea9SAlexander Motin 	}
604984a2ea9SAlexander Motin 	if (list == NULL) {
605984a2ea9SAlexander Motin 		mtx_unlock(&lun->lun_lock);
606984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
607984a2ea9SAlexander Motin 		    /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0,
608984a2ea9SAlexander Motin 		    /*bit*/ 0);
609984a2ea9SAlexander Motin 		ctl_done((union ctl_io *)ctsio);
610984a2ea9SAlexander Motin 		return (retval);
611984a2ea9SAlexander Motin 	}
612984a2ea9SAlexander Motin 	list->abort = 1;
613984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
614984a2ea9SAlexander Motin 
615984a2ea9SAlexander Motin 	ctl_set_success(ctsio);
616984a2ea9SAlexander Motin 	ctl_done((union ctl_io *)ctsio);
617984a2ea9SAlexander Motin 	return (retval);
618984a2ea9SAlexander Motin }
619984a2ea9SAlexander Motin 
620984a2ea9SAlexander Motin static uint64_t
621984a2ea9SAlexander Motin tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss)
622984a2ea9SAlexander Motin {
623984a2ea9SAlexander Motin 
624984a2ea9SAlexander Motin 	if (idx == 0xffff) {
625984a2ea9SAlexander Motin 		if (ss && list->lun->be_lun)
626984a2ea9SAlexander Motin 			*ss = list->lun->be_lun->blocksize;
627984a2ea9SAlexander Motin 		return (list->lun->lun);
628984a2ea9SAlexander Motin 	}
629984a2ea9SAlexander Motin 	if (idx >= list->ncscd)
630984a2ea9SAlexander Motin 		return (UINT64_MAX);
631984a2ea9SAlexander Motin 	return (tpcl_resolve(list->init_port, &list->cscd[idx], ss));
632984a2ea9SAlexander Motin }
633984a2ea9SAlexander Motin 
634984a2ea9SAlexander Motin static int
635984a2ea9SAlexander Motin tpc_process_b2b(struct tpc_list *list)
636984a2ea9SAlexander Motin {
637984a2ea9SAlexander Motin 	struct scsi_ec_segment_b2b *seg;
638984a2ea9SAlexander Motin 	struct scsi_ec_cscd_dtsp *sdstp, *ddstp;
639984a2ea9SAlexander Motin 	struct tpc_io *tior, *tiow;
640984a2ea9SAlexander Motin 	struct runl run, *prun;
641984a2ea9SAlexander Motin 	uint64_t sl, dl;
642984a2ea9SAlexander Motin 	off_t srclba, dstlba, numbytes, donebytes, roundbytes;
643984a2ea9SAlexander Motin 	int numlba;
644984a2ea9SAlexander Motin 	uint32_t srcblock, dstblock;
645984a2ea9SAlexander Motin 
646984a2ea9SAlexander Motin 	if (list->stage == 1) {
647984a2ea9SAlexander Motin complete:
648984a2ea9SAlexander Motin 		while ((tior = TAILQ_FIRST(&list->allio)) != NULL) {
649984a2ea9SAlexander Motin 			TAILQ_REMOVE(&list->allio, tior, links);
650984a2ea9SAlexander Motin 			ctl_free_io(tior->io);
651984a2ea9SAlexander Motin 			free(tior, M_CTL);
652984a2ea9SAlexander Motin 		}
653984a2ea9SAlexander Motin 		free(list->buf, M_CTL);
654984a2ea9SAlexander Motin 		if (list->abort) {
655984a2ea9SAlexander Motin 			ctl_set_task_aborted(list->ctsio);
656984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
657984a2ea9SAlexander Motin 		} else if (list->error) {
658984a2ea9SAlexander Motin 			ctl_set_sense(list->ctsio, /*current_error*/ 1,
659984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_COPY_ABORTED,
660984a2ea9SAlexander Motin 			    /*asc*/ 0x0d, /*ascq*/ 0x01, SSD_ELEM_NONE);
661984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
662984a2ea9SAlexander Motin 		} else {
663984a2ea9SAlexander Motin 			list->curbytes += list->segbytes;
664984a2ea9SAlexander Motin 			return (CTL_RETVAL_COMPLETE);
665984a2ea9SAlexander Motin 		}
666984a2ea9SAlexander Motin 	}
667984a2ea9SAlexander Motin 
668984a2ea9SAlexander Motin 	TAILQ_INIT(&list->allio);
669984a2ea9SAlexander Motin 	seg = (struct scsi_ec_segment_b2b *)list->seg[list->curseg];
670984a2ea9SAlexander Motin 	sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), &srcblock);
671984a2ea9SAlexander Motin 	dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), &dstblock);
672984a2ea9SAlexander Motin 	if (sl >= CTL_MAX_LUNS || dl >= CTL_MAX_LUNS) {
673984a2ea9SAlexander Motin 		ctl_set_sense(list->ctsio, /*current_error*/ 1,
674984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_COPY_ABORTED,
675984a2ea9SAlexander Motin 		    /*asc*/ 0x08, /*ascq*/ 0x04, SSD_ELEM_NONE);
676984a2ea9SAlexander Motin 		return (CTL_RETVAL_ERROR);
677984a2ea9SAlexander Motin 	}
678984a2ea9SAlexander Motin 	sdstp = &list->cscd[scsi_2btoul(seg->src_cscd)].dtsp;
679984a2ea9SAlexander Motin 	if (scsi_3btoul(sdstp->block_length) != 0)
680984a2ea9SAlexander Motin 		srcblock = scsi_3btoul(sdstp->block_length);
681984a2ea9SAlexander Motin 	ddstp = &list->cscd[scsi_2btoul(seg->dst_cscd)].dtsp;
682984a2ea9SAlexander Motin 	if (scsi_3btoul(ddstp->block_length) != 0)
683984a2ea9SAlexander Motin 		dstblock = scsi_3btoul(ddstp->block_length);
684984a2ea9SAlexander Motin 	numlba = scsi_2btoul(seg->number_of_blocks);
685984a2ea9SAlexander Motin 	if (seg->flags & EC_SEG_DC)
686984a2ea9SAlexander Motin 		numbytes = (off_t)numlba * dstblock;
687984a2ea9SAlexander Motin 	else
688984a2ea9SAlexander Motin 		numbytes = (off_t)numlba * srcblock;
689984a2ea9SAlexander Motin 	srclba = scsi_8btou64(seg->src_lba);
690984a2ea9SAlexander Motin 	dstlba = scsi_8btou64(seg->dst_lba);
691984a2ea9SAlexander Motin 
692984a2ea9SAlexander Motin //	printf("Copy %ju bytes from %ju @ %ju to %ju @ %ju\n",
693984a2ea9SAlexander Motin //	    (uintmax_t)numbytes, sl, scsi_8btou64(seg->src_lba),
694984a2ea9SAlexander Motin //	    dl, scsi_8btou64(seg->dst_lba));
695984a2ea9SAlexander Motin 
696984a2ea9SAlexander Motin 	if (numbytes == 0)
697984a2ea9SAlexander Motin 		return (CTL_RETVAL_COMPLETE);
698984a2ea9SAlexander Motin 
699984a2ea9SAlexander Motin 	if (numbytes % srcblock != 0 || numbytes % dstblock != 0) {
700984a2ea9SAlexander Motin 		ctl_set_sense(list->ctsio, /*current_error*/ 1,
701984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_COPY_ABORTED,
702984a2ea9SAlexander Motin 		    /*asc*/ 0x26, /*ascq*/ 0x0A, SSD_ELEM_NONE);
703984a2ea9SAlexander Motin 		return (CTL_RETVAL_ERROR);
704984a2ea9SAlexander Motin 	}
705984a2ea9SAlexander Motin 
706984a2ea9SAlexander Motin 	list->buf = malloc(numbytes, M_CTL, M_WAITOK);
707984a2ea9SAlexander Motin 	list->segbytes = numbytes;
708984a2ea9SAlexander Motin 	donebytes = 0;
709984a2ea9SAlexander Motin 	TAILQ_INIT(&run);
710984a2ea9SAlexander Motin 	prun = &run;
711984a2ea9SAlexander Motin 	list->tbdio = 1;
712984a2ea9SAlexander Motin 	while (donebytes < numbytes) {
713984a2ea9SAlexander Motin 		roundbytes = MIN(numbytes - donebytes, TPC_MAX_IO_SIZE);
714984a2ea9SAlexander Motin 
715984a2ea9SAlexander Motin 		tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO);
716984a2ea9SAlexander Motin 		TAILQ_INIT(&tior->run);
717984a2ea9SAlexander Motin 		tior->list = list;
718984a2ea9SAlexander Motin 		TAILQ_INSERT_TAIL(&list->allio, tior, links);
719984a2ea9SAlexander Motin 		tior->io = tpcl_alloc_io();
720984a2ea9SAlexander Motin 		if (tior->io == NULL) {
721984a2ea9SAlexander Motin 			list->error = 1;
722984a2ea9SAlexander Motin 			goto complete;
723984a2ea9SAlexander Motin 		}
724984a2ea9SAlexander Motin 		ctl_scsi_read_write(tior->io,
725984a2ea9SAlexander Motin 				    /*data_ptr*/ &list->buf[donebytes],
726984a2ea9SAlexander Motin 				    /*data_len*/ roundbytes,
727984a2ea9SAlexander Motin 				    /*read_op*/ 1,
728984a2ea9SAlexander Motin 				    /*byte2*/ 0,
729984a2ea9SAlexander Motin 				    /*minimum_cdb_size*/ 0,
730984a2ea9SAlexander Motin 				    /*lba*/ srclba + donebytes / srcblock,
731984a2ea9SAlexander Motin 				    /*num_blocks*/ roundbytes / srcblock,
732984a2ea9SAlexander Motin 				    /*tag_type*/ CTL_TAG_SIMPLE,
733984a2ea9SAlexander Motin 				    /*control*/ 0);
734984a2ea9SAlexander Motin 		tior->io->io_hdr.retries = 3;
735984a2ea9SAlexander Motin 		tior->lun = sl;
736984a2ea9SAlexander Motin 		tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior;
737984a2ea9SAlexander Motin 
738984a2ea9SAlexander Motin 		tiow = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO);
739984a2ea9SAlexander Motin 		TAILQ_INIT(&tiow->run);
740984a2ea9SAlexander Motin 		tiow->list = list;
741984a2ea9SAlexander Motin 		TAILQ_INSERT_TAIL(&list->allio, tiow, links);
742984a2ea9SAlexander Motin 		tiow->io = tpcl_alloc_io();
743984a2ea9SAlexander Motin 		if (tiow->io == NULL) {
744984a2ea9SAlexander Motin 			list->error = 1;
745984a2ea9SAlexander Motin 			goto complete;
746984a2ea9SAlexander Motin 		}
747984a2ea9SAlexander Motin 		ctl_scsi_read_write(tiow->io,
748984a2ea9SAlexander Motin 				    /*data_ptr*/ &list->buf[donebytes],
749984a2ea9SAlexander Motin 				    /*data_len*/ roundbytes,
750984a2ea9SAlexander Motin 				    /*read_op*/ 0,
751984a2ea9SAlexander Motin 				    /*byte2*/ 0,
752984a2ea9SAlexander Motin 				    /*minimum_cdb_size*/ 0,
753984a2ea9SAlexander Motin 				    /*lba*/ dstlba + donebytes / dstblock,
754984a2ea9SAlexander Motin 				    /*num_blocks*/ roundbytes / dstblock,
755984a2ea9SAlexander Motin 				    /*tag_type*/ CTL_TAG_SIMPLE,
756984a2ea9SAlexander Motin 				    /*control*/ 0);
757984a2ea9SAlexander Motin 		tiow->io->io_hdr.retries = 3;
758984a2ea9SAlexander Motin 		tiow->lun = dl;
759984a2ea9SAlexander Motin 		tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior;
760984a2ea9SAlexander Motin 
761984a2ea9SAlexander Motin 		TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks);
762984a2ea9SAlexander Motin 		TAILQ_INSERT_TAIL(prun, tior, rlinks);
763984a2ea9SAlexander Motin 		prun = &tior->run;
764984a2ea9SAlexander Motin 		donebytes += roundbytes;
765984a2ea9SAlexander Motin 	}
766984a2ea9SAlexander Motin 
767984a2ea9SAlexander Motin 	while ((tior = TAILQ_FIRST(&run)) != NULL) {
768984a2ea9SAlexander Motin 		TAILQ_REMOVE(&run, tior, rlinks);
769984a2ea9SAlexander Motin 		if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE)
770984a2ea9SAlexander Motin 			panic("tpcl_queue() error");
771984a2ea9SAlexander Motin 	}
772984a2ea9SAlexander Motin 
773984a2ea9SAlexander Motin 	list->stage++;
774984a2ea9SAlexander Motin 	return (CTL_RETVAL_QUEUED);
775984a2ea9SAlexander Motin }
776984a2ea9SAlexander Motin 
777984a2ea9SAlexander Motin static int
778984a2ea9SAlexander Motin tpc_process_verify(struct tpc_list *list)
779984a2ea9SAlexander Motin {
780984a2ea9SAlexander Motin 	struct scsi_ec_segment_verify *seg;
781984a2ea9SAlexander Motin 	struct tpc_io *tio;
782984a2ea9SAlexander Motin 	uint64_t sl;
783984a2ea9SAlexander Motin 
784984a2ea9SAlexander Motin 	if (list->stage == 1) {
785984a2ea9SAlexander Motin complete:
786984a2ea9SAlexander Motin 		while ((tio = TAILQ_FIRST(&list->allio)) != NULL) {
787984a2ea9SAlexander Motin 			TAILQ_REMOVE(&list->allio, tio, links);
788984a2ea9SAlexander Motin 			ctl_free_io(tio->io);
789984a2ea9SAlexander Motin 			free(tio, M_CTL);
790984a2ea9SAlexander Motin 		}
791984a2ea9SAlexander Motin 		if (list->abort) {
792984a2ea9SAlexander Motin 			ctl_set_task_aborted(list->ctsio);
793984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
794984a2ea9SAlexander Motin 		} else if (list->error) {
795984a2ea9SAlexander Motin 			ctl_set_sense(list->ctsio, /*current_error*/ 1,
796984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_COPY_ABORTED,
797984a2ea9SAlexander Motin 			    /*asc*/ 0x0d, /*ascq*/ 0x01, SSD_ELEM_NONE);
798984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
799984a2ea9SAlexander Motin 		} else
800984a2ea9SAlexander Motin 			return (CTL_RETVAL_COMPLETE);
801984a2ea9SAlexander Motin 	}
802984a2ea9SAlexander Motin 
803984a2ea9SAlexander Motin 	TAILQ_INIT(&list->allio);
804984a2ea9SAlexander Motin 	seg = (struct scsi_ec_segment_verify *)list->seg[list->curseg];
805984a2ea9SAlexander Motin 	sl = tpc_resolve(list, scsi_2btoul(seg->src_cscd), NULL);
806984a2ea9SAlexander Motin 	if (sl >= CTL_MAX_LUNS) {
807984a2ea9SAlexander Motin 		ctl_set_sense(list->ctsio, /*current_error*/ 1,
808984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_COPY_ABORTED,
809984a2ea9SAlexander Motin 		    /*asc*/ 0x08, /*ascq*/ 0x04, SSD_ELEM_NONE);
810984a2ea9SAlexander Motin 		return (CTL_RETVAL_ERROR);
811984a2ea9SAlexander Motin 	}
812984a2ea9SAlexander Motin 
813984a2ea9SAlexander Motin //	printf("Verify %ju\n", sl);
814984a2ea9SAlexander Motin 
815984a2ea9SAlexander Motin 	if ((seg->tur & 0x01) == 0)
816984a2ea9SAlexander Motin 		return (CTL_RETVAL_COMPLETE);
817984a2ea9SAlexander Motin 
818984a2ea9SAlexander Motin 	list->tbdio = 1;
819984a2ea9SAlexander Motin 	tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO);
820984a2ea9SAlexander Motin 	TAILQ_INIT(&tio->run);
821984a2ea9SAlexander Motin 	tio->list = list;
822984a2ea9SAlexander Motin 	TAILQ_INSERT_TAIL(&list->allio, tio, links);
823984a2ea9SAlexander Motin 	tio->io = tpcl_alloc_io();
824984a2ea9SAlexander Motin 	if (tio->io == NULL) {
825984a2ea9SAlexander Motin 		list->error = 1;
826984a2ea9SAlexander Motin 		goto complete;
827984a2ea9SAlexander Motin 	}
828984a2ea9SAlexander Motin 	ctl_scsi_tur(tio->io, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0);
829984a2ea9SAlexander Motin 	tio->io->io_hdr.retries = 3;
830984a2ea9SAlexander Motin 	tio->lun = sl;
831984a2ea9SAlexander Motin 	tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio;
832984a2ea9SAlexander Motin 	list->stage++;
833984a2ea9SAlexander Motin 	if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE)
834984a2ea9SAlexander Motin 		panic("tpcl_queue() error");
835984a2ea9SAlexander Motin 	return (CTL_RETVAL_QUEUED);
836984a2ea9SAlexander Motin }
837984a2ea9SAlexander Motin 
838984a2ea9SAlexander Motin static int
839984a2ea9SAlexander Motin tpc_process_register_key(struct tpc_list *list)
840984a2ea9SAlexander Motin {
841984a2ea9SAlexander Motin 	struct scsi_ec_segment_register_key *seg;
842984a2ea9SAlexander Motin 	struct tpc_io *tio;
843984a2ea9SAlexander Motin 	uint64_t dl;
844984a2ea9SAlexander Motin 	int datalen;
845984a2ea9SAlexander Motin 
846984a2ea9SAlexander Motin 	if (list->stage == 1) {
847984a2ea9SAlexander Motin complete:
848984a2ea9SAlexander Motin 		while ((tio = TAILQ_FIRST(&list->allio)) != NULL) {
849984a2ea9SAlexander Motin 			TAILQ_REMOVE(&list->allio, tio, links);
850984a2ea9SAlexander Motin 			ctl_free_io(tio->io);
851984a2ea9SAlexander Motin 			free(tio, M_CTL);
852984a2ea9SAlexander Motin 		}
853984a2ea9SAlexander Motin 		free(list->buf, M_CTL);
854984a2ea9SAlexander Motin 		if (list->abort) {
855984a2ea9SAlexander Motin 			ctl_set_task_aborted(list->ctsio);
856984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
857984a2ea9SAlexander Motin 		} else if (list->error) {
858984a2ea9SAlexander Motin 			ctl_set_sense(list->ctsio, /*current_error*/ 1,
859984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_COPY_ABORTED,
860984a2ea9SAlexander Motin 			    /*asc*/ 0x0d, /*ascq*/ 0x01, SSD_ELEM_NONE);
861984a2ea9SAlexander Motin 			return (CTL_RETVAL_ERROR);
862984a2ea9SAlexander Motin 		} else
863984a2ea9SAlexander Motin 			return (CTL_RETVAL_COMPLETE);
864984a2ea9SAlexander Motin 	}
865984a2ea9SAlexander Motin 
866984a2ea9SAlexander Motin 	TAILQ_INIT(&list->allio);
867984a2ea9SAlexander Motin 	seg = (struct scsi_ec_segment_register_key *)list->seg[list->curseg];
868984a2ea9SAlexander Motin 	dl = tpc_resolve(list, scsi_2btoul(seg->dst_cscd), NULL);
869984a2ea9SAlexander Motin 	if (dl >= CTL_MAX_LUNS) {
870984a2ea9SAlexander Motin 		ctl_set_sense(list->ctsio, /*current_error*/ 1,
871984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_COPY_ABORTED,
872984a2ea9SAlexander Motin 		    /*asc*/ 0x08, /*ascq*/ 0x04, SSD_ELEM_NONE);
873984a2ea9SAlexander Motin 		return (CTL_RETVAL_ERROR);
874984a2ea9SAlexander Motin 	}
875984a2ea9SAlexander Motin 
876984a2ea9SAlexander Motin //	printf("Register Key %ju\n", dl);
877984a2ea9SAlexander Motin 
878984a2ea9SAlexander Motin 	list->tbdio = 1;
879984a2ea9SAlexander Motin 	tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO);
880984a2ea9SAlexander Motin 	TAILQ_INIT(&tio->run);
881984a2ea9SAlexander Motin 	tio->list = list;
882984a2ea9SAlexander Motin 	TAILQ_INSERT_TAIL(&list->allio, tio, links);
883984a2ea9SAlexander Motin 	tio->io = tpcl_alloc_io();
884984a2ea9SAlexander Motin 	if (tio->io == NULL) {
885984a2ea9SAlexander Motin 		list->error = 1;
886984a2ea9SAlexander Motin 		goto complete;
887984a2ea9SAlexander Motin 	}
888984a2ea9SAlexander Motin 	datalen = sizeof(struct scsi_per_res_out_parms);
889984a2ea9SAlexander Motin 	list->buf = malloc(datalen, M_CTL, M_WAITOK);
890984a2ea9SAlexander Motin 	ctl_scsi_persistent_res_out(tio->io,
891984a2ea9SAlexander Motin 	    list->buf, datalen, SPRO_REGISTER, -1,
892984a2ea9SAlexander Motin 	    scsi_8btou64(seg->res_key), scsi_8btou64(seg->sa_res_key),
893984a2ea9SAlexander Motin 	    /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0);
894984a2ea9SAlexander Motin 	tio->io->io_hdr.retries = 3;
895984a2ea9SAlexander Motin 	tio->lun = dl;
896984a2ea9SAlexander Motin 	tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio;
897984a2ea9SAlexander Motin 	list->stage++;
898984a2ea9SAlexander Motin 	if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE)
899984a2ea9SAlexander Motin 		panic("tpcl_queue() error");
900984a2ea9SAlexander Motin 	return (CTL_RETVAL_QUEUED);
901984a2ea9SAlexander Motin }
902984a2ea9SAlexander Motin 
903984a2ea9SAlexander Motin static void
904984a2ea9SAlexander Motin tpc_process(struct tpc_list *list)
905984a2ea9SAlexander Motin {
906984a2ea9SAlexander Motin 	struct ctl_lun *lun = list->lun;
907984a2ea9SAlexander Motin 	struct scsi_ec_segment *seg;
908984a2ea9SAlexander Motin 	struct ctl_scsiio *ctsio = list->ctsio;
909984a2ea9SAlexander Motin 	int retval = CTL_RETVAL_COMPLETE;
910984a2ea9SAlexander Motin 
911984a2ea9SAlexander Motin //printf("ZZZ %d cscd, %d segs\n", list->ncscd, list->nseg);
912984a2ea9SAlexander Motin 	while (list->curseg < list->nseg) {
913984a2ea9SAlexander Motin 		seg = list->seg[list->curseg];
914984a2ea9SAlexander Motin 		switch (seg->type_code) {
915984a2ea9SAlexander Motin 		case EC_SEG_B2B:
916984a2ea9SAlexander Motin 			retval = tpc_process_b2b(list);
917984a2ea9SAlexander Motin 			break;
918984a2ea9SAlexander Motin 		case EC_SEG_VERIFY:
919984a2ea9SAlexander Motin 			retval = tpc_process_verify(list);
920984a2ea9SAlexander Motin 			break;
921984a2ea9SAlexander Motin 		case EC_SEG_REGISTER_KEY:
922984a2ea9SAlexander Motin 			retval = tpc_process_register_key(list);
923984a2ea9SAlexander Motin 			break;
924984a2ea9SAlexander Motin 		default:
925984a2ea9SAlexander Motin 			ctl_set_sense(ctsio, /*current_error*/ 1,
926984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_COPY_ABORTED,
927984a2ea9SAlexander Motin 			    /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE);
928984a2ea9SAlexander Motin 			goto done;
929984a2ea9SAlexander Motin 		}
930984a2ea9SAlexander Motin 		if (retval == CTL_RETVAL_QUEUED)
931984a2ea9SAlexander Motin 			return;
932984a2ea9SAlexander Motin 		if (retval == CTL_RETVAL_ERROR) {
933984a2ea9SAlexander Motin 			list->error = 1;
934984a2ea9SAlexander Motin 			goto done;
935984a2ea9SAlexander Motin 		}
936984a2ea9SAlexander Motin 		list->curseg++;
937984a2ea9SAlexander Motin 		list->stage = 0;
938984a2ea9SAlexander Motin 	}
939984a2ea9SAlexander Motin 
940984a2ea9SAlexander Motin 	ctl_set_success(ctsio);
941984a2ea9SAlexander Motin 
942984a2ea9SAlexander Motin done:
943984a2ea9SAlexander Motin //printf("ZZZ done\n");
944984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
945984a2ea9SAlexander Motin 	if ((list->flags & EC_LIST_ID_USAGE_MASK) == EC_LIST_ID_USAGE_NONE) {
946984a2ea9SAlexander Motin 		TAILQ_REMOVE(&lun->tpc_lists, list, links);
947984a2ea9SAlexander Motin 		free(list, M_CTL);
948984a2ea9SAlexander Motin 	} else {
949984a2ea9SAlexander Motin 		list->completed = 1;
950984a2ea9SAlexander Motin 		list->sense_data = ctsio->sense_data;
951984a2ea9SAlexander Motin 		list->sense_len = ctsio->sense_len;
952984a2ea9SAlexander Motin 		list->scsi_status = ctsio->scsi_status;
953984a2ea9SAlexander Motin 	}
954984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
955984a2ea9SAlexander Motin 
956984a2ea9SAlexander Motin 	ctl_done((union ctl_io *)ctsio);
957984a2ea9SAlexander Motin }
958984a2ea9SAlexander Motin 
959984a2ea9SAlexander Motin /*
960984a2ea9SAlexander Motin  * For any sort of check condition, busy, etc., we just retry.  We do not
961984a2ea9SAlexander Motin  * decrement the retry count for unit attention type errors.  These are
962984a2ea9SAlexander Motin  * normal, and we want to save the retry count for "real" errors.  Otherwise,
963984a2ea9SAlexander Motin  * we could end up with situations where a command will succeed in some
964984a2ea9SAlexander Motin  * situations and fail in others, depending on whether a unit attention is
965984a2ea9SAlexander Motin  * pending.  Also, some of our error recovery actions, most notably the
966984a2ea9SAlexander Motin  * LUN reset action, will cause a unit attention.
967984a2ea9SAlexander Motin  *
968984a2ea9SAlexander Motin  * We can add more detail here later if necessary.
969984a2ea9SAlexander Motin  */
970984a2ea9SAlexander Motin static tpc_error_action
971984a2ea9SAlexander Motin tpc_checkcond_parse(union ctl_io *io)
972984a2ea9SAlexander Motin {
973984a2ea9SAlexander Motin 	tpc_error_action error_action;
974984a2ea9SAlexander Motin 	int error_code, sense_key, asc, ascq;
975984a2ea9SAlexander Motin 
976984a2ea9SAlexander Motin 	/*
977984a2ea9SAlexander Motin 	 * Default to retrying the command.
978984a2ea9SAlexander Motin 	 */
979984a2ea9SAlexander Motin 	error_action = TPC_ERR_RETRY;
980984a2ea9SAlexander Motin 
981984a2ea9SAlexander Motin 	scsi_extract_sense_len(&io->scsiio.sense_data,
982984a2ea9SAlexander Motin 			       io->scsiio.sense_len,
983984a2ea9SAlexander Motin 			       &error_code,
984984a2ea9SAlexander Motin 			       &sense_key,
985984a2ea9SAlexander Motin 			       &asc,
986984a2ea9SAlexander Motin 			       &ascq,
987984a2ea9SAlexander Motin 			       /*show_errors*/ 1);
988984a2ea9SAlexander Motin 
989984a2ea9SAlexander Motin 	switch (error_code) {
990984a2ea9SAlexander Motin 	case SSD_DEFERRED_ERROR:
991984a2ea9SAlexander Motin 	case SSD_DESC_DEFERRED_ERROR:
992984a2ea9SAlexander Motin 		error_action |= TPC_ERR_NO_DECREMENT;
993984a2ea9SAlexander Motin 		break;
994984a2ea9SAlexander Motin 	case SSD_CURRENT_ERROR:
995984a2ea9SAlexander Motin 	case SSD_DESC_CURRENT_ERROR:
996984a2ea9SAlexander Motin 	default:
997984a2ea9SAlexander Motin 		switch (sense_key) {
998984a2ea9SAlexander Motin 		case SSD_KEY_UNIT_ATTENTION:
999984a2ea9SAlexander Motin 			error_action |= TPC_ERR_NO_DECREMENT;
1000984a2ea9SAlexander Motin 			break;
1001984a2ea9SAlexander Motin 		case SSD_KEY_HARDWARE_ERROR:
1002984a2ea9SAlexander Motin 			/*
1003984a2ea9SAlexander Motin 			 * This is our generic "something bad happened"
1004984a2ea9SAlexander Motin 			 * error code.  It often isn't recoverable.
1005984a2ea9SAlexander Motin 			 */
1006984a2ea9SAlexander Motin 			if ((asc == 0x44) && (ascq == 0x00))
1007984a2ea9SAlexander Motin 				error_action = TPC_ERR_FAIL;
1008984a2ea9SAlexander Motin 			break;
1009984a2ea9SAlexander Motin 		case SSD_KEY_NOT_READY:
1010984a2ea9SAlexander Motin 			/*
1011984a2ea9SAlexander Motin 			 * If the LUN is powered down, there likely isn't
1012984a2ea9SAlexander Motin 			 * much point in retrying right now.
1013984a2ea9SAlexander Motin 			 */
1014984a2ea9SAlexander Motin 			if ((asc == 0x04) && (ascq == 0x02))
1015984a2ea9SAlexander Motin 				error_action = TPC_ERR_FAIL;
1016984a2ea9SAlexander Motin 			/*
1017984a2ea9SAlexander Motin 			 * If the LUN is offline, there probably isn't much
1018984a2ea9SAlexander Motin 			 * point in retrying, either.
1019984a2ea9SAlexander Motin 			 */
1020984a2ea9SAlexander Motin 			if ((asc == 0x04) && (ascq == 0x03))
1021984a2ea9SAlexander Motin 				error_action = TPC_ERR_FAIL;
1022984a2ea9SAlexander Motin 			break;
1023984a2ea9SAlexander Motin 		}
1024984a2ea9SAlexander Motin 	}
1025984a2ea9SAlexander Motin 	return (error_action);
1026984a2ea9SAlexander Motin }
1027984a2ea9SAlexander Motin 
1028984a2ea9SAlexander Motin static tpc_error_action
1029984a2ea9SAlexander Motin tpc_error_parse(union ctl_io *io)
1030984a2ea9SAlexander Motin {
1031984a2ea9SAlexander Motin 	tpc_error_action error_action = TPC_ERR_RETRY;
1032984a2ea9SAlexander Motin 
1033984a2ea9SAlexander Motin 	switch (io->io_hdr.io_type) {
1034984a2ea9SAlexander Motin 	case CTL_IO_SCSI:
1035984a2ea9SAlexander Motin 		switch (io->io_hdr.status & CTL_STATUS_MASK) {
1036984a2ea9SAlexander Motin 		case CTL_SCSI_ERROR:
1037984a2ea9SAlexander Motin 			switch (io->scsiio.scsi_status) {
1038984a2ea9SAlexander Motin 			case SCSI_STATUS_CHECK_COND:
1039984a2ea9SAlexander Motin 				error_action = tpc_checkcond_parse(io);
1040984a2ea9SAlexander Motin 				break;
1041984a2ea9SAlexander Motin 			default:
1042984a2ea9SAlexander Motin 				break;
1043984a2ea9SAlexander Motin 			}
1044984a2ea9SAlexander Motin 			break;
1045984a2ea9SAlexander Motin 		default:
1046984a2ea9SAlexander Motin 			break;
1047984a2ea9SAlexander Motin 		}
1048984a2ea9SAlexander Motin 		break;
1049984a2ea9SAlexander Motin 	case CTL_IO_TASK:
1050984a2ea9SAlexander Motin 		break;
1051984a2ea9SAlexander Motin 	default:
1052984a2ea9SAlexander Motin 		panic("%s: invalid ctl_io type %d\n", __func__,
1053984a2ea9SAlexander Motin 		      io->io_hdr.io_type);
1054984a2ea9SAlexander Motin 		break;
1055984a2ea9SAlexander Motin 	}
1056984a2ea9SAlexander Motin 	return (error_action);
1057984a2ea9SAlexander Motin }
1058984a2ea9SAlexander Motin 
1059984a2ea9SAlexander Motin void
1060984a2ea9SAlexander Motin tpc_done(union ctl_io *io)
1061984a2ea9SAlexander Motin {
1062984a2ea9SAlexander Motin 	struct tpc_io *tio, *tior;
1063984a2ea9SAlexander Motin 
1064984a2ea9SAlexander Motin 	/*
1065984a2ea9SAlexander Motin 	 * Very minimal retry logic.  We basically retry if we got an error
1066984a2ea9SAlexander Motin 	 * back, and the retry count is greater than 0.  If we ever want
1067984a2ea9SAlexander Motin 	 * more sophisticated initiator type behavior, the CAM error
1068984a2ea9SAlexander Motin 	 * recovery code in ../common might be helpful.
1069984a2ea9SAlexander Motin 	 */
1070984a2ea9SAlexander Motin //	if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
1071984a2ea9SAlexander Motin //		ctl_io_error_print(io, NULL);
1072984a2ea9SAlexander Motin 	tio = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
1073984a2ea9SAlexander Motin 	if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
1074984a2ea9SAlexander Motin 	 && (io->io_hdr.retries > 0)) {
1075984a2ea9SAlexander Motin 		ctl_io_status old_status;
1076984a2ea9SAlexander Motin 		tpc_error_action error_action;
1077984a2ea9SAlexander Motin 
1078984a2ea9SAlexander Motin 		error_action = tpc_error_parse(io);
1079984a2ea9SAlexander Motin 		switch (error_action & TPC_ERR_MASK) {
1080984a2ea9SAlexander Motin 		case TPC_ERR_FAIL:
1081984a2ea9SAlexander Motin 			break;
1082984a2ea9SAlexander Motin 		case TPC_ERR_RETRY:
1083984a2ea9SAlexander Motin 		default:
1084984a2ea9SAlexander Motin 			if ((error_action & TPC_ERR_NO_DECREMENT) == 0)
1085984a2ea9SAlexander Motin 				io->io_hdr.retries--;
1086984a2ea9SAlexander Motin 			old_status = io->io_hdr.status;
1087984a2ea9SAlexander Motin 			io->io_hdr.status = CTL_STATUS_NONE;
1088984a2ea9SAlexander Motin 			io->io_hdr.flags &= ~CTL_FLAG_ABORT;
1089984a2ea9SAlexander Motin 			io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC;
1090984a2ea9SAlexander Motin 			if (tpcl_queue(io, tio->lun) != CTL_RETVAL_COMPLETE) {
1091984a2ea9SAlexander Motin 				printf("%s: error returned from ctl_queue()!\n",
1092984a2ea9SAlexander Motin 				       __func__);
1093984a2ea9SAlexander Motin 				io->io_hdr.status = old_status;
1094984a2ea9SAlexander Motin 			} else
1095984a2ea9SAlexander Motin 				return;
1096984a2ea9SAlexander Motin 		}
1097984a2ea9SAlexander Motin 	}
1098984a2ea9SAlexander Motin 
1099984a2ea9SAlexander Motin 	if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)
1100984a2ea9SAlexander Motin 		tio->list->error = 1;
1101984a2ea9SAlexander Motin 	else
1102984a2ea9SAlexander Motin 		atomic_add_int(&tio->list->curops, 1);
1103984a2ea9SAlexander Motin 	if (!tio->list->error && !tio->list->abort) {
1104984a2ea9SAlexander Motin 		while ((tior = TAILQ_FIRST(&tio->run)) != NULL) {
1105984a2ea9SAlexander Motin 			TAILQ_REMOVE(&tio->run, tior, rlinks);
1106984a2ea9SAlexander Motin 			atomic_add_int(&tio->list->tbdio, 1);
1107984a2ea9SAlexander Motin 			if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE)
1108984a2ea9SAlexander Motin 				panic("tpcl_queue() error");
1109984a2ea9SAlexander Motin 		}
1110984a2ea9SAlexander Motin 	}
1111984a2ea9SAlexander Motin 	if (atomic_fetchadd_int(&tio->list->tbdio, -1) == 1)
1112984a2ea9SAlexander Motin 		tpc_process(tio->list);
1113984a2ea9SAlexander Motin }
1114984a2ea9SAlexander Motin 
1115984a2ea9SAlexander Motin int
1116984a2ea9SAlexander Motin ctl_extended_copy_lid1(struct ctl_scsiio *ctsio)
1117984a2ea9SAlexander Motin {
1118984a2ea9SAlexander Motin 	struct scsi_extended_copy *cdb;
1119984a2ea9SAlexander Motin 	struct scsi_extended_copy_lid1_data *data;
1120984a2ea9SAlexander Motin 	struct ctl_lun *lun;
1121984a2ea9SAlexander Motin 	struct tpc_list *list, *tlist;
1122984a2ea9SAlexander Motin 	uint8_t *ptr;
1123984a2ea9SAlexander Motin 	char *value;
1124984a2ea9SAlexander Motin 	int len, off, lencscd, lenseg, leninl, nseg;
1125984a2ea9SAlexander Motin 
1126984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_extended_copy_lid1\n"));
1127984a2ea9SAlexander Motin 
1128984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
1129984a2ea9SAlexander Motin 	cdb = (struct scsi_extended_copy *)ctsio->cdb;
1130984a2ea9SAlexander Motin 	len = scsi_4btoul(cdb->length);
1131984a2ea9SAlexander Motin 
1132984a2ea9SAlexander Motin 	if (len < sizeof(struct scsi_extended_copy_lid1_data) ||
1133984a2ea9SAlexander Motin 	    len > sizeof(struct scsi_extended_copy_lid1_data) +
1134984a2ea9SAlexander Motin 	    TPC_MAX_LIST + TPC_MAX_INLINE) {
1135984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1,
1136984a2ea9SAlexander Motin 		    /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0);
1137984a2ea9SAlexander Motin 		goto done;
1138984a2ea9SAlexander Motin 	}
1139984a2ea9SAlexander Motin 
1140984a2ea9SAlexander Motin 	/*
1141984a2ea9SAlexander Motin 	 * If we've got a kernel request that hasn't been malloced yet,
1142984a2ea9SAlexander Motin 	 * malloc it and tell the caller the data buffer is here.
1143984a2ea9SAlexander Motin 	 */
1144984a2ea9SAlexander Motin 	if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
1145984a2ea9SAlexander Motin 		ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK);
1146984a2ea9SAlexander Motin 		ctsio->kern_data_len = len;
1147984a2ea9SAlexander Motin 		ctsio->kern_total_len = len;
1148984a2ea9SAlexander Motin 		ctsio->kern_data_resid = 0;
1149984a2ea9SAlexander Motin 		ctsio->kern_rel_offset = 0;
1150984a2ea9SAlexander Motin 		ctsio->kern_sg_entries = 0;
1151984a2ea9SAlexander Motin 		ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
1152984a2ea9SAlexander Motin 		ctsio->be_move_done = ctl_config_move_done;
1153984a2ea9SAlexander Motin 		ctl_datamove((union ctl_io *)ctsio);
1154984a2ea9SAlexander Motin 
1155984a2ea9SAlexander Motin 		return (CTL_RETVAL_COMPLETE);
1156984a2ea9SAlexander Motin 	}
1157984a2ea9SAlexander Motin 
1158984a2ea9SAlexander Motin 	data = (struct scsi_extended_copy_lid1_data *)ctsio->kern_data_ptr;
1159984a2ea9SAlexander Motin 	lencscd = scsi_2btoul(data->cscd_list_length);
1160984a2ea9SAlexander Motin 	lenseg = scsi_4btoul(data->segment_list_length);
1161984a2ea9SAlexander Motin 	leninl = scsi_4btoul(data->inline_data_length);
1162984a2ea9SAlexander Motin 	if (len < sizeof(struct scsi_extended_copy_lid1_data) +
1163984a2ea9SAlexander Motin 	    lencscd + lenseg + leninl ||
1164984a2ea9SAlexander Motin 	    leninl > TPC_MAX_INLINE) {
1165984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0,
1166984a2ea9SAlexander Motin 		    /*field*/ 2, /*bit_valid*/ 0, /*bit*/ 0);
1167984a2ea9SAlexander Motin 		goto done;
1168984a2ea9SAlexander Motin 	}
1169984a2ea9SAlexander Motin 	if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) {
1170984a2ea9SAlexander Motin 		ctl_set_sense(ctsio, /*current_error*/ 1,
1171984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
1172984a2ea9SAlexander Motin 		    /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE);
1173984a2ea9SAlexander Motin 		goto done;
1174984a2ea9SAlexander Motin 	}
1175984a2ea9SAlexander Motin 	if (lencscd + lenseg > TPC_MAX_LIST) {
1176984a2ea9SAlexander Motin 		ctl_set_param_len_error(ctsio);
1177984a2ea9SAlexander Motin 		goto done;
1178984a2ea9SAlexander Motin 	}
1179984a2ea9SAlexander Motin 
1180984a2ea9SAlexander Motin 	list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO);
1181984a2ea9SAlexander Motin 	list->service_action = cdb->service_action;
1182984a2ea9SAlexander Motin 	value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc");
1183984a2ea9SAlexander Motin 	if (value != NULL && strcmp(value, "on") == 0)
1184984a2ea9SAlexander Motin 		list->init_port = -1;
1185984a2ea9SAlexander Motin 	else
1186984a2ea9SAlexander Motin 		list->init_port = ctsio->io_hdr.nexus.targ_port;
1187984a2ea9SAlexander Motin 	list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus);
1188984a2ea9SAlexander Motin 	list->list_id = data->list_identifier;
1189984a2ea9SAlexander Motin 	list->flags = data->flags;
1190984a2ea9SAlexander Motin 	list->params = ctsio->kern_data_ptr;
1191984a2ea9SAlexander Motin 	list->cscd = (struct scsi_ec_cscd *)&data->data[0];
1192984a2ea9SAlexander Motin 	ptr = &data->data[lencscd];
1193984a2ea9SAlexander Motin 	for (nseg = 0, off = 0; off < lenseg; nseg++) {
1194984a2ea9SAlexander Motin 		if (nseg >= TPC_MAX_SEGS) {
1195984a2ea9SAlexander Motin 			free(list, M_CTL);
1196984a2ea9SAlexander Motin 			ctl_set_sense(ctsio, /*current_error*/ 1,
1197984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
1198984a2ea9SAlexander Motin 			    /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
1199984a2ea9SAlexander Motin 			goto done;
1200984a2ea9SAlexander Motin 		}
1201984a2ea9SAlexander Motin 		list->seg[nseg] = (struct scsi_ec_segment *)(ptr + off);
1202984a2ea9SAlexander Motin 		off += sizeof(struct scsi_ec_segment) +
1203984a2ea9SAlexander Motin 		    scsi_2btoul(list->seg[nseg]->descr_length);
1204984a2ea9SAlexander Motin 	}
1205984a2ea9SAlexander Motin 	list->inl = &data->data[lencscd + lenseg];
1206984a2ea9SAlexander Motin 	list->ncscd = lencscd / sizeof(struct scsi_ec_cscd);
1207984a2ea9SAlexander Motin 	list->nseg = nseg;
1208984a2ea9SAlexander Motin 	list->leninl = leninl;
1209984a2ea9SAlexander Motin 	list->ctsio = ctsio;
1210984a2ea9SAlexander Motin 	list->lun = lun;
1211984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
1212984a2ea9SAlexander Motin 	if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) {
1213984a2ea9SAlexander Motin 		TAILQ_FOREACH(tlist, &lun->tpc_lists, links) {
1214984a2ea9SAlexander Motin 			if ((tlist->flags & EC_LIST_ID_USAGE_MASK) !=
1215984a2ea9SAlexander Motin 			     EC_LIST_ID_USAGE_NONE &&
1216984a2ea9SAlexander Motin 			    tlist->list_id == list->list_id)
1217984a2ea9SAlexander Motin 				break;
1218984a2ea9SAlexander Motin 		}
1219984a2ea9SAlexander Motin 		if (tlist != NULL && !tlist->completed) {
1220984a2ea9SAlexander Motin 			mtx_unlock(&lun->lun_lock);
1221984a2ea9SAlexander Motin 			free(list, M_CTL);
1222984a2ea9SAlexander Motin 			ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
1223984a2ea9SAlexander Motin 			    /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0,
1224984a2ea9SAlexander Motin 			    /*bit*/ 0);
1225984a2ea9SAlexander Motin 			goto done;
1226984a2ea9SAlexander Motin 		}
1227984a2ea9SAlexander Motin 		if (tlist != NULL) {
1228984a2ea9SAlexander Motin 			TAILQ_REMOVE(&lun->tpc_lists, tlist, links);
1229984a2ea9SAlexander Motin 			free(tlist, M_CTL);
1230984a2ea9SAlexander Motin 		}
1231984a2ea9SAlexander Motin 	}
1232984a2ea9SAlexander Motin 	TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links);
1233984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
1234984a2ea9SAlexander Motin 
1235984a2ea9SAlexander Motin 	tpc_process(list);
1236984a2ea9SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
1237984a2ea9SAlexander Motin 
1238984a2ea9SAlexander Motin done:
1239984a2ea9SAlexander Motin 	ctl_done((union ctl_io *)ctsio);
1240984a2ea9SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
1241984a2ea9SAlexander Motin }
1242984a2ea9SAlexander Motin 
1243984a2ea9SAlexander Motin int
1244984a2ea9SAlexander Motin ctl_extended_copy_lid4(struct ctl_scsiio *ctsio)
1245984a2ea9SAlexander Motin {
1246984a2ea9SAlexander Motin 	struct scsi_extended_copy *cdb;
1247984a2ea9SAlexander Motin 	struct scsi_extended_copy_lid4_data *data;
1248984a2ea9SAlexander Motin 	struct ctl_lun *lun;
1249984a2ea9SAlexander Motin 	struct tpc_list *list, *tlist;
1250984a2ea9SAlexander Motin 	uint8_t *ptr;
1251984a2ea9SAlexander Motin 	char *value;
1252984a2ea9SAlexander Motin 	int len, off, lencscd, lenseg, leninl, nseg;
1253984a2ea9SAlexander Motin 
1254984a2ea9SAlexander Motin 	CTL_DEBUG_PRINT(("ctl_extended_copy_lid4\n"));
1255984a2ea9SAlexander Motin 
1256984a2ea9SAlexander Motin 	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
1257984a2ea9SAlexander Motin 	cdb = (struct scsi_extended_copy *)ctsio->cdb;
1258984a2ea9SAlexander Motin 	len = scsi_4btoul(cdb->length);
1259984a2ea9SAlexander Motin 
1260984a2ea9SAlexander Motin 	if (len < sizeof(struct scsi_extended_copy_lid4_data) ||
1261984a2ea9SAlexander Motin 	    len > sizeof(struct scsi_extended_copy_lid4_data) +
1262984a2ea9SAlexander Motin 	    TPC_MAX_LIST + TPC_MAX_INLINE) {
1263984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1,
1264984a2ea9SAlexander Motin 		    /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0);
1265984a2ea9SAlexander Motin 		goto done;
1266984a2ea9SAlexander Motin 	}
1267984a2ea9SAlexander Motin 
1268984a2ea9SAlexander Motin 	/*
1269984a2ea9SAlexander Motin 	 * If we've got a kernel request that hasn't been malloced yet,
1270984a2ea9SAlexander Motin 	 * malloc it and tell the caller the data buffer is here.
1271984a2ea9SAlexander Motin 	 */
1272984a2ea9SAlexander Motin 	if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
1273984a2ea9SAlexander Motin 		ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK);
1274984a2ea9SAlexander Motin 		ctsio->kern_data_len = len;
1275984a2ea9SAlexander Motin 		ctsio->kern_total_len = len;
1276984a2ea9SAlexander Motin 		ctsio->kern_data_resid = 0;
1277984a2ea9SAlexander Motin 		ctsio->kern_rel_offset = 0;
1278984a2ea9SAlexander Motin 		ctsio->kern_sg_entries = 0;
1279984a2ea9SAlexander Motin 		ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
1280984a2ea9SAlexander Motin 		ctsio->be_move_done = ctl_config_move_done;
1281984a2ea9SAlexander Motin 		ctl_datamove((union ctl_io *)ctsio);
1282984a2ea9SAlexander Motin 
1283984a2ea9SAlexander Motin 		return (CTL_RETVAL_COMPLETE);
1284984a2ea9SAlexander Motin 	}
1285984a2ea9SAlexander Motin 
1286984a2ea9SAlexander Motin 	data = (struct scsi_extended_copy_lid4_data *)ctsio->kern_data_ptr;
1287984a2ea9SAlexander Motin 	lencscd = scsi_2btoul(data->cscd_list_length);
1288984a2ea9SAlexander Motin 	lenseg = scsi_2btoul(data->segment_list_length);
1289984a2ea9SAlexander Motin 	leninl = scsi_2btoul(data->inline_data_length);
1290984a2ea9SAlexander Motin 	if (len < sizeof(struct scsi_extended_copy_lid4_data) +
1291984a2ea9SAlexander Motin 	    lencscd + lenseg + leninl ||
1292984a2ea9SAlexander Motin 	    leninl > TPC_MAX_INLINE) {
1293984a2ea9SAlexander Motin 		ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0,
1294984a2ea9SAlexander Motin 		    /*field*/ 2, /*bit_valid*/ 0, /*bit*/ 0);
1295984a2ea9SAlexander Motin 		goto done;
1296984a2ea9SAlexander Motin 	}
1297984a2ea9SAlexander Motin 	if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) {
1298984a2ea9SAlexander Motin 		ctl_set_sense(ctsio, /*current_error*/ 1,
1299984a2ea9SAlexander Motin 		    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
1300984a2ea9SAlexander Motin 		    /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE);
1301984a2ea9SAlexander Motin 		goto done;
1302984a2ea9SAlexander Motin 	}
1303984a2ea9SAlexander Motin 	if (lencscd + lenseg > TPC_MAX_LIST) {
1304984a2ea9SAlexander Motin 		ctl_set_param_len_error(ctsio);
1305984a2ea9SAlexander Motin 		goto done;
1306984a2ea9SAlexander Motin 	}
1307984a2ea9SAlexander Motin 
1308984a2ea9SAlexander Motin 	list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO);
1309984a2ea9SAlexander Motin 	list->service_action = cdb->service_action;
1310984a2ea9SAlexander Motin 	value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc");
1311984a2ea9SAlexander Motin 	if (value != NULL && strcmp(value, "on") == 0)
1312984a2ea9SAlexander Motin 		list->init_port = -1;
1313984a2ea9SAlexander Motin 	else
1314984a2ea9SAlexander Motin 		list->init_port = ctsio->io_hdr.nexus.targ_port;
1315984a2ea9SAlexander Motin 	list->init_idx = ctl_get_resindex(&ctsio->io_hdr.nexus);
1316984a2ea9SAlexander Motin 	list->list_id = scsi_4btoul(data->list_identifier);
1317984a2ea9SAlexander Motin 	list->flags = data->flags;
1318984a2ea9SAlexander Motin 	list->params = ctsio->kern_data_ptr;
1319984a2ea9SAlexander Motin 	list->cscd = (struct scsi_ec_cscd *)&data->data[0];
1320984a2ea9SAlexander Motin 	ptr = &data->data[lencscd];
1321984a2ea9SAlexander Motin 	for (nseg = 0, off = 0; off < lenseg; nseg++) {
1322984a2ea9SAlexander Motin 		if (nseg >= TPC_MAX_SEGS) {
1323984a2ea9SAlexander Motin 			free(list, M_CTL);
1324984a2ea9SAlexander Motin 			ctl_set_sense(ctsio, /*current_error*/ 1,
1325984a2ea9SAlexander Motin 			    /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
1326984a2ea9SAlexander Motin 			    /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE);
1327984a2ea9SAlexander Motin 			goto done;
1328984a2ea9SAlexander Motin 		}
1329984a2ea9SAlexander Motin 		list->seg[nseg] = (struct scsi_ec_segment *)(ptr + off);
1330984a2ea9SAlexander Motin 		off += sizeof(struct scsi_ec_segment) +
1331984a2ea9SAlexander Motin 		    scsi_2btoul(list->seg[nseg]->descr_length);
1332984a2ea9SAlexander Motin 	}
1333984a2ea9SAlexander Motin 	list->inl = &data->data[lencscd + lenseg];
1334984a2ea9SAlexander Motin 	list->ncscd = lencscd / sizeof(struct scsi_ec_cscd);
1335984a2ea9SAlexander Motin 	list->nseg = nseg;
1336984a2ea9SAlexander Motin 	list->leninl = leninl;
1337984a2ea9SAlexander Motin 	list->ctsio = ctsio;
1338984a2ea9SAlexander Motin 	list->lun = lun;
1339984a2ea9SAlexander Motin 	mtx_lock(&lun->lun_lock);
1340984a2ea9SAlexander Motin 	if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) {
1341984a2ea9SAlexander Motin 		TAILQ_FOREACH(tlist, &lun->tpc_lists, links) {
1342984a2ea9SAlexander Motin 			if ((tlist->flags & EC_LIST_ID_USAGE_MASK) !=
1343984a2ea9SAlexander Motin 			     EC_LIST_ID_USAGE_NONE &&
1344984a2ea9SAlexander Motin 			    tlist->list_id == list->list_id)
1345984a2ea9SAlexander Motin 				break;
1346984a2ea9SAlexander Motin 		}
1347984a2ea9SAlexander Motin 		if (tlist != NULL && !tlist->completed) {
1348984a2ea9SAlexander Motin 			mtx_unlock(&lun->lun_lock);
1349984a2ea9SAlexander Motin 			free(list, M_CTL);
1350984a2ea9SAlexander Motin 			ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
1351984a2ea9SAlexander Motin 			    /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0,
1352984a2ea9SAlexander Motin 			    /*bit*/ 0);
1353984a2ea9SAlexander Motin 			goto done;
1354984a2ea9SAlexander Motin 		}
1355984a2ea9SAlexander Motin 		if (tlist != NULL) {
1356984a2ea9SAlexander Motin 			TAILQ_REMOVE(&lun->tpc_lists, tlist, links);
1357984a2ea9SAlexander Motin 			free(tlist, M_CTL);
1358984a2ea9SAlexander Motin 		}
1359984a2ea9SAlexander Motin 	}
1360984a2ea9SAlexander Motin 	TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links);
1361984a2ea9SAlexander Motin 	mtx_unlock(&lun->lun_lock);
1362984a2ea9SAlexander Motin 
1363984a2ea9SAlexander Motin 	tpc_process(list);
1364984a2ea9SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
1365984a2ea9SAlexander Motin 
1366984a2ea9SAlexander Motin done:
1367984a2ea9SAlexander Motin 	ctl_done((union ctl_io *)ctsio);
1368984a2ea9SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
1369984a2ea9SAlexander Motin }
1370984a2ea9SAlexander Motin 
1371