1984a2ea9SAlexander Motin /*- 2f24882ecSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3f24882ecSPedro F. Giffuni * 4984a2ea9SAlexander Motin * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org> 5984a2ea9SAlexander Motin * All rights reserved. 6984a2ea9SAlexander Motin * 7984a2ea9SAlexander Motin * Redistribution and use in source and binary forms, with or without 8984a2ea9SAlexander Motin * modification, are permitted provided that the following conditions 9984a2ea9SAlexander Motin * are met: 10984a2ea9SAlexander Motin * 1. Redistributions of source code must retain the above copyright 11984a2ea9SAlexander Motin * notice, this list of conditions and the following disclaimer, 12984a2ea9SAlexander Motin * without modification, immediately at the beginning of the file. 13984a2ea9SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 14984a2ea9SAlexander Motin * notice, this list of conditions and the following disclaimer in the 15984a2ea9SAlexander Motin * documentation and/or other materials provided with the distribution. 16984a2ea9SAlexander Motin * 17984a2ea9SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18984a2ea9SAlexander Motin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19984a2ea9SAlexander Motin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20984a2ea9SAlexander Motin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21984a2ea9SAlexander Motin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22984a2ea9SAlexander Motin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23984a2ea9SAlexander Motin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24984a2ea9SAlexander Motin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25984a2ea9SAlexander Motin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26984a2ea9SAlexander Motin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27984a2ea9SAlexander Motin */ 28984a2ea9SAlexander Motin 29984a2ea9SAlexander Motin #include <sys/cdefs.h> 30984a2ea9SAlexander Motin __FBSDID("$FreeBSD$"); 31984a2ea9SAlexander Motin 32984a2ea9SAlexander Motin #include <sys/param.h> 33984a2ea9SAlexander Motin #include <sys/systm.h> 34984a2ea9SAlexander Motin #include <sys/kernel.h> 35984a2ea9SAlexander Motin #include <sys/types.h> 36984a2ea9SAlexander Motin #include <sys/lock.h> 37984a2ea9SAlexander Motin #include <sys/module.h> 38984a2ea9SAlexander Motin #include <sys/mutex.h> 39984a2ea9SAlexander Motin #include <sys/condvar.h> 40984a2ea9SAlexander Motin #include <sys/malloc.h> 41984a2ea9SAlexander Motin #include <sys/conf.h> 42984a2ea9SAlexander Motin #include <sys/queue.h> 43984a2ea9SAlexander Motin #include <sys/sysctl.h> 44*8951f055SMarcelo Araujo #include <sys/nv.h> 45*8951f055SMarcelo Araujo #include <sys/dnv.h> 46984a2ea9SAlexander Motin #include <machine/atomic.h> 47984a2ea9SAlexander Motin 48984a2ea9SAlexander Motin #include <cam/cam.h> 49984a2ea9SAlexander Motin #include <cam/scsi/scsi_all.h> 50984a2ea9SAlexander Motin #include <cam/scsi/scsi_da.h> 51984a2ea9SAlexander Motin #include <cam/ctl/ctl_io.h> 52984a2ea9SAlexander Motin #include <cam/ctl/ctl.h> 53984a2ea9SAlexander Motin #include <cam/ctl/ctl_frontend.h> 54984a2ea9SAlexander Motin #include <cam/ctl/ctl_util.h> 55984a2ea9SAlexander Motin #include <cam/ctl/ctl_backend.h> 56984a2ea9SAlexander Motin #include <cam/ctl/ctl_ioctl.h> 57984a2ea9SAlexander Motin #include <cam/ctl/ctl_ha.h> 58984a2ea9SAlexander Motin #include <cam/ctl/ctl_private.h> 59984a2ea9SAlexander Motin #include <cam/ctl/ctl_debug.h> 60984a2ea9SAlexander Motin #include <cam/ctl/ctl_scsi_all.h> 61984a2ea9SAlexander Motin #include <cam/ctl/ctl_tpc.h> 62984a2ea9SAlexander Motin #include <cam/ctl/ctl_error.h> 63984a2ea9SAlexander Motin 64984a2ea9SAlexander Motin #define TPC_MAX_CSCDS 64 65984a2ea9SAlexander Motin #define TPC_MAX_SEGS 64 66984a2ea9SAlexander Motin #define TPC_MAX_SEG 0 67984a2ea9SAlexander Motin #define TPC_MAX_LIST 8192 68984a2ea9SAlexander Motin #define TPC_MAX_INLINE 0 69984a2ea9SAlexander Motin #define TPC_MAX_LISTS 255 70984a2ea9SAlexander Motin #define TPC_MAX_IO_SIZE (1024 * 1024) 7125eee848SAlexander Motin #define TPC_MAX_IOCHUNK_SIZE (TPC_MAX_IO_SIZE * 16) 7225eee848SAlexander Motin #define TPC_MIN_TOKEN_TIMEOUT 1 7325eee848SAlexander Motin #define TPC_DFL_TOKEN_TIMEOUT 60 7425eee848SAlexander Motin #define TPC_MAX_TOKEN_TIMEOUT 600 75984a2ea9SAlexander Motin 76984a2ea9SAlexander Motin MALLOC_DEFINE(M_CTL_TPC, "ctltpc", "CTL TPC"); 77984a2ea9SAlexander Motin 78984a2ea9SAlexander Motin typedef enum { 79984a2ea9SAlexander Motin TPC_ERR_RETRY = 0x000, 80984a2ea9SAlexander Motin TPC_ERR_FAIL = 0x001, 81984a2ea9SAlexander Motin TPC_ERR_MASK = 0x0ff, 82984a2ea9SAlexander Motin TPC_ERR_NO_DECREMENT = 0x100 83984a2ea9SAlexander Motin } tpc_error_action; 84984a2ea9SAlexander Motin 85984a2ea9SAlexander Motin struct tpc_list; 86984a2ea9SAlexander Motin TAILQ_HEAD(runl, tpc_io); 87984a2ea9SAlexander Motin struct tpc_io { 88984a2ea9SAlexander Motin union ctl_io *io; 89a3dd8378SAlexander Motin uint8_t target; 90a3dd8378SAlexander Motin uint32_t cscd; 91984a2ea9SAlexander Motin uint64_t lun; 9246511441SAlexander Motin uint8_t *buf; 93984a2ea9SAlexander Motin struct tpc_list *list; 94984a2ea9SAlexander Motin struct runl run; 95984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_io) rlinks; 96984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_io) links; 97984a2ea9SAlexander Motin }; 98984a2ea9SAlexander Motin 9925eee848SAlexander Motin struct tpc_token { 10025eee848SAlexander Motin uint8_t token[512]; 10125eee848SAlexander Motin uint64_t lun; 10225eee848SAlexander Motin uint32_t blocksize; 10325eee848SAlexander Motin uint8_t *params; 10425eee848SAlexander Motin struct scsi_range_desc *range; 10525eee848SAlexander Motin int nrange; 10625eee848SAlexander Motin int active; 10725eee848SAlexander Motin time_t last_active; 10825eee848SAlexander Motin uint32_t timeout; 10925eee848SAlexander Motin TAILQ_ENTRY(tpc_token) links; 11025eee848SAlexander Motin }; 11125eee848SAlexander Motin 112984a2ea9SAlexander Motin struct tpc_list { 113984a2ea9SAlexander Motin uint8_t service_action; 114984a2ea9SAlexander Motin int init_port; 1158cbf9eaeSAlexander Motin uint32_t init_idx; 116984a2ea9SAlexander Motin uint32_t list_id; 117984a2ea9SAlexander Motin uint8_t flags; 118984a2ea9SAlexander Motin uint8_t *params; 119984a2ea9SAlexander Motin struct scsi_ec_cscd *cscd; 120984a2ea9SAlexander Motin struct scsi_ec_segment *seg[TPC_MAX_SEGS]; 121984a2ea9SAlexander Motin uint8_t *inl; 122984a2ea9SAlexander Motin int ncscd; 123984a2ea9SAlexander Motin int nseg; 124984a2ea9SAlexander Motin int leninl; 12525eee848SAlexander Motin struct tpc_token *token; 12625eee848SAlexander Motin struct scsi_range_desc *range; 12725eee848SAlexander Motin int nrange; 12825eee848SAlexander Motin off_t offset_into_rod; 12925eee848SAlexander Motin 130984a2ea9SAlexander Motin int curseg; 13125eee848SAlexander Motin off_t cursectors; 132984a2ea9SAlexander Motin off_t curbytes; 133984a2ea9SAlexander Motin int curops; 134984a2ea9SAlexander Motin int stage; 13525eee848SAlexander Motin off_t segsectors; 13625eee848SAlexander Motin off_t segbytes; 137984a2ea9SAlexander Motin int tbdio; 138984a2ea9SAlexander Motin int error; 139984a2ea9SAlexander Motin int abort; 140984a2ea9SAlexander Motin int completed; 14125eee848SAlexander Motin time_t last_active; 142984a2ea9SAlexander Motin TAILQ_HEAD(, tpc_io) allio; 143a3dd8378SAlexander Motin struct scsi_sense_data fwd_sense_data; 144a3dd8378SAlexander Motin uint8_t fwd_sense_len; 145a3dd8378SAlexander Motin uint8_t fwd_scsi_status; 146a3dd8378SAlexander Motin uint8_t fwd_target; 147a3dd8378SAlexander Motin uint16_t fwd_cscd; 148984a2ea9SAlexander Motin struct scsi_sense_data sense_data; 149984a2ea9SAlexander Motin uint8_t sense_len; 150984a2ea9SAlexander Motin uint8_t scsi_status; 151984a2ea9SAlexander Motin struct ctl_scsiio *ctsio; 152984a2ea9SAlexander Motin struct ctl_lun *lun; 15325eee848SAlexander Motin int res_token_valid; 15425eee848SAlexander Motin uint8_t res_token[512]; 155984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_list) links; 156984a2ea9SAlexander Motin }; 157984a2ea9SAlexander Motin 15825eee848SAlexander Motin static void 15925eee848SAlexander Motin tpc_timeout(void *arg) 16025eee848SAlexander Motin { 16125eee848SAlexander Motin struct ctl_softc *softc = arg; 16225eee848SAlexander Motin struct ctl_lun *lun; 16325eee848SAlexander Motin struct tpc_token *token, *ttoken; 16425eee848SAlexander Motin struct tpc_list *list, *tlist; 16525eee848SAlexander Motin 16625eee848SAlexander Motin /* Free completed lists with expired timeout. */ 16725eee848SAlexander Motin STAILQ_FOREACH(lun, &softc->lun_list, links) { 16825eee848SAlexander Motin mtx_lock(&lun->lun_lock); 16925eee848SAlexander Motin TAILQ_FOREACH_SAFE(list, &lun->tpc_lists, links, tlist) { 17025eee848SAlexander Motin if (!list->completed || time_uptime < list->last_active + 17125eee848SAlexander Motin TPC_DFL_TOKEN_TIMEOUT) 17225eee848SAlexander Motin continue; 17325eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 17425eee848SAlexander Motin free(list, M_CTL); 17525eee848SAlexander Motin } 17625eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 17725eee848SAlexander Motin } 17825eee848SAlexander Motin 17925eee848SAlexander Motin /* Free inactive ROD tokens with expired timeout. */ 1802d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 18125eee848SAlexander Motin TAILQ_FOREACH_SAFE(token, &softc->tpc_tokens, links, ttoken) { 18225eee848SAlexander Motin if (token->active || 18325eee848SAlexander Motin time_uptime < token->last_active + token->timeout + 1) 18425eee848SAlexander Motin continue; 18525eee848SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 18625eee848SAlexander Motin free(token->params, M_CTL); 18725eee848SAlexander Motin free(token, M_CTL); 18825eee848SAlexander Motin } 1892d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 19025eee848SAlexander Motin callout_schedule(&softc->tpc_timeout, hz); 19125eee848SAlexander Motin } 19225eee848SAlexander Motin 193984a2ea9SAlexander Motin void 19425eee848SAlexander Motin ctl_tpc_init(struct ctl_softc *softc) 19525eee848SAlexander Motin { 19625eee848SAlexander Motin 1972d8b2876SAlexander Motin mtx_init(&softc->tpc_lock, "CTL TPC mutex", NULL, MTX_DEF); 19825eee848SAlexander Motin TAILQ_INIT(&softc->tpc_tokens); 19925eee848SAlexander Motin callout_init_mtx(&softc->tpc_timeout, &softc->ctl_lock, 0); 20025eee848SAlexander Motin callout_reset(&softc->tpc_timeout, hz, tpc_timeout, softc); 20125eee848SAlexander Motin } 20225eee848SAlexander Motin 20325eee848SAlexander Motin void 20425eee848SAlexander Motin ctl_tpc_shutdown(struct ctl_softc *softc) 20525eee848SAlexander Motin { 20625eee848SAlexander Motin struct tpc_token *token; 20725eee848SAlexander Motin 20825eee848SAlexander Motin callout_drain(&softc->tpc_timeout); 20925eee848SAlexander Motin 21025eee848SAlexander Motin /* Free ROD tokens. */ 2112d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 21225eee848SAlexander Motin while ((token = TAILQ_FIRST(&softc->tpc_tokens)) != NULL) { 21325eee848SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 21425eee848SAlexander Motin free(token->params, M_CTL); 21525eee848SAlexander Motin free(token, M_CTL); 21625eee848SAlexander Motin } 2172d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 2182d8b2876SAlexander Motin mtx_destroy(&softc->tpc_lock); 21925eee848SAlexander Motin } 22025eee848SAlexander Motin 22125eee848SAlexander Motin void 22225eee848SAlexander Motin ctl_tpc_lun_init(struct ctl_lun *lun) 223984a2ea9SAlexander Motin { 224984a2ea9SAlexander Motin 225984a2ea9SAlexander Motin TAILQ_INIT(&lun->tpc_lists); 226984a2ea9SAlexander Motin } 227984a2ea9SAlexander Motin 228984a2ea9SAlexander Motin void 2299ff948d0SAlexander Motin ctl_tpc_lun_clear(struct ctl_lun *lun, uint32_t initidx) 2309ff948d0SAlexander Motin { 2319ff948d0SAlexander Motin struct tpc_list *list, *tlist; 2329ff948d0SAlexander Motin 2339ff948d0SAlexander Motin TAILQ_FOREACH_SAFE(list, &lun->tpc_lists, links, tlist) { 2349ff948d0SAlexander Motin if (initidx != -1 && list->init_idx != initidx) 2359ff948d0SAlexander Motin continue; 2369ff948d0SAlexander Motin if (!list->completed) 2379ff948d0SAlexander Motin continue; 2389ff948d0SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 2399ff948d0SAlexander Motin free(list, M_CTL); 2409ff948d0SAlexander Motin } 2419ff948d0SAlexander Motin } 2429ff948d0SAlexander Motin 2439ff948d0SAlexander Motin void 24425eee848SAlexander Motin ctl_tpc_lun_shutdown(struct ctl_lun *lun) 245984a2ea9SAlexander Motin { 2469602f436SAlexander Motin struct ctl_softc *softc = lun->ctl_softc; 247984a2ea9SAlexander Motin struct tpc_list *list; 24825eee848SAlexander Motin struct tpc_token *token, *ttoken; 249984a2ea9SAlexander Motin 25025eee848SAlexander Motin /* Free lists for this LUN. */ 251984a2ea9SAlexander Motin while ((list = TAILQ_FIRST(&lun->tpc_lists)) != NULL) { 252984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 253984a2ea9SAlexander Motin KASSERT(list->completed, 254984a2ea9SAlexander Motin ("Not completed TPC (%p) on shutdown", list)); 255984a2ea9SAlexander Motin free(list, M_CTL); 256984a2ea9SAlexander Motin } 25725eee848SAlexander Motin 25825eee848SAlexander Motin /* Free ROD tokens for this LUN. */ 2592d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 2609602f436SAlexander Motin TAILQ_FOREACH_SAFE(token, &softc->tpc_tokens, links, ttoken) { 26125eee848SAlexander Motin if (token->lun != lun->lun || token->active) 26225eee848SAlexander Motin continue; 2639602f436SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 26425eee848SAlexander Motin free(token->params, M_CTL); 26525eee848SAlexander Motin free(token, M_CTL); 26625eee848SAlexander Motin } 2672d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 268984a2ea9SAlexander Motin } 269984a2ea9SAlexander Motin 270984a2ea9SAlexander Motin int 271984a2ea9SAlexander Motin ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len) 272984a2ea9SAlexander Motin { 2739cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 274984a2ea9SAlexander Motin struct scsi_vpd_tpc *tpc_ptr; 275984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor *d_ptr; 27625eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_bdrl *bdrl_ptr; 277984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sc *sc_ptr; 278984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sc_descr *scd_ptr; 279984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_pd *pd_ptr; 280984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sd *sd_ptr; 281984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sdid *sdid_ptr; 28225eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_rtf *rtf_ptr; 28325eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_rtf_block *rtfb_ptr; 28425eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_srt *srt_ptr; 28525eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_srtd *srtd_ptr; 286984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_gco *gco_ptr; 287984a2ea9SAlexander Motin int data_len; 288984a2ea9SAlexander Motin 289984a2ea9SAlexander Motin data_len = sizeof(struct scsi_vpd_tpc) + 29025eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_bdrl) + 291984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sc) + 29225eee848SAlexander Motin 2 * sizeof(struct scsi_vpd_tpc_descriptor_sc_descr) + 11, 4) + 293984a2ea9SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_pd) + 294984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sd) + 4, 4) + 295984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sdid) + 2, 4) + 29625eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_rtf) + 29725eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_rtf_block) + 29825eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_srt) + 29925eee848SAlexander Motin 2*sizeof(struct scsi_vpd_tpc_descriptor_srtd) + 300984a2ea9SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_gco); 301984a2ea9SAlexander Motin 302984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); 303984a2ea9SAlexander Motin tpc_ptr = (struct scsi_vpd_tpc *)ctsio->kern_data_ptr; 304984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 305984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 306640603fbSAlexander Motin ctsio->kern_data_len = min(data_len, alloc_len); 307640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 308984a2ea9SAlexander Motin 309984a2ea9SAlexander Motin /* 310984a2ea9SAlexander Motin * The control device is always connected. The disk device, on the 311984a2ea9SAlexander Motin * other hand, may not be online all the time. 312984a2ea9SAlexander Motin */ 313984a2ea9SAlexander Motin if (lun != NULL) 314984a2ea9SAlexander Motin tpc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | 315984a2ea9SAlexander Motin lun->be_lun->lun_type; 316984a2ea9SAlexander Motin else 317984a2ea9SAlexander Motin tpc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; 318984a2ea9SAlexander Motin tpc_ptr->page_code = SVPD_SCSI_TPC; 319984a2ea9SAlexander Motin scsi_ulto2b(data_len - 4, tpc_ptr->page_length); 320984a2ea9SAlexander Motin 32125eee848SAlexander Motin /* Block Device ROD Limits */ 322984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *)&tpc_ptr->descr[0]; 32325eee848SAlexander Motin bdrl_ptr = (struct scsi_vpd_tpc_descriptor_bdrl *)d_ptr; 32425eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_BDRL, bdrl_ptr->desc_type); 32525eee848SAlexander Motin scsi_ulto2b(sizeof(*bdrl_ptr) - 4, bdrl_ptr->desc_length); 32625eee848SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, bdrl_ptr->maximum_ranges); 32725eee848SAlexander Motin scsi_ulto4b(TPC_MAX_TOKEN_TIMEOUT, 32825eee848SAlexander Motin bdrl_ptr->maximum_inactivity_timeout); 32925eee848SAlexander Motin scsi_ulto4b(TPC_DFL_TOKEN_TIMEOUT, 33025eee848SAlexander Motin bdrl_ptr->default_inactivity_timeout); 33125eee848SAlexander Motin scsi_u64to8b(0, bdrl_ptr->maximum_token_transfer_size); 33225eee848SAlexander Motin scsi_u64to8b(0, bdrl_ptr->optimal_transfer_count); 33325eee848SAlexander Motin 33425eee848SAlexander Motin /* Supported commands */ 33525eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 33625eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 337984a2ea9SAlexander Motin sc_ptr = (struct scsi_vpd_tpc_descriptor_sc *)d_ptr; 338984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SC, sc_ptr->desc_type); 33925eee848SAlexander Motin sc_ptr->list_length = 2 * sizeof(*scd_ptr) + 11; 340984a2ea9SAlexander Motin scsi_ulto2b(roundup2(1 + sc_ptr->list_length, 4), sc_ptr->desc_length); 341984a2ea9SAlexander Motin scd_ptr = &sc_ptr->descr[0]; 342984a2ea9SAlexander Motin scd_ptr->opcode = EXTENDED_COPY; 34325eee848SAlexander Motin scd_ptr->sa_length = 5; 344984a2ea9SAlexander Motin scd_ptr->supported_service_actions[0] = EC_EC_LID1; 345984a2ea9SAlexander Motin scd_ptr->supported_service_actions[1] = EC_EC_LID4; 34625eee848SAlexander Motin scd_ptr->supported_service_actions[2] = EC_PT; 34725eee848SAlexander Motin scd_ptr->supported_service_actions[3] = EC_WUT; 34825eee848SAlexander Motin scd_ptr->supported_service_actions[4] = EC_COA; 349984a2ea9SAlexander Motin scd_ptr = (struct scsi_vpd_tpc_descriptor_sc_descr *) 350984a2ea9SAlexander Motin &scd_ptr->supported_service_actions[scd_ptr->sa_length]; 351984a2ea9SAlexander Motin scd_ptr->opcode = RECEIVE_COPY_STATUS; 35225eee848SAlexander Motin scd_ptr->sa_length = 6; 353984a2ea9SAlexander Motin scd_ptr->supported_service_actions[0] = RCS_RCS_LID1; 354984a2ea9SAlexander Motin scd_ptr->supported_service_actions[1] = RCS_RCFD; 355984a2ea9SAlexander Motin scd_ptr->supported_service_actions[2] = RCS_RCS_LID4; 356984a2ea9SAlexander Motin scd_ptr->supported_service_actions[3] = RCS_RCOP; 35725eee848SAlexander Motin scd_ptr->supported_service_actions[4] = RCS_RRTI; 35825eee848SAlexander Motin scd_ptr->supported_service_actions[5] = RCS_RART; 359984a2ea9SAlexander Motin 360984a2ea9SAlexander Motin /* Parameter data. */ 361984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 362984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 363984a2ea9SAlexander Motin pd_ptr = (struct scsi_vpd_tpc_descriptor_pd *)d_ptr; 364984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_PD, pd_ptr->desc_type); 365984a2ea9SAlexander Motin scsi_ulto2b(sizeof(*pd_ptr) - 4, pd_ptr->desc_length); 366984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_CSCDS, pd_ptr->maximum_cscd_descriptor_count); 367984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, pd_ptr->maximum_segment_descriptor_count); 368984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LIST, pd_ptr->maximum_descriptor_list_length); 369984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_INLINE, pd_ptr->maximum_inline_data_length); 370984a2ea9SAlexander Motin 371984a2ea9SAlexander Motin /* Supported Descriptors */ 372984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 373984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 374984a2ea9SAlexander Motin sd_ptr = (struct scsi_vpd_tpc_descriptor_sd *)d_ptr; 375984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SD, sd_ptr->desc_type); 376984a2ea9SAlexander Motin scsi_ulto2b(roundup2(sizeof(*sd_ptr) - 4 + 4, 4), sd_ptr->desc_length); 377984a2ea9SAlexander Motin sd_ptr->list_length = 4; 378984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[0] = EC_SEG_B2B; 379984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[1] = EC_SEG_VERIFY; 380984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[2] = EC_SEG_REGISTER_KEY; 381984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[3] = EC_CSCD_ID; 382984a2ea9SAlexander Motin 383984a2ea9SAlexander Motin /* Supported CSCD Descriptor IDs */ 384984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 385984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 386984a2ea9SAlexander Motin sdid_ptr = (struct scsi_vpd_tpc_descriptor_sdid *)d_ptr; 387984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SDID, sdid_ptr->desc_type); 388984a2ea9SAlexander Motin scsi_ulto2b(roundup2(sizeof(*sdid_ptr) - 4 + 2, 4), sdid_ptr->desc_length); 389984a2ea9SAlexander Motin scsi_ulto2b(2, sdid_ptr->list_length); 390984a2ea9SAlexander Motin scsi_ulto2b(0xffff, &sdid_ptr->supported_descriptor_ids[0]); 391984a2ea9SAlexander Motin 39225eee848SAlexander Motin /* ROD Token Features */ 39325eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 39425eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 39525eee848SAlexander Motin rtf_ptr = (struct scsi_vpd_tpc_descriptor_rtf *)d_ptr; 39625eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_RTF, rtf_ptr->desc_type); 39725eee848SAlexander Motin scsi_ulto2b(sizeof(*rtf_ptr) - 4 + sizeof(*rtfb_ptr), rtf_ptr->desc_length); 39825eee848SAlexander Motin rtf_ptr->remote_tokens = 0; 39925eee848SAlexander Motin scsi_ulto4b(TPC_MIN_TOKEN_TIMEOUT, rtf_ptr->minimum_token_lifetime); 40025eee848SAlexander Motin scsi_ulto4b(UINT32_MAX, rtf_ptr->maximum_token_lifetime); 40125eee848SAlexander Motin scsi_ulto4b(TPC_MAX_TOKEN_TIMEOUT, 40225eee848SAlexander Motin rtf_ptr->maximum_token_inactivity_timeout); 40325eee848SAlexander Motin scsi_ulto2b(sizeof(*rtfb_ptr), rtf_ptr->type_specific_features_length); 40425eee848SAlexander Motin rtfb_ptr = (struct scsi_vpd_tpc_descriptor_rtf_block *) 40525eee848SAlexander Motin &rtf_ptr->type_specific_features; 40625eee848SAlexander Motin rtfb_ptr->type_format = SVPD_TPC_RTF_BLOCK; 40725eee848SAlexander Motin scsi_ulto2b(sizeof(*rtfb_ptr) - 4, rtfb_ptr->desc_length); 40825eee848SAlexander Motin scsi_ulto2b(0, rtfb_ptr->optimal_length_granularity); 40925eee848SAlexander Motin scsi_u64to8b(0, rtfb_ptr->maximum_bytes); 41025eee848SAlexander Motin scsi_u64to8b(0, rtfb_ptr->optimal_bytes); 411238b6b7cSAlexander Motin scsi_u64to8b(UINT64_MAX, rtfb_ptr->optimal_bytes_to_token_per_segment); 41225eee848SAlexander Motin scsi_u64to8b(TPC_MAX_IOCHUNK_SIZE, 41325eee848SAlexander Motin rtfb_ptr->optimal_bytes_from_token_per_segment); 41425eee848SAlexander Motin 41525eee848SAlexander Motin /* Supported ROD Tokens */ 41625eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 41725eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 41825eee848SAlexander Motin srt_ptr = (struct scsi_vpd_tpc_descriptor_srt *)d_ptr; 41925eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_SRT, srt_ptr->desc_type); 42025eee848SAlexander Motin scsi_ulto2b(sizeof(*srt_ptr) - 4 + 2*sizeof(*srtd_ptr), srt_ptr->desc_length); 42125eee848SAlexander Motin scsi_ulto2b(2*sizeof(*srtd_ptr), srt_ptr->rod_type_descriptors_length); 42225eee848SAlexander Motin srtd_ptr = (struct scsi_vpd_tpc_descriptor_srtd *) 42325eee848SAlexander Motin &srt_ptr->rod_type_descriptors; 42425eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_AUR, srtd_ptr->rod_type); 42525eee848SAlexander Motin srtd_ptr->flags = SVPD_TPC_SRTD_TIN | SVPD_TPC_SRTD_TOUT; 42625eee848SAlexander Motin scsi_ulto2b(0, srtd_ptr->preference_indicator); 42725eee848SAlexander Motin srtd_ptr++; 42825eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_BLOCK_ZERO, srtd_ptr->rod_type); 42925eee848SAlexander Motin srtd_ptr->flags = SVPD_TPC_SRTD_TIN; 43025eee848SAlexander Motin scsi_ulto2b(0, srtd_ptr->preference_indicator); 43125eee848SAlexander Motin 432984a2ea9SAlexander Motin /* General Copy Operations */ 433984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 434984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 435984a2ea9SAlexander Motin gco_ptr = (struct scsi_vpd_tpc_descriptor_gco *)d_ptr; 436984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_GCO, gco_ptr->desc_type); 437984a2ea9SAlexander Motin scsi_ulto2b(sizeof(*gco_ptr) - 4, gco_ptr->desc_length); 438984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->total_concurrent_copies); 439984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->maximum_identified_concurrent_copies); 440984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_SEG, gco_ptr->maximum_segment_length); 441984a2ea9SAlexander Motin gco_ptr->data_segment_granularity = 0; 442984a2ea9SAlexander Motin gco_ptr->inline_data_granularity = 0; 443984a2ea9SAlexander Motin 444f7241cceSAlexander Motin ctl_set_success(ctsio); 445984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 446984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 447984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 448984a2ea9SAlexander Motin 449984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 450984a2ea9SAlexander Motin } 451984a2ea9SAlexander Motin 452984a2ea9SAlexander Motin int 453984a2ea9SAlexander Motin ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio) 454984a2ea9SAlexander Motin { 455984a2ea9SAlexander Motin struct scsi_receive_copy_operating_parameters *cdb; 456984a2ea9SAlexander Motin struct scsi_receive_copy_operating_parameters_data *data; 457984a2ea9SAlexander Motin int retval; 458984a2ea9SAlexander Motin int alloc_len, total_len; 459984a2ea9SAlexander Motin 460984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_report_supported_tmf\n")); 461984a2ea9SAlexander Motin 462984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_operating_parameters *)ctsio->cdb; 463984a2ea9SAlexander Motin 464984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 465984a2ea9SAlexander Motin 466984a2ea9SAlexander Motin total_len = sizeof(*data) + 4; 467984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 468984a2ea9SAlexander Motin 469984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 470984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 471984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 472640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 473640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 474984a2ea9SAlexander Motin 475984a2ea9SAlexander Motin data = (struct scsi_receive_copy_operating_parameters_data *)ctsio->kern_data_ptr; 476984a2ea9SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + 4, data->length); 477984a2ea9SAlexander Motin data->snlid = RCOP_SNLID; 478984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_CSCDS, data->maximum_cscd_descriptor_count); 479984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, data->maximum_segment_descriptor_count); 480984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LIST, data->maximum_descriptor_list_length); 481984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_SEG, data->maximum_segment_length); 482984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_INLINE, data->maximum_inline_data_length); 483984a2ea9SAlexander Motin scsi_ulto4b(0, data->held_data_limit); 484984a2ea9SAlexander Motin scsi_ulto4b(0, data->maximum_stream_device_transfer_size); 485984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_LISTS, data->total_concurrent_copies); 486984a2ea9SAlexander Motin data->maximum_concurrent_copies = TPC_MAX_LISTS; 487984a2ea9SAlexander Motin data->data_segment_granularity = 0; 488984a2ea9SAlexander Motin data->inline_data_granularity = 0; 489984a2ea9SAlexander Motin data->held_data_granularity = 0; 490984a2ea9SAlexander Motin data->implemented_descriptor_list_length = 4; 491984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[0] = EC_SEG_B2B; 492984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[1] = EC_SEG_VERIFY; 493984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[2] = EC_SEG_REGISTER_KEY; 494984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[3] = EC_CSCD_ID; 495984a2ea9SAlexander Motin 496f7241cceSAlexander Motin ctl_set_success(ctsio); 497984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 498984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 499984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 500984a2ea9SAlexander Motin return (retval); 501984a2ea9SAlexander Motin } 502984a2ea9SAlexander Motin 50343d2d719SAlexander Motin static struct tpc_list * 50443d2d719SAlexander Motin tpc_find_list(struct ctl_lun *lun, uint32_t list_id, uint32_t init_idx) 50543d2d719SAlexander Motin { 50643d2d719SAlexander Motin struct tpc_list *list; 50743d2d719SAlexander Motin 50843d2d719SAlexander Motin mtx_assert(&lun->lun_lock, MA_OWNED); 50943d2d719SAlexander Motin TAILQ_FOREACH(list, &lun->tpc_lists, links) { 51043d2d719SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != 51143d2d719SAlexander Motin EC_LIST_ID_USAGE_NONE && list->list_id == list_id && 51243d2d719SAlexander Motin list->init_idx == init_idx) 51343d2d719SAlexander Motin break; 51443d2d719SAlexander Motin } 51543d2d719SAlexander Motin return (list); 51643d2d719SAlexander Motin } 51743d2d719SAlexander Motin 518984a2ea9SAlexander Motin int 519984a2ea9SAlexander Motin ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio) 520984a2ea9SAlexander Motin { 5219cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 522984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid1 *cdb; 523984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid1_data *data; 524984a2ea9SAlexander Motin struct tpc_list *list; 525984a2ea9SAlexander Motin struct tpc_list list_copy; 526984a2ea9SAlexander Motin int retval; 527984a2ea9SAlexander Motin int alloc_len, total_len; 528984a2ea9SAlexander Motin uint32_t list_id; 529984a2ea9SAlexander Motin 530984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid1\n")); 531984a2ea9SAlexander Motin 532984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_status_lid1 *)ctsio->cdb; 533984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 534984a2ea9SAlexander Motin 535984a2ea9SAlexander Motin list_id = cdb->list_identifier; 536984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 53743d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 5387ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 539984a2ea9SAlexander Motin if (list == NULL) { 540984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 541984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 542984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 543984a2ea9SAlexander Motin /*bit*/ 0); 544984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 545984a2ea9SAlexander Motin return (retval); 546984a2ea9SAlexander Motin } 547984a2ea9SAlexander Motin list_copy = *list; 548984a2ea9SAlexander Motin if (list->completed) { 549984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 550984a2ea9SAlexander Motin free(list, M_CTL); 551984a2ea9SAlexander Motin } 552984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 553984a2ea9SAlexander Motin 554984a2ea9SAlexander Motin total_len = sizeof(*data); 555984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 556984a2ea9SAlexander Motin 557984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 558984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 559984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 560640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 561640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 562984a2ea9SAlexander Motin 563984a2ea9SAlexander Motin data = (struct scsi_receive_copy_status_lid1_data *)ctsio->kern_data_ptr; 564984a2ea9SAlexander Motin scsi_ulto4b(sizeof(*data) - 4, data->available_data); 565984a2ea9SAlexander Motin if (list_copy.completed) { 566984a2ea9SAlexander Motin if (list_copy.error || list_copy.abort) 567984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 568984a2ea9SAlexander Motin else 569984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 570984a2ea9SAlexander Motin } else 571984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_INPROG; 572984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 573984a2ea9SAlexander Motin if (list_copy.curbytes <= UINT32_MAX) { 574984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_BYTES; 575984a2ea9SAlexander Motin scsi_ulto4b(list_copy.curbytes, data->transfer_count); 576984a2ea9SAlexander Motin } else { 577984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_MBYTES; 578984a2ea9SAlexander Motin scsi_ulto4b(list_copy.curbytes >> 20, data->transfer_count); 579984a2ea9SAlexander Motin } 580984a2ea9SAlexander Motin 581f7241cceSAlexander Motin ctl_set_success(ctsio); 582984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 583984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 584984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 585984a2ea9SAlexander Motin return (retval); 586984a2ea9SAlexander Motin } 587984a2ea9SAlexander Motin 588984a2ea9SAlexander Motin int 589984a2ea9SAlexander Motin ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio) 590984a2ea9SAlexander Motin { 5919cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 592984a2ea9SAlexander Motin struct scsi_receive_copy_failure_details *cdb; 593984a2ea9SAlexander Motin struct scsi_receive_copy_failure_details_data *data; 594984a2ea9SAlexander Motin struct tpc_list *list; 595984a2ea9SAlexander Motin struct tpc_list list_copy; 596984a2ea9SAlexander Motin int retval; 597984a2ea9SAlexander Motin int alloc_len, total_len; 598984a2ea9SAlexander Motin uint32_t list_id; 599984a2ea9SAlexander Motin 600984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_failure_details\n")); 601984a2ea9SAlexander Motin 602984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_failure_details *)ctsio->cdb; 603984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 604984a2ea9SAlexander Motin 605984a2ea9SAlexander Motin list_id = cdb->list_identifier; 606984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 60743d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 6087ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 60943d2d719SAlexander Motin if (list == NULL || !list->completed) { 610984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 611984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 612984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 613984a2ea9SAlexander Motin /*bit*/ 0); 614984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 615984a2ea9SAlexander Motin return (retval); 616984a2ea9SAlexander Motin } 617984a2ea9SAlexander Motin list_copy = *list; 618984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 619984a2ea9SAlexander Motin free(list, M_CTL); 620984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 621984a2ea9SAlexander Motin 622984a2ea9SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len; 623984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 624984a2ea9SAlexander Motin 625984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 626984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 627984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 628640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 629640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 630984a2ea9SAlexander Motin 631984a2ea9SAlexander Motin data = (struct scsi_receive_copy_failure_details_data *)ctsio->kern_data_ptr; 632984a2ea9SAlexander Motin if (list_copy.completed && (list_copy.error || list_copy.abort)) { 633a7c09f5cSAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len, 634a7c09f5cSAlexander Motin data->available_data); 635984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 636984a2ea9SAlexander Motin } else 637984a2ea9SAlexander Motin scsi_ulto4b(0, data->available_data); 638984a2ea9SAlexander Motin scsi_ulto2b(list_copy.sense_len, data->sense_data_length); 639984a2ea9SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 640984a2ea9SAlexander Motin 641f7241cceSAlexander Motin ctl_set_success(ctsio); 642984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 643984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 644984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 645984a2ea9SAlexander Motin return (retval); 646984a2ea9SAlexander Motin } 647984a2ea9SAlexander Motin 648984a2ea9SAlexander Motin int 649984a2ea9SAlexander Motin ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio) 650984a2ea9SAlexander Motin { 6519cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 652984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid4 *cdb; 653984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid4_data *data; 654984a2ea9SAlexander Motin struct tpc_list *list; 655984a2ea9SAlexander Motin struct tpc_list list_copy; 656984a2ea9SAlexander Motin int retval; 657984a2ea9SAlexander Motin int alloc_len, total_len; 658984a2ea9SAlexander Motin uint32_t list_id; 659984a2ea9SAlexander Motin 660984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid4\n")); 661984a2ea9SAlexander Motin 662984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_status_lid4 *)ctsio->cdb; 663984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 664984a2ea9SAlexander Motin 665984a2ea9SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 666984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 66743d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 6687ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 669984a2ea9SAlexander Motin if (list == NULL) { 670984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 671984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 672984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 673984a2ea9SAlexander Motin /*bit*/ 0); 674984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 675984a2ea9SAlexander Motin return (retval); 676984a2ea9SAlexander Motin } 677984a2ea9SAlexander Motin list_copy = *list; 678984a2ea9SAlexander Motin if (list->completed) { 679984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 680984a2ea9SAlexander Motin free(list, M_CTL); 681984a2ea9SAlexander Motin } 682984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 683984a2ea9SAlexander Motin 684984a2ea9SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len; 685984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 686984a2ea9SAlexander Motin 687984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 688984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 689984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 690640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 691640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 692984a2ea9SAlexander Motin 693984a2ea9SAlexander Motin data = (struct scsi_receive_copy_status_lid4_data *)ctsio->kern_data_ptr; 694a7c09f5cSAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len, 695a7c09f5cSAlexander Motin data->available_data); 696984a2ea9SAlexander Motin data->response_to_service_action = list_copy.service_action; 697984a2ea9SAlexander Motin if (list_copy.completed) { 698984a2ea9SAlexander Motin if (list_copy.error) 699984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 700984a2ea9SAlexander Motin else if (list_copy.abort) 701984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ABORTED; 702984a2ea9SAlexander Motin else 703984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 704984a2ea9SAlexander Motin } else 705984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_INPROG_FG; 706984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curops, data->operation_counter); 707984a2ea9SAlexander Motin scsi_ulto4b(UINT32_MAX, data->estimated_status_update_delay); 708984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_BYTES; 709a7c09f5cSAlexander Motin scsi_u64to8b(list_copy.curbytes, data->transfer_count); 710984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 711a7c09f5cSAlexander Motin data->length_of_the_sense_data_field = list_copy.sense_len; 712984a2ea9SAlexander Motin data->sense_data_length = list_copy.sense_len; 713984a2ea9SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 714984a2ea9SAlexander Motin 715f7241cceSAlexander Motin ctl_set_success(ctsio); 716984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 717984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 718984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 719984a2ea9SAlexander Motin return (retval); 720984a2ea9SAlexander Motin } 721984a2ea9SAlexander Motin 722984a2ea9SAlexander Motin int 723984a2ea9SAlexander Motin ctl_copy_operation_abort(struct ctl_scsiio *ctsio) 724984a2ea9SAlexander Motin { 7259cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 726984a2ea9SAlexander Motin struct scsi_copy_operation_abort *cdb; 727984a2ea9SAlexander Motin struct tpc_list *list; 728984a2ea9SAlexander Motin int retval; 729984a2ea9SAlexander Motin uint32_t list_id; 730984a2ea9SAlexander Motin 731984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_copy_operation_abort\n")); 732984a2ea9SAlexander Motin 733984a2ea9SAlexander Motin cdb = (struct scsi_copy_operation_abort *)ctsio->cdb; 734984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 735984a2ea9SAlexander Motin 736984a2ea9SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 737984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 73843d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 7397ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 740984a2ea9SAlexander Motin if (list == NULL) { 741984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 742984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 743984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 744984a2ea9SAlexander Motin /*bit*/ 0); 745984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 746984a2ea9SAlexander Motin return (retval); 747984a2ea9SAlexander Motin } 748984a2ea9SAlexander Motin list->abort = 1; 749984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 750984a2ea9SAlexander Motin 751984a2ea9SAlexander Motin ctl_set_success(ctsio); 752984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 753984a2ea9SAlexander Motin return (retval); 754984a2ea9SAlexander Motin } 755984a2ea9SAlexander Motin 756984a2ea9SAlexander Motin static uint64_t 757fee04ef7SAlexander Motin tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss, 758fee04ef7SAlexander Motin uint32_t *pb, uint32_t *pbo) 759984a2ea9SAlexander Motin { 760984a2ea9SAlexander Motin 761984a2ea9SAlexander Motin if (idx == 0xffff) { 762984a2ea9SAlexander Motin if (ss && list->lun->be_lun) 763984a2ea9SAlexander Motin *ss = list->lun->be_lun->blocksize; 764fee04ef7SAlexander Motin if (pb && list->lun->be_lun) 765fee04ef7SAlexander Motin *pb = list->lun->be_lun->blocksize << 766fee04ef7SAlexander Motin list->lun->be_lun->pblockexp; 767fee04ef7SAlexander Motin if (pbo && list->lun->be_lun) 768fee04ef7SAlexander Motin *pbo = list->lun->be_lun->blocksize * 769fee04ef7SAlexander Motin list->lun->be_lun->pblockoff; 770984a2ea9SAlexander Motin return (list->lun->lun); 771984a2ea9SAlexander Motin } 772984a2ea9SAlexander Motin if (idx >= list->ncscd) 773984a2ea9SAlexander Motin return (UINT64_MAX); 7749602f436SAlexander Motin return (tpcl_resolve(list->lun->ctl_softc, 775fee04ef7SAlexander Motin list->init_port, &list->cscd[idx], ss, pb, pbo)); 776984a2ea9SAlexander Motin } 777984a2ea9SAlexander Motin 778a3dd8378SAlexander Motin static void 779a3dd8378SAlexander Motin tpc_set_io_error_sense(struct tpc_list *list) 780a3dd8378SAlexander Motin { 781a3dd8378SAlexander Motin int flen; 782a3dd8378SAlexander Motin uint8_t csi[4]; 783a3dd8378SAlexander Motin uint8_t sks[3]; 784a3dd8378SAlexander Motin uint8_t fbuf[4 + 64]; 785a3dd8378SAlexander Motin 786a3dd8378SAlexander Motin scsi_ulto4b(list->curseg, csi); 787a3dd8378SAlexander Motin if (list->fwd_cscd <= 0x07ff) { 788a3dd8378SAlexander Motin sks[0] = SSD_SKS_SEGMENT_VALID; 789a3dd8378SAlexander Motin scsi_ulto2b((uint8_t *)&list->cscd[list->fwd_cscd] - 790a3dd8378SAlexander Motin list->params, &sks[1]); 791a3dd8378SAlexander Motin } else 792a3dd8378SAlexander Motin sks[0] = 0; 793a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 794a3dd8378SAlexander Motin fbuf[0] = 0x0c; 795a3dd8378SAlexander Motin fbuf[2] = list->fwd_target; 796a3dd8378SAlexander Motin flen = list->fwd_sense_len; 797a3dd8378SAlexander Motin if (flen > 64) { 798a3dd8378SAlexander Motin flen = 64; 799a3dd8378SAlexander Motin fbuf[2] |= SSD_FORWARDED_FSDT; 800a3dd8378SAlexander Motin } 801a3dd8378SAlexander Motin fbuf[1] = 2 + flen; 802a3dd8378SAlexander Motin fbuf[3] = list->fwd_scsi_status; 803a3dd8378SAlexander Motin bcopy(&list->fwd_sense_data, &fbuf[4], flen); 804a3dd8378SAlexander Motin flen += 4; 805a3dd8378SAlexander Motin } else 806a3dd8378SAlexander Motin flen = 0; 807a3dd8378SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 808a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 809a3dd8378SAlexander Motin /*asc*/ 0x0d, /*ascq*/ 0x01, 810a3dd8378SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 811a3dd8378SAlexander Motin sks[0] ? SSD_ELEM_SKS : SSD_ELEM_SKIP, sizeof(sks), sks, 812a3dd8378SAlexander Motin flen ? SSD_ELEM_DESC : SSD_ELEM_SKIP, flen, fbuf, 813a3dd8378SAlexander Motin SSD_ELEM_NONE); 814a3dd8378SAlexander Motin } 815a3dd8378SAlexander Motin 816984a2ea9SAlexander Motin static int 817984a2ea9SAlexander Motin tpc_process_b2b(struct tpc_list *list) 818984a2ea9SAlexander Motin { 819984a2ea9SAlexander Motin struct scsi_ec_segment_b2b *seg; 820984a2ea9SAlexander Motin struct scsi_ec_cscd_dtsp *sdstp, *ddstp; 821984a2ea9SAlexander Motin struct tpc_io *tior, *tiow; 82273942c5cSAlexander Motin struct runl run; 823984a2ea9SAlexander Motin uint64_t sl, dl; 824984a2ea9SAlexander Motin off_t srclba, dstlba, numbytes, donebytes, roundbytes; 825984a2ea9SAlexander Motin int numlba; 826fee04ef7SAlexander Motin uint32_t srcblock, dstblock, pb, pbo, adj; 827a3dd8378SAlexander Motin uint16_t scscd, dcscd; 828042e9bdcSAlexander Motin uint8_t csi[4]; 829984a2ea9SAlexander Motin 830042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 831984a2ea9SAlexander Motin if (list->stage == 1) { 832984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&list->allio)) != NULL) { 833984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tior, links); 834984a2ea9SAlexander Motin ctl_free_io(tior->io); 83546511441SAlexander Motin free(tior->buf, M_CTL); 836984a2ea9SAlexander Motin free(tior, M_CTL); 837984a2ea9SAlexander Motin } 838984a2ea9SAlexander Motin if (list->abort) { 839984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 840984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 841984a2ea9SAlexander Motin } else if (list->error) { 842a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 843984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 844e3e592bbSAlexander Motin } 84525eee848SAlexander Motin list->cursectors += list->segsectors; 846984a2ea9SAlexander Motin list->curbytes += list->segbytes; 847984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 848984a2ea9SAlexander Motin } 849984a2ea9SAlexander Motin 850984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 851984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_b2b *)list->seg[list->curseg]; 852a3dd8378SAlexander Motin scscd = scsi_2btoul(seg->src_cscd); 853a3dd8378SAlexander Motin dcscd = scsi_2btoul(seg->dst_cscd); 854a3dd8378SAlexander Motin sl = tpc_resolve(list, scscd, &srcblock, NULL, NULL); 855a3dd8378SAlexander Motin dl = tpc_resolve(list, dcscd, &dstblock, &pb, &pbo); 85641243159SAlexander Motin if (sl == UINT64_MAX || dl == UINT64_MAX) { 857984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 858984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 859042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 860862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 861042e9bdcSAlexander Motin SSD_ELEM_NONE); 862984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 863984a2ea9SAlexander Motin } 864fee04ef7SAlexander Motin if (pbo > 0) 865fee04ef7SAlexander Motin pbo = pb - pbo; 866a3dd8378SAlexander Motin sdstp = &list->cscd[scscd].dtsp; 867984a2ea9SAlexander Motin if (scsi_3btoul(sdstp->block_length) != 0) 868984a2ea9SAlexander Motin srcblock = scsi_3btoul(sdstp->block_length); 869a3dd8378SAlexander Motin ddstp = &list->cscd[dcscd].dtsp; 870984a2ea9SAlexander Motin if (scsi_3btoul(ddstp->block_length) != 0) 871984a2ea9SAlexander Motin dstblock = scsi_3btoul(ddstp->block_length); 872984a2ea9SAlexander Motin numlba = scsi_2btoul(seg->number_of_blocks); 873984a2ea9SAlexander Motin if (seg->flags & EC_SEG_DC) 874984a2ea9SAlexander Motin numbytes = (off_t)numlba * dstblock; 875984a2ea9SAlexander Motin else 876984a2ea9SAlexander Motin numbytes = (off_t)numlba * srcblock; 877984a2ea9SAlexander Motin srclba = scsi_8btou64(seg->src_lba); 878984a2ea9SAlexander Motin dstlba = scsi_8btou64(seg->dst_lba); 879984a2ea9SAlexander Motin 880984a2ea9SAlexander Motin // printf("Copy %ju bytes from %ju @ %ju to %ju @ %ju\n", 881984a2ea9SAlexander Motin // (uintmax_t)numbytes, sl, scsi_8btou64(seg->src_lba), 882984a2ea9SAlexander Motin // dl, scsi_8btou64(seg->dst_lba)); 883984a2ea9SAlexander Motin 884984a2ea9SAlexander Motin if (numbytes == 0) 885984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 886984a2ea9SAlexander Motin 887984a2ea9SAlexander Motin if (numbytes % srcblock != 0 || numbytes % dstblock != 0) { 888984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 889984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 890042e9bdcSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x0A, 891862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 892042e9bdcSAlexander Motin SSD_ELEM_NONE); 893984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 894984a2ea9SAlexander Motin } 895984a2ea9SAlexander Motin 896984a2ea9SAlexander Motin list->segbytes = numbytes; 89725eee848SAlexander Motin list->segsectors = numbytes / dstblock; 898984a2ea9SAlexander Motin donebytes = 0; 899984a2ea9SAlexander Motin TAILQ_INIT(&run); 90073942c5cSAlexander Motin list->tbdio = 0; 901984a2ea9SAlexander Motin while (donebytes < numbytes) { 902fee04ef7SAlexander Motin roundbytes = numbytes - donebytes; 903fee04ef7SAlexander Motin if (roundbytes > TPC_MAX_IO_SIZE) { 904fee04ef7SAlexander Motin roundbytes = TPC_MAX_IO_SIZE; 905fee04ef7SAlexander Motin roundbytes -= roundbytes % dstblock; 906fee04ef7SAlexander Motin if (pb > dstblock) { 907fee04ef7SAlexander Motin adj = (dstlba * dstblock + roundbytes - pbo) % pb; 908fee04ef7SAlexander Motin if (roundbytes > adj) 909fee04ef7SAlexander Motin roundbytes -= adj; 910fee04ef7SAlexander Motin } 911fee04ef7SAlexander Motin } 912984a2ea9SAlexander Motin 913984a2ea9SAlexander Motin tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 914984a2ea9SAlexander Motin TAILQ_INIT(&tior->run); 91546511441SAlexander Motin tior->buf = malloc(roundbytes, M_CTL, M_WAITOK); 916984a2ea9SAlexander Motin tior->list = list; 917984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tior, links); 918984a2ea9SAlexander Motin tior->io = tpcl_alloc_io(); 919984a2ea9SAlexander Motin ctl_scsi_read_write(tior->io, 92046511441SAlexander Motin /*data_ptr*/ tior->buf, 921984a2ea9SAlexander Motin /*data_len*/ roundbytes, 922984a2ea9SAlexander Motin /*read_op*/ 1, 923984a2ea9SAlexander Motin /*byte2*/ 0, 924984a2ea9SAlexander Motin /*minimum_cdb_size*/ 0, 925fee04ef7SAlexander Motin /*lba*/ srclba, 926984a2ea9SAlexander Motin /*num_blocks*/ roundbytes / srcblock, 927984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 928984a2ea9SAlexander Motin /*control*/ 0); 929984a2ea9SAlexander Motin tior->io->io_hdr.retries = 3; 930a3dd8378SAlexander Motin tior->target = SSD_FORWARDED_SDS_EXSRC; 931a3dd8378SAlexander Motin tior->cscd = scscd; 932984a2ea9SAlexander Motin tior->lun = sl; 933984a2ea9SAlexander Motin tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior; 934984a2ea9SAlexander Motin 935984a2ea9SAlexander Motin tiow = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 936984a2ea9SAlexander Motin TAILQ_INIT(&tiow->run); 937984a2ea9SAlexander Motin tiow->list = list; 938984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 939984a2ea9SAlexander Motin tiow->io = tpcl_alloc_io(); 940984a2ea9SAlexander Motin ctl_scsi_read_write(tiow->io, 94146511441SAlexander Motin /*data_ptr*/ tior->buf, 942984a2ea9SAlexander Motin /*data_len*/ roundbytes, 943984a2ea9SAlexander Motin /*read_op*/ 0, 944984a2ea9SAlexander Motin /*byte2*/ 0, 945984a2ea9SAlexander Motin /*minimum_cdb_size*/ 0, 946fee04ef7SAlexander Motin /*lba*/ dstlba, 947984a2ea9SAlexander Motin /*num_blocks*/ roundbytes / dstblock, 948984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 949984a2ea9SAlexander Motin /*control*/ 0); 950984a2ea9SAlexander Motin tiow->io->io_hdr.retries = 3; 951a3dd8378SAlexander Motin tiow->target = SSD_FORWARDED_SDS_EXDST; 952a3dd8378SAlexander Motin tiow->cscd = dcscd; 953984a2ea9SAlexander Motin tiow->lun = dl; 954117f1bc1SAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 955984a2ea9SAlexander Motin 956984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks); 95773942c5cSAlexander Motin TAILQ_INSERT_TAIL(&run, tior, rlinks); 95873942c5cSAlexander Motin list->tbdio++; 959984a2ea9SAlexander Motin donebytes += roundbytes; 960fee04ef7SAlexander Motin srclba += roundbytes / srcblock; 961fee04ef7SAlexander Motin dstlba += roundbytes / dstblock; 962984a2ea9SAlexander Motin } 963984a2ea9SAlexander Motin 964984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&run)) != NULL) { 965984a2ea9SAlexander Motin TAILQ_REMOVE(&run, tior, rlinks); 966984a2ea9SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 967984a2ea9SAlexander Motin panic("tpcl_queue() error"); 968984a2ea9SAlexander Motin } 969984a2ea9SAlexander Motin 970984a2ea9SAlexander Motin list->stage++; 971984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 972984a2ea9SAlexander Motin } 973984a2ea9SAlexander Motin 974984a2ea9SAlexander Motin static int 975984a2ea9SAlexander Motin tpc_process_verify(struct tpc_list *list) 976984a2ea9SAlexander Motin { 977984a2ea9SAlexander Motin struct scsi_ec_segment_verify *seg; 978984a2ea9SAlexander Motin struct tpc_io *tio; 979984a2ea9SAlexander Motin uint64_t sl; 980a3dd8378SAlexander Motin uint16_t cscd; 981042e9bdcSAlexander Motin uint8_t csi[4]; 982984a2ea9SAlexander Motin 983042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 984984a2ea9SAlexander Motin if (list->stage == 1) { 985984a2ea9SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 986984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 987984a2ea9SAlexander Motin ctl_free_io(tio->io); 988984a2ea9SAlexander Motin free(tio, M_CTL); 989984a2ea9SAlexander Motin } 990984a2ea9SAlexander Motin if (list->abort) { 991984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 992984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 993984a2ea9SAlexander Motin } else if (list->error) { 994a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 995984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 996984a2ea9SAlexander Motin } else 997984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 998984a2ea9SAlexander Motin } 999984a2ea9SAlexander Motin 1000984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 1001984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_verify *)list->seg[list->curseg]; 1002a3dd8378SAlexander Motin cscd = scsi_2btoul(seg->src_cscd); 1003a3dd8378SAlexander Motin sl = tpc_resolve(list, cscd, NULL, NULL, NULL); 100441243159SAlexander Motin if (sl == UINT64_MAX) { 1005984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 1006984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1007042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 1008862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1009042e9bdcSAlexander Motin SSD_ELEM_NONE); 1010984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1011984a2ea9SAlexander Motin } 1012984a2ea9SAlexander Motin 1013984a2ea9SAlexander Motin // printf("Verify %ju\n", sl); 1014984a2ea9SAlexander Motin 1015984a2ea9SAlexander Motin if ((seg->tur & 0x01) == 0) 1016984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1017984a2ea9SAlexander Motin 1018984a2ea9SAlexander Motin list->tbdio = 1; 1019984a2ea9SAlexander Motin tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO); 1020984a2ea9SAlexander Motin TAILQ_INIT(&tio->run); 1021984a2ea9SAlexander Motin tio->list = list; 1022984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tio, links); 1023984a2ea9SAlexander Motin tio->io = tpcl_alloc_io(); 1024984a2ea9SAlexander Motin ctl_scsi_tur(tio->io, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); 1025984a2ea9SAlexander Motin tio->io->io_hdr.retries = 3; 1026a3dd8378SAlexander Motin tio->target = SSD_FORWARDED_SDS_EXSRC; 1027a3dd8378SAlexander Motin tio->cscd = cscd; 1028984a2ea9SAlexander Motin tio->lun = sl; 1029984a2ea9SAlexander Motin tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio; 1030984a2ea9SAlexander Motin list->stage++; 1031984a2ea9SAlexander Motin if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE) 1032984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1033984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 1034984a2ea9SAlexander Motin } 1035984a2ea9SAlexander Motin 1036984a2ea9SAlexander Motin static int 1037984a2ea9SAlexander Motin tpc_process_register_key(struct tpc_list *list) 1038984a2ea9SAlexander Motin { 1039984a2ea9SAlexander Motin struct scsi_ec_segment_register_key *seg; 1040984a2ea9SAlexander Motin struct tpc_io *tio; 1041984a2ea9SAlexander Motin uint64_t dl; 1042984a2ea9SAlexander Motin int datalen; 1043a3dd8378SAlexander Motin uint16_t cscd; 1044042e9bdcSAlexander Motin uint8_t csi[4]; 1045984a2ea9SAlexander Motin 1046042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 1047984a2ea9SAlexander Motin if (list->stage == 1) { 1048984a2ea9SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 1049984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 1050984a2ea9SAlexander Motin ctl_free_io(tio->io); 105146511441SAlexander Motin free(tio->buf, M_CTL); 1052984a2ea9SAlexander Motin free(tio, M_CTL); 1053984a2ea9SAlexander Motin } 1054984a2ea9SAlexander Motin if (list->abort) { 1055984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 1056984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1057984a2ea9SAlexander Motin } else if (list->error) { 1058a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 1059984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1060984a2ea9SAlexander Motin } else 1061984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1062984a2ea9SAlexander Motin } 1063984a2ea9SAlexander Motin 1064984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 1065984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_register_key *)list->seg[list->curseg]; 1066a3dd8378SAlexander Motin cscd = scsi_2btoul(seg->dst_cscd); 1067a3dd8378SAlexander Motin dl = tpc_resolve(list, cscd, NULL, NULL, NULL); 106841243159SAlexander Motin if (dl == UINT64_MAX) { 1069984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 1070984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1071042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 1072862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1073042e9bdcSAlexander Motin SSD_ELEM_NONE); 1074984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1075984a2ea9SAlexander Motin } 1076984a2ea9SAlexander Motin 1077984a2ea9SAlexander Motin // printf("Register Key %ju\n", dl); 1078984a2ea9SAlexander Motin 1079984a2ea9SAlexander Motin list->tbdio = 1; 1080984a2ea9SAlexander Motin tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO); 1081984a2ea9SAlexander Motin TAILQ_INIT(&tio->run); 1082984a2ea9SAlexander Motin tio->list = list; 1083984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tio, links); 1084984a2ea9SAlexander Motin tio->io = tpcl_alloc_io(); 1085984a2ea9SAlexander Motin datalen = sizeof(struct scsi_per_res_out_parms); 108646511441SAlexander Motin tio->buf = malloc(datalen, M_CTL, M_WAITOK); 1087984a2ea9SAlexander Motin ctl_scsi_persistent_res_out(tio->io, 108846511441SAlexander Motin tio->buf, datalen, SPRO_REGISTER, -1, 1089984a2ea9SAlexander Motin scsi_8btou64(seg->res_key), scsi_8btou64(seg->sa_res_key), 1090984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); 1091984a2ea9SAlexander Motin tio->io->io_hdr.retries = 3; 1092a3dd8378SAlexander Motin tio->target = SSD_FORWARDED_SDS_EXDST; 1093a3dd8378SAlexander Motin tio->cscd = cscd; 1094984a2ea9SAlexander Motin tio->lun = dl; 1095984a2ea9SAlexander Motin tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio; 1096984a2ea9SAlexander Motin list->stage++; 1097984a2ea9SAlexander Motin if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE) 1098984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1099984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 1100984a2ea9SAlexander Motin } 1101984a2ea9SAlexander Motin 110225eee848SAlexander Motin static off_t 110325eee848SAlexander Motin tpc_ranges_length(struct scsi_range_desc *range, int nrange) 110425eee848SAlexander Motin { 110525eee848SAlexander Motin off_t length = 0; 110625eee848SAlexander Motin int r; 110725eee848SAlexander Motin 110825eee848SAlexander Motin for (r = 0; r < nrange; r++) 110925eee848SAlexander Motin length += scsi_4btoul(range[r].length); 111025eee848SAlexander Motin return (length); 111125eee848SAlexander Motin } 111225eee848SAlexander Motin 111325eee848SAlexander Motin static int 111432920cbfSAlexander Motin tpc_check_ranges_l(struct scsi_range_desc *range, int nrange, uint64_t maxlba, 111532920cbfSAlexander Motin uint64_t *lba) 1116e13f4248SAlexander Motin { 11178fadf660SAlexander Motin uint64_t b1; 11188fadf660SAlexander Motin uint32_t l1; 11198fadf660SAlexander Motin int i; 1120e13f4248SAlexander Motin 112138618bf4SAlexander Motin for (i = 0; i < nrange; i++) { 112238618bf4SAlexander Motin b1 = scsi_8btou64(range[i].lba); 112338618bf4SAlexander Motin l1 = scsi_4btoul(range[i].length); 112432920cbfSAlexander Motin if (b1 + l1 < b1 || b1 + l1 > maxlba + 1) { 112532920cbfSAlexander Motin *lba = MAX(b1, maxlba + 1); 112638618bf4SAlexander Motin return (-1); 112738618bf4SAlexander Motin } 112832920cbfSAlexander Motin } 11298fadf660SAlexander Motin return (0); 11308fadf660SAlexander Motin } 11318fadf660SAlexander Motin 11328fadf660SAlexander Motin static int 11338fadf660SAlexander Motin tpc_check_ranges_x(struct scsi_range_desc *range, int nrange) 11348fadf660SAlexander Motin { 11358fadf660SAlexander Motin uint64_t b1, b2; 11368fadf660SAlexander Motin uint32_t l1, l2; 11378fadf660SAlexander Motin int i, j; 11388fadf660SAlexander Motin 1139e13f4248SAlexander Motin for (i = 0; i < nrange - 1; i++) { 1140e13f4248SAlexander Motin b1 = scsi_8btou64(range[i].lba); 1141e13f4248SAlexander Motin l1 = scsi_4btoul(range[i].length); 1142e13f4248SAlexander Motin for (j = i + 1; j < nrange; j++) { 1143e13f4248SAlexander Motin b2 = scsi_8btou64(range[j].lba); 1144e13f4248SAlexander Motin l2 = scsi_4btoul(range[j].length); 1145e13f4248SAlexander Motin if (b1 + l1 > b2 && b2 + l2 > b1) 1146e13f4248SAlexander Motin return (-1); 1147e13f4248SAlexander Motin } 1148e13f4248SAlexander Motin } 1149e13f4248SAlexander Motin return (0); 1150e13f4248SAlexander Motin } 1151e13f4248SAlexander Motin 1152e13f4248SAlexander Motin static int 115325eee848SAlexander Motin tpc_skip_ranges(struct scsi_range_desc *range, int nrange, off_t skip, 115425eee848SAlexander Motin int *srange, off_t *soffset) 115525eee848SAlexander Motin { 115625eee848SAlexander Motin off_t off; 115725eee848SAlexander Motin int r; 115825eee848SAlexander Motin 115925eee848SAlexander Motin r = 0; 116025eee848SAlexander Motin off = 0; 116125eee848SAlexander Motin while (r < nrange) { 116225eee848SAlexander Motin if (skip - off < scsi_4btoul(range[r].length)) { 116325eee848SAlexander Motin *srange = r; 116425eee848SAlexander Motin *soffset = skip - off; 116525eee848SAlexander Motin return (0); 116625eee848SAlexander Motin } 116725eee848SAlexander Motin off += scsi_4btoul(range[r].length); 116825eee848SAlexander Motin r++; 116925eee848SAlexander Motin } 117025eee848SAlexander Motin return (-1); 117125eee848SAlexander Motin } 117225eee848SAlexander Motin 117325eee848SAlexander Motin static int 117425eee848SAlexander Motin tpc_process_wut(struct tpc_list *list) 117525eee848SAlexander Motin { 117625eee848SAlexander Motin struct tpc_io *tio, *tior, *tiow; 11770952a19fSAlexander Motin struct runl run; 117825eee848SAlexander Motin int drange, srange; 117925eee848SAlexander Motin off_t doffset, soffset; 118025eee848SAlexander Motin off_t srclba, dstlba, numbytes, donebytes, roundbytes; 1181fee04ef7SAlexander Motin uint32_t srcblock, dstblock, pb, pbo, adj; 118225eee848SAlexander Motin 118325eee848SAlexander Motin if (list->stage > 0) { 118425eee848SAlexander Motin /* Cleanup after previous rounds. */ 118525eee848SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 118625eee848SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 118725eee848SAlexander Motin ctl_free_io(tio->io); 118846511441SAlexander Motin free(tio->buf, M_CTL); 118925eee848SAlexander Motin free(tio, M_CTL); 119025eee848SAlexander Motin } 119125eee848SAlexander Motin if (list->abort) { 119225eee848SAlexander Motin ctl_set_task_aborted(list->ctsio); 119325eee848SAlexander Motin return (CTL_RETVAL_ERROR); 119425eee848SAlexander Motin } else if (list->error) { 1195a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 1196a3dd8378SAlexander Motin list->ctsio->io_hdr.status = 1197a3dd8378SAlexander Motin CTL_SCSI_ERROR | CTL_AUTOSENSE; 1198a3dd8378SAlexander Motin list->ctsio->scsi_status = list->fwd_scsi_status; 1199a3dd8378SAlexander Motin list->ctsio->sense_data = list->fwd_sense_data; 1200a3dd8378SAlexander Motin list->ctsio->sense_len = list->fwd_sense_len; 1201a3dd8378SAlexander Motin } else { 1202a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, 1203a3dd8378SAlexander Motin /*sks_valid*/ 0, /*command*/ 0, 1204a3dd8378SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 1205a3dd8378SAlexander Motin } 120625eee848SAlexander Motin return (CTL_RETVAL_ERROR); 120725eee848SAlexander Motin } 120825eee848SAlexander Motin list->cursectors += list->segsectors; 120925eee848SAlexander Motin list->curbytes += list->segbytes; 121025eee848SAlexander Motin } 121125eee848SAlexander Motin 121225eee848SAlexander Motin /* Check where we are on destination ranges list. */ 121325eee848SAlexander Motin if (tpc_skip_ranges(list->range, list->nrange, list->cursectors, 121425eee848SAlexander Motin &drange, &doffset) != 0) 121525eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 121625eee848SAlexander Motin dstblock = list->lun->be_lun->blocksize; 1217fee04ef7SAlexander Motin pb = dstblock << list->lun->be_lun->pblockexp; 1218fee04ef7SAlexander Motin if (list->lun->be_lun->pblockoff > 0) 1219fee04ef7SAlexander Motin pbo = pb - dstblock * list->lun->be_lun->pblockoff; 1220fee04ef7SAlexander Motin else 1221fee04ef7SAlexander Motin pbo = 0; 122225eee848SAlexander Motin 122325eee848SAlexander Motin /* Check where we are on source ranges list. */ 122425eee848SAlexander Motin srcblock = list->token->blocksize; 122525eee848SAlexander Motin if (tpc_skip_ranges(list->token->range, list->token->nrange, 122625eee848SAlexander Motin list->offset_into_rod + list->cursectors * dstblock / srcblock, 122725eee848SAlexander Motin &srange, &soffset) != 0) { 1228a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0, 1229a3dd8378SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 123025eee848SAlexander Motin return (CTL_RETVAL_ERROR); 123125eee848SAlexander Motin } 123225eee848SAlexander Motin 123325eee848SAlexander Motin srclba = scsi_8btou64(list->token->range[srange].lba) + soffset; 123425eee848SAlexander Motin dstlba = scsi_8btou64(list->range[drange].lba) + doffset; 1235fee04ef7SAlexander Motin numbytes = srcblock * 1236fee04ef7SAlexander Motin (scsi_4btoul(list->token->range[srange].length) - soffset); 1237fee04ef7SAlexander Motin numbytes = omin(numbytes, dstblock * 1238fee04ef7SAlexander Motin (scsi_4btoul(list->range[drange].length) - doffset)); 1239fee04ef7SAlexander Motin if (numbytes > TPC_MAX_IOCHUNK_SIZE) { 1240fee04ef7SAlexander Motin numbytes = TPC_MAX_IOCHUNK_SIZE; 1241fee04ef7SAlexander Motin numbytes -= numbytes % dstblock; 1242fee04ef7SAlexander Motin if (pb > dstblock) { 1243fee04ef7SAlexander Motin adj = (dstlba * dstblock + numbytes - pbo) % pb; 1244fee04ef7SAlexander Motin if (numbytes > adj) 1245fee04ef7SAlexander Motin numbytes -= adj; 1246fee04ef7SAlexander Motin } 1247fee04ef7SAlexander Motin } 124825eee848SAlexander Motin 124925eee848SAlexander Motin if (numbytes % srcblock != 0 || numbytes % dstblock != 0) { 1250a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0, 1251a3dd8378SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 125225eee848SAlexander Motin return (CTL_RETVAL_ERROR); 125325eee848SAlexander Motin } 125425eee848SAlexander Motin 125525eee848SAlexander Motin list->segbytes = numbytes; 125625eee848SAlexander Motin list->segsectors = numbytes / dstblock; 125725eee848SAlexander Motin //printf("Copy chunk of %ju sectors from %ju to %ju\n", list->segsectors, 125825eee848SAlexander Motin // srclba, dstlba); 125925eee848SAlexander Motin donebytes = 0; 126025eee848SAlexander Motin TAILQ_INIT(&run); 12610952a19fSAlexander Motin list->tbdio = 0; 126225eee848SAlexander Motin TAILQ_INIT(&list->allio); 126325eee848SAlexander Motin while (donebytes < numbytes) { 1264fee04ef7SAlexander Motin roundbytes = numbytes - donebytes; 1265fee04ef7SAlexander Motin if (roundbytes > TPC_MAX_IO_SIZE) { 1266fee04ef7SAlexander Motin roundbytes = TPC_MAX_IO_SIZE; 1267fee04ef7SAlexander Motin roundbytes -= roundbytes % dstblock; 1268fee04ef7SAlexander Motin if (pb > dstblock) { 1269fee04ef7SAlexander Motin adj = (dstlba * dstblock + roundbytes - pbo) % pb; 1270fee04ef7SAlexander Motin if (roundbytes > adj) 1271fee04ef7SAlexander Motin roundbytes -= adj; 1272fee04ef7SAlexander Motin } 1273fee04ef7SAlexander Motin } 127425eee848SAlexander Motin 127525eee848SAlexander Motin tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 127625eee848SAlexander Motin TAILQ_INIT(&tior->run); 127746511441SAlexander Motin tior->buf = malloc(roundbytes, M_CTL, M_WAITOK); 127825eee848SAlexander Motin tior->list = list; 127925eee848SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tior, links); 128025eee848SAlexander Motin tior->io = tpcl_alloc_io(); 128125eee848SAlexander Motin ctl_scsi_read_write(tior->io, 128246511441SAlexander Motin /*data_ptr*/ tior->buf, 128325eee848SAlexander Motin /*data_len*/ roundbytes, 128425eee848SAlexander Motin /*read_op*/ 1, 128525eee848SAlexander Motin /*byte2*/ 0, 128625eee848SAlexander Motin /*minimum_cdb_size*/ 0, 1287fee04ef7SAlexander Motin /*lba*/ srclba, 128825eee848SAlexander Motin /*num_blocks*/ roundbytes / srcblock, 128925eee848SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 129025eee848SAlexander Motin /*control*/ 0); 129125eee848SAlexander Motin tior->io->io_hdr.retries = 3; 129225eee848SAlexander Motin tior->lun = list->token->lun; 129325eee848SAlexander Motin tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior; 129425eee848SAlexander Motin 129525eee848SAlexander Motin tiow = malloc(sizeof(*tiow), M_CTL, M_WAITOK | M_ZERO); 129625eee848SAlexander Motin TAILQ_INIT(&tiow->run); 129725eee848SAlexander Motin tiow->list = list; 129825eee848SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 129925eee848SAlexander Motin tiow->io = tpcl_alloc_io(); 130025eee848SAlexander Motin ctl_scsi_read_write(tiow->io, 130146511441SAlexander Motin /*data_ptr*/ tior->buf, 130225eee848SAlexander Motin /*data_len*/ roundbytes, 130325eee848SAlexander Motin /*read_op*/ 0, 130425eee848SAlexander Motin /*byte2*/ 0, 130525eee848SAlexander Motin /*minimum_cdb_size*/ 0, 1306fee04ef7SAlexander Motin /*lba*/ dstlba, 130725eee848SAlexander Motin /*num_blocks*/ roundbytes / dstblock, 130825eee848SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 130925eee848SAlexander Motin /*control*/ 0); 131025eee848SAlexander Motin tiow->io->io_hdr.retries = 3; 131125eee848SAlexander Motin tiow->lun = list->lun->lun; 131225eee848SAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 131325eee848SAlexander Motin 131425eee848SAlexander Motin TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks); 13150952a19fSAlexander Motin TAILQ_INSERT_TAIL(&run, tior, rlinks); 13160952a19fSAlexander Motin list->tbdio++; 131725eee848SAlexander Motin donebytes += roundbytes; 1318fee04ef7SAlexander Motin srclba += roundbytes / srcblock; 1319fee04ef7SAlexander Motin dstlba += roundbytes / dstblock; 132025eee848SAlexander Motin } 132125eee848SAlexander Motin 132225eee848SAlexander Motin while ((tior = TAILQ_FIRST(&run)) != NULL) { 132325eee848SAlexander Motin TAILQ_REMOVE(&run, tior, rlinks); 132425eee848SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 132525eee848SAlexander Motin panic("tpcl_queue() error"); 132625eee848SAlexander Motin } 132725eee848SAlexander Motin 132825eee848SAlexander Motin list->stage++; 132925eee848SAlexander Motin return (CTL_RETVAL_QUEUED); 133025eee848SAlexander Motin } 133125eee848SAlexander Motin 1332e3e592bbSAlexander Motin static int 1333e3e592bbSAlexander Motin tpc_process_zero_wut(struct tpc_list *list) 1334e3e592bbSAlexander Motin { 1335e3e592bbSAlexander Motin struct tpc_io *tio, *tiow; 1336e3e592bbSAlexander Motin struct runl run, *prun; 1337e3e592bbSAlexander Motin int r; 1338e3e592bbSAlexander Motin uint32_t dstblock, len; 1339e3e592bbSAlexander Motin 1340e3e592bbSAlexander Motin if (list->stage > 0) { 1341e3e592bbSAlexander Motin complete: 1342e3e592bbSAlexander Motin /* Cleanup after previous rounds. */ 1343e3e592bbSAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 1344e3e592bbSAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 1345e3e592bbSAlexander Motin ctl_free_io(tio->io); 1346e3e592bbSAlexander Motin free(tio, M_CTL); 1347e3e592bbSAlexander Motin } 1348e3e592bbSAlexander Motin if (list->abort) { 1349e3e592bbSAlexander Motin ctl_set_task_aborted(list->ctsio); 1350e3e592bbSAlexander Motin return (CTL_RETVAL_ERROR); 1351e3e592bbSAlexander Motin } else if (list->error) { 1352a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 1353a3dd8378SAlexander Motin list->ctsio->io_hdr.status = 1354a3dd8378SAlexander Motin CTL_SCSI_ERROR | CTL_AUTOSENSE; 1355a3dd8378SAlexander Motin list->ctsio->scsi_status = list->fwd_scsi_status; 1356a3dd8378SAlexander Motin list->ctsio->sense_data = list->fwd_sense_data; 1357a3dd8378SAlexander Motin list->ctsio->sense_len = list->fwd_sense_len; 1358a3dd8378SAlexander Motin } else { 1359a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, 1360a3dd8378SAlexander Motin /*sks_valid*/ 0, /*command*/ 0, 1361a3dd8378SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 1362a3dd8378SAlexander Motin } 1363e3e592bbSAlexander Motin return (CTL_RETVAL_ERROR); 1364e3e592bbSAlexander Motin } 1365e3e592bbSAlexander Motin list->cursectors += list->segsectors; 1366e3e592bbSAlexander Motin list->curbytes += list->segbytes; 1367e3e592bbSAlexander Motin return (CTL_RETVAL_COMPLETE); 1368e3e592bbSAlexander Motin } 1369e3e592bbSAlexander Motin 1370e3e592bbSAlexander Motin dstblock = list->lun->be_lun->blocksize; 1371e3e592bbSAlexander Motin TAILQ_INIT(&run); 1372e3e592bbSAlexander Motin prun = &run; 1373e3e592bbSAlexander Motin list->tbdio = 1; 1374e3e592bbSAlexander Motin TAILQ_INIT(&list->allio); 1375e3e592bbSAlexander Motin list->segsectors = 0; 1376e3e592bbSAlexander Motin for (r = 0; r < list->nrange; r++) { 1377e3e592bbSAlexander Motin len = scsi_4btoul(list->range[r].length); 1378e3e592bbSAlexander Motin if (len == 0) 1379e3e592bbSAlexander Motin continue; 1380e3e592bbSAlexander Motin 1381e3e592bbSAlexander Motin tiow = malloc(sizeof(*tiow), M_CTL, M_WAITOK | M_ZERO); 1382e3e592bbSAlexander Motin TAILQ_INIT(&tiow->run); 1383e3e592bbSAlexander Motin tiow->list = list; 1384e3e592bbSAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 1385e3e592bbSAlexander Motin tiow->io = tpcl_alloc_io(); 1386e3e592bbSAlexander Motin ctl_scsi_write_same(tiow->io, 13876ac1446dSAlexander Motin /*data_ptr*/ NULL, 13886ac1446dSAlexander Motin /*data_len*/ 0, 13896ac1446dSAlexander Motin /*byte2*/ SWS_NDOB, 1390e3e592bbSAlexander Motin /*lba*/ scsi_8btou64(list->range[r].lba), 1391e3e592bbSAlexander Motin /*num_blocks*/ len, 1392e3e592bbSAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 1393e3e592bbSAlexander Motin /*control*/ 0); 1394e3e592bbSAlexander Motin tiow->io->io_hdr.retries = 3; 1395e3e592bbSAlexander Motin tiow->lun = list->lun->lun; 1396e3e592bbSAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 1397e3e592bbSAlexander Motin 1398e3e592bbSAlexander Motin TAILQ_INSERT_TAIL(prun, tiow, rlinks); 1399e3e592bbSAlexander Motin prun = &tiow->run; 1400e3e592bbSAlexander Motin list->segsectors += len; 1401e3e592bbSAlexander Motin } 1402e3e592bbSAlexander Motin list->segbytes = list->segsectors * dstblock; 1403e3e592bbSAlexander Motin 1404e3e592bbSAlexander Motin if (TAILQ_EMPTY(&run)) 1405e3e592bbSAlexander Motin goto complete; 1406e3e592bbSAlexander Motin 1407e3e592bbSAlexander Motin while ((tiow = TAILQ_FIRST(&run)) != NULL) { 1408e3e592bbSAlexander Motin TAILQ_REMOVE(&run, tiow, rlinks); 1409e3e592bbSAlexander Motin if (tpcl_queue(tiow->io, tiow->lun) != CTL_RETVAL_COMPLETE) 1410e3e592bbSAlexander Motin panic("tpcl_queue() error"); 1411e3e592bbSAlexander Motin } 1412e3e592bbSAlexander Motin 1413e3e592bbSAlexander Motin list->stage++; 1414e3e592bbSAlexander Motin return (CTL_RETVAL_QUEUED); 1415e3e592bbSAlexander Motin } 1416e3e592bbSAlexander Motin 1417984a2ea9SAlexander Motin static void 1418984a2ea9SAlexander Motin tpc_process(struct tpc_list *list) 1419984a2ea9SAlexander Motin { 1420984a2ea9SAlexander Motin struct ctl_lun *lun = list->lun; 14219602f436SAlexander Motin struct ctl_softc *softc = lun->ctl_softc; 1422984a2ea9SAlexander Motin struct scsi_ec_segment *seg; 1423984a2ea9SAlexander Motin struct ctl_scsiio *ctsio = list->ctsio; 1424984a2ea9SAlexander Motin int retval = CTL_RETVAL_COMPLETE; 1425042e9bdcSAlexander Motin uint8_t csi[4]; 1426984a2ea9SAlexander Motin 142725eee848SAlexander Motin if (list->service_action == EC_WUT) { 1428e3e592bbSAlexander Motin if (list->token != NULL) 142925eee848SAlexander Motin retval = tpc_process_wut(list); 1430e3e592bbSAlexander Motin else 1431e3e592bbSAlexander Motin retval = tpc_process_zero_wut(list); 143225eee848SAlexander Motin if (retval == CTL_RETVAL_QUEUED) 143325eee848SAlexander Motin return; 143425eee848SAlexander Motin if (retval == CTL_RETVAL_ERROR) { 143525eee848SAlexander Motin list->error = 1; 143625eee848SAlexander Motin goto done; 143725eee848SAlexander Motin } 143825eee848SAlexander Motin } else { 1439984a2ea9SAlexander Motin //printf("ZZZ %d cscd, %d segs\n", list->ncscd, list->nseg); 1440984a2ea9SAlexander Motin while (list->curseg < list->nseg) { 1441984a2ea9SAlexander Motin seg = list->seg[list->curseg]; 1442984a2ea9SAlexander Motin switch (seg->type_code) { 1443984a2ea9SAlexander Motin case EC_SEG_B2B: 1444984a2ea9SAlexander Motin retval = tpc_process_b2b(list); 1445984a2ea9SAlexander Motin break; 1446984a2ea9SAlexander Motin case EC_SEG_VERIFY: 1447984a2ea9SAlexander Motin retval = tpc_process_verify(list); 1448984a2ea9SAlexander Motin break; 1449984a2ea9SAlexander Motin case EC_SEG_REGISTER_KEY: 1450984a2ea9SAlexander Motin retval = tpc_process_register_key(list); 1451984a2ea9SAlexander Motin break; 1452984a2ea9SAlexander Motin default: 1453042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 1454984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1455984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1456042e9bdcSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, 1457862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1458042e9bdcSAlexander Motin SSD_ELEM_NONE); 1459984a2ea9SAlexander Motin goto done; 1460984a2ea9SAlexander Motin } 1461984a2ea9SAlexander Motin if (retval == CTL_RETVAL_QUEUED) 1462984a2ea9SAlexander Motin return; 1463984a2ea9SAlexander Motin if (retval == CTL_RETVAL_ERROR) { 1464984a2ea9SAlexander Motin list->error = 1; 1465984a2ea9SAlexander Motin goto done; 1466984a2ea9SAlexander Motin } 1467984a2ea9SAlexander Motin list->curseg++; 1468984a2ea9SAlexander Motin list->stage = 0; 1469984a2ea9SAlexander Motin } 147025eee848SAlexander Motin } 1471984a2ea9SAlexander Motin 1472984a2ea9SAlexander Motin ctl_set_success(ctsio); 1473984a2ea9SAlexander Motin 1474984a2ea9SAlexander Motin done: 1475984a2ea9SAlexander Motin //printf("ZZZ done\n"); 1476c5c60595SAlexander Motin free(list->params, M_CTL); 1477c5c60595SAlexander Motin list->params = NULL; 147825eee848SAlexander Motin if (list->token) { 14792d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 148025eee848SAlexander Motin if (--list->token->active == 0) 148125eee848SAlexander Motin list->token->last_active = time_uptime; 14822d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 148325eee848SAlexander Motin list->token = NULL; 148425eee848SAlexander Motin } 1485984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1486984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) == EC_LIST_ID_USAGE_NONE) { 1487984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 1488984a2ea9SAlexander Motin free(list, M_CTL); 1489984a2ea9SAlexander Motin } else { 1490984a2ea9SAlexander Motin list->completed = 1; 149125eee848SAlexander Motin list->last_active = time_uptime; 1492984a2ea9SAlexander Motin list->sense_data = ctsio->sense_data; 1493984a2ea9SAlexander Motin list->sense_len = ctsio->sense_len; 1494984a2ea9SAlexander Motin list->scsi_status = ctsio->scsi_status; 1495984a2ea9SAlexander Motin } 1496984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1497984a2ea9SAlexander Motin 1498984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1499984a2ea9SAlexander Motin } 1500984a2ea9SAlexander Motin 1501984a2ea9SAlexander Motin /* 1502984a2ea9SAlexander Motin * For any sort of check condition, busy, etc., we just retry. We do not 1503984a2ea9SAlexander Motin * decrement the retry count for unit attention type errors. These are 1504984a2ea9SAlexander Motin * normal, and we want to save the retry count for "real" errors. Otherwise, 1505984a2ea9SAlexander Motin * we could end up with situations where a command will succeed in some 1506984a2ea9SAlexander Motin * situations and fail in others, depending on whether a unit attention is 1507984a2ea9SAlexander Motin * pending. Also, some of our error recovery actions, most notably the 1508984a2ea9SAlexander Motin * LUN reset action, will cause a unit attention. 1509984a2ea9SAlexander Motin * 1510984a2ea9SAlexander Motin * We can add more detail here later if necessary. 1511984a2ea9SAlexander Motin */ 1512984a2ea9SAlexander Motin static tpc_error_action 1513984a2ea9SAlexander Motin tpc_checkcond_parse(union ctl_io *io) 1514984a2ea9SAlexander Motin { 1515984a2ea9SAlexander Motin tpc_error_action error_action; 1516984a2ea9SAlexander Motin int error_code, sense_key, asc, ascq; 1517984a2ea9SAlexander Motin 1518984a2ea9SAlexander Motin /* 1519984a2ea9SAlexander Motin * Default to retrying the command. 1520984a2ea9SAlexander Motin */ 1521984a2ea9SAlexander Motin error_action = TPC_ERR_RETRY; 1522984a2ea9SAlexander Motin 1523984a2ea9SAlexander Motin scsi_extract_sense_len(&io->scsiio.sense_data, 1524984a2ea9SAlexander Motin io->scsiio.sense_len, 1525984a2ea9SAlexander Motin &error_code, 1526984a2ea9SAlexander Motin &sense_key, 1527984a2ea9SAlexander Motin &asc, 1528984a2ea9SAlexander Motin &ascq, 1529984a2ea9SAlexander Motin /*show_errors*/ 1); 1530984a2ea9SAlexander Motin 1531984a2ea9SAlexander Motin switch (error_code) { 1532984a2ea9SAlexander Motin case SSD_DEFERRED_ERROR: 1533984a2ea9SAlexander Motin case SSD_DESC_DEFERRED_ERROR: 1534984a2ea9SAlexander Motin error_action |= TPC_ERR_NO_DECREMENT; 1535984a2ea9SAlexander Motin break; 1536984a2ea9SAlexander Motin case SSD_CURRENT_ERROR: 1537984a2ea9SAlexander Motin case SSD_DESC_CURRENT_ERROR: 1538984a2ea9SAlexander Motin default: 1539984a2ea9SAlexander Motin switch (sense_key) { 1540984a2ea9SAlexander Motin case SSD_KEY_UNIT_ATTENTION: 1541984a2ea9SAlexander Motin error_action |= TPC_ERR_NO_DECREMENT; 1542984a2ea9SAlexander Motin break; 1543984a2ea9SAlexander Motin case SSD_KEY_HARDWARE_ERROR: 1544984a2ea9SAlexander Motin /* 1545984a2ea9SAlexander Motin * This is our generic "something bad happened" 1546984a2ea9SAlexander Motin * error code. It often isn't recoverable. 1547984a2ea9SAlexander Motin */ 1548984a2ea9SAlexander Motin if ((asc == 0x44) && (ascq == 0x00)) 1549984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1550984a2ea9SAlexander Motin break; 1551984a2ea9SAlexander Motin case SSD_KEY_NOT_READY: 1552984a2ea9SAlexander Motin /* 1553984a2ea9SAlexander Motin * If the LUN is powered down, there likely isn't 1554984a2ea9SAlexander Motin * much point in retrying right now. 1555984a2ea9SAlexander Motin */ 1556984a2ea9SAlexander Motin if ((asc == 0x04) && (ascq == 0x02)) 1557984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1558984a2ea9SAlexander Motin /* 1559984a2ea9SAlexander Motin * If the LUN is offline, there probably isn't much 1560984a2ea9SAlexander Motin * point in retrying, either. 1561984a2ea9SAlexander Motin */ 1562984a2ea9SAlexander Motin if ((asc == 0x04) && (ascq == 0x03)) 1563984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1564984a2ea9SAlexander Motin break; 1565984a2ea9SAlexander Motin } 1566984a2ea9SAlexander Motin } 1567984a2ea9SAlexander Motin return (error_action); 1568984a2ea9SAlexander Motin } 1569984a2ea9SAlexander Motin 1570984a2ea9SAlexander Motin static tpc_error_action 1571984a2ea9SAlexander Motin tpc_error_parse(union ctl_io *io) 1572984a2ea9SAlexander Motin { 1573984a2ea9SAlexander Motin tpc_error_action error_action = TPC_ERR_RETRY; 1574984a2ea9SAlexander Motin 1575984a2ea9SAlexander Motin switch (io->io_hdr.io_type) { 1576984a2ea9SAlexander Motin case CTL_IO_SCSI: 1577984a2ea9SAlexander Motin switch (io->io_hdr.status & CTL_STATUS_MASK) { 1578984a2ea9SAlexander Motin case CTL_SCSI_ERROR: 1579984a2ea9SAlexander Motin switch (io->scsiio.scsi_status) { 1580984a2ea9SAlexander Motin case SCSI_STATUS_CHECK_COND: 1581984a2ea9SAlexander Motin error_action = tpc_checkcond_parse(io); 1582984a2ea9SAlexander Motin break; 1583984a2ea9SAlexander Motin default: 1584984a2ea9SAlexander Motin break; 1585984a2ea9SAlexander Motin } 1586984a2ea9SAlexander Motin break; 1587984a2ea9SAlexander Motin default: 1588984a2ea9SAlexander Motin break; 1589984a2ea9SAlexander Motin } 1590984a2ea9SAlexander Motin break; 1591984a2ea9SAlexander Motin case CTL_IO_TASK: 1592984a2ea9SAlexander Motin break; 1593984a2ea9SAlexander Motin default: 1594984a2ea9SAlexander Motin panic("%s: invalid ctl_io type %d\n", __func__, 1595984a2ea9SAlexander Motin io->io_hdr.io_type); 1596984a2ea9SAlexander Motin break; 1597984a2ea9SAlexander Motin } 1598984a2ea9SAlexander Motin return (error_action); 1599984a2ea9SAlexander Motin } 1600984a2ea9SAlexander Motin 1601984a2ea9SAlexander Motin void 1602984a2ea9SAlexander Motin tpc_done(union ctl_io *io) 1603984a2ea9SAlexander Motin { 1604984a2ea9SAlexander Motin struct tpc_io *tio, *tior; 1605984a2ea9SAlexander Motin 1606984a2ea9SAlexander Motin /* 1607984a2ea9SAlexander Motin * Very minimal retry logic. We basically retry if we got an error 1608984a2ea9SAlexander Motin * back, and the retry count is greater than 0. If we ever want 1609984a2ea9SAlexander Motin * more sophisticated initiator type behavior, the CAM error 1610984a2ea9SAlexander Motin * recovery code in ../common might be helpful. 1611984a2ea9SAlexander Motin */ 1612984a2ea9SAlexander Motin tio = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 1613984a2ea9SAlexander Motin if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 1614984a2ea9SAlexander Motin && (io->io_hdr.retries > 0)) { 1615984a2ea9SAlexander Motin ctl_io_status old_status; 1616984a2ea9SAlexander Motin tpc_error_action error_action; 1617984a2ea9SAlexander Motin 1618984a2ea9SAlexander Motin error_action = tpc_error_parse(io); 1619984a2ea9SAlexander Motin switch (error_action & TPC_ERR_MASK) { 1620984a2ea9SAlexander Motin case TPC_ERR_FAIL: 1621984a2ea9SAlexander Motin break; 1622984a2ea9SAlexander Motin case TPC_ERR_RETRY: 1623984a2ea9SAlexander Motin default: 1624984a2ea9SAlexander Motin if ((error_action & TPC_ERR_NO_DECREMENT) == 0) 1625984a2ea9SAlexander Motin io->io_hdr.retries--; 1626984a2ea9SAlexander Motin old_status = io->io_hdr.status; 1627984a2ea9SAlexander Motin io->io_hdr.status = CTL_STATUS_NONE; 1628984a2ea9SAlexander Motin io->io_hdr.flags &= ~CTL_FLAG_ABORT; 1629984a2ea9SAlexander Motin io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC; 1630984a2ea9SAlexander Motin if (tpcl_queue(io, tio->lun) != CTL_RETVAL_COMPLETE) { 1631984a2ea9SAlexander Motin printf("%s: error returned from ctl_queue()!\n", 1632984a2ea9SAlexander Motin __func__); 1633984a2ea9SAlexander Motin io->io_hdr.status = old_status; 1634984a2ea9SAlexander Motin } else 1635984a2ea9SAlexander Motin return; 1636984a2ea9SAlexander Motin } 1637984a2ea9SAlexander Motin } 1638984a2ea9SAlexander Motin 1639a3dd8378SAlexander Motin if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) { 1640984a2ea9SAlexander Motin tio->list->error = 1; 1641a3dd8378SAlexander Motin if (io->io_hdr.io_type == CTL_IO_SCSI && 1642a3dd8378SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR) { 1643a3dd8378SAlexander Motin tio->list->fwd_scsi_status = io->scsiio.scsi_status; 1644a3dd8378SAlexander Motin tio->list->fwd_sense_data = io->scsiio.sense_data; 1645a3dd8378SAlexander Motin tio->list->fwd_sense_len = io->scsiio.sense_len; 1646a3dd8378SAlexander Motin tio->list->fwd_target = tio->target; 1647a3dd8378SAlexander Motin tio->list->fwd_cscd = tio->cscd; 1648a3dd8378SAlexander Motin } 1649a3dd8378SAlexander Motin } else 1650984a2ea9SAlexander Motin atomic_add_int(&tio->list->curops, 1); 1651984a2ea9SAlexander Motin if (!tio->list->error && !tio->list->abort) { 1652984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&tio->run)) != NULL) { 1653984a2ea9SAlexander Motin TAILQ_REMOVE(&tio->run, tior, rlinks); 1654984a2ea9SAlexander Motin atomic_add_int(&tio->list->tbdio, 1); 1655984a2ea9SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 1656984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1657984a2ea9SAlexander Motin } 1658984a2ea9SAlexander Motin } 1659984a2ea9SAlexander Motin if (atomic_fetchadd_int(&tio->list->tbdio, -1) == 1) 1660984a2ea9SAlexander Motin tpc_process(tio->list); 1661984a2ea9SAlexander Motin } 1662984a2ea9SAlexander Motin 1663984a2ea9SAlexander Motin int 1664984a2ea9SAlexander Motin ctl_extended_copy_lid1(struct ctl_scsiio *ctsio) 1665984a2ea9SAlexander Motin { 16669cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 1667984a2ea9SAlexander Motin struct scsi_extended_copy *cdb; 1668984a2ea9SAlexander Motin struct scsi_extended_copy_lid1_data *data; 1669a3dd8378SAlexander Motin struct scsi_ec_cscd *cscd; 1670a3dd8378SAlexander Motin struct scsi_ec_segment *seg; 1671984a2ea9SAlexander Motin struct tpc_list *list, *tlist; 1672984a2ea9SAlexander Motin uint8_t *ptr; 1673*8951f055SMarcelo Araujo const char *value; 1674984a2ea9SAlexander Motin int len, off, lencscd, lenseg, leninl, nseg; 1675984a2ea9SAlexander Motin 1676984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_extended_copy_lid1\n")); 1677984a2ea9SAlexander Motin 1678984a2ea9SAlexander Motin cdb = (struct scsi_extended_copy *)ctsio->cdb; 1679984a2ea9SAlexander Motin len = scsi_4btoul(cdb->length); 1680984a2ea9SAlexander Motin 1681a65a997fSAlexander Motin if (len == 0) { 1682a65a997fSAlexander Motin ctl_set_success(ctsio); 1683a65a997fSAlexander Motin goto done; 1684a65a997fSAlexander Motin } 1685984a2ea9SAlexander Motin if (len < sizeof(struct scsi_extended_copy_lid1_data) || 1686984a2ea9SAlexander Motin len > sizeof(struct scsi_extended_copy_lid1_data) + 1687984a2ea9SAlexander Motin TPC_MAX_LIST + TPC_MAX_INLINE) { 1688984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 1689984a2ea9SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 1690984a2ea9SAlexander Motin goto done; 1691984a2ea9SAlexander Motin } 1692984a2ea9SAlexander Motin 1693984a2ea9SAlexander Motin /* 1694984a2ea9SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 1695984a2ea9SAlexander Motin * malloc it and tell the caller the data buffer is here. 1696984a2ea9SAlexander Motin */ 1697984a2ea9SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 1698984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 1699984a2ea9SAlexander Motin ctsio->kern_data_len = len; 1700984a2ea9SAlexander Motin ctsio->kern_total_len = len; 1701984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 1702984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 1703984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1704984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 1705984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 1706984a2ea9SAlexander Motin 1707984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1708984a2ea9SAlexander Motin } 1709984a2ea9SAlexander Motin 1710984a2ea9SAlexander Motin data = (struct scsi_extended_copy_lid1_data *)ctsio->kern_data_ptr; 1711984a2ea9SAlexander Motin lencscd = scsi_2btoul(data->cscd_list_length); 1712984a2ea9SAlexander Motin lenseg = scsi_4btoul(data->segment_list_length); 1713984a2ea9SAlexander Motin leninl = scsi_4btoul(data->inline_data_length); 1714984a2ea9SAlexander Motin if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) { 1715984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1716984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1717984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE); 1718984a2ea9SAlexander Motin goto done; 1719984a2ea9SAlexander Motin } 1720a65a997fSAlexander Motin if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) { 1721a65a997fSAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1722a65a997fSAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1723a65a997fSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1724a65a997fSAlexander Motin goto done; 1725a65a997fSAlexander Motin } 1726a65a997fSAlexander Motin if (lencscd + lenseg > TPC_MAX_LIST || 1727a65a997fSAlexander Motin leninl > TPC_MAX_INLINE || 1728a65a997fSAlexander Motin len < sizeof(struct scsi_extended_copy_lid1_data) + 1729a65a997fSAlexander Motin lencscd + lenseg + leninl) { 1730984a2ea9SAlexander Motin ctl_set_param_len_error(ctsio); 1731984a2ea9SAlexander Motin goto done; 1732984a2ea9SAlexander Motin } 1733984a2ea9SAlexander Motin 1734984a2ea9SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 1735984a2ea9SAlexander Motin list->service_action = cdb->service_action; 1736*8951f055SMarcelo Araujo value = dnvlist_get_string(lun->be_lun->options, "insecure_tpc", NULL); 1737984a2ea9SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 1738984a2ea9SAlexander Motin list->init_port = -1; 1739984a2ea9SAlexander Motin else 1740984a2ea9SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 17417ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 1742984a2ea9SAlexander Motin list->list_id = data->list_identifier; 1743984a2ea9SAlexander Motin list->flags = data->flags; 1744984a2ea9SAlexander Motin list->params = ctsio->kern_data_ptr; 1745984a2ea9SAlexander Motin list->cscd = (struct scsi_ec_cscd *)&data->data[0]; 1746a3dd8378SAlexander Motin ptr = &data->data[0]; 1747a3dd8378SAlexander Motin for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) { 1748a3dd8378SAlexander Motin cscd = (struct scsi_ec_cscd *)(ptr + off); 1749a3dd8378SAlexander Motin if (cscd->type_code != EC_CSCD_ID) { 1750a3dd8378SAlexander Motin free(list, M_CTL); 1751a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1752a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1753a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE); 1754a3dd8378SAlexander Motin goto done; 1755a3dd8378SAlexander Motin } 1756a3dd8378SAlexander Motin } 1757984a2ea9SAlexander Motin ptr = &data->data[lencscd]; 1758984a2ea9SAlexander Motin for (nseg = 0, off = 0; off < lenseg; nseg++) { 1759984a2ea9SAlexander Motin if (nseg >= TPC_MAX_SEGS) { 1760984a2ea9SAlexander Motin free(list, M_CTL); 1761984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1762984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1763984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1764984a2ea9SAlexander Motin goto done; 1765984a2ea9SAlexander Motin } 1766a3dd8378SAlexander Motin seg = (struct scsi_ec_segment *)(ptr + off); 1767a3dd8378SAlexander Motin if (seg->type_code != EC_SEG_B2B && 1768a3dd8378SAlexander Motin seg->type_code != EC_SEG_VERIFY && 1769a3dd8378SAlexander Motin seg->type_code != EC_SEG_REGISTER_KEY) { 1770a3dd8378SAlexander Motin free(list, M_CTL); 1771a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1772a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1773a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE); 1774a3dd8378SAlexander Motin goto done; 1775a3dd8378SAlexander Motin } 1776a3dd8378SAlexander Motin list->seg[nseg] = seg; 1777984a2ea9SAlexander Motin off += sizeof(struct scsi_ec_segment) + 1778a3dd8378SAlexander Motin scsi_2btoul(seg->descr_length); 1779984a2ea9SAlexander Motin } 1780984a2ea9SAlexander Motin list->inl = &data->data[lencscd + lenseg]; 1781984a2ea9SAlexander Motin list->ncscd = lencscd / sizeof(struct scsi_ec_cscd); 1782984a2ea9SAlexander Motin list->nseg = nseg; 1783984a2ea9SAlexander Motin list->leninl = leninl; 1784984a2ea9SAlexander Motin list->ctsio = ctsio; 1785984a2ea9SAlexander Motin list->lun = lun; 1786984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1787984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) { 178843d2d719SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 1789984a2ea9SAlexander Motin if (tlist != NULL && !tlist->completed) { 1790984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1791984a2ea9SAlexander Motin free(list, M_CTL); 1792984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 1793984a2ea9SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 1794984a2ea9SAlexander Motin /*bit*/ 0); 1795984a2ea9SAlexander Motin goto done; 1796984a2ea9SAlexander Motin } 1797984a2ea9SAlexander Motin if (tlist != NULL) { 1798984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 1799984a2ea9SAlexander Motin free(tlist, M_CTL); 1800984a2ea9SAlexander Motin } 1801984a2ea9SAlexander Motin } 1802984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 1803984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1804984a2ea9SAlexander Motin 1805984a2ea9SAlexander Motin tpc_process(list); 1806984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1807984a2ea9SAlexander Motin 1808984a2ea9SAlexander Motin done: 18092a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 18102a72b593SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 18112a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 18122a72b593SAlexander Motin } 1813984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1814984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1815984a2ea9SAlexander Motin } 1816984a2ea9SAlexander Motin 1817984a2ea9SAlexander Motin int 1818984a2ea9SAlexander Motin ctl_extended_copy_lid4(struct ctl_scsiio *ctsio) 1819984a2ea9SAlexander Motin { 18209cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 1821984a2ea9SAlexander Motin struct scsi_extended_copy *cdb; 1822984a2ea9SAlexander Motin struct scsi_extended_copy_lid4_data *data; 1823a3dd8378SAlexander Motin struct scsi_ec_cscd *cscd; 1824a3dd8378SAlexander Motin struct scsi_ec_segment *seg; 1825984a2ea9SAlexander Motin struct tpc_list *list, *tlist; 1826984a2ea9SAlexander Motin uint8_t *ptr; 1827*8951f055SMarcelo Araujo const char *value; 1828984a2ea9SAlexander Motin int len, off, lencscd, lenseg, leninl, nseg; 1829984a2ea9SAlexander Motin 1830984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_extended_copy_lid4\n")); 1831984a2ea9SAlexander Motin 1832984a2ea9SAlexander Motin cdb = (struct scsi_extended_copy *)ctsio->cdb; 1833984a2ea9SAlexander Motin len = scsi_4btoul(cdb->length); 1834984a2ea9SAlexander Motin 1835a65a997fSAlexander Motin if (len == 0) { 1836a65a997fSAlexander Motin ctl_set_success(ctsio); 1837a65a997fSAlexander Motin goto done; 1838a65a997fSAlexander Motin } 1839984a2ea9SAlexander Motin if (len < sizeof(struct scsi_extended_copy_lid4_data) || 1840984a2ea9SAlexander Motin len > sizeof(struct scsi_extended_copy_lid4_data) + 1841984a2ea9SAlexander Motin TPC_MAX_LIST + TPC_MAX_INLINE) { 1842984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 1843984a2ea9SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 1844984a2ea9SAlexander Motin goto done; 1845984a2ea9SAlexander Motin } 1846984a2ea9SAlexander Motin 1847984a2ea9SAlexander Motin /* 1848984a2ea9SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 1849984a2ea9SAlexander Motin * malloc it and tell the caller the data buffer is here. 1850984a2ea9SAlexander Motin */ 1851984a2ea9SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 1852984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 1853984a2ea9SAlexander Motin ctsio->kern_data_len = len; 1854984a2ea9SAlexander Motin ctsio->kern_total_len = len; 1855984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 1856984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 1857984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1858984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 1859984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 1860984a2ea9SAlexander Motin 1861984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1862984a2ea9SAlexander Motin } 1863984a2ea9SAlexander Motin 1864984a2ea9SAlexander Motin data = (struct scsi_extended_copy_lid4_data *)ctsio->kern_data_ptr; 1865984a2ea9SAlexander Motin lencscd = scsi_2btoul(data->cscd_list_length); 1866984a2ea9SAlexander Motin lenseg = scsi_2btoul(data->segment_list_length); 1867984a2ea9SAlexander Motin leninl = scsi_2btoul(data->inline_data_length); 1868984a2ea9SAlexander Motin if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) { 1869984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1870984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1871984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE); 1872984a2ea9SAlexander Motin goto done; 1873984a2ea9SAlexander Motin } 1874a65a997fSAlexander Motin if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) { 1875a65a997fSAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1876a65a997fSAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1877a65a997fSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1878a65a997fSAlexander Motin goto done; 1879a65a997fSAlexander Motin } 1880a65a997fSAlexander Motin if (lencscd + lenseg > TPC_MAX_LIST || 1881a65a997fSAlexander Motin leninl > TPC_MAX_INLINE || 1882a65a997fSAlexander Motin len < sizeof(struct scsi_extended_copy_lid1_data) + 1883a65a997fSAlexander Motin lencscd + lenseg + leninl) { 1884984a2ea9SAlexander Motin ctl_set_param_len_error(ctsio); 1885984a2ea9SAlexander Motin goto done; 1886984a2ea9SAlexander Motin } 1887984a2ea9SAlexander Motin 1888984a2ea9SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 1889984a2ea9SAlexander Motin list->service_action = cdb->service_action; 1890*8951f055SMarcelo Araujo value = dnvlist_get_string(lun->be_lun->options, "insecure_tpc", NULL); 1891984a2ea9SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 1892984a2ea9SAlexander Motin list->init_port = -1; 1893984a2ea9SAlexander Motin else 1894984a2ea9SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 18957ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 1896984a2ea9SAlexander Motin list->list_id = scsi_4btoul(data->list_identifier); 1897984a2ea9SAlexander Motin list->flags = data->flags; 1898984a2ea9SAlexander Motin list->params = ctsio->kern_data_ptr; 1899984a2ea9SAlexander Motin list->cscd = (struct scsi_ec_cscd *)&data->data[0]; 1900a3dd8378SAlexander Motin ptr = &data->data[0]; 1901a3dd8378SAlexander Motin for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) { 1902a3dd8378SAlexander Motin cscd = (struct scsi_ec_cscd *)(ptr + off); 1903a3dd8378SAlexander Motin if (cscd->type_code != EC_CSCD_ID) { 1904a3dd8378SAlexander Motin free(list, M_CTL); 1905a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1906a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1907a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE); 1908a3dd8378SAlexander Motin goto done; 1909a3dd8378SAlexander Motin } 1910a3dd8378SAlexander Motin } 1911984a2ea9SAlexander Motin ptr = &data->data[lencscd]; 1912984a2ea9SAlexander Motin for (nseg = 0, off = 0; off < lenseg; nseg++) { 1913984a2ea9SAlexander Motin if (nseg >= TPC_MAX_SEGS) { 1914984a2ea9SAlexander Motin free(list, M_CTL); 1915984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1916984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1917984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1918984a2ea9SAlexander Motin goto done; 1919984a2ea9SAlexander Motin } 1920a3dd8378SAlexander Motin seg = (struct scsi_ec_segment *)(ptr + off); 1921a3dd8378SAlexander Motin if (seg->type_code != EC_SEG_B2B && 1922a3dd8378SAlexander Motin seg->type_code != EC_SEG_VERIFY && 1923a3dd8378SAlexander Motin seg->type_code != EC_SEG_REGISTER_KEY) { 1924a3dd8378SAlexander Motin free(list, M_CTL); 1925a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1926a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1927a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE); 1928a3dd8378SAlexander Motin goto done; 1929a3dd8378SAlexander Motin } 1930a3dd8378SAlexander Motin list->seg[nseg] = seg; 1931984a2ea9SAlexander Motin off += sizeof(struct scsi_ec_segment) + 1932a3dd8378SAlexander Motin scsi_2btoul(seg->descr_length); 1933984a2ea9SAlexander Motin } 1934984a2ea9SAlexander Motin list->inl = &data->data[lencscd + lenseg]; 1935984a2ea9SAlexander Motin list->ncscd = lencscd / sizeof(struct scsi_ec_cscd); 1936984a2ea9SAlexander Motin list->nseg = nseg; 1937984a2ea9SAlexander Motin list->leninl = leninl; 1938984a2ea9SAlexander Motin list->ctsio = ctsio; 1939984a2ea9SAlexander Motin list->lun = lun; 1940984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1941984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) { 194243d2d719SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 1943984a2ea9SAlexander Motin if (tlist != NULL && !tlist->completed) { 1944984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1945984a2ea9SAlexander Motin free(list, M_CTL); 1946984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 1947984a2ea9SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 1948984a2ea9SAlexander Motin /*bit*/ 0); 1949984a2ea9SAlexander Motin goto done; 1950984a2ea9SAlexander Motin } 1951984a2ea9SAlexander Motin if (tlist != NULL) { 1952984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 1953984a2ea9SAlexander Motin free(tlist, M_CTL); 1954984a2ea9SAlexander Motin } 1955984a2ea9SAlexander Motin } 1956984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 1957984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1958984a2ea9SAlexander Motin 1959984a2ea9SAlexander Motin tpc_process(list); 1960984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1961984a2ea9SAlexander Motin 1962984a2ea9SAlexander Motin done: 19632a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 19642a72b593SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 19652a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 19662a72b593SAlexander Motin } 1967984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1968984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1969984a2ea9SAlexander Motin } 1970984a2ea9SAlexander Motin 197125eee848SAlexander Motin static void 197225eee848SAlexander Motin tpc_create_token(struct ctl_lun *lun, struct ctl_port *port, off_t len, 197325eee848SAlexander Motin struct scsi_token *token) 197425eee848SAlexander Motin { 197525eee848SAlexander Motin static int id = 0; 197625eee848SAlexander Motin struct scsi_vpd_id_descriptor *idd = NULL; 19774ab4d687SAlexander Motin struct scsi_ec_cscd_id *cscd; 19780b060244SAlexander Motin struct scsi_read_capacity_data_long *dtsd; 197925eee848SAlexander Motin int targid_len; 198025eee848SAlexander Motin 198125eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_AUR, token->type); 198225eee848SAlexander Motin scsi_ulto2b(0x01f8, token->length); 198325eee848SAlexander Motin scsi_u64to8b(atomic_fetchadd_int(&id, 1), &token->body[0]); 198425eee848SAlexander Motin if (lun->lun_devid) 198525eee848SAlexander Motin idd = scsi_get_devid_desc((struct scsi_vpd_id_descriptor *) 198625eee848SAlexander Motin lun->lun_devid->data, lun->lun_devid->len, 198725eee848SAlexander Motin scsi_devid_is_lun_naa); 198825eee848SAlexander Motin if (idd == NULL && lun->lun_devid) 198925eee848SAlexander Motin idd = scsi_get_devid_desc((struct scsi_vpd_id_descriptor *) 199025eee848SAlexander Motin lun->lun_devid->data, lun->lun_devid->len, 199125eee848SAlexander Motin scsi_devid_is_lun_eui64); 19924ab4d687SAlexander Motin if (idd != NULL) { 19934ab4d687SAlexander Motin cscd = (struct scsi_ec_cscd_id *)&token->body[8]; 19944ab4d687SAlexander Motin cscd->type_code = EC_CSCD_ID; 19954ab4d687SAlexander Motin cscd->luidt_pdt = T_DIRECT; 19964ab4d687SAlexander Motin memcpy(&cscd->codeset, idd, 4 + idd->length); 19970b060244SAlexander Motin scsi_ulto3b(lun->be_lun->blocksize, cscd->dtsp.block_length); 19984ab4d687SAlexander Motin } 19990b060244SAlexander Motin scsi_u64to8b(0, &token->body[40]); /* XXX: Should be 128bit value. */ 200025eee848SAlexander Motin scsi_u64to8b(len, &token->body[48]); 20010b060244SAlexander Motin 20020b060244SAlexander Motin /* ROD token device type specific data (RC16 without first field) */ 20030b060244SAlexander Motin dtsd = (struct scsi_read_capacity_data_long *)&token->body[88 - 8]; 20040b060244SAlexander Motin scsi_ulto4b(lun->be_lun->blocksize, dtsd->length); 20050b060244SAlexander Motin dtsd->prot_lbppbe = lun->be_lun->pblockexp & SRC16_LBPPBE; 20060b060244SAlexander Motin scsi_ulto2b(lun->be_lun->pblockoff & SRC16_LALBA_A, dtsd->lalba_lbp); 20070b060244SAlexander Motin if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) 20080b060244SAlexander Motin dtsd->lalba_lbp[0] |= SRC16_LBPME | SRC16_LBPRZ; 20090b060244SAlexander Motin 201025eee848SAlexander Motin if (port->target_devid) { 201125eee848SAlexander Motin targid_len = port->target_devid->len; 201225eee848SAlexander Motin memcpy(&token->body[120], port->target_devid->data, targid_len); 201325eee848SAlexander Motin } else 201425eee848SAlexander Motin targid_len = 32; 201525eee848SAlexander Motin arc4rand(&token->body[120 + targid_len], 384 - targid_len, 0); 201625eee848SAlexander Motin }; 201725eee848SAlexander Motin 201825eee848SAlexander Motin int 201925eee848SAlexander Motin ctl_populate_token(struct ctl_scsiio *ctsio) 202025eee848SAlexander Motin { 20219cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 20229cbbfd2fSAlexander Motin struct ctl_port *port = CTL_PORT(ctsio); 20239cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 202425eee848SAlexander Motin struct scsi_populate_token *cdb; 202525eee848SAlexander Motin struct scsi_populate_token_data *data; 202625eee848SAlexander Motin struct tpc_list *list, *tlist; 202725eee848SAlexander Motin struct tpc_token *token; 202832920cbfSAlexander Motin uint64_t lba; 20293eb7651aSAlexander Motin int len, lendata, lendesc; 203025eee848SAlexander Motin 203125eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_populate_token\n")); 203225eee848SAlexander Motin 203325eee848SAlexander Motin cdb = (struct scsi_populate_token *)ctsio->cdb; 203425eee848SAlexander Motin len = scsi_4btoul(cdb->length); 203525eee848SAlexander Motin 203625eee848SAlexander Motin if (len < sizeof(struct scsi_populate_token_data) || 203725eee848SAlexander Motin len > sizeof(struct scsi_populate_token_data) + 203825eee848SAlexander Motin TPC_MAX_SEGS * sizeof(struct scsi_range_desc)) { 203925eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 204025eee848SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 204125eee848SAlexander Motin goto done; 204225eee848SAlexander Motin } 204325eee848SAlexander Motin 204425eee848SAlexander Motin /* 204525eee848SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 204625eee848SAlexander Motin * malloc it and tell the caller the data buffer is here. 204725eee848SAlexander Motin */ 204825eee848SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 204925eee848SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 205025eee848SAlexander Motin ctsio->kern_data_len = len; 205125eee848SAlexander Motin ctsio->kern_total_len = len; 205225eee848SAlexander Motin ctsio->kern_rel_offset = 0; 205325eee848SAlexander Motin ctsio->kern_sg_entries = 0; 205425eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 205525eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 205625eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 205725eee848SAlexander Motin 205825eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 205925eee848SAlexander Motin } 206025eee848SAlexander Motin 206125eee848SAlexander Motin data = (struct scsi_populate_token_data *)ctsio->kern_data_ptr; 20623eb7651aSAlexander Motin lendata = scsi_2btoul(data->length); 20633eb7651aSAlexander Motin if (lendata < sizeof(struct scsi_populate_token_data) - 2 + 20643eb7651aSAlexander Motin sizeof(struct scsi_range_desc)) { 206525eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 20663eb7651aSAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 20673eb7651aSAlexander Motin goto done; 20683eb7651aSAlexander Motin } 20693eb7651aSAlexander Motin lendesc = scsi_2btoul(data->range_descriptor_length); 20703eb7651aSAlexander Motin if (lendesc < sizeof(struct scsi_range_desc) || 20713eb7651aSAlexander Motin len < sizeof(struct scsi_populate_token_data) + lendesc || 20723eb7651aSAlexander Motin lendata < sizeof(struct scsi_populate_token_data) - 2 + lendesc) { 20733eb7651aSAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 20743eb7651aSAlexander Motin /*field*/ 14, /*bit_valid*/ 0, /*bit*/ 0); 207525eee848SAlexander Motin goto done; 207625eee848SAlexander Motin } 207725eee848SAlexander Motin /* 207825eee848SAlexander Motin printf("PT(list=%u) flags=%x to=%d rt=%x len=%x\n", 207925eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), 208025eee848SAlexander Motin data->flags, scsi_4btoul(data->inactivity_timeout), 208125eee848SAlexander Motin scsi_4btoul(data->rod_type), 208225eee848SAlexander Motin scsi_2btoul(data->range_descriptor_length)); 208325eee848SAlexander Motin */ 20843eb7651aSAlexander Motin 20853eb7651aSAlexander Motin /* Validate INACTIVITY TIMEOUT field */ 20863eb7651aSAlexander Motin if (scsi_4btoul(data->inactivity_timeout) > TPC_MAX_TOKEN_TIMEOUT) { 20873eb7651aSAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 20883eb7651aSAlexander Motin /*command*/ 0, /*field*/ 4, /*bit_valid*/ 0, 20893eb7651aSAlexander Motin /*bit*/ 0); 20903eb7651aSAlexander Motin goto done; 20913eb7651aSAlexander Motin } 20923eb7651aSAlexander Motin 20933eb7651aSAlexander Motin /* Validate ROD TYPE field */ 209425eee848SAlexander Motin if ((data->flags & EC_PT_RTV) && 209525eee848SAlexander Motin scsi_4btoul(data->rod_type) != ROD_TYPE_AUR) { 209625eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 209725eee848SAlexander Motin /*field*/ 8, /*bit_valid*/ 0, /*bit*/ 0); 209825eee848SAlexander Motin goto done; 209925eee848SAlexander Motin } 210025eee848SAlexander Motin 2101e13f4248SAlexander Motin /* Validate list of ranges */ 21028fadf660SAlexander Motin if (tpc_check_ranges_l(&data->desc[0], 2103e13f4248SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 210438618bf4SAlexander Motin sizeof(struct scsi_range_desc), 210532920cbfSAlexander Motin lun->be_lun->maxlba, &lba) != 0) { 210632920cbfSAlexander Motin ctl_set_lba_out_of_range(ctsio, lba); 21078fadf660SAlexander Motin goto done; 21088fadf660SAlexander Motin } 21098fadf660SAlexander Motin if (tpc_check_ranges_x(&data->desc[0], 21108fadf660SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 21118fadf660SAlexander Motin sizeof(struct scsi_range_desc)) != 0) { 2112e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 0, 2113e13f4248SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 2114e13f4248SAlexander Motin /*bit*/ 0); 2115e13f4248SAlexander Motin goto done; 2116e13f4248SAlexander Motin } 2117e13f4248SAlexander Motin 211825eee848SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 211925eee848SAlexander Motin list->service_action = cdb->service_action; 212025eee848SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 21217ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 212225eee848SAlexander Motin list->list_id = scsi_4btoul(cdb->list_identifier); 212325eee848SAlexander Motin list->flags = data->flags; 212425eee848SAlexander Motin list->ctsio = ctsio; 212525eee848SAlexander Motin list->lun = lun; 212625eee848SAlexander Motin mtx_lock(&lun->lun_lock); 212725eee848SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 212825eee848SAlexander Motin if (tlist != NULL && !tlist->completed) { 212925eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 213025eee848SAlexander Motin free(list, M_CTL); 213125eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 213225eee848SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 213325eee848SAlexander Motin /*bit*/ 0); 213425eee848SAlexander Motin goto done; 213525eee848SAlexander Motin } 213625eee848SAlexander Motin if (tlist != NULL) { 213725eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 213825eee848SAlexander Motin free(tlist, M_CTL); 213925eee848SAlexander Motin } 214025eee848SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 214125eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 214225eee848SAlexander Motin 214325eee848SAlexander Motin token = malloc(sizeof(*token), M_CTL, M_WAITOK | M_ZERO); 214425eee848SAlexander Motin token->lun = lun->lun; 214525eee848SAlexander Motin token->blocksize = lun->be_lun->blocksize; 214625eee848SAlexander Motin token->params = ctsio->kern_data_ptr; 214725eee848SAlexander Motin token->range = &data->desc[0]; 214825eee848SAlexander Motin token->nrange = scsi_2btoul(data->range_descriptor_length) / 214925eee848SAlexander Motin sizeof(struct scsi_range_desc); 21500b060244SAlexander Motin list->cursectors = tpc_ranges_length(token->range, token->nrange); 21510b060244SAlexander Motin list->curbytes = (off_t)list->cursectors * lun->be_lun->blocksize; 215225eee848SAlexander Motin tpc_create_token(lun, port, list->curbytes, 215325eee848SAlexander Motin (struct scsi_token *)token->token); 215425eee848SAlexander Motin token->active = 0; 215525eee848SAlexander Motin token->last_active = time_uptime; 215625eee848SAlexander Motin token->timeout = scsi_4btoul(data->inactivity_timeout); 215725eee848SAlexander Motin if (token->timeout == 0) 215825eee848SAlexander Motin token->timeout = TPC_DFL_TOKEN_TIMEOUT; 215925eee848SAlexander Motin else if (token->timeout < TPC_MIN_TOKEN_TIMEOUT) 216025eee848SAlexander Motin token->timeout = TPC_MIN_TOKEN_TIMEOUT; 216125eee848SAlexander Motin memcpy(list->res_token, token->token, sizeof(list->res_token)); 216225eee848SAlexander Motin list->res_token_valid = 1; 216325eee848SAlexander Motin list->curseg = 0; 216425eee848SAlexander Motin list->completed = 1; 216525eee848SAlexander Motin list->last_active = time_uptime; 21662d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 21679602f436SAlexander Motin TAILQ_INSERT_TAIL(&softc->tpc_tokens, token, links); 21682d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 216925eee848SAlexander Motin ctl_set_success(ctsio); 217025eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 217125eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 217225eee848SAlexander Motin 217325eee848SAlexander Motin done: 21742a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 217525eee848SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 21762a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 21772a72b593SAlexander Motin } 217825eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 217925eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 218025eee848SAlexander Motin } 218125eee848SAlexander Motin 218225eee848SAlexander Motin int 218325eee848SAlexander Motin ctl_write_using_token(struct ctl_scsiio *ctsio) 218425eee848SAlexander Motin { 21859cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 21869cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 218725eee848SAlexander Motin struct scsi_write_using_token *cdb; 218825eee848SAlexander Motin struct scsi_write_using_token_data *data; 218925eee848SAlexander Motin struct tpc_list *list, *tlist; 219025eee848SAlexander Motin struct tpc_token *token; 219132920cbfSAlexander Motin uint64_t lba; 2192e13f4248SAlexander Motin int len, lendata, lendesc; 219325eee848SAlexander Motin 219425eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_write_using_token\n")); 219525eee848SAlexander Motin 219625eee848SAlexander Motin cdb = (struct scsi_write_using_token *)ctsio->cdb; 219725eee848SAlexander Motin len = scsi_4btoul(cdb->length); 219825eee848SAlexander Motin 2199e13f4248SAlexander Motin if (len < sizeof(struct scsi_write_using_token_data) || 2200e13f4248SAlexander Motin len > sizeof(struct scsi_write_using_token_data) + 220125eee848SAlexander Motin TPC_MAX_SEGS * sizeof(struct scsi_range_desc)) { 220225eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 220325eee848SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 220425eee848SAlexander Motin goto done; 220525eee848SAlexander Motin } 220625eee848SAlexander Motin 220725eee848SAlexander Motin /* 220825eee848SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 220925eee848SAlexander Motin * malloc it and tell the caller the data buffer is here. 221025eee848SAlexander Motin */ 221125eee848SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 221225eee848SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 221325eee848SAlexander Motin ctsio->kern_data_len = len; 221425eee848SAlexander Motin ctsio->kern_total_len = len; 221525eee848SAlexander Motin ctsio->kern_rel_offset = 0; 221625eee848SAlexander Motin ctsio->kern_sg_entries = 0; 221725eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 221825eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 221925eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 222025eee848SAlexander Motin 222125eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 222225eee848SAlexander Motin } 222325eee848SAlexander Motin 222425eee848SAlexander Motin data = (struct scsi_write_using_token_data *)ctsio->kern_data_ptr; 2225e13f4248SAlexander Motin lendata = scsi_2btoul(data->length); 2226e13f4248SAlexander Motin if (lendata < sizeof(struct scsi_write_using_token_data) - 2 + 2227e13f4248SAlexander Motin sizeof(struct scsi_range_desc)) { 222825eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 2229e13f4248SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 2230e13f4248SAlexander Motin goto done; 2231e13f4248SAlexander Motin } 2232e13f4248SAlexander Motin lendesc = scsi_2btoul(data->range_descriptor_length); 2233e13f4248SAlexander Motin if (lendesc < sizeof(struct scsi_range_desc) || 2234e13f4248SAlexander Motin len < sizeof(struct scsi_write_using_token_data) + lendesc || 2235e13f4248SAlexander Motin lendata < sizeof(struct scsi_write_using_token_data) - 2 + lendesc) { 2236e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 2237e13f4248SAlexander Motin /*field*/ 534, /*bit_valid*/ 0, /*bit*/ 0); 223825eee848SAlexander Motin goto done; 223925eee848SAlexander Motin } 224025eee848SAlexander Motin /* 224125eee848SAlexander Motin printf("WUT(list=%u) flags=%x off=%ju len=%x\n", 224225eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), 224325eee848SAlexander Motin data->flags, scsi_8btou64(data->offset_into_rod), 224425eee848SAlexander Motin scsi_2btoul(data->range_descriptor_length)); 224525eee848SAlexander Motin */ 2246e13f4248SAlexander Motin 2247e13f4248SAlexander Motin /* Validate list of ranges */ 22488fadf660SAlexander Motin if (tpc_check_ranges_l(&data->desc[0], 2249e13f4248SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 225038618bf4SAlexander Motin sizeof(struct scsi_range_desc), 225132920cbfSAlexander Motin lun->be_lun->maxlba, &lba) != 0) { 225232920cbfSAlexander Motin ctl_set_lba_out_of_range(ctsio, lba); 22538fadf660SAlexander Motin goto done; 22548fadf660SAlexander Motin } 22558fadf660SAlexander Motin if (tpc_check_ranges_x(&data->desc[0], 22568fadf660SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 22578fadf660SAlexander Motin sizeof(struct scsi_range_desc)) != 0) { 2258e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 0, 2259e13f4248SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 2260e13f4248SAlexander Motin /*bit*/ 0); 2261e13f4248SAlexander Motin goto done; 2262e13f4248SAlexander Motin } 2263e13f4248SAlexander Motin 226425eee848SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 226525eee848SAlexander Motin list->service_action = cdb->service_action; 226625eee848SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 22677ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 226825eee848SAlexander Motin list->list_id = scsi_4btoul(cdb->list_identifier); 226925eee848SAlexander Motin list->flags = data->flags; 227025eee848SAlexander Motin list->params = ctsio->kern_data_ptr; 227125eee848SAlexander Motin list->range = &data->desc[0]; 227225eee848SAlexander Motin list->nrange = scsi_2btoul(data->range_descriptor_length) / 227325eee848SAlexander Motin sizeof(struct scsi_range_desc); 227425eee848SAlexander Motin list->offset_into_rod = scsi_8btou64(data->offset_into_rod); 227525eee848SAlexander Motin list->ctsio = ctsio; 227625eee848SAlexander Motin list->lun = lun; 227725eee848SAlexander Motin mtx_lock(&lun->lun_lock); 227825eee848SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 227925eee848SAlexander Motin if (tlist != NULL && !tlist->completed) { 228025eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 228125eee848SAlexander Motin free(list, M_CTL); 228225eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 228325eee848SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 228425eee848SAlexander Motin /*bit*/ 0); 228525eee848SAlexander Motin goto done; 228625eee848SAlexander Motin } 228725eee848SAlexander Motin if (tlist != NULL) { 228825eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 228925eee848SAlexander Motin free(tlist, M_CTL); 229025eee848SAlexander Motin } 229125eee848SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 229225eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 229325eee848SAlexander Motin 229425eee848SAlexander Motin /* Block device zero ROD token -> no token. */ 229525eee848SAlexander Motin if (scsi_4btoul(data->rod_token) == ROD_TYPE_BLOCK_ZERO) { 229625eee848SAlexander Motin tpc_process(list); 229725eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 229825eee848SAlexander Motin } 229925eee848SAlexander Motin 23002d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 23019602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) { 230225eee848SAlexander Motin if (memcmp(token->token, data->rod_token, 230325eee848SAlexander Motin sizeof(data->rod_token)) == 0) 230425eee848SAlexander Motin break; 230525eee848SAlexander Motin } 230625eee848SAlexander Motin if (token != NULL) { 230725eee848SAlexander Motin token->active++; 230825eee848SAlexander Motin list->token = token; 230925eee848SAlexander Motin if (data->flags & EC_WUT_DEL_TKN) 231025eee848SAlexander Motin token->timeout = 0; 231125eee848SAlexander Motin } 23122d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 231325eee848SAlexander Motin if (token == NULL) { 231425eee848SAlexander Motin mtx_lock(&lun->lun_lock); 231525eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 231625eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 231725eee848SAlexander Motin free(list, M_CTL); 231825eee848SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 231925eee848SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 232025eee848SAlexander Motin /*asc*/ 0x23, /*ascq*/ 0x04, SSD_ELEM_NONE); 232125eee848SAlexander Motin goto done; 232225eee848SAlexander Motin } 232325eee848SAlexander Motin 232425eee848SAlexander Motin tpc_process(list); 232525eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 232625eee848SAlexander Motin 232725eee848SAlexander Motin done: 23282a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 232925eee848SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 23302a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 23312a72b593SAlexander Motin } 233225eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 233325eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 233425eee848SAlexander Motin } 233525eee848SAlexander Motin 233625eee848SAlexander Motin int 233725eee848SAlexander Motin ctl_receive_rod_token_information(struct ctl_scsiio *ctsio) 233825eee848SAlexander Motin { 23399cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 234025eee848SAlexander Motin struct scsi_receive_rod_token_information *cdb; 234125eee848SAlexander Motin struct scsi_receive_copy_status_lid4_data *data; 234225eee848SAlexander Motin struct tpc_list *list; 234325eee848SAlexander Motin struct tpc_list list_copy; 234425eee848SAlexander Motin uint8_t *ptr; 234525eee848SAlexander Motin int retval; 234625eee848SAlexander Motin int alloc_len, total_len, token_len; 234725eee848SAlexander Motin uint32_t list_id; 234825eee848SAlexander Motin 234925eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_rod_token_information\n")); 235025eee848SAlexander Motin 235125eee848SAlexander Motin cdb = (struct scsi_receive_rod_token_information *)ctsio->cdb; 235225eee848SAlexander Motin retval = CTL_RETVAL_COMPLETE; 235325eee848SAlexander Motin 235425eee848SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 235525eee848SAlexander Motin mtx_lock(&lun->lun_lock); 235625eee848SAlexander Motin list = tpc_find_list(lun, list_id, 23577ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 235825eee848SAlexander Motin if (list == NULL) { 235925eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 236025eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 236125eee848SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 236225eee848SAlexander Motin /*bit*/ 0); 236325eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 236425eee848SAlexander Motin return (retval); 236525eee848SAlexander Motin } 236625eee848SAlexander Motin list_copy = *list; 236725eee848SAlexander Motin if (list->completed) { 236825eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 236925eee848SAlexander Motin free(list, M_CTL); 237025eee848SAlexander Motin } 237125eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 237225eee848SAlexander Motin 237325eee848SAlexander Motin token_len = list_copy.res_token_valid ? 2 + sizeof(list_copy.res_token) : 0; 237425eee848SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len + 4 + token_len; 237525eee848SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 237625eee848SAlexander Motin 237725eee848SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 237825eee848SAlexander Motin ctsio->kern_sg_entries = 0; 237925eee848SAlexander Motin ctsio->kern_rel_offset = 0; 2380640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 2381640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 238225eee848SAlexander Motin 238325eee848SAlexander Motin data = (struct scsi_receive_copy_status_lid4_data *)ctsio->kern_data_ptr; 238425eee848SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len + 238525eee848SAlexander Motin 4 + token_len, data->available_data); 238625eee848SAlexander Motin data->response_to_service_action = list_copy.service_action; 238725eee848SAlexander Motin if (list_copy.completed) { 238825eee848SAlexander Motin if (list_copy.error) 238925eee848SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 239025eee848SAlexander Motin else if (list_copy.abort) 239125eee848SAlexander Motin data->copy_command_status = RCS_CCS_ABORTED; 239225eee848SAlexander Motin else 239325eee848SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 239425eee848SAlexander Motin } else 239525eee848SAlexander Motin data->copy_command_status = RCS_CCS_INPROG_FG; 239625eee848SAlexander Motin scsi_ulto2b(list_copy.curops, data->operation_counter); 239725eee848SAlexander Motin scsi_ulto4b(UINT32_MAX, data->estimated_status_update_delay); 239825eee848SAlexander Motin data->transfer_count_units = RCS_TC_LBAS; 239925eee848SAlexander Motin scsi_u64to8b(list_copy.cursectors, data->transfer_count); 240025eee848SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 240125eee848SAlexander Motin data->length_of_the_sense_data_field = list_copy.sense_len; 240225eee848SAlexander Motin data->sense_data_length = list_copy.sense_len; 240325eee848SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 240425eee848SAlexander Motin 240525eee848SAlexander Motin ptr = &data->sense_data[data->length_of_the_sense_data_field]; 240625eee848SAlexander Motin scsi_ulto4b(token_len, &ptr[0]); 240725eee848SAlexander Motin if (list_copy.res_token_valid) { 240825eee848SAlexander Motin scsi_ulto2b(0, &ptr[4]); 240925eee848SAlexander Motin memcpy(&ptr[6], list_copy.res_token, sizeof(list_copy.res_token)); 241025eee848SAlexander Motin } 241125eee848SAlexander Motin /* 241225eee848SAlexander Motin printf("RRTI(list=%u) valid=%d\n", 241325eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), list_copy.res_token_valid); 241425eee848SAlexander Motin */ 2415f7241cceSAlexander Motin ctl_set_success(ctsio); 241625eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 241725eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 241825eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 241925eee848SAlexander Motin return (retval); 242025eee848SAlexander Motin } 242125eee848SAlexander Motin 242225eee848SAlexander Motin int 242325eee848SAlexander Motin ctl_report_all_rod_tokens(struct ctl_scsiio *ctsio) 242425eee848SAlexander Motin { 24259cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 242625eee848SAlexander Motin struct scsi_report_all_rod_tokens *cdb; 242725eee848SAlexander Motin struct scsi_report_all_rod_tokens_data *data; 242825eee848SAlexander Motin struct tpc_token *token; 242925eee848SAlexander Motin int retval; 243025eee848SAlexander Motin int alloc_len, total_len, tokens, i; 243125eee848SAlexander Motin 243225eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_rod_token_information\n")); 243325eee848SAlexander Motin 243425eee848SAlexander Motin cdb = (struct scsi_report_all_rod_tokens *)ctsio->cdb; 243525eee848SAlexander Motin retval = CTL_RETVAL_COMPLETE; 243625eee848SAlexander Motin 243725eee848SAlexander Motin tokens = 0; 24382d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 24399602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) 244025eee848SAlexander Motin tokens++; 24412d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 244225eee848SAlexander Motin if (tokens > 512) 244325eee848SAlexander Motin tokens = 512; 244425eee848SAlexander Motin 244525eee848SAlexander Motin total_len = sizeof(*data) + tokens * 96; 244625eee848SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 244725eee848SAlexander Motin 244825eee848SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 244925eee848SAlexander Motin ctsio->kern_sg_entries = 0; 245025eee848SAlexander Motin ctsio->kern_rel_offset = 0; 2451640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 2452640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 245325eee848SAlexander Motin 245425eee848SAlexander Motin data = (struct scsi_report_all_rod_tokens_data *)ctsio->kern_data_ptr; 245525eee848SAlexander Motin i = 0; 24562d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 24579602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) { 245825eee848SAlexander Motin if (i >= tokens) 245925eee848SAlexander Motin break; 246025eee848SAlexander Motin memcpy(&data->rod_management_token_list[i * 96], 246125eee848SAlexander Motin token->token, 96); 246225eee848SAlexander Motin i++; 246325eee848SAlexander Motin } 24642d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 246525eee848SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + i * 96, data->available_data); 246625eee848SAlexander Motin /* 246725eee848SAlexander Motin printf("RART tokens=%d\n", i); 246825eee848SAlexander Motin */ 2469f7241cceSAlexander Motin ctl_set_success(ctsio); 247025eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 247125eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 247225eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 247325eee848SAlexander Motin return (retval); 247425eee848SAlexander Motin } 247525eee848SAlexander Motin 2476