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