1984a2ea9SAlexander Motin /*- 2984a2ea9SAlexander Motin * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org> 3984a2ea9SAlexander Motin * All rights reserved. 4984a2ea9SAlexander Motin * 5984a2ea9SAlexander Motin * Redistribution and use in source and binary forms, with or without 6984a2ea9SAlexander Motin * modification, are permitted provided that the following conditions 7984a2ea9SAlexander Motin * are met: 8984a2ea9SAlexander Motin * 1. Redistributions of source code must retain the above copyright 9984a2ea9SAlexander Motin * notice, this list of conditions and the following disclaimer, 10984a2ea9SAlexander Motin * without modification, immediately at the beginning of the file. 11984a2ea9SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 12984a2ea9SAlexander Motin * notice, this list of conditions and the following disclaimer in the 13984a2ea9SAlexander Motin * documentation and/or other materials provided with the distribution. 14984a2ea9SAlexander Motin * 15984a2ea9SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16984a2ea9SAlexander Motin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17984a2ea9SAlexander Motin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18984a2ea9SAlexander Motin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19984a2ea9SAlexander Motin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20984a2ea9SAlexander Motin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21984a2ea9SAlexander Motin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22984a2ea9SAlexander Motin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23984a2ea9SAlexander Motin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24984a2ea9SAlexander Motin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25984a2ea9SAlexander Motin */ 26984a2ea9SAlexander Motin 27984a2ea9SAlexander Motin #include <sys/cdefs.h> 28984a2ea9SAlexander Motin __FBSDID("$FreeBSD$"); 29984a2ea9SAlexander Motin 30984a2ea9SAlexander Motin #include <sys/param.h> 31984a2ea9SAlexander Motin #include <sys/systm.h> 32984a2ea9SAlexander Motin #include <sys/kernel.h> 33984a2ea9SAlexander Motin #include <sys/types.h> 34984a2ea9SAlexander Motin #include <sys/lock.h> 35984a2ea9SAlexander Motin #include <sys/module.h> 36984a2ea9SAlexander Motin #include <sys/mutex.h> 37984a2ea9SAlexander Motin #include <sys/condvar.h> 38984a2ea9SAlexander Motin #include <sys/malloc.h> 39984a2ea9SAlexander Motin #include <sys/conf.h> 40984a2ea9SAlexander Motin #include <sys/queue.h> 41984a2ea9SAlexander Motin #include <sys/sysctl.h> 42984a2ea9SAlexander Motin #include <machine/atomic.h> 43984a2ea9SAlexander Motin 44984a2ea9SAlexander Motin #include <cam/cam.h> 45984a2ea9SAlexander Motin #include <cam/scsi/scsi_all.h> 46984a2ea9SAlexander Motin #include <cam/scsi/scsi_da.h> 47984a2ea9SAlexander Motin #include <cam/ctl/ctl_io.h> 48984a2ea9SAlexander Motin #include <cam/ctl/ctl.h> 49984a2ea9SAlexander Motin #include <cam/ctl/ctl_frontend.h> 50984a2ea9SAlexander Motin #include <cam/ctl/ctl_util.h> 51984a2ea9SAlexander Motin #include <cam/ctl/ctl_backend.h> 52984a2ea9SAlexander Motin #include <cam/ctl/ctl_ioctl.h> 53984a2ea9SAlexander Motin #include <cam/ctl/ctl_ha.h> 54984a2ea9SAlexander Motin #include <cam/ctl/ctl_private.h> 55984a2ea9SAlexander Motin #include <cam/ctl/ctl_debug.h> 56984a2ea9SAlexander Motin #include <cam/ctl/ctl_scsi_all.h> 57984a2ea9SAlexander Motin #include <cam/ctl/ctl_tpc.h> 58984a2ea9SAlexander Motin #include <cam/ctl/ctl_error.h> 59984a2ea9SAlexander Motin 60984a2ea9SAlexander Motin #define TPC_MAX_CSCDS 64 61984a2ea9SAlexander Motin #define TPC_MAX_SEGS 64 62984a2ea9SAlexander Motin #define TPC_MAX_SEG 0 63984a2ea9SAlexander Motin #define TPC_MAX_LIST 8192 64984a2ea9SAlexander Motin #define TPC_MAX_INLINE 0 65984a2ea9SAlexander Motin #define TPC_MAX_LISTS 255 66984a2ea9SAlexander Motin #define TPC_MAX_IO_SIZE (1024 * 1024) 6725eee848SAlexander Motin #define TPC_MAX_IOCHUNK_SIZE (TPC_MAX_IO_SIZE * 16) 6825eee848SAlexander Motin #define TPC_MIN_TOKEN_TIMEOUT 1 6925eee848SAlexander Motin #define TPC_DFL_TOKEN_TIMEOUT 60 7025eee848SAlexander Motin #define TPC_MAX_TOKEN_TIMEOUT 600 71984a2ea9SAlexander Motin 72984a2ea9SAlexander Motin MALLOC_DEFINE(M_CTL_TPC, "ctltpc", "CTL TPC"); 73984a2ea9SAlexander Motin 74984a2ea9SAlexander Motin typedef enum { 75984a2ea9SAlexander Motin TPC_ERR_RETRY = 0x000, 76984a2ea9SAlexander Motin TPC_ERR_FAIL = 0x001, 77984a2ea9SAlexander Motin TPC_ERR_MASK = 0x0ff, 78984a2ea9SAlexander Motin TPC_ERR_NO_DECREMENT = 0x100 79984a2ea9SAlexander Motin } tpc_error_action; 80984a2ea9SAlexander Motin 81984a2ea9SAlexander Motin struct tpc_list; 82984a2ea9SAlexander Motin TAILQ_HEAD(runl, tpc_io); 83984a2ea9SAlexander Motin struct tpc_io { 84984a2ea9SAlexander Motin union ctl_io *io; 85a3dd8378SAlexander Motin uint8_t target; 86a3dd8378SAlexander Motin uint32_t cscd; 87984a2ea9SAlexander Motin uint64_t lun; 8846511441SAlexander Motin uint8_t *buf; 89984a2ea9SAlexander Motin struct tpc_list *list; 90984a2ea9SAlexander Motin struct runl run; 91984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_io) rlinks; 92984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_io) links; 93984a2ea9SAlexander Motin }; 94984a2ea9SAlexander Motin 9525eee848SAlexander Motin struct tpc_token { 9625eee848SAlexander Motin uint8_t token[512]; 9725eee848SAlexander Motin uint64_t lun; 9825eee848SAlexander Motin uint32_t blocksize; 9925eee848SAlexander Motin uint8_t *params; 10025eee848SAlexander Motin struct scsi_range_desc *range; 10125eee848SAlexander Motin int nrange; 10225eee848SAlexander Motin int active; 10325eee848SAlexander Motin time_t last_active; 10425eee848SAlexander Motin uint32_t timeout; 10525eee848SAlexander Motin TAILQ_ENTRY(tpc_token) links; 10625eee848SAlexander Motin }; 10725eee848SAlexander Motin 108984a2ea9SAlexander Motin struct tpc_list { 109984a2ea9SAlexander Motin uint8_t service_action; 110984a2ea9SAlexander Motin int init_port; 1118cbf9eaeSAlexander Motin uint32_t init_idx; 112984a2ea9SAlexander Motin uint32_t list_id; 113984a2ea9SAlexander Motin uint8_t flags; 114984a2ea9SAlexander Motin uint8_t *params; 115984a2ea9SAlexander Motin struct scsi_ec_cscd *cscd; 116984a2ea9SAlexander Motin struct scsi_ec_segment *seg[TPC_MAX_SEGS]; 117984a2ea9SAlexander Motin uint8_t *inl; 118984a2ea9SAlexander Motin int ncscd; 119984a2ea9SAlexander Motin int nseg; 120984a2ea9SAlexander Motin int leninl; 12125eee848SAlexander Motin struct tpc_token *token; 12225eee848SAlexander Motin struct scsi_range_desc *range; 12325eee848SAlexander Motin int nrange; 12425eee848SAlexander Motin off_t offset_into_rod; 12525eee848SAlexander Motin 126984a2ea9SAlexander Motin int curseg; 12725eee848SAlexander Motin off_t cursectors; 128984a2ea9SAlexander Motin off_t curbytes; 129984a2ea9SAlexander Motin int curops; 130984a2ea9SAlexander Motin int stage; 13125eee848SAlexander Motin off_t segsectors; 13225eee848SAlexander Motin off_t segbytes; 133984a2ea9SAlexander Motin int tbdio; 134984a2ea9SAlexander Motin int error; 135984a2ea9SAlexander Motin int abort; 136984a2ea9SAlexander Motin int completed; 13725eee848SAlexander Motin time_t last_active; 138984a2ea9SAlexander Motin TAILQ_HEAD(, tpc_io) allio; 139a3dd8378SAlexander Motin struct scsi_sense_data fwd_sense_data; 140a3dd8378SAlexander Motin uint8_t fwd_sense_len; 141a3dd8378SAlexander Motin uint8_t fwd_scsi_status; 142a3dd8378SAlexander Motin uint8_t fwd_target; 143a3dd8378SAlexander Motin uint16_t fwd_cscd; 144984a2ea9SAlexander Motin struct scsi_sense_data sense_data; 145984a2ea9SAlexander Motin uint8_t sense_len; 146984a2ea9SAlexander Motin uint8_t scsi_status; 147984a2ea9SAlexander Motin struct ctl_scsiio *ctsio; 148984a2ea9SAlexander Motin struct ctl_lun *lun; 14925eee848SAlexander Motin int res_token_valid; 15025eee848SAlexander Motin uint8_t res_token[512]; 151984a2ea9SAlexander Motin TAILQ_ENTRY(tpc_list) links; 152984a2ea9SAlexander Motin }; 153984a2ea9SAlexander Motin 15425eee848SAlexander Motin static void 15525eee848SAlexander Motin tpc_timeout(void *arg) 15625eee848SAlexander Motin { 15725eee848SAlexander Motin struct ctl_softc *softc = arg; 15825eee848SAlexander Motin struct ctl_lun *lun; 15925eee848SAlexander Motin struct tpc_token *token, *ttoken; 16025eee848SAlexander Motin struct tpc_list *list, *tlist; 16125eee848SAlexander Motin 16225eee848SAlexander Motin /* Free completed lists with expired timeout. */ 16325eee848SAlexander Motin STAILQ_FOREACH(lun, &softc->lun_list, links) { 16425eee848SAlexander Motin mtx_lock(&lun->lun_lock); 16525eee848SAlexander Motin TAILQ_FOREACH_SAFE(list, &lun->tpc_lists, links, tlist) { 16625eee848SAlexander Motin if (!list->completed || time_uptime < list->last_active + 16725eee848SAlexander Motin TPC_DFL_TOKEN_TIMEOUT) 16825eee848SAlexander Motin continue; 16925eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 17025eee848SAlexander Motin free(list, M_CTL); 17125eee848SAlexander Motin } 17225eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 17325eee848SAlexander Motin } 17425eee848SAlexander Motin 17525eee848SAlexander Motin /* Free inactive ROD tokens with expired timeout. */ 1762d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 17725eee848SAlexander Motin TAILQ_FOREACH_SAFE(token, &softc->tpc_tokens, links, ttoken) { 17825eee848SAlexander Motin if (token->active || 17925eee848SAlexander Motin time_uptime < token->last_active + token->timeout + 1) 18025eee848SAlexander Motin continue; 18125eee848SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 18225eee848SAlexander Motin free(token->params, M_CTL); 18325eee848SAlexander Motin free(token, M_CTL); 18425eee848SAlexander Motin } 1852d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 18625eee848SAlexander Motin callout_schedule(&softc->tpc_timeout, hz); 18725eee848SAlexander Motin } 18825eee848SAlexander Motin 189984a2ea9SAlexander Motin void 19025eee848SAlexander Motin ctl_tpc_init(struct ctl_softc *softc) 19125eee848SAlexander Motin { 19225eee848SAlexander Motin 1932d8b2876SAlexander Motin mtx_init(&softc->tpc_lock, "CTL TPC mutex", NULL, MTX_DEF); 19425eee848SAlexander Motin TAILQ_INIT(&softc->tpc_tokens); 19525eee848SAlexander Motin callout_init_mtx(&softc->tpc_timeout, &softc->ctl_lock, 0); 19625eee848SAlexander Motin callout_reset(&softc->tpc_timeout, hz, tpc_timeout, softc); 19725eee848SAlexander Motin } 19825eee848SAlexander Motin 19925eee848SAlexander Motin void 20025eee848SAlexander Motin ctl_tpc_shutdown(struct ctl_softc *softc) 20125eee848SAlexander Motin { 20225eee848SAlexander Motin struct tpc_token *token; 20325eee848SAlexander Motin 20425eee848SAlexander Motin callout_drain(&softc->tpc_timeout); 20525eee848SAlexander Motin 20625eee848SAlexander Motin /* Free ROD tokens. */ 2072d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 20825eee848SAlexander Motin while ((token = TAILQ_FIRST(&softc->tpc_tokens)) != NULL) { 20925eee848SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 21025eee848SAlexander Motin free(token->params, M_CTL); 21125eee848SAlexander Motin free(token, M_CTL); 21225eee848SAlexander Motin } 2132d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 2142d8b2876SAlexander Motin mtx_destroy(&softc->tpc_lock); 21525eee848SAlexander Motin } 21625eee848SAlexander Motin 21725eee848SAlexander Motin void 21825eee848SAlexander Motin ctl_tpc_lun_init(struct ctl_lun *lun) 219984a2ea9SAlexander Motin { 220984a2ea9SAlexander Motin 221984a2ea9SAlexander Motin TAILQ_INIT(&lun->tpc_lists); 222984a2ea9SAlexander Motin } 223984a2ea9SAlexander Motin 224984a2ea9SAlexander Motin void 225*9ff948d0SAlexander Motin ctl_tpc_lun_clear(struct ctl_lun *lun, uint32_t initidx) 226*9ff948d0SAlexander Motin { 227*9ff948d0SAlexander Motin struct tpc_list *list, *tlist; 228*9ff948d0SAlexander Motin 229*9ff948d0SAlexander Motin TAILQ_FOREACH_SAFE(list, &lun->tpc_lists, links, tlist) { 230*9ff948d0SAlexander Motin if (initidx != -1 && list->init_idx != initidx) 231*9ff948d0SAlexander Motin continue; 232*9ff948d0SAlexander Motin if (!list->completed) 233*9ff948d0SAlexander Motin continue; 234*9ff948d0SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 235*9ff948d0SAlexander Motin free(list, M_CTL); 236*9ff948d0SAlexander Motin } 237*9ff948d0SAlexander Motin } 238*9ff948d0SAlexander Motin 239*9ff948d0SAlexander Motin void 24025eee848SAlexander Motin ctl_tpc_lun_shutdown(struct ctl_lun *lun) 241984a2ea9SAlexander Motin { 2429602f436SAlexander Motin struct ctl_softc *softc = lun->ctl_softc; 243984a2ea9SAlexander Motin struct tpc_list *list; 24425eee848SAlexander Motin struct tpc_token *token, *ttoken; 245984a2ea9SAlexander Motin 24625eee848SAlexander Motin /* Free lists for this LUN. */ 247984a2ea9SAlexander Motin while ((list = TAILQ_FIRST(&lun->tpc_lists)) != NULL) { 248984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 249984a2ea9SAlexander Motin KASSERT(list->completed, 250984a2ea9SAlexander Motin ("Not completed TPC (%p) on shutdown", list)); 251984a2ea9SAlexander Motin free(list, M_CTL); 252984a2ea9SAlexander Motin } 25325eee848SAlexander Motin 25425eee848SAlexander Motin /* Free ROD tokens for this LUN. */ 2552d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 2569602f436SAlexander Motin TAILQ_FOREACH_SAFE(token, &softc->tpc_tokens, links, ttoken) { 25725eee848SAlexander Motin if (token->lun != lun->lun || token->active) 25825eee848SAlexander Motin continue; 2599602f436SAlexander Motin TAILQ_REMOVE(&softc->tpc_tokens, token, links); 26025eee848SAlexander Motin free(token->params, M_CTL); 26125eee848SAlexander Motin free(token, M_CTL); 26225eee848SAlexander Motin } 2632d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 264984a2ea9SAlexander Motin } 265984a2ea9SAlexander Motin 266984a2ea9SAlexander Motin int 267984a2ea9SAlexander Motin ctl_inquiry_evpd_tpc(struct ctl_scsiio *ctsio, int alloc_len) 268984a2ea9SAlexander Motin { 2699cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 270984a2ea9SAlexander Motin struct scsi_vpd_tpc *tpc_ptr; 271984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor *d_ptr; 27225eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_bdrl *bdrl_ptr; 273984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sc *sc_ptr; 274984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sc_descr *scd_ptr; 275984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_pd *pd_ptr; 276984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sd *sd_ptr; 277984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_sdid *sdid_ptr; 27825eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_rtf *rtf_ptr; 27925eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_rtf_block *rtfb_ptr; 28025eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_srt *srt_ptr; 28125eee848SAlexander Motin struct scsi_vpd_tpc_descriptor_srtd *srtd_ptr; 282984a2ea9SAlexander Motin struct scsi_vpd_tpc_descriptor_gco *gco_ptr; 283984a2ea9SAlexander Motin int data_len; 284984a2ea9SAlexander Motin 285984a2ea9SAlexander Motin data_len = sizeof(struct scsi_vpd_tpc) + 28625eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_bdrl) + 287984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sc) + 28825eee848SAlexander Motin 2 * sizeof(struct scsi_vpd_tpc_descriptor_sc_descr) + 11, 4) + 289984a2ea9SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_pd) + 290984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sd) + 4, 4) + 291984a2ea9SAlexander Motin roundup2(sizeof(struct scsi_vpd_tpc_descriptor_sdid) + 2, 4) + 29225eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_rtf) + 29325eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_rtf_block) + 29425eee848SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_srt) + 29525eee848SAlexander Motin 2*sizeof(struct scsi_vpd_tpc_descriptor_srtd) + 296984a2ea9SAlexander Motin sizeof(struct scsi_vpd_tpc_descriptor_gco); 297984a2ea9SAlexander Motin 298984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); 299984a2ea9SAlexander Motin tpc_ptr = (struct scsi_vpd_tpc *)ctsio->kern_data_ptr; 300984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 301984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 302640603fbSAlexander Motin ctsio->kern_data_len = min(data_len, alloc_len); 303640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 304984a2ea9SAlexander Motin 305984a2ea9SAlexander Motin /* 306984a2ea9SAlexander Motin * The control device is always connected. The disk device, on the 307984a2ea9SAlexander Motin * other hand, may not be online all the time. 308984a2ea9SAlexander Motin */ 309984a2ea9SAlexander Motin if (lun != NULL) 310984a2ea9SAlexander Motin tpc_ptr->device = (SID_QUAL_LU_CONNECTED << 5) | 311984a2ea9SAlexander Motin lun->be_lun->lun_type; 312984a2ea9SAlexander Motin else 313984a2ea9SAlexander Motin tpc_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | T_DIRECT; 314984a2ea9SAlexander Motin tpc_ptr->page_code = SVPD_SCSI_TPC; 315984a2ea9SAlexander Motin scsi_ulto2b(data_len - 4, tpc_ptr->page_length); 316984a2ea9SAlexander Motin 31725eee848SAlexander Motin /* Block Device ROD Limits */ 318984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *)&tpc_ptr->descr[0]; 31925eee848SAlexander Motin bdrl_ptr = (struct scsi_vpd_tpc_descriptor_bdrl *)d_ptr; 32025eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_BDRL, bdrl_ptr->desc_type); 32125eee848SAlexander Motin scsi_ulto2b(sizeof(*bdrl_ptr) - 4, bdrl_ptr->desc_length); 32225eee848SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, bdrl_ptr->maximum_ranges); 32325eee848SAlexander Motin scsi_ulto4b(TPC_MAX_TOKEN_TIMEOUT, 32425eee848SAlexander Motin bdrl_ptr->maximum_inactivity_timeout); 32525eee848SAlexander Motin scsi_ulto4b(TPC_DFL_TOKEN_TIMEOUT, 32625eee848SAlexander Motin bdrl_ptr->default_inactivity_timeout); 32725eee848SAlexander Motin scsi_u64to8b(0, bdrl_ptr->maximum_token_transfer_size); 32825eee848SAlexander Motin scsi_u64to8b(0, bdrl_ptr->optimal_transfer_count); 32925eee848SAlexander Motin 33025eee848SAlexander Motin /* Supported commands */ 33125eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 33225eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 333984a2ea9SAlexander Motin sc_ptr = (struct scsi_vpd_tpc_descriptor_sc *)d_ptr; 334984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SC, sc_ptr->desc_type); 33525eee848SAlexander Motin sc_ptr->list_length = 2 * sizeof(*scd_ptr) + 11; 336984a2ea9SAlexander Motin scsi_ulto2b(roundup2(1 + sc_ptr->list_length, 4), sc_ptr->desc_length); 337984a2ea9SAlexander Motin scd_ptr = &sc_ptr->descr[0]; 338984a2ea9SAlexander Motin scd_ptr->opcode = EXTENDED_COPY; 33925eee848SAlexander Motin scd_ptr->sa_length = 5; 340984a2ea9SAlexander Motin scd_ptr->supported_service_actions[0] = EC_EC_LID1; 341984a2ea9SAlexander Motin scd_ptr->supported_service_actions[1] = EC_EC_LID4; 34225eee848SAlexander Motin scd_ptr->supported_service_actions[2] = EC_PT; 34325eee848SAlexander Motin scd_ptr->supported_service_actions[3] = EC_WUT; 34425eee848SAlexander Motin scd_ptr->supported_service_actions[4] = EC_COA; 345984a2ea9SAlexander Motin scd_ptr = (struct scsi_vpd_tpc_descriptor_sc_descr *) 346984a2ea9SAlexander Motin &scd_ptr->supported_service_actions[scd_ptr->sa_length]; 347984a2ea9SAlexander Motin scd_ptr->opcode = RECEIVE_COPY_STATUS; 34825eee848SAlexander Motin scd_ptr->sa_length = 6; 349984a2ea9SAlexander Motin scd_ptr->supported_service_actions[0] = RCS_RCS_LID1; 350984a2ea9SAlexander Motin scd_ptr->supported_service_actions[1] = RCS_RCFD; 351984a2ea9SAlexander Motin scd_ptr->supported_service_actions[2] = RCS_RCS_LID4; 352984a2ea9SAlexander Motin scd_ptr->supported_service_actions[3] = RCS_RCOP; 35325eee848SAlexander Motin scd_ptr->supported_service_actions[4] = RCS_RRTI; 35425eee848SAlexander Motin scd_ptr->supported_service_actions[5] = RCS_RART; 355984a2ea9SAlexander Motin 356984a2ea9SAlexander Motin /* Parameter data. */ 357984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 358984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 359984a2ea9SAlexander Motin pd_ptr = (struct scsi_vpd_tpc_descriptor_pd *)d_ptr; 360984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_PD, pd_ptr->desc_type); 361984a2ea9SAlexander Motin scsi_ulto2b(sizeof(*pd_ptr) - 4, pd_ptr->desc_length); 362984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_CSCDS, pd_ptr->maximum_cscd_descriptor_count); 363984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, pd_ptr->maximum_segment_descriptor_count); 364984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LIST, pd_ptr->maximum_descriptor_list_length); 365984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_INLINE, pd_ptr->maximum_inline_data_length); 366984a2ea9SAlexander Motin 367984a2ea9SAlexander Motin /* Supported Descriptors */ 368984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 369984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 370984a2ea9SAlexander Motin sd_ptr = (struct scsi_vpd_tpc_descriptor_sd *)d_ptr; 371984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SD, sd_ptr->desc_type); 372984a2ea9SAlexander Motin scsi_ulto2b(roundup2(sizeof(*sd_ptr) - 4 + 4, 4), sd_ptr->desc_length); 373984a2ea9SAlexander Motin sd_ptr->list_length = 4; 374984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[0] = EC_SEG_B2B; 375984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[1] = EC_SEG_VERIFY; 376984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[2] = EC_SEG_REGISTER_KEY; 377984a2ea9SAlexander Motin sd_ptr->supported_descriptor_codes[3] = EC_CSCD_ID; 378984a2ea9SAlexander Motin 379984a2ea9SAlexander Motin /* Supported CSCD Descriptor IDs */ 380984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 381984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 382984a2ea9SAlexander Motin sdid_ptr = (struct scsi_vpd_tpc_descriptor_sdid *)d_ptr; 383984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_SDID, sdid_ptr->desc_type); 384984a2ea9SAlexander Motin scsi_ulto2b(roundup2(sizeof(*sdid_ptr) - 4 + 2, 4), sdid_ptr->desc_length); 385984a2ea9SAlexander Motin scsi_ulto2b(2, sdid_ptr->list_length); 386984a2ea9SAlexander Motin scsi_ulto2b(0xffff, &sdid_ptr->supported_descriptor_ids[0]); 387984a2ea9SAlexander Motin 38825eee848SAlexander Motin /* ROD Token Features */ 38925eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 39025eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 39125eee848SAlexander Motin rtf_ptr = (struct scsi_vpd_tpc_descriptor_rtf *)d_ptr; 39225eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_RTF, rtf_ptr->desc_type); 39325eee848SAlexander Motin scsi_ulto2b(sizeof(*rtf_ptr) - 4 + sizeof(*rtfb_ptr), rtf_ptr->desc_length); 39425eee848SAlexander Motin rtf_ptr->remote_tokens = 0; 39525eee848SAlexander Motin scsi_ulto4b(TPC_MIN_TOKEN_TIMEOUT, rtf_ptr->minimum_token_lifetime); 39625eee848SAlexander Motin scsi_ulto4b(UINT32_MAX, rtf_ptr->maximum_token_lifetime); 39725eee848SAlexander Motin scsi_ulto4b(TPC_MAX_TOKEN_TIMEOUT, 39825eee848SAlexander Motin rtf_ptr->maximum_token_inactivity_timeout); 39925eee848SAlexander Motin scsi_ulto2b(sizeof(*rtfb_ptr), rtf_ptr->type_specific_features_length); 40025eee848SAlexander Motin rtfb_ptr = (struct scsi_vpd_tpc_descriptor_rtf_block *) 40125eee848SAlexander Motin &rtf_ptr->type_specific_features; 40225eee848SAlexander Motin rtfb_ptr->type_format = SVPD_TPC_RTF_BLOCK; 40325eee848SAlexander Motin scsi_ulto2b(sizeof(*rtfb_ptr) - 4, rtfb_ptr->desc_length); 40425eee848SAlexander Motin scsi_ulto2b(0, rtfb_ptr->optimal_length_granularity); 40525eee848SAlexander Motin scsi_u64to8b(0, rtfb_ptr->maximum_bytes); 40625eee848SAlexander Motin scsi_u64to8b(0, rtfb_ptr->optimal_bytes); 407238b6b7cSAlexander Motin scsi_u64to8b(UINT64_MAX, rtfb_ptr->optimal_bytes_to_token_per_segment); 40825eee848SAlexander Motin scsi_u64to8b(TPC_MAX_IOCHUNK_SIZE, 40925eee848SAlexander Motin rtfb_ptr->optimal_bytes_from_token_per_segment); 41025eee848SAlexander Motin 41125eee848SAlexander Motin /* Supported ROD Tokens */ 41225eee848SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 41325eee848SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 41425eee848SAlexander Motin srt_ptr = (struct scsi_vpd_tpc_descriptor_srt *)d_ptr; 41525eee848SAlexander Motin scsi_ulto2b(SVPD_TPC_SRT, srt_ptr->desc_type); 41625eee848SAlexander Motin scsi_ulto2b(sizeof(*srt_ptr) - 4 + 2*sizeof(*srtd_ptr), srt_ptr->desc_length); 41725eee848SAlexander Motin scsi_ulto2b(2*sizeof(*srtd_ptr), srt_ptr->rod_type_descriptors_length); 41825eee848SAlexander Motin srtd_ptr = (struct scsi_vpd_tpc_descriptor_srtd *) 41925eee848SAlexander Motin &srt_ptr->rod_type_descriptors; 42025eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_AUR, srtd_ptr->rod_type); 42125eee848SAlexander Motin srtd_ptr->flags = SVPD_TPC_SRTD_TIN | SVPD_TPC_SRTD_TOUT; 42225eee848SAlexander Motin scsi_ulto2b(0, srtd_ptr->preference_indicator); 42325eee848SAlexander Motin srtd_ptr++; 42425eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_BLOCK_ZERO, srtd_ptr->rod_type); 42525eee848SAlexander Motin srtd_ptr->flags = SVPD_TPC_SRTD_TIN; 42625eee848SAlexander Motin scsi_ulto2b(0, srtd_ptr->preference_indicator); 42725eee848SAlexander Motin 428984a2ea9SAlexander Motin /* General Copy Operations */ 429984a2ea9SAlexander Motin d_ptr = (struct scsi_vpd_tpc_descriptor *) 430984a2ea9SAlexander Motin (&d_ptr->parameters[0] + scsi_2btoul(d_ptr->desc_length)); 431984a2ea9SAlexander Motin gco_ptr = (struct scsi_vpd_tpc_descriptor_gco *)d_ptr; 432984a2ea9SAlexander Motin scsi_ulto2b(SVPD_TPC_GCO, gco_ptr->desc_type); 433984a2ea9SAlexander Motin scsi_ulto2b(sizeof(*gco_ptr) - 4, gco_ptr->desc_length); 434984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->total_concurrent_copies); 435984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LISTS, gco_ptr->maximum_identified_concurrent_copies); 436984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_SEG, gco_ptr->maximum_segment_length); 437984a2ea9SAlexander Motin gco_ptr->data_segment_granularity = 0; 438984a2ea9SAlexander Motin gco_ptr->inline_data_granularity = 0; 439984a2ea9SAlexander Motin 440f7241cceSAlexander Motin ctl_set_success(ctsio); 441984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 442984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 443984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 444984a2ea9SAlexander Motin 445984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 446984a2ea9SAlexander Motin } 447984a2ea9SAlexander Motin 448984a2ea9SAlexander Motin int 449984a2ea9SAlexander Motin ctl_receive_copy_operating_parameters(struct ctl_scsiio *ctsio) 450984a2ea9SAlexander Motin { 451984a2ea9SAlexander Motin struct scsi_receive_copy_operating_parameters *cdb; 452984a2ea9SAlexander Motin struct scsi_receive_copy_operating_parameters_data *data; 453984a2ea9SAlexander Motin int retval; 454984a2ea9SAlexander Motin int alloc_len, total_len; 455984a2ea9SAlexander Motin 456984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_report_supported_tmf\n")); 457984a2ea9SAlexander Motin 458984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_operating_parameters *)ctsio->cdb; 459984a2ea9SAlexander Motin 460984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 461984a2ea9SAlexander Motin 462984a2ea9SAlexander Motin total_len = sizeof(*data) + 4; 463984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 464984a2ea9SAlexander Motin 465984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 466984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 467984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 468640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 469640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 470984a2ea9SAlexander Motin 471984a2ea9SAlexander Motin data = (struct scsi_receive_copy_operating_parameters_data *)ctsio->kern_data_ptr; 472984a2ea9SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + 4, data->length); 473984a2ea9SAlexander Motin data->snlid = RCOP_SNLID; 474984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_CSCDS, data->maximum_cscd_descriptor_count); 475984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_SEGS, data->maximum_segment_descriptor_count); 476984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_LIST, data->maximum_descriptor_list_length); 477984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_SEG, data->maximum_segment_length); 478984a2ea9SAlexander Motin scsi_ulto4b(TPC_MAX_INLINE, data->maximum_inline_data_length); 479984a2ea9SAlexander Motin scsi_ulto4b(0, data->held_data_limit); 480984a2ea9SAlexander Motin scsi_ulto4b(0, data->maximum_stream_device_transfer_size); 481984a2ea9SAlexander Motin scsi_ulto2b(TPC_MAX_LISTS, data->total_concurrent_copies); 482984a2ea9SAlexander Motin data->maximum_concurrent_copies = TPC_MAX_LISTS; 483984a2ea9SAlexander Motin data->data_segment_granularity = 0; 484984a2ea9SAlexander Motin data->inline_data_granularity = 0; 485984a2ea9SAlexander Motin data->held_data_granularity = 0; 486984a2ea9SAlexander Motin data->implemented_descriptor_list_length = 4; 487984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[0] = EC_SEG_B2B; 488984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[1] = EC_SEG_VERIFY; 489984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[2] = EC_SEG_REGISTER_KEY; 490984a2ea9SAlexander Motin data->list_of_implemented_descriptor_type_codes[3] = EC_CSCD_ID; 491984a2ea9SAlexander Motin 492f7241cceSAlexander Motin ctl_set_success(ctsio); 493984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 494984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 495984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 496984a2ea9SAlexander Motin return (retval); 497984a2ea9SAlexander Motin } 498984a2ea9SAlexander Motin 49943d2d719SAlexander Motin static struct tpc_list * 50043d2d719SAlexander Motin tpc_find_list(struct ctl_lun *lun, uint32_t list_id, uint32_t init_idx) 50143d2d719SAlexander Motin { 50243d2d719SAlexander Motin struct tpc_list *list; 50343d2d719SAlexander Motin 50443d2d719SAlexander Motin mtx_assert(&lun->lun_lock, MA_OWNED); 50543d2d719SAlexander Motin TAILQ_FOREACH(list, &lun->tpc_lists, links) { 50643d2d719SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != 50743d2d719SAlexander Motin EC_LIST_ID_USAGE_NONE && list->list_id == list_id && 50843d2d719SAlexander Motin list->init_idx == init_idx) 50943d2d719SAlexander Motin break; 51043d2d719SAlexander Motin } 51143d2d719SAlexander Motin return (list); 51243d2d719SAlexander Motin } 51343d2d719SAlexander Motin 514984a2ea9SAlexander Motin int 515984a2ea9SAlexander Motin ctl_receive_copy_status_lid1(struct ctl_scsiio *ctsio) 516984a2ea9SAlexander Motin { 5179cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 518984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid1 *cdb; 519984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid1_data *data; 520984a2ea9SAlexander Motin struct tpc_list *list; 521984a2ea9SAlexander Motin struct tpc_list list_copy; 522984a2ea9SAlexander Motin int retval; 523984a2ea9SAlexander Motin int alloc_len, total_len; 524984a2ea9SAlexander Motin uint32_t list_id; 525984a2ea9SAlexander Motin 526984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid1\n")); 527984a2ea9SAlexander Motin 528984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_status_lid1 *)ctsio->cdb; 529984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 530984a2ea9SAlexander Motin 531984a2ea9SAlexander Motin list_id = cdb->list_identifier; 532984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 53343d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 5347ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 535984a2ea9SAlexander Motin if (list == NULL) { 536984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 537984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 538984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 539984a2ea9SAlexander Motin /*bit*/ 0); 540984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 541984a2ea9SAlexander Motin return (retval); 542984a2ea9SAlexander Motin } 543984a2ea9SAlexander Motin list_copy = *list; 544984a2ea9SAlexander Motin if (list->completed) { 545984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 546984a2ea9SAlexander Motin free(list, M_CTL); 547984a2ea9SAlexander Motin } 548984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 549984a2ea9SAlexander Motin 550984a2ea9SAlexander Motin total_len = sizeof(*data); 551984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 552984a2ea9SAlexander Motin 553984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 554984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 555984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 556640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 557640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 558984a2ea9SAlexander Motin 559984a2ea9SAlexander Motin data = (struct scsi_receive_copy_status_lid1_data *)ctsio->kern_data_ptr; 560984a2ea9SAlexander Motin scsi_ulto4b(sizeof(*data) - 4, data->available_data); 561984a2ea9SAlexander Motin if (list_copy.completed) { 562984a2ea9SAlexander Motin if (list_copy.error || list_copy.abort) 563984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 564984a2ea9SAlexander Motin else 565984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 566984a2ea9SAlexander Motin } else 567984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_INPROG; 568984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 569984a2ea9SAlexander Motin if (list_copy.curbytes <= UINT32_MAX) { 570984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_BYTES; 571984a2ea9SAlexander Motin scsi_ulto4b(list_copy.curbytes, data->transfer_count); 572984a2ea9SAlexander Motin } else { 573984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_MBYTES; 574984a2ea9SAlexander Motin scsi_ulto4b(list_copy.curbytes >> 20, data->transfer_count); 575984a2ea9SAlexander Motin } 576984a2ea9SAlexander Motin 577f7241cceSAlexander Motin ctl_set_success(ctsio); 578984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 579984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 580984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 581984a2ea9SAlexander Motin return (retval); 582984a2ea9SAlexander Motin } 583984a2ea9SAlexander Motin 584984a2ea9SAlexander Motin int 585984a2ea9SAlexander Motin ctl_receive_copy_failure_details(struct ctl_scsiio *ctsio) 586984a2ea9SAlexander Motin { 5879cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 588984a2ea9SAlexander Motin struct scsi_receive_copy_failure_details *cdb; 589984a2ea9SAlexander Motin struct scsi_receive_copy_failure_details_data *data; 590984a2ea9SAlexander Motin struct tpc_list *list; 591984a2ea9SAlexander Motin struct tpc_list list_copy; 592984a2ea9SAlexander Motin int retval; 593984a2ea9SAlexander Motin int alloc_len, total_len; 594984a2ea9SAlexander Motin uint32_t list_id; 595984a2ea9SAlexander Motin 596984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_failure_details\n")); 597984a2ea9SAlexander Motin 598984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_failure_details *)ctsio->cdb; 599984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 600984a2ea9SAlexander Motin 601984a2ea9SAlexander Motin list_id = cdb->list_identifier; 602984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 60343d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 6047ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 60543d2d719SAlexander Motin if (list == NULL || !list->completed) { 606984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 607984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 608984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 609984a2ea9SAlexander Motin /*bit*/ 0); 610984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 611984a2ea9SAlexander Motin return (retval); 612984a2ea9SAlexander Motin } 613984a2ea9SAlexander Motin list_copy = *list; 614984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 615984a2ea9SAlexander Motin free(list, M_CTL); 616984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 617984a2ea9SAlexander Motin 618984a2ea9SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len; 619984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 620984a2ea9SAlexander Motin 621984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 622984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 623984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 624640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 625640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 626984a2ea9SAlexander Motin 627984a2ea9SAlexander Motin data = (struct scsi_receive_copy_failure_details_data *)ctsio->kern_data_ptr; 628984a2ea9SAlexander Motin if (list_copy.completed && (list_copy.error || list_copy.abort)) { 629a7c09f5cSAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len, 630a7c09f5cSAlexander Motin data->available_data); 631984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 632984a2ea9SAlexander Motin } else 633984a2ea9SAlexander Motin scsi_ulto4b(0, data->available_data); 634984a2ea9SAlexander Motin scsi_ulto2b(list_copy.sense_len, data->sense_data_length); 635984a2ea9SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 636984a2ea9SAlexander Motin 637f7241cceSAlexander Motin ctl_set_success(ctsio); 638984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 639984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 640984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 641984a2ea9SAlexander Motin return (retval); 642984a2ea9SAlexander Motin } 643984a2ea9SAlexander Motin 644984a2ea9SAlexander Motin int 645984a2ea9SAlexander Motin ctl_receive_copy_status_lid4(struct ctl_scsiio *ctsio) 646984a2ea9SAlexander Motin { 6479cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 648984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid4 *cdb; 649984a2ea9SAlexander Motin struct scsi_receive_copy_status_lid4_data *data; 650984a2ea9SAlexander Motin struct tpc_list *list; 651984a2ea9SAlexander Motin struct tpc_list list_copy; 652984a2ea9SAlexander Motin int retval; 653984a2ea9SAlexander Motin int alloc_len, total_len; 654984a2ea9SAlexander Motin uint32_t list_id; 655984a2ea9SAlexander Motin 656984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_copy_status_lid4\n")); 657984a2ea9SAlexander Motin 658984a2ea9SAlexander Motin cdb = (struct scsi_receive_copy_status_lid4 *)ctsio->cdb; 659984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 660984a2ea9SAlexander Motin 661984a2ea9SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 662984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 66343d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 6647ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 665984a2ea9SAlexander Motin if (list == NULL) { 666984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 667984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 668984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 669984a2ea9SAlexander Motin /*bit*/ 0); 670984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 671984a2ea9SAlexander Motin return (retval); 672984a2ea9SAlexander Motin } 673984a2ea9SAlexander Motin list_copy = *list; 674984a2ea9SAlexander Motin if (list->completed) { 675984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 676984a2ea9SAlexander Motin free(list, M_CTL); 677984a2ea9SAlexander Motin } 678984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 679984a2ea9SAlexander Motin 680984a2ea9SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len; 681984a2ea9SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 682984a2ea9SAlexander Motin 683984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 684984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 685984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 686640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 687640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 688984a2ea9SAlexander Motin 689984a2ea9SAlexander Motin data = (struct scsi_receive_copy_status_lid4_data *)ctsio->kern_data_ptr; 690a7c09f5cSAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len, 691a7c09f5cSAlexander Motin data->available_data); 692984a2ea9SAlexander Motin data->response_to_service_action = list_copy.service_action; 693984a2ea9SAlexander Motin if (list_copy.completed) { 694984a2ea9SAlexander Motin if (list_copy.error) 695984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 696984a2ea9SAlexander Motin else if (list_copy.abort) 697984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_ABORTED; 698984a2ea9SAlexander Motin else 699984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 700984a2ea9SAlexander Motin } else 701984a2ea9SAlexander Motin data->copy_command_status = RCS_CCS_INPROG_FG; 702984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curops, data->operation_counter); 703984a2ea9SAlexander Motin scsi_ulto4b(UINT32_MAX, data->estimated_status_update_delay); 704984a2ea9SAlexander Motin data->transfer_count_units = RCS_TC_BYTES; 705a7c09f5cSAlexander Motin scsi_u64to8b(list_copy.curbytes, data->transfer_count); 706984a2ea9SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 707a7c09f5cSAlexander Motin data->length_of_the_sense_data_field = list_copy.sense_len; 708984a2ea9SAlexander Motin data->sense_data_length = list_copy.sense_len; 709984a2ea9SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 710984a2ea9SAlexander Motin 711f7241cceSAlexander Motin ctl_set_success(ctsio); 712984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 713984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 714984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 715984a2ea9SAlexander Motin return (retval); 716984a2ea9SAlexander Motin } 717984a2ea9SAlexander Motin 718984a2ea9SAlexander Motin int 719984a2ea9SAlexander Motin ctl_copy_operation_abort(struct ctl_scsiio *ctsio) 720984a2ea9SAlexander Motin { 7219cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 722984a2ea9SAlexander Motin struct scsi_copy_operation_abort *cdb; 723984a2ea9SAlexander Motin struct tpc_list *list; 724984a2ea9SAlexander Motin int retval; 725984a2ea9SAlexander Motin uint32_t list_id; 726984a2ea9SAlexander Motin 727984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_copy_operation_abort\n")); 728984a2ea9SAlexander Motin 729984a2ea9SAlexander Motin cdb = (struct scsi_copy_operation_abort *)ctsio->cdb; 730984a2ea9SAlexander Motin retval = CTL_RETVAL_COMPLETE; 731984a2ea9SAlexander Motin 732984a2ea9SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 733984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 73443d2d719SAlexander Motin list = tpc_find_list(lun, list_id, 7357ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 736984a2ea9SAlexander Motin if (list == NULL) { 737984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 738984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 739984a2ea9SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 740984a2ea9SAlexander Motin /*bit*/ 0); 741984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 742984a2ea9SAlexander Motin return (retval); 743984a2ea9SAlexander Motin } 744984a2ea9SAlexander Motin list->abort = 1; 745984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 746984a2ea9SAlexander Motin 747984a2ea9SAlexander Motin ctl_set_success(ctsio); 748984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 749984a2ea9SAlexander Motin return (retval); 750984a2ea9SAlexander Motin } 751984a2ea9SAlexander Motin 752984a2ea9SAlexander Motin static uint64_t 753fee04ef7SAlexander Motin tpc_resolve(struct tpc_list *list, uint16_t idx, uint32_t *ss, 754fee04ef7SAlexander Motin uint32_t *pb, uint32_t *pbo) 755984a2ea9SAlexander Motin { 756984a2ea9SAlexander Motin 757984a2ea9SAlexander Motin if (idx == 0xffff) { 758984a2ea9SAlexander Motin if (ss && list->lun->be_lun) 759984a2ea9SAlexander Motin *ss = list->lun->be_lun->blocksize; 760fee04ef7SAlexander Motin if (pb && list->lun->be_lun) 761fee04ef7SAlexander Motin *pb = list->lun->be_lun->blocksize << 762fee04ef7SAlexander Motin list->lun->be_lun->pblockexp; 763fee04ef7SAlexander Motin if (pbo && list->lun->be_lun) 764fee04ef7SAlexander Motin *pbo = list->lun->be_lun->blocksize * 765fee04ef7SAlexander Motin list->lun->be_lun->pblockoff; 766984a2ea9SAlexander Motin return (list->lun->lun); 767984a2ea9SAlexander Motin } 768984a2ea9SAlexander Motin if (idx >= list->ncscd) 769984a2ea9SAlexander Motin return (UINT64_MAX); 7709602f436SAlexander Motin return (tpcl_resolve(list->lun->ctl_softc, 771fee04ef7SAlexander Motin list->init_port, &list->cscd[idx], ss, pb, pbo)); 772984a2ea9SAlexander Motin } 773984a2ea9SAlexander Motin 774a3dd8378SAlexander Motin static void 775a3dd8378SAlexander Motin tpc_set_io_error_sense(struct tpc_list *list) 776a3dd8378SAlexander Motin { 777a3dd8378SAlexander Motin int flen; 778a3dd8378SAlexander Motin uint8_t csi[4]; 779a3dd8378SAlexander Motin uint8_t sks[3]; 780a3dd8378SAlexander Motin uint8_t fbuf[4 + 64]; 781a3dd8378SAlexander Motin 782a3dd8378SAlexander Motin scsi_ulto4b(list->curseg, csi); 783a3dd8378SAlexander Motin if (list->fwd_cscd <= 0x07ff) { 784a3dd8378SAlexander Motin sks[0] = SSD_SKS_SEGMENT_VALID; 785a3dd8378SAlexander Motin scsi_ulto2b((uint8_t *)&list->cscd[list->fwd_cscd] - 786a3dd8378SAlexander Motin list->params, &sks[1]); 787a3dd8378SAlexander Motin } else 788a3dd8378SAlexander Motin sks[0] = 0; 789a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 790a3dd8378SAlexander Motin fbuf[0] = 0x0c; 791a3dd8378SAlexander Motin fbuf[2] = list->fwd_target; 792a3dd8378SAlexander Motin flen = list->fwd_sense_len; 793a3dd8378SAlexander Motin if (flen > 64) { 794a3dd8378SAlexander Motin flen = 64; 795a3dd8378SAlexander Motin fbuf[2] |= SSD_FORWARDED_FSDT; 796a3dd8378SAlexander Motin } 797a3dd8378SAlexander Motin fbuf[1] = 2 + flen; 798a3dd8378SAlexander Motin fbuf[3] = list->fwd_scsi_status; 799a3dd8378SAlexander Motin bcopy(&list->fwd_sense_data, &fbuf[4], flen); 800a3dd8378SAlexander Motin flen += 4; 801a3dd8378SAlexander Motin } else 802a3dd8378SAlexander Motin flen = 0; 803a3dd8378SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 804a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 805a3dd8378SAlexander Motin /*asc*/ 0x0d, /*ascq*/ 0x01, 806a3dd8378SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 807a3dd8378SAlexander Motin sks[0] ? SSD_ELEM_SKS : SSD_ELEM_SKIP, sizeof(sks), sks, 808a3dd8378SAlexander Motin flen ? SSD_ELEM_DESC : SSD_ELEM_SKIP, flen, fbuf, 809a3dd8378SAlexander Motin SSD_ELEM_NONE); 810a3dd8378SAlexander Motin } 811a3dd8378SAlexander Motin 812984a2ea9SAlexander Motin static int 813984a2ea9SAlexander Motin tpc_process_b2b(struct tpc_list *list) 814984a2ea9SAlexander Motin { 815984a2ea9SAlexander Motin struct scsi_ec_segment_b2b *seg; 816984a2ea9SAlexander Motin struct scsi_ec_cscd_dtsp *sdstp, *ddstp; 817984a2ea9SAlexander Motin struct tpc_io *tior, *tiow; 81873942c5cSAlexander Motin struct runl run; 819984a2ea9SAlexander Motin uint64_t sl, dl; 820984a2ea9SAlexander Motin off_t srclba, dstlba, numbytes, donebytes, roundbytes; 821984a2ea9SAlexander Motin int numlba; 822fee04ef7SAlexander Motin uint32_t srcblock, dstblock, pb, pbo, adj; 823a3dd8378SAlexander Motin uint16_t scscd, dcscd; 824042e9bdcSAlexander Motin uint8_t csi[4]; 825984a2ea9SAlexander Motin 826042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 827984a2ea9SAlexander Motin if (list->stage == 1) { 828984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&list->allio)) != NULL) { 829984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tior, links); 830984a2ea9SAlexander Motin ctl_free_io(tior->io); 83146511441SAlexander Motin free(tior->buf, M_CTL); 832984a2ea9SAlexander Motin free(tior, M_CTL); 833984a2ea9SAlexander Motin } 834984a2ea9SAlexander Motin if (list->abort) { 835984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 836984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 837984a2ea9SAlexander Motin } else if (list->error) { 838a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 839984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 840e3e592bbSAlexander Motin } 84125eee848SAlexander Motin list->cursectors += list->segsectors; 842984a2ea9SAlexander Motin list->curbytes += list->segbytes; 843984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 844984a2ea9SAlexander Motin } 845984a2ea9SAlexander Motin 846984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 847984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_b2b *)list->seg[list->curseg]; 848a3dd8378SAlexander Motin scscd = scsi_2btoul(seg->src_cscd); 849a3dd8378SAlexander Motin dcscd = scsi_2btoul(seg->dst_cscd); 850a3dd8378SAlexander Motin sl = tpc_resolve(list, scscd, &srcblock, NULL, NULL); 851a3dd8378SAlexander Motin dl = tpc_resolve(list, dcscd, &dstblock, &pb, &pbo); 85241243159SAlexander Motin if (sl == UINT64_MAX || dl == UINT64_MAX) { 853984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 854984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 855042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 856862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 857042e9bdcSAlexander Motin SSD_ELEM_NONE); 858984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 859984a2ea9SAlexander Motin } 860fee04ef7SAlexander Motin if (pbo > 0) 861fee04ef7SAlexander Motin pbo = pb - pbo; 862a3dd8378SAlexander Motin sdstp = &list->cscd[scscd].dtsp; 863984a2ea9SAlexander Motin if (scsi_3btoul(sdstp->block_length) != 0) 864984a2ea9SAlexander Motin srcblock = scsi_3btoul(sdstp->block_length); 865a3dd8378SAlexander Motin ddstp = &list->cscd[dcscd].dtsp; 866984a2ea9SAlexander Motin if (scsi_3btoul(ddstp->block_length) != 0) 867984a2ea9SAlexander Motin dstblock = scsi_3btoul(ddstp->block_length); 868984a2ea9SAlexander Motin numlba = scsi_2btoul(seg->number_of_blocks); 869984a2ea9SAlexander Motin if (seg->flags & EC_SEG_DC) 870984a2ea9SAlexander Motin numbytes = (off_t)numlba * dstblock; 871984a2ea9SAlexander Motin else 872984a2ea9SAlexander Motin numbytes = (off_t)numlba * srcblock; 873984a2ea9SAlexander Motin srclba = scsi_8btou64(seg->src_lba); 874984a2ea9SAlexander Motin dstlba = scsi_8btou64(seg->dst_lba); 875984a2ea9SAlexander Motin 876984a2ea9SAlexander Motin // printf("Copy %ju bytes from %ju @ %ju to %ju @ %ju\n", 877984a2ea9SAlexander Motin // (uintmax_t)numbytes, sl, scsi_8btou64(seg->src_lba), 878984a2ea9SAlexander Motin // dl, scsi_8btou64(seg->dst_lba)); 879984a2ea9SAlexander Motin 880984a2ea9SAlexander Motin if (numbytes == 0) 881984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 882984a2ea9SAlexander Motin 883984a2ea9SAlexander Motin if (numbytes % srcblock != 0 || numbytes % dstblock != 0) { 884984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 885984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 886042e9bdcSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x0A, 887862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 888042e9bdcSAlexander Motin SSD_ELEM_NONE); 889984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 890984a2ea9SAlexander Motin } 891984a2ea9SAlexander Motin 892984a2ea9SAlexander Motin list->segbytes = numbytes; 89325eee848SAlexander Motin list->segsectors = numbytes / dstblock; 894984a2ea9SAlexander Motin donebytes = 0; 895984a2ea9SAlexander Motin TAILQ_INIT(&run); 89673942c5cSAlexander Motin list->tbdio = 0; 897984a2ea9SAlexander Motin while (donebytes < numbytes) { 898fee04ef7SAlexander Motin roundbytes = numbytes - donebytes; 899fee04ef7SAlexander Motin if (roundbytes > TPC_MAX_IO_SIZE) { 900fee04ef7SAlexander Motin roundbytes = TPC_MAX_IO_SIZE; 901fee04ef7SAlexander Motin roundbytes -= roundbytes % dstblock; 902fee04ef7SAlexander Motin if (pb > dstblock) { 903fee04ef7SAlexander Motin adj = (dstlba * dstblock + roundbytes - pbo) % pb; 904fee04ef7SAlexander Motin if (roundbytes > adj) 905fee04ef7SAlexander Motin roundbytes -= adj; 906fee04ef7SAlexander Motin } 907fee04ef7SAlexander Motin } 908984a2ea9SAlexander Motin 909984a2ea9SAlexander Motin tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 910984a2ea9SAlexander Motin TAILQ_INIT(&tior->run); 91146511441SAlexander Motin tior->buf = malloc(roundbytes, M_CTL, M_WAITOK); 912984a2ea9SAlexander Motin tior->list = list; 913984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tior, links); 914984a2ea9SAlexander Motin tior->io = tpcl_alloc_io(); 915984a2ea9SAlexander Motin ctl_scsi_read_write(tior->io, 91646511441SAlexander Motin /*data_ptr*/ tior->buf, 917984a2ea9SAlexander Motin /*data_len*/ roundbytes, 918984a2ea9SAlexander Motin /*read_op*/ 1, 919984a2ea9SAlexander Motin /*byte2*/ 0, 920984a2ea9SAlexander Motin /*minimum_cdb_size*/ 0, 921fee04ef7SAlexander Motin /*lba*/ srclba, 922984a2ea9SAlexander Motin /*num_blocks*/ roundbytes / srcblock, 923984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 924984a2ea9SAlexander Motin /*control*/ 0); 925984a2ea9SAlexander Motin tior->io->io_hdr.retries = 3; 926a3dd8378SAlexander Motin tior->target = SSD_FORWARDED_SDS_EXSRC; 927a3dd8378SAlexander Motin tior->cscd = scscd; 928984a2ea9SAlexander Motin tior->lun = sl; 929984a2ea9SAlexander Motin tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior; 930984a2ea9SAlexander Motin 931984a2ea9SAlexander Motin tiow = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 932984a2ea9SAlexander Motin TAILQ_INIT(&tiow->run); 933984a2ea9SAlexander Motin tiow->list = list; 934984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 935984a2ea9SAlexander Motin tiow->io = tpcl_alloc_io(); 936984a2ea9SAlexander Motin ctl_scsi_read_write(tiow->io, 93746511441SAlexander Motin /*data_ptr*/ tior->buf, 938984a2ea9SAlexander Motin /*data_len*/ roundbytes, 939984a2ea9SAlexander Motin /*read_op*/ 0, 940984a2ea9SAlexander Motin /*byte2*/ 0, 941984a2ea9SAlexander Motin /*minimum_cdb_size*/ 0, 942fee04ef7SAlexander Motin /*lba*/ dstlba, 943984a2ea9SAlexander Motin /*num_blocks*/ roundbytes / dstblock, 944984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 945984a2ea9SAlexander Motin /*control*/ 0); 946984a2ea9SAlexander Motin tiow->io->io_hdr.retries = 3; 947a3dd8378SAlexander Motin tiow->target = SSD_FORWARDED_SDS_EXDST; 948a3dd8378SAlexander Motin tiow->cscd = dcscd; 949984a2ea9SAlexander Motin tiow->lun = dl; 950117f1bc1SAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 951984a2ea9SAlexander Motin 952984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks); 95373942c5cSAlexander Motin TAILQ_INSERT_TAIL(&run, tior, rlinks); 95473942c5cSAlexander Motin list->tbdio++; 955984a2ea9SAlexander Motin donebytes += roundbytes; 956fee04ef7SAlexander Motin srclba += roundbytes / srcblock; 957fee04ef7SAlexander Motin dstlba += roundbytes / dstblock; 958984a2ea9SAlexander Motin } 959984a2ea9SAlexander Motin 960984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&run)) != NULL) { 961984a2ea9SAlexander Motin TAILQ_REMOVE(&run, tior, rlinks); 962984a2ea9SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 963984a2ea9SAlexander Motin panic("tpcl_queue() error"); 964984a2ea9SAlexander Motin } 965984a2ea9SAlexander Motin 966984a2ea9SAlexander Motin list->stage++; 967984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 968984a2ea9SAlexander Motin } 969984a2ea9SAlexander Motin 970984a2ea9SAlexander Motin static int 971984a2ea9SAlexander Motin tpc_process_verify(struct tpc_list *list) 972984a2ea9SAlexander Motin { 973984a2ea9SAlexander Motin struct scsi_ec_segment_verify *seg; 974984a2ea9SAlexander Motin struct tpc_io *tio; 975984a2ea9SAlexander Motin uint64_t sl; 976a3dd8378SAlexander Motin uint16_t cscd; 977042e9bdcSAlexander Motin uint8_t csi[4]; 978984a2ea9SAlexander Motin 979042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 980984a2ea9SAlexander Motin if (list->stage == 1) { 981984a2ea9SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 982984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 983984a2ea9SAlexander Motin ctl_free_io(tio->io); 984984a2ea9SAlexander Motin free(tio, M_CTL); 985984a2ea9SAlexander Motin } 986984a2ea9SAlexander Motin if (list->abort) { 987984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 988984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 989984a2ea9SAlexander Motin } else if (list->error) { 990a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 991984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 992984a2ea9SAlexander Motin } else 993984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 994984a2ea9SAlexander Motin } 995984a2ea9SAlexander Motin 996984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 997984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_verify *)list->seg[list->curseg]; 998a3dd8378SAlexander Motin cscd = scsi_2btoul(seg->src_cscd); 999a3dd8378SAlexander Motin sl = tpc_resolve(list, cscd, NULL, NULL, NULL); 100041243159SAlexander Motin if (sl == UINT64_MAX) { 1001984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 1002984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1003042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 1004862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1005042e9bdcSAlexander Motin SSD_ELEM_NONE); 1006984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1007984a2ea9SAlexander Motin } 1008984a2ea9SAlexander Motin 1009984a2ea9SAlexander Motin // printf("Verify %ju\n", sl); 1010984a2ea9SAlexander Motin 1011984a2ea9SAlexander Motin if ((seg->tur & 0x01) == 0) 1012984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1013984a2ea9SAlexander Motin 1014984a2ea9SAlexander Motin list->tbdio = 1; 1015984a2ea9SAlexander Motin tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO); 1016984a2ea9SAlexander Motin TAILQ_INIT(&tio->run); 1017984a2ea9SAlexander Motin tio->list = list; 1018984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tio, links); 1019984a2ea9SAlexander Motin tio->io = tpcl_alloc_io(); 1020984a2ea9SAlexander Motin ctl_scsi_tur(tio->io, /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); 1021984a2ea9SAlexander Motin tio->io->io_hdr.retries = 3; 1022a3dd8378SAlexander Motin tio->target = SSD_FORWARDED_SDS_EXSRC; 1023a3dd8378SAlexander Motin tio->cscd = cscd; 1024984a2ea9SAlexander Motin tio->lun = sl; 1025984a2ea9SAlexander Motin tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio; 1026984a2ea9SAlexander Motin list->stage++; 1027984a2ea9SAlexander Motin if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE) 1028984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1029984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 1030984a2ea9SAlexander Motin } 1031984a2ea9SAlexander Motin 1032984a2ea9SAlexander Motin static int 1033984a2ea9SAlexander Motin tpc_process_register_key(struct tpc_list *list) 1034984a2ea9SAlexander Motin { 1035984a2ea9SAlexander Motin struct scsi_ec_segment_register_key *seg; 1036984a2ea9SAlexander Motin struct tpc_io *tio; 1037984a2ea9SAlexander Motin uint64_t dl; 1038984a2ea9SAlexander Motin int datalen; 1039a3dd8378SAlexander Motin uint16_t cscd; 1040042e9bdcSAlexander Motin uint8_t csi[4]; 1041984a2ea9SAlexander Motin 1042042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 1043984a2ea9SAlexander Motin if (list->stage == 1) { 1044984a2ea9SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 1045984a2ea9SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 1046984a2ea9SAlexander Motin ctl_free_io(tio->io); 104746511441SAlexander Motin free(tio->buf, M_CTL); 1048984a2ea9SAlexander Motin free(tio, M_CTL); 1049984a2ea9SAlexander Motin } 1050984a2ea9SAlexander Motin if (list->abort) { 1051984a2ea9SAlexander Motin ctl_set_task_aborted(list->ctsio); 1052984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1053984a2ea9SAlexander Motin } else if (list->error) { 1054a3dd8378SAlexander Motin tpc_set_io_error_sense(list); 1055984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1056984a2ea9SAlexander Motin } else 1057984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1058984a2ea9SAlexander Motin } 1059984a2ea9SAlexander Motin 1060984a2ea9SAlexander Motin TAILQ_INIT(&list->allio); 1061984a2ea9SAlexander Motin seg = (struct scsi_ec_segment_register_key *)list->seg[list->curseg]; 1062a3dd8378SAlexander Motin cscd = scsi_2btoul(seg->dst_cscd); 1063a3dd8378SAlexander Motin dl = tpc_resolve(list, cscd, NULL, NULL, NULL); 106441243159SAlexander Motin if (dl == UINT64_MAX) { 1065984a2ea9SAlexander Motin ctl_set_sense(list->ctsio, /*current_error*/ 1, 1066984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1067042e9bdcSAlexander Motin /*asc*/ 0x08, /*ascq*/ 0x04, 1068862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1069042e9bdcSAlexander Motin SSD_ELEM_NONE); 1070984a2ea9SAlexander Motin return (CTL_RETVAL_ERROR); 1071984a2ea9SAlexander Motin } 1072984a2ea9SAlexander Motin 1073984a2ea9SAlexander Motin // printf("Register Key %ju\n", dl); 1074984a2ea9SAlexander Motin 1075984a2ea9SAlexander Motin list->tbdio = 1; 1076984a2ea9SAlexander Motin tio = malloc(sizeof(*tio), M_CTL, M_WAITOK | M_ZERO); 1077984a2ea9SAlexander Motin TAILQ_INIT(&tio->run); 1078984a2ea9SAlexander Motin tio->list = list; 1079984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tio, links); 1080984a2ea9SAlexander Motin tio->io = tpcl_alloc_io(); 1081984a2ea9SAlexander Motin datalen = sizeof(struct scsi_per_res_out_parms); 108246511441SAlexander Motin tio->buf = malloc(datalen, M_CTL, M_WAITOK); 1083984a2ea9SAlexander Motin ctl_scsi_persistent_res_out(tio->io, 108446511441SAlexander Motin tio->buf, datalen, SPRO_REGISTER, -1, 1085984a2ea9SAlexander Motin scsi_8btou64(seg->res_key), scsi_8btou64(seg->sa_res_key), 1086984a2ea9SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, /*control*/ 0); 1087984a2ea9SAlexander Motin tio->io->io_hdr.retries = 3; 1088a3dd8378SAlexander Motin tio->target = SSD_FORWARDED_SDS_EXDST; 1089a3dd8378SAlexander Motin tio->cscd = cscd; 1090984a2ea9SAlexander Motin tio->lun = dl; 1091984a2ea9SAlexander Motin tio->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tio; 1092984a2ea9SAlexander Motin list->stage++; 1093984a2ea9SAlexander Motin if (tpcl_queue(tio->io, tio->lun) != CTL_RETVAL_COMPLETE) 1094984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1095984a2ea9SAlexander Motin return (CTL_RETVAL_QUEUED); 1096984a2ea9SAlexander Motin } 1097984a2ea9SAlexander Motin 109825eee848SAlexander Motin static off_t 109925eee848SAlexander Motin tpc_ranges_length(struct scsi_range_desc *range, int nrange) 110025eee848SAlexander Motin { 110125eee848SAlexander Motin off_t length = 0; 110225eee848SAlexander Motin int r; 110325eee848SAlexander Motin 110425eee848SAlexander Motin for (r = 0; r < nrange; r++) 110525eee848SAlexander Motin length += scsi_4btoul(range[r].length); 110625eee848SAlexander Motin return (length); 110725eee848SAlexander Motin } 110825eee848SAlexander Motin 110925eee848SAlexander Motin static int 111032920cbfSAlexander Motin tpc_check_ranges_l(struct scsi_range_desc *range, int nrange, uint64_t maxlba, 111132920cbfSAlexander Motin uint64_t *lba) 1112e13f4248SAlexander Motin { 11138fadf660SAlexander Motin uint64_t b1; 11148fadf660SAlexander Motin uint32_t l1; 11158fadf660SAlexander Motin int i; 1116e13f4248SAlexander Motin 111738618bf4SAlexander Motin for (i = 0; i < nrange; i++) { 111838618bf4SAlexander Motin b1 = scsi_8btou64(range[i].lba); 111938618bf4SAlexander Motin l1 = scsi_4btoul(range[i].length); 112032920cbfSAlexander Motin if (b1 + l1 < b1 || b1 + l1 > maxlba + 1) { 112132920cbfSAlexander Motin *lba = MAX(b1, maxlba + 1); 112238618bf4SAlexander Motin return (-1); 112338618bf4SAlexander Motin } 112432920cbfSAlexander Motin } 11258fadf660SAlexander Motin return (0); 11268fadf660SAlexander Motin } 11278fadf660SAlexander Motin 11288fadf660SAlexander Motin static int 11298fadf660SAlexander Motin tpc_check_ranges_x(struct scsi_range_desc *range, int nrange) 11308fadf660SAlexander Motin { 11318fadf660SAlexander Motin uint64_t b1, b2; 11328fadf660SAlexander Motin uint32_t l1, l2; 11338fadf660SAlexander Motin int i, j; 11348fadf660SAlexander Motin 1135e13f4248SAlexander Motin for (i = 0; i < nrange - 1; i++) { 1136e13f4248SAlexander Motin b1 = scsi_8btou64(range[i].lba); 1137e13f4248SAlexander Motin l1 = scsi_4btoul(range[i].length); 1138e13f4248SAlexander Motin for (j = i + 1; j < nrange; j++) { 1139e13f4248SAlexander Motin b2 = scsi_8btou64(range[j].lba); 1140e13f4248SAlexander Motin l2 = scsi_4btoul(range[j].length); 1141e13f4248SAlexander Motin if (b1 + l1 > b2 && b2 + l2 > b1) 1142e13f4248SAlexander Motin return (-1); 1143e13f4248SAlexander Motin } 1144e13f4248SAlexander Motin } 1145e13f4248SAlexander Motin return (0); 1146e13f4248SAlexander Motin } 1147e13f4248SAlexander Motin 1148e13f4248SAlexander Motin static int 114925eee848SAlexander Motin tpc_skip_ranges(struct scsi_range_desc *range, int nrange, off_t skip, 115025eee848SAlexander Motin int *srange, off_t *soffset) 115125eee848SAlexander Motin { 115225eee848SAlexander Motin off_t off; 115325eee848SAlexander Motin int r; 115425eee848SAlexander Motin 115525eee848SAlexander Motin r = 0; 115625eee848SAlexander Motin off = 0; 115725eee848SAlexander Motin while (r < nrange) { 115825eee848SAlexander Motin if (skip - off < scsi_4btoul(range[r].length)) { 115925eee848SAlexander Motin *srange = r; 116025eee848SAlexander Motin *soffset = skip - off; 116125eee848SAlexander Motin return (0); 116225eee848SAlexander Motin } 116325eee848SAlexander Motin off += scsi_4btoul(range[r].length); 116425eee848SAlexander Motin r++; 116525eee848SAlexander Motin } 116625eee848SAlexander Motin return (-1); 116725eee848SAlexander Motin } 116825eee848SAlexander Motin 116925eee848SAlexander Motin static int 117025eee848SAlexander Motin tpc_process_wut(struct tpc_list *list) 117125eee848SAlexander Motin { 117225eee848SAlexander Motin struct tpc_io *tio, *tior, *tiow; 11730952a19fSAlexander Motin struct runl run; 117425eee848SAlexander Motin int drange, srange; 117525eee848SAlexander Motin off_t doffset, soffset; 117625eee848SAlexander Motin off_t srclba, dstlba, numbytes, donebytes, roundbytes; 1177fee04ef7SAlexander Motin uint32_t srcblock, dstblock, pb, pbo, adj; 117825eee848SAlexander Motin 117925eee848SAlexander Motin if (list->stage > 0) { 118025eee848SAlexander Motin /* Cleanup after previous rounds. */ 118125eee848SAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 118225eee848SAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 118325eee848SAlexander Motin ctl_free_io(tio->io); 118446511441SAlexander Motin free(tio->buf, M_CTL); 118525eee848SAlexander Motin free(tio, M_CTL); 118625eee848SAlexander Motin } 118725eee848SAlexander Motin if (list->abort) { 118825eee848SAlexander Motin ctl_set_task_aborted(list->ctsio); 118925eee848SAlexander Motin return (CTL_RETVAL_ERROR); 119025eee848SAlexander Motin } else if (list->error) { 1191a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 1192a3dd8378SAlexander Motin list->ctsio->io_hdr.status = 1193a3dd8378SAlexander Motin CTL_SCSI_ERROR | CTL_AUTOSENSE; 1194a3dd8378SAlexander Motin list->ctsio->scsi_status = list->fwd_scsi_status; 1195a3dd8378SAlexander Motin list->ctsio->sense_data = list->fwd_sense_data; 1196a3dd8378SAlexander Motin list->ctsio->sense_len = list->fwd_sense_len; 1197a3dd8378SAlexander Motin } else { 1198a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, 1199a3dd8378SAlexander Motin /*sks_valid*/ 0, /*command*/ 0, 1200a3dd8378SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 1201a3dd8378SAlexander Motin } 120225eee848SAlexander Motin return (CTL_RETVAL_ERROR); 120325eee848SAlexander Motin } 120425eee848SAlexander Motin list->cursectors += list->segsectors; 120525eee848SAlexander Motin list->curbytes += list->segbytes; 120625eee848SAlexander Motin } 120725eee848SAlexander Motin 120825eee848SAlexander Motin /* Check where we are on destination ranges list. */ 120925eee848SAlexander Motin if (tpc_skip_ranges(list->range, list->nrange, list->cursectors, 121025eee848SAlexander Motin &drange, &doffset) != 0) 121125eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 121225eee848SAlexander Motin dstblock = list->lun->be_lun->blocksize; 1213fee04ef7SAlexander Motin pb = dstblock << list->lun->be_lun->pblockexp; 1214fee04ef7SAlexander Motin if (list->lun->be_lun->pblockoff > 0) 1215fee04ef7SAlexander Motin pbo = pb - dstblock * list->lun->be_lun->pblockoff; 1216fee04ef7SAlexander Motin else 1217fee04ef7SAlexander Motin pbo = 0; 121825eee848SAlexander Motin 121925eee848SAlexander Motin /* Check where we are on source ranges list. */ 122025eee848SAlexander Motin srcblock = list->token->blocksize; 122125eee848SAlexander Motin if (tpc_skip_ranges(list->token->range, list->token->nrange, 122225eee848SAlexander Motin list->offset_into_rod + list->cursectors * dstblock / srcblock, 122325eee848SAlexander Motin &srange, &soffset) != 0) { 1224a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0, 1225a3dd8378SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 122625eee848SAlexander Motin return (CTL_RETVAL_ERROR); 122725eee848SAlexander Motin } 122825eee848SAlexander Motin 122925eee848SAlexander Motin srclba = scsi_8btou64(list->token->range[srange].lba) + soffset; 123025eee848SAlexander Motin dstlba = scsi_8btou64(list->range[drange].lba) + doffset; 1231fee04ef7SAlexander Motin numbytes = srcblock * 1232fee04ef7SAlexander Motin (scsi_4btoul(list->token->range[srange].length) - soffset); 1233fee04ef7SAlexander Motin numbytes = omin(numbytes, dstblock * 1234fee04ef7SAlexander Motin (scsi_4btoul(list->range[drange].length) - doffset)); 1235fee04ef7SAlexander Motin if (numbytes > TPC_MAX_IOCHUNK_SIZE) { 1236fee04ef7SAlexander Motin numbytes = TPC_MAX_IOCHUNK_SIZE; 1237fee04ef7SAlexander Motin numbytes -= numbytes % dstblock; 1238fee04ef7SAlexander Motin if (pb > dstblock) { 1239fee04ef7SAlexander Motin adj = (dstlba * dstblock + numbytes - pbo) % pb; 1240fee04ef7SAlexander Motin if (numbytes > adj) 1241fee04ef7SAlexander Motin numbytes -= adj; 1242fee04ef7SAlexander Motin } 1243fee04ef7SAlexander Motin } 124425eee848SAlexander Motin 124525eee848SAlexander Motin if (numbytes % srcblock != 0 || numbytes % dstblock != 0) { 1246a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, /*sks_valid*/ 0, 1247a3dd8378SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 124825eee848SAlexander Motin return (CTL_RETVAL_ERROR); 124925eee848SAlexander Motin } 125025eee848SAlexander Motin 125125eee848SAlexander Motin list->segbytes = numbytes; 125225eee848SAlexander Motin list->segsectors = numbytes / dstblock; 125325eee848SAlexander Motin //printf("Copy chunk of %ju sectors from %ju to %ju\n", list->segsectors, 125425eee848SAlexander Motin // srclba, dstlba); 125525eee848SAlexander Motin donebytes = 0; 125625eee848SAlexander Motin TAILQ_INIT(&run); 12570952a19fSAlexander Motin list->tbdio = 0; 125825eee848SAlexander Motin TAILQ_INIT(&list->allio); 125925eee848SAlexander Motin while (donebytes < numbytes) { 1260fee04ef7SAlexander Motin roundbytes = numbytes - donebytes; 1261fee04ef7SAlexander Motin if (roundbytes > TPC_MAX_IO_SIZE) { 1262fee04ef7SAlexander Motin roundbytes = TPC_MAX_IO_SIZE; 1263fee04ef7SAlexander Motin roundbytes -= roundbytes % dstblock; 1264fee04ef7SAlexander Motin if (pb > dstblock) { 1265fee04ef7SAlexander Motin adj = (dstlba * dstblock + roundbytes - pbo) % pb; 1266fee04ef7SAlexander Motin if (roundbytes > adj) 1267fee04ef7SAlexander Motin roundbytes -= adj; 1268fee04ef7SAlexander Motin } 1269fee04ef7SAlexander Motin } 127025eee848SAlexander Motin 127125eee848SAlexander Motin tior = malloc(sizeof(*tior), M_CTL, M_WAITOK | M_ZERO); 127225eee848SAlexander Motin TAILQ_INIT(&tior->run); 127346511441SAlexander Motin tior->buf = malloc(roundbytes, M_CTL, M_WAITOK); 127425eee848SAlexander Motin tior->list = list; 127525eee848SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tior, links); 127625eee848SAlexander Motin tior->io = tpcl_alloc_io(); 127725eee848SAlexander Motin ctl_scsi_read_write(tior->io, 127846511441SAlexander Motin /*data_ptr*/ tior->buf, 127925eee848SAlexander Motin /*data_len*/ roundbytes, 128025eee848SAlexander Motin /*read_op*/ 1, 128125eee848SAlexander Motin /*byte2*/ 0, 128225eee848SAlexander Motin /*minimum_cdb_size*/ 0, 1283fee04ef7SAlexander Motin /*lba*/ srclba, 128425eee848SAlexander Motin /*num_blocks*/ roundbytes / srcblock, 128525eee848SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 128625eee848SAlexander Motin /*control*/ 0); 128725eee848SAlexander Motin tior->io->io_hdr.retries = 3; 128825eee848SAlexander Motin tior->lun = list->token->lun; 128925eee848SAlexander Motin tior->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tior; 129025eee848SAlexander Motin 129125eee848SAlexander Motin tiow = malloc(sizeof(*tiow), M_CTL, M_WAITOK | M_ZERO); 129225eee848SAlexander Motin TAILQ_INIT(&tiow->run); 129325eee848SAlexander Motin tiow->list = list; 129425eee848SAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 129525eee848SAlexander Motin tiow->io = tpcl_alloc_io(); 129625eee848SAlexander Motin ctl_scsi_read_write(tiow->io, 129746511441SAlexander Motin /*data_ptr*/ tior->buf, 129825eee848SAlexander Motin /*data_len*/ roundbytes, 129925eee848SAlexander Motin /*read_op*/ 0, 130025eee848SAlexander Motin /*byte2*/ 0, 130125eee848SAlexander Motin /*minimum_cdb_size*/ 0, 1302fee04ef7SAlexander Motin /*lba*/ dstlba, 130325eee848SAlexander Motin /*num_blocks*/ roundbytes / dstblock, 130425eee848SAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 130525eee848SAlexander Motin /*control*/ 0); 130625eee848SAlexander Motin tiow->io->io_hdr.retries = 3; 130725eee848SAlexander Motin tiow->lun = list->lun->lun; 130825eee848SAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 130925eee848SAlexander Motin 131025eee848SAlexander Motin TAILQ_INSERT_TAIL(&tior->run, tiow, rlinks); 13110952a19fSAlexander Motin TAILQ_INSERT_TAIL(&run, tior, rlinks); 13120952a19fSAlexander Motin list->tbdio++; 131325eee848SAlexander Motin donebytes += roundbytes; 1314fee04ef7SAlexander Motin srclba += roundbytes / srcblock; 1315fee04ef7SAlexander Motin dstlba += roundbytes / dstblock; 131625eee848SAlexander Motin } 131725eee848SAlexander Motin 131825eee848SAlexander Motin while ((tior = TAILQ_FIRST(&run)) != NULL) { 131925eee848SAlexander Motin TAILQ_REMOVE(&run, tior, rlinks); 132025eee848SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 132125eee848SAlexander Motin panic("tpcl_queue() error"); 132225eee848SAlexander Motin } 132325eee848SAlexander Motin 132425eee848SAlexander Motin list->stage++; 132525eee848SAlexander Motin return (CTL_RETVAL_QUEUED); 132625eee848SAlexander Motin } 132725eee848SAlexander Motin 1328e3e592bbSAlexander Motin static int 1329e3e592bbSAlexander Motin tpc_process_zero_wut(struct tpc_list *list) 1330e3e592bbSAlexander Motin { 1331e3e592bbSAlexander Motin struct tpc_io *tio, *tiow; 1332e3e592bbSAlexander Motin struct runl run, *prun; 1333e3e592bbSAlexander Motin int r; 1334e3e592bbSAlexander Motin uint32_t dstblock, len; 1335e3e592bbSAlexander Motin 1336e3e592bbSAlexander Motin if (list->stage > 0) { 1337e3e592bbSAlexander Motin complete: 1338e3e592bbSAlexander Motin /* Cleanup after previous rounds. */ 1339e3e592bbSAlexander Motin while ((tio = TAILQ_FIRST(&list->allio)) != NULL) { 1340e3e592bbSAlexander Motin TAILQ_REMOVE(&list->allio, tio, links); 1341e3e592bbSAlexander Motin ctl_free_io(tio->io); 1342e3e592bbSAlexander Motin free(tio, M_CTL); 1343e3e592bbSAlexander Motin } 1344e3e592bbSAlexander Motin if (list->abort) { 1345e3e592bbSAlexander Motin ctl_set_task_aborted(list->ctsio); 1346e3e592bbSAlexander Motin return (CTL_RETVAL_ERROR); 1347e3e592bbSAlexander Motin } else if (list->error) { 1348a3dd8378SAlexander Motin if (list->fwd_scsi_status) { 1349a3dd8378SAlexander Motin list->ctsio->io_hdr.status = 1350a3dd8378SAlexander Motin CTL_SCSI_ERROR | CTL_AUTOSENSE; 1351a3dd8378SAlexander Motin list->ctsio->scsi_status = list->fwd_scsi_status; 1352a3dd8378SAlexander Motin list->ctsio->sense_data = list->fwd_sense_data; 1353a3dd8378SAlexander Motin list->ctsio->sense_len = list->fwd_sense_len; 1354a3dd8378SAlexander Motin } else { 1355a3dd8378SAlexander Motin ctl_set_invalid_field(list->ctsio, 1356a3dd8378SAlexander Motin /*sks_valid*/ 0, /*command*/ 0, 1357a3dd8378SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 1358a3dd8378SAlexander Motin } 1359e3e592bbSAlexander Motin return (CTL_RETVAL_ERROR); 1360e3e592bbSAlexander Motin } 1361e3e592bbSAlexander Motin list->cursectors += list->segsectors; 1362e3e592bbSAlexander Motin list->curbytes += list->segbytes; 1363e3e592bbSAlexander Motin return (CTL_RETVAL_COMPLETE); 1364e3e592bbSAlexander Motin } 1365e3e592bbSAlexander Motin 1366e3e592bbSAlexander Motin dstblock = list->lun->be_lun->blocksize; 1367e3e592bbSAlexander Motin TAILQ_INIT(&run); 1368e3e592bbSAlexander Motin prun = &run; 1369e3e592bbSAlexander Motin list->tbdio = 1; 1370e3e592bbSAlexander Motin TAILQ_INIT(&list->allio); 1371e3e592bbSAlexander Motin list->segsectors = 0; 1372e3e592bbSAlexander Motin for (r = 0; r < list->nrange; r++) { 1373e3e592bbSAlexander Motin len = scsi_4btoul(list->range[r].length); 1374e3e592bbSAlexander Motin if (len == 0) 1375e3e592bbSAlexander Motin continue; 1376e3e592bbSAlexander Motin 1377e3e592bbSAlexander Motin tiow = malloc(sizeof(*tiow), M_CTL, M_WAITOK | M_ZERO); 1378e3e592bbSAlexander Motin TAILQ_INIT(&tiow->run); 1379e3e592bbSAlexander Motin tiow->list = list; 1380e3e592bbSAlexander Motin TAILQ_INSERT_TAIL(&list->allio, tiow, links); 1381e3e592bbSAlexander Motin tiow->io = tpcl_alloc_io(); 1382e3e592bbSAlexander Motin ctl_scsi_write_same(tiow->io, 13836ac1446dSAlexander Motin /*data_ptr*/ NULL, 13846ac1446dSAlexander Motin /*data_len*/ 0, 13856ac1446dSAlexander Motin /*byte2*/ SWS_NDOB, 1386e3e592bbSAlexander Motin /*lba*/ scsi_8btou64(list->range[r].lba), 1387e3e592bbSAlexander Motin /*num_blocks*/ len, 1388e3e592bbSAlexander Motin /*tag_type*/ CTL_TAG_SIMPLE, 1389e3e592bbSAlexander Motin /*control*/ 0); 1390e3e592bbSAlexander Motin tiow->io->io_hdr.retries = 3; 1391e3e592bbSAlexander Motin tiow->lun = list->lun->lun; 1392e3e592bbSAlexander Motin tiow->io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = tiow; 1393e3e592bbSAlexander Motin 1394e3e592bbSAlexander Motin TAILQ_INSERT_TAIL(prun, tiow, rlinks); 1395e3e592bbSAlexander Motin prun = &tiow->run; 1396e3e592bbSAlexander Motin list->segsectors += len; 1397e3e592bbSAlexander Motin } 1398e3e592bbSAlexander Motin list->segbytes = list->segsectors * dstblock; 1399e3e592bbSAlexander Motin 1400e3e592bbSAlexander Motin if (TAILQ_EMPTY(&run)) 1401e3e592bbSAlexander Motin goto complete; 1402e3e592bbSAlexander Motin 1403e3e592bbSAlexander Motin while ((tiow = TAILQ_FIRST(&run)) != NULL) { 1404e3e592bbSAlexander Motin TAILQ_REMOVE(&run, tiow, rlinks); 1405e3e592bbSAlexander Motin if (tpcl_queue(tiow->io, tiow->lun) != CTL_RETVAL_COMPLETE) 1406e3e592bbSAlexander Motin panic("tpcl_queue() error"); 1407e3e592bbSAlexander Motin } 1408e3e592bbSAlexander Motin 1409e3e592bbSAlexander Motin list->stage++; 1410e3e592bbSAlexander Motin return (CTL_RETVAL_QUEUED); 1411e3e592bbSAlexander Motin } 1412e3e592bbSAlexander Motin 1413984a2ea9SAlexander Motin static void 1414984a2ea9SAlexander Motin tpc_process(struct tpc_list *list) 1415984a2ea9SAlexander Motin { 1416984a2ea9SAlexander Motin struct ctl_lun *lun = list->lun; 14179602f436SAlexander Motin struct ctl_softc *softc = lun->ctl_softc; 1418984a2ea9SAlexander Motin struct scsi_ec_segment *seg; 1419984a2ea9SAlexander Motin struct ctl_scsiio *ctsio = list->ctsio; 1420984a2ea9SAlexander Motin int retval = CTL_RETVAL_COMPLETE; 1421042e9bdcSAlexander Motin uint8_t csi[4]; 1422984a2ea9SAlexander Motin 142325eee848SAlexander Motin if (list->service_action == EC_WUT) { 1424e3e592bbSAlexander Motin if (list->token != NULL) 142525eee848SAlexander Motin retval = tpc_process_wut(list); 1426e3e592bbSAlexander Motin else 1427e3e592bbSAlexander Motin retval = tpc_process_zero_wut(list); 142825eee848SAlexander Motin if (retval == CTL_RETVAL_QUEUED) 142925eee848SAlexander Motin return; 143025eee848SAlexander Motin if (retval == CTL_RETVAL_ERROR) { 143125eee848SAlexander Motin list->error = 1; 143225eee848SAlexander Motin goto done; 143325eee848SAlexander Motin } 143425eee848SAlexander Motin } else { 1435984a2ea9SAlexander Motin //printf("ZZZ %d cscd, %d segs\n", list->ncscd, list->nseg); 1436984a2ea9SAlexander Motin while (list->curseg < list->nseg) { 1437984a2ea9SAlexander Motin seg = list->seg[list->curseg]; 1438984a2ea9SAlexander Motin switch (seg->type_code) { 1439984a2ea9SAlexander Motin case EC_SEG_B2B: 1440984a2ea9SAlexander Motin retval = tpc_process_b2b(list); 1441984a2ea9SAlexander Motin break; 1442984a2ea9SAlexander Motin case EC_SEG_VERIFY: 1443984a2ea9SAlexander Motin retval = tpc_process_verify(list); 1444984a2ea9SAlexander Motin break; 1445984a2ea9SAlexander Motin case EC_SEG_REGISTER_KEY: 1446984a2ea9SAlexander Motin retval = tpc_process_register_key(list); 1447984a2ea9SAlexander Motin break; 1448984a2ea9SAlexander Motin default: 1449042e9bdcSAlexander Motin scsi_ulto4b(list->curseg, csi); 1450984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1451984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_COPY_ABORTED, 1452042e9bdcSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, 1453862aedb0SAlexander Motin SSD_ELEM_COMMAND, sizeof(csi), csi, 1454042e9bdcSAlexander Motin SSD_ELEM_NONE); 1455984a2ea9SAlexander Motin goto done; 1456984a2ea9SAlexander Motin } 1457984a2ea9SAlexander Motin if (retval == CTL_RETVAL_QUEUED) 1458984a2ea9SAlexander Motin return; 1459984a2ea9SAlexander Motin if (retval == CTL_RETVAL_ERROR) { 1460984a2ea9SAlexander Motin list->error = 1; 1461984a2ea9SAlexander Motin goto done; 1462984a2ea9SAlexander Motin } 1463984a2ea9SAlexander Motin list->curseg++; 1464984a2ea9SAlexander Motin list->stage = 0; 1465984a2ea9SAlexander Motin } 146625eee848SAlexander Motin } 1467984a2ea9SAlexander Motin 1468984a2ea9SAlexander Motin ctl_set_success(ctsio); 1469984a2ea9SAlexander Motin 1470984a2ea9SAlexander Motin done: 1471984a2ea9SAlexander Motin //printf("ZZZ done\n"); 1472c5c60595SAlexander Motin free(list->params, M_CTL); 1473c5c60595SAlexander Motin list->params = NULL; 147425eee848SAlexander Motin if (list->token) { 14752d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 147625eee848SAlexander Motin if (--list->token->active == 0) 147725eee848SAlexander Motin list->token->last_active = time_uptime; 14782d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 147925eee848SAlexander Motin list->token = NULL; 148025eee848SAlexander Motin } 1481984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1482984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) == EC_LIST_ID_USAGE_NONE) { 1483984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 1484984a2ea9SAlexander Motin free(list, M_CTL); 1485984a2ea9SAlexander Motin } else { 1486984a2ea9SAlexander Motin list->completed = 1; 148725eee848SAlexander Motin list->last_active = time_uptime; 1488984a2ea9SAlexander Motin list->sense_data = ctsio->sense_data; 1489984a2ea9SAlexander Motin list->sense_len = ctsio->sense_len; 1490984a2ea9SAlexander Motin list->scsi_status = ctsio->scsi_status; 1491984a2ea9SAlexander Motin } 1492984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1493984a2ea9SAlexander Motin 1494984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1495984a2ea9SAlexander Motin } 1496984a2ea9SAlexander Motin 1497984a2ea9SAlexander Motin /* 1498984a2ea9SAlexander Motin * For any sort of check condition, busy, etc., we just retry. We do not 1499984a2ea9SAlexander Motin * decrement the retry count for unit attention type errors. These are 1500984a2ea9SAlexander Motin * normal, and we want to save the retry count for "real" errors. Otherwise, 1501984a2ea9SAlexander Motin * we could end up with situations where a command will succeed in some 1502984a2ea9SAlexander Motin * situations and fail in others, depending on whether a unit attention is 1503984a2ea9SAlexander Motin * pending. Also, some of our error recovery actions, most notably the 1504984a2ea9SAlexander Motin * LUN reset action, will cause a unit attention. 1505984a2ea9SAlexander Motin * 1506984a2ea9SAlexander Motin * We can add more detail here later if necessary. 1507984a2ea9SAlexander Motin */ 1508984a2ea9SAlexander Motin static tpc_error_action 1509984a2ea9SAlexander Motin tpc_checkcond_parse(union ctl_io *io) 1510984a2ea9SAlexander Motin { 1511984a2ea9SAlexander Motin tpc_error_action error_action; 1512984a2ea9SAlexander Motin int error_code, sense_key, asc, ascq; 1513984a2ea9SAlexander Motin 1514984a2ea9SAlexander Motin /* 1515984a2ea9SAlexander Motin * Default to retrying the command. 1516984a2ea9SAlexander Motin */ 1517984a2ea9SAlexander Motin error_action = TPC_ERR_RETRY; 1518984a2ea9SAlexander Motin 1519984a2ea9SAlexander Motin scsi_extract_sense_len(&io->scsiio.sense_data, 1520984a2ea9SAlexander Motin io->scsiio.sense_len, 1521984a2ea9SAlexander Motin &error_code, 1522984a2ea9SAlexander Motin &sense_key, 1523984a2ea9SAlexander Motin &asc, 1524984a2ea9SAlexander Motin &ascq, 1525984a2ea9SAlexander Motin /*show_errors*/ 1); 1526984a2ea9SAlexander Motin 1527984a2ea9SAlexander Motin switch (error_code) { 1528984a2ea9SAlexander Motin case SSD_DEFERRED_ERROR: 1529984a2ea9SAlexander Motin case SSD_DESC_DEFERRED_ERROR: 1530984a2ea9SAlexander Motin error_action |= TPC_ERR_NO_DECREMENT; 1531984a2ea9SAlexander Motin break; 1532984a2ea9SAlexander Motin case SSD_CURRENT_ERROR: 1533984a2ea9SAlexander Motin case SSD_DESC_CURRENT_ERROR: 1534984a2ea9SAlexander Motin default: 1535984a2ea9SAlexander Motin switch (sense_key) { 1536984a2ea9SAlexander Motin case SSD_KEY_UNIT_ATTENTION: 1537984a2ea9SAlexander Motin error_action |= TPC_ERR_NO_DECREMENT; 1538984a2ea9SAlexander Motin break; 1539984a2ea9SAlexander Motin case SSD_KEY_HARDWARE_ERROR: 1540984a2ea9SAlexander Motin /* 1541984a2ea9SAlexander Motin * This is our generic "something bad happened" 1542984a2ea9SAlexander Motin * error code. It often isn't recoverable. 1543984a2ea9SAlexander Motin */ 1544984a2ea9SAlexander Motin if ((asc == 0x44) && (ascq == 0x00)) 1545984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1546984a2ea9SAlexander Motin break; 1547984a2ea9SAlexander Motin case SSD_KEY_NOT_READY: 1548984a2ea9SAlexander Motin /* 1549984a2ea9SAlexander Motin * If the LUN is powered down, there likely isn't 1550984a2ea9SAlexander Motin * much point in retrying right now. 1551984a2ea9SAlexander Motin */ 1552984a2ea9SAlexander Motin if ((asc == 0x04) && (ascq == 0x02)) 1553984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1554984a2ea9SAlexander Motin /* 1555984a2ea9SAlexander Motin * If the LUN is offline, there probably isn't much 1556984a2ea9SAlexander Motin * point in retrying, either. 1557984a2ea9SAlexander Motin */ 1558984a2ea9SAlexander Motin if ((asc == 0x04) && (ascq == 0x03)) 1559984a2ea9SAlexander Motin error_action = TPC_ERR_FAIL; 1560984a2ea9SAlexander Motin break; 1561984a2ea9SAlexander Motin } 1562984a2ea9SAlexander Motin } 1563984a2ea9SAlexander Motin return (error_action); 1564984a2ea9SAlexander Motin } 1565984a2ea9SAlexander Motin 1566984a2ea9SAlexander Motin static tpc_error_action 1567984a2ea9SAlexander Motin tpc_error_parse(union ctl_io *io) 1568984a2ea9SAlexander Motin { 1569984a2ea9SAlexander Motin tpc_error_action error_action = TPC_ERR_RETRY; 1570984a2ea9SAlexander Motin 1571984a2ea9SAlexander Motin switch (io->io_hdr.io_type) { 1572984a2ea9SAlexander Motin case CTL_IO_SCSI: 1573984a2ea9SAlexander Motin switch (io->io_hdr.status & CTL_STATUS_MASK) { 1574984a2ea9SAlexander Motin case CTL_SCSI_ERROR: 1575984a2ea9SAlexander Motin switch (io->scsiio.scsi_status) { 1576984a2ea9SAlexander Motin case SCSI_STATUS_CHECK_COND: 1577984a2ea9SAlexander Motin error_action = tpc_checkcond_parse(io); 1578984a2ea9SAlexander Motin break; 1579984a2ea9SAlexander Motin default: 1580984a2ea9SAlexander Motin break; 1581984a2ea9SAlexander Motin } 1582984a2ea9SAlexander Motin break; 1583984a2ea9SAlexander Motin default: 1584984a2ea9SAlexander Motin break; 1585984a2ea9SAlexander Motin } 1586984a2ea9SAlexander Motin break; 1587984a2ea9SAlexander Motin case CTL_IO_TASK: 1588984a2ea9SAlexander Motin break; 1589984a2ea9SAlexander Motin default: 1590984a2ea9SAlexander Motin panic("%s: invalid ctl_io type %d\n", __func__, 1591984a2ea9SAlexander Motin io->io_hdr.io_type); 1592984a2ea9SAlexander Motin break; 1593984a2ea9SAlexander Motin } 1594984a2ea9SAlexander Motin return (error_action); 1595984a2ea9SAlexander Motin } 1596984a2ea9SAlexander Motin 1597984a2ea9SAlexander Motin void 1598984a2ea9SAlexander Motin tpc_done(union ctl_io *io) 1599984a2ea9SAlexander Motin { 1600984a2ea9SAlexander Motin struct tpc_io *tio, *tior; 1601984a2ea9SAlexander Motin 1602984a2ea9SAlexander Motin /* 1603984a2ea9SAlexander Motin * Very minimal retry logic. We basically retry if we got an error 1604984a2ea9SAlexander Motin * back, and the retry count is greater than 0. If we ever want 1605984a2ea9SAlexander Motin * more sophisticated initiator type behavior, the CAM error 1606984a2ea9SAlexander Motin * recovery code in ../common might be helpful. 1607984a2ea9SAlexander Motin */ 1608984a2ea9SAlexander Motin tio = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 1609984a2ea9SAlexander Motin if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 1610984a2ea9SAlexander Motin && (io->io_hdr.retries > 0)) { 1611984a2ea9SAlexander Motin ctl_io_status old_status; 1612984a2ea9SAlexander Motin tpc_error_action error_action; 1613984a2ea9SAlexander Motin 1614984a2ea9SAlexander Motin error_action = tpc_error_parse(io); 1615984a2ea9SAlexander Motin switch (error_action & TPC_ERR_MASK) { 1616984a2ea9SAlexander Motin case TPC_ERR_FAIL: 1617984a2ea9SAlexander Motin break; 1618984a2ea9SAlexander Motin case TPC_ERR_RETRY: 1619984a2ea9SAlexander Motin default: 1620984a2ea9SAlexander Motin if ((error_action & TPC_ERR_NO_DECREMENT) == 0) 1621984a2ea9SAlexander Motin io->io_hdr.retries--; 1622984a2ea9SAlexander Motin old_status = io->io_hdr.status; 1623984a2ea9SAlexander Motin io->io_hdr.status = CTL_STATUS_NONE; 1624984a2ea9SAlexander Motin io->io_hdr.flags &= ~CTL_FLAG_ABORT; 1625984a2ea9SAlexander Motin io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC; 1626984a2ea9SAlexander Motin if (tpcl_queue(io, tio->lun) != CTL_RETVAL_COMPLETE) { 1627984a2ea9SAlexander Motin printf("%s: error returned from ctl_queue()!\n", 1628984a2ea9SAlexander Motin __func__); 1629984a2ea9SAlexander Motin io->io_hdr.status = old_status; 1630984a2ea9SAlexander Motin } else 1631984a2ea9SAlexander Motin return; 1632984a2ea9SAlexander Motin } 1633984a2ea9SAlexander Motin } 1634984a2ea9SAlexander Motin 1635a3dd8378SAlexander Motin if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) { 1636984a2ea9SAlexander Motin tio->list->error = 1; 1637a3dd8378SAlexander Motin if (io->io_hdr.io_type == CTL_IO_SCSI && 1638a3dd8378SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR) { 1639a3dd8378SAlexander Motin tio->list->fwd_scsi_status = io->scsiio.scsi_status; 1640a3dd8378SAlexander Motin tio->list->fwd_sense_data = io->scsiio.sense_data; 1641a3dd8378SAlexander Motin tio->list->fwd_sense_len = io->scsiio.sense_len; 1642a3dd8378SAlexander Motin tio->list->fwd_target = tio->target; 1643a3dd8378SAlexander Motin tio->list->fwd_cscd = tio->cscd; 1644a3dd8378SAlexander Motin } 1645a3dd8378SAlexander Motin } else 1646984a2ea9SAlexander Motin atomic_add_int(&tio->list->curops, 1); 1647984a2ea9SAlexander Motin if (!tio->list->error && !tio->list->abort) { 1648984a2ea9SAlexander Motin while ((tior = TAILQ_FIRST(&tio->run)) != NULL) { 1649984a2ea9SAlexander Motin TAILQ_REMOVE(&tio->run, tior, rlinks); 1650984a2ea9SAlexander Motin atomic_add_int(&tio->list->tbdio, 1); 1651984a2ea9SAlexander Motin if (tpcl_queue(tior->io, tior->lun) != CTL_RETVAL_COMPLETE) 1652984a2ea9SAlexander Motin panic("tpcl_queue() error"); 1653984a2ea9SAlexander Motin } 1654984a2ea9SAlexander Motin } 1655984a2ea9SAlexander Motin if (atomic_fetchadd_int(&tio->list->tbdio, -1) == 1) 1656984a2ea9SAlexander Motin tpc_process(tio->list); 1657984a2ea9SAlexander Motin } 1658984a2ea9SAlexander Motin 1659984a2ea9SAlexander Motin int 1660984a2ea9SAlexander Motin ctl_extended_copy_lid1(struct ctl_scsiio *ctsio) 1661984a2ea9SAlexander Motin { 16629cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 1663984a2ea9SAlexander Motin struct scsi_extended_copy *cdb; 1664984a2ea9SAlexander Motin struct scsi_extended_copy_lid1_data *data; 1665a3dd8378SAlexander Motin struct scsi_ec_cscd *cscd; 1666a3dd8378SAlexander Motin struct scsi_ec_segment *seg; 1667984a2ea9SAlexander Motin struct tpc_list *list, *tlist; 1668984a2ea9SAlexander Motin uint8_t *ptr; 1669984a2ea9SAlexander Motin char *value; 1670984a2ea9SAlexander Motin int len, off, lencscd, lenseg, leninl, nseg; 1671984a2ea9SAlexander Motin 1672984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_extended_copy_lid1\n")); 1673984a2ea9SAlexander Motin 1674984a2ea9SAlexander Motin cdb = (struct scsi_extended_copy *)ctsio->cdb; 1675984a2ea9SAlexander Motin len = scsi_4btoul(cdb->length); 1676984a2ea9SAlexander Motin 1677a65a997fSAlexander Motin if (len == 0) { 1678a65a997fSAlexander Motin ctl_set_success(ctsio); 1679a65a997fSAlexander Motin goto done; 1680a65a997fSAlexander Motin } 1681984a2ea9SAlexander Motin if (len < sizeof(struct scsi_extended_copy_lid1_data) || 1682984a2ea9SAlexander Motin len > sizeof(struct scsi_extended_copy_lid1_data) + 1683984a2ea9SAlexander Motin TPC_MAX_LIST + TPC_MAX_INLINE) { 1684984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 1685984a2ea9SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 1686984a2ea9SAlexander Motin goto done; 1687984a2ea9SAlexander Motin } 1688984a2ea9SAlexander Motin 1689984a2ea9SAlexander Motin /* 1690984a2ea9SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 1691984a2ea9SAlexander Motin * malloc it and tell the caller the data buffer is here. 1692984a2ea9SAlexander Motin */ 1693984a2ea9SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 1694984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 1695984a2ea9SAlexander Motin ctsio->kern_data_len = len; 1696984a2ea9SAlexander Motin ctsio->kern_total_len = len; 1697984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 1698984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 1699984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1700984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 1701984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 1702984a2ea9SAlexander Motin 1703984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1704984a2ea9SAlexander Motin } 1705984a2ea9SAlexander Motin 1706984a2ea9SAlexander Motin data = (struct scsi_extended_copy_lid1_data *)ctsio->kern_data_ptr; 1707984a2ea9SAlexander Motin lencscd = scsi_2btoul(data->cscd_list_length); 1708984a2ea9SAlexander Motin lenseg = scsi_4btoul(data->segment_list_length); 1709984a2ea9SAlexander Motin leninl = scsi_4btoul(data->inline_data_length); 1710984a2ea9SAlexander Motin if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) { 1711984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1712984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1713984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE); 1714984a2ea9SAlexander Motin goto done; 1715984a2ea9SAlexander Motin } 1716a65a997fSAlexander Motin if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) { 1717a65a997fSAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1718a65a997fSAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1719a65a997fSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1720a65a997fSAlexander Motin goto done; 1721a65a997fSAlexander Motin } 1722a65a997fSAlexander Motin if (lencscd + lenseg > TPC_MAX_LIST || 1723a65a997fSAlexander Motin leninl > TPC_MAX_INLINE || 1724a65a997fSAlexander Motin len < sizeof(struct scsi_extended_copy_lid1_data) + 1725a65a997fSAlexander Motin lencscd + lenseg + leninl) { 1726984a2ea9SAlexander Motin ctl_set_param_len_error(ctsio); 1727984a2ea9SAlexander Motin goto done; 1728984a2ea9SAlexander Motin } 1729984a2ea9SAlexander Motin 1730984a2ea9SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 1731984a2ea9SAlexander Motin list->service_action = cdb->service_action; 1732984a2ea9SAlexander Motin value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc"); 1733984a2ea9SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 1734984a2ea9SAlexander Motin list->init_port = -1; 1735984a2ea9SAlexander Motin else 1736984a2ea9SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 17377ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 1738984a2ea9SAlexander Motin list->list_id = data->list_identifier; 1739984a2ea9SAlexander Motin list->flags = data->flags; 1740984a2ea9SAlexander Motin list->params = ctsio->kern_data_ptr; 1741984a2ea9SAlexander Motin list->cscd = (struct scsi_ec_cscd *)&data->data[0]; 1742a3dd8378SAlexander Motin ptr = &data->data[0]; 1743a3dd8378SAlexander Motin for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) { 1744a3dd8378SAlexander Motin cscd = (struct scsi_ec_cscd *)(ptr + off); 1745a3dd8378SAlexander Motin if (cscd->type_code != EC_CSCD_ID) { 1746a3dd8378SAlexander Motin free(list, M_CTL); 1747a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1748a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1749a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE); 1750a3dd8378SAlexander Motin goto done; 1751a3dd8378SAlexander Motin } 1752a3dd8378SAlexander Motin } 1753984a2ea9SAlexander Motin ptr = &data->data[lencscd]; 1754984a2ea9SAlexander Motin for (nseg = 0, off = 0; off < lenseg; nseg++) { 1755984a2ea9SAlexander Motin if (nseg >= TPC_MAX_SEGS) { 1756984a2ea9SAlexander Motin free(list, M_CTL); 1757984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1758984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1759984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1760984a2ea9SAlexander Motin goto done; 1761984a2ea9SAlexander Motin } 1762a3dd8378SAlexander Motin seg = (struct scsi_ec_segment *)(ptr + off); 1763a3dd8378SAlexander Motin if (seg->type_code != EC_SEG_B2B && 1764a3dd8378SAlexander Motin seg->type_code != EC_SEG_VERIFY && 1765a3dd8378SAlexander Motin seg->type_code != EC_SEG_REGISTER_KEY) { 1766a3dd8378SAlexander Motin free(list, M_CTL); 1767a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1768a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1769a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE); 1770a3dd8378SAlexander Motin goto done; 1771a3dd8378SAlexander Motin } 1772a3dd8378SAlexander Motin list->seg[nseg] = seg; 1773984a2ea9SAlexander Motin off += sizeof(struct scsi_ec_segment) + 1774a3dd8378SAlexander Motin scsi_2btoul(seg->descr_length); 1775984a2ea9SAlexander Motin } 1776984a2ea9SAlexander Motin list->inl = &data->data[lencscd + lenseg]; 1777984a2ea9SAlexander Motin list->ncscd = lencscd / sizeof(struct scsi_ec_cscd); 1778984a2ea9SAlexander Motin list->nseg = nseg; 1779984a2ea9SAlexander Motin list->leninl = leninl; 1780984a2ea9SAlexander Motin list->ctsio = ctsio; 1781984a2ea9SAlexander Motin list->lun = lun; 1782984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1783984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) { 178443d2d719SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 1785984a2ea9SAlexander Motin if (tlist != NULL && !tlist->completed) { 1786984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1787984a2ea9SAlexander Motin free(list, M_CTL); 1788984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 1789984a2ea9SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 1790984a2ea9SAlexander Motin /*bit*/ 0); 1791984a2ea9SAlexander Motin goto done; 1792984a2ea9SAlexander Motin } 1793984a2ea9SAlexander Motin if (tlist != NULL) { 1794984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 1795984a2ea9SAlexander Motin free(tlist, M_CTL); 1796984a2ea9SAlexander Motin } 1797984a2ea9SAlexander Motin } 1798984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 1799984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1800984a2ea9SAlexander Motin 1801984a2ea9SAlexander Motin tpc_process(list); 1802984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1803984a2ea9SAlexander Motin 1804984a2ea9SAlexander Motin done: 18052a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 18062a72b593SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 18072a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 18082a72b593SAlexander Motin } 1809984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1810984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1811984a2ea9SAlexander Motin } 1812984a2ea9SAlexander Motin 1813984a2ea9SAlexander Motin int 1814984a2ea9SAlexander Motin ctl_extended_copy_lid4(struct ctl_scsiio *ctsio) 1815984a2ea9SAlexander Motin { 18169cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 1817984a2ea9SAlexander Motin struct scsi_extended_copy *cdb; 1818984a2ea9SAlexander Motin struct scsi_extended_copy_lid4_data *data; 1819a3dd8378SAlexander Motin struct scsi_ec_cscd *cscd; 1820a3dd8378SAlexander Motin struct scsi_ec_segment *seg; 1821984a2ea9SAlexander Motin struct tpc_list *list, *tlist; 1822984a2ea9SAlexander Motin uint8_t *ptr; 1823984a2ea9SAlexander Motin char *value; 1824984a2ea9SAlexander Motin int len, off, lencscd, lenseg, leninl, nseg; 1825984a2ea9SAlexander Motin 1826984a2ea9SAlexander Motin CTL_DEBUG_PRINT(("ctl_extended_copy_lid4\n")); 1827984a2ea9SAlexander Motin 1828984a2ea9SAlexander Motin cdb = (struct scsi_extended_copy *)ctsio->cdb; 1829984a2ea9SAlexander Motin len = scsi_4btoul(cdb->length); 1830984a2ea9SAlexander Motin 1831a65a997fSAlexander Motin if (len == 0) { 1832a65a997fSAlexander Motin ctl_set_success(ctsio); 1833a65a997fSAlexander Motin goto done; 1834a65a997fSAlexander Motin } 1835984a2ea9SAlexander Motin if (len < sizeof(struct scsi_extended_copy_lid4_data) || 1836984a2ea9SAlexander Motin len > sizeof(struct scsi_extended_copy_lid4_data) + 1837984a2ea9SAlexander Motin TPC_MAX_LIST + TPC_MAX_INLINE) { 1838984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 1839984a2ea9SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 1840984a2ea9SAlexander Motin goto done; 1841984a2ea9SAlexander Motin } 1842984a2ea9SAlexander Motin 1843984a2ea9SAlexander Motin /* 1844984a2ea9SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 1845984a2ea9SAlexander Motin * malloc it and tell the caller the data buffer is here. 1846984a2ea9SAlexander Motin */ 1847984a2ea9SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 1848984a2ea9SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 1849984a2ea9SAlexander Motin ctsio->kern_data_len = len; 1850984a2ea9SAlexander Motin ctsio->kern_total_len = len; 1851984a2ea9SAlexander Motin ctsio->kern_rel_offset = 0; 1852984a2ea9SAlexander Motin ctsio->kern_sg_entries = 0; 1853984a2ea9SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1854984a2ea9SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 1855984a2ea9SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 1856984a2ea9SAlexander Motin 1857984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1858984a2ea9SAlexander Motin } 1859984a2ea9SAlexander Motin 1860984a2ea9SAlexander Motin data = (struct scsi_extended_copy_lid4_data *)ctsio->kern_data_ptr; 1861984a2ea9SAlexander Motin lencscd = scsi_2btoul(data->cscd_list_length); 1862984a2ea9SAlexander Motin lenseg = scsi_2btoul(data->segment_list_length); 1863984a2ea9SAlexander Motin leninl = scsi_2btoul(data->inline_data_length); 1864984a2ea9SAlexander Motin if (lencscd > TPC_MAX_CSCDS * sizeof(struct scsi_ec_cscd)) { 1865984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1866984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1867984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x06, SSD_ELEM_NONE); 1868984a2ea9SAlexander Motin goto done; 1869984a2ea9SAlexander Motin } 1870a65a997fSAlexander Motin if (lenseg > TPC_MAX_SEGS * sizeof(struct scsi_ec_segment)) { 1871a65a997fSAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1872a65a997fSAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1873a65a997fSAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1874a65a997fSAlexander Motin goto done; 1875a65a997fSAlexander Motin } 1876a65a997fSAlexander Motin if (lencscd + lenseg > TPC_MAX_LIST || 1877a65a997fSAlexander Motin leninl > TPC_MAX_INLINE || 1878a65a997fSAlexander Motin len < sizeof(struct scsi_extended_copy_lid1_data) + 1879a65a997fSAlexander Motin lencscd + lenseg + leninl) { 1880984a2ea9SAlexander Motin ctl_set_param_len_error(ctsio); 1881984a2ea9SAlexander Motin goto done; 1882984a2ea9SAlexander Motin } 1883984a2ea9SAlexander Motin 1884984a2ea9SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 1885984a2ea9SAlexander Motin list->service_action = cdb->service_action; 1886984a2ea9SAlexander Motin value = ctl_get_opt(&lun->be_lun->options, "insecure_tpc"); 1887984a2ea9SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 1888984a2ea9SAlexander Motin list->init_port = -1; 1889984a2ea9SAlexander Motin else 1890984a2ea9SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 18917ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 1892984a2ea9SAlexander Motin list->list_id = scsi_4btoul(data->list_identifier); 1893984a2ea9SAlexander Motin list->flags = data->flags; 1894984a2ea9SAlexander Motin list->params = ctsio->kern_data_ptr; 1895984a2ea9SAlexander Motin list->cscd = (struct scsi_ec_cscd *)&data->data[0]; 1896a3dd8378SAlexander Motin ptr = &data->data[0]; 1897a3dd8378SAlexander Motin for (off = 0; off < lencscd; off += sizeof(struct scsi_ec_cscd)) { 1898a3dd8378SAlexander Motin cscd = (struct scsi_ec_cscd *)(ptr + off); 1899a3dd8378SAlexander Motin if (cscd->type_code != EC_CSCD_ID) { 1900a3dd8378SAlexander Motin free(list, M_CTL); 1901a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1902a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1903a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x07, SSD_ELEM_NONE); 1904a3dd8378SAlexander Motin goto done; 1905a3dd8378SAlexander Motin } 1906a3dd8378SAlexander Motin } 1907984a2ea9SAlexander Motin ptr = &data->data[lencscd]; 1908984a2ea9SAlexander Motin for (nseg = 0, off = 0; off < lenseg; nseg++) { 1909984a2ea9SAlexander Motin if (nseg >= TPC_MAX_SEGS) { 1910984a2ea9SAlexander Motin free(list, M_CTL); 1911984a2ea9SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1912984a2ea9SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1913984a2ea9SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x08, SSD_ELEM_NONE); 1914984a2ea9SAlexander Motin goto done; 1915984a2ea9SAlexander Motin } 1916a3dd8378SAlexander Motin seg = (struct scsi_ec_segment *)(ptr + off); 1917a3dd8378SAlexander Motin if (seg->type_code != EC_SEG_B2B && 1918a3dd8378SAlexander Motin seg->type_code != EC_SEG_VERIFY && 1919a3dd8378SAlexander Motin seg->type_code != EC_SEG_REGISTER_KEY) { 1920a3dd8378SAlexander Motin free(list, M_CTL); 1921a3dd8378SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 1922a3dd8378SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 1923a3dd8378SAlexander Motin /*asc*/ 0x26, /*ascq*/ 0x09, SSD_ELEM_NONE); 1924a3dd8378SAlexander Motin goto done; 1925a3dd8378SAlexander Motin } 1926a3dd8378SAlexander Motin list->seg[nseg] = seg; 1927984a2ea9SAlexander Motin off += sizeof(struct scsi_ec_segment) + 1928a3dd8378SAlexander Motin scsi_2btoul(seg->descr_length); 1929984a2ea9SAlexander Motin } 1930984a2ea9SAlexander Motin list->inl = &data->data[lencscd + lenseg]; 1931984a2ea9SAlexander Motin list->ncscd = lencscd / sizeof(struct scsi_ec_cscd); 1932984a2ea9SAlexander Motin list->nseg = nseg; 1933984a2ea9SAlexander Motin list->leninl = leninl; 1934984a2ea9SAlexander Motin list->ctsio = ctsio; 1935984a2ea9SAlexander Motin list->lun = lun; 1936984a2ea9SAlexander Motin mtx_lock(&lun->lun_lock); 1937984a2ea9SAlexander Motin if ((list->flags & EC_LIST_ID_USAGE_MASK) != EC_LIST_ID_USAGE_NONE) { 193843d2d719SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 1939984a2ea9SAlexander Motin if (tlist != NULL && !tlist->completed) { 1940984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1941984a2ea9SAlexander Motin free(list, M_CTL); 1942984a2ea9SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 1943984a2ea9SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 1944984a2ea9SAlexander Motin /*bit*/ 0); 1945984a2ea9SAlexander Motin goto done; 1946984a2ea9SAlexander Motin } 1947984a2ea9SAlexander Motin if (tlist != NULL) { 1948984a2ea9SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 1949984a2ea9SAlexander Motin free(tlist, M_CTL); 1950984a2ea9SAlexander Motin } 1951984a2ea9SAlexander Motin } 1952984a2ea9SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 1953984a2ea9SAlexander Motin mtx_unlock(&lun->lun_lock); 1954984a2ea9SAlexander Motin 1955984a2ea9SAlexander Motin tpc_process(list); 1956984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1957984a2ea9SAlexander Motin 1958984a2ea9SAlexander Motin done: 19592a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 19602a72b593SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 19612a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 19622a72b593SAlexander Motin } 1963984a2ea9SAlexander Motin ctl_done((union ctl_io *)ctsio); 1964984a2ea9SAlexander Motin return (CTL_RETVAL_COMPLETE); 1965984a2ea9SAlexander Motin } 1966984a2ea9SAlexander Motin 196725eee848SAlexander Motin static void 196825eee848SAlexander Motin tpc_create_token(struct ctl_lun *lun, struct ctl_port *port, off_t len, 196925eee848SAlexander Motin struct scsi_token *token) 197025eee848SAlexander Motin { 197125eee848SAlexander Motin static int id = 0; 197225eee848SAlexander Motin struct scsi_vpd_id_descriptor *idd = NULL; 19734ab4d687SAlexander Motin struct scsi_ec_cscd_id *cscd; 19740b060244SAlexander Motin struct scsi_read_capacity_data_long *dtsd; 197525eee848SAlexander Motin int targid_len; 197625eee848SAlexander Motin 197725eee848SAlexander Motin scsi_ulto4b(ROD_TYPE_AUR, token->type); 197825eee848SAlexander Motin scsi_ulto2b(0x01f8, token->length); 197925eee848SAlexander Motin scsi_u64to8b(atomic_fetchadd_int(&id, 1), &token->body[0]); 198025eee848SAlexander Motin if (lun->lun_devid) 198125eee848SAlexander Motin idd = scsi_get_devid_desc((struct scsi_vpd_id_descriptor *) 198225eee848SAlexander Motin lun->lun_devid->data, lun->lun_devid->len, 198325eee848SAlexander Motin scsi_devid_is_lun_naa); 198425eee848SAlexander Motin if (idd == NULL && 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_eui64); 19884ab4d687SAlexander Motin if (idd != NULL) { 19894ab4d687SAlexander Motin cscd = (struct scsi_ec_cscd_id *)&token->body[8]; 19904ab4d687SAlexander Motin cscd->type_code = EC_CSCD_ID; 19914ab4d687SAlexander Motin cscd->luidt_pdt = T_DIRECT; 19924ab4d687SAlexander Motin memcpy(&cscd->codeset, idd, 4 + idd->length); 19930b060244SAlexander Motin scsi_ulto3b(lun->be_lun->blocksize, cscd->dtsp.block_length); 19944ab4d687SAlexander Motin } 19950b060244SAlexander Motin scsi_u64to8b(0, &token->body[40]); /* XXX: Should be 128bit value. */ 199625eee848SAlexander Motin scsi_u64to8b(len, &token->body[48]); 19970b060244SAlexander Motin 19980b060244SAlexander Motin /* ROD token device type specific data (RC16 without first field) */ 19990b060244SAlexander Motin dtsd = (struct scsi_read_capacity_data_long *)&token->body[88 - 8]; 20000b060244SAlexander Motin scsi_ulto4b(lun->be_lun->blocksize, dtsd->length); 20010b060244SAlexander Motin dtsd->prot_lbppbe = lun->be_lun->pblockexp & SRC16_LBPPBE; 20020b060244SAlexander Motin scsi_ulto2b(lun->be_lun->pblockoff & SRC16_LALBA_A, dtsd->lalba_lbp); 20030b060244SAlexander Motin if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) 20040b060244SAlexander Motin dtsd->lalba_lbp[0] |= SRC16_LBPME | SRC16_LBPRZ; 20050b060244SAlexander Motin 200625eee848SAlexander Motin if (port->target_devid) { 200725eee848SAlexander Motin targid_len = port->target_devid->len; 200825eee848SAlexander Motin memcpy(&token->body[120], port->target_devid->data, targid_len); 200925eee848SAlexander Motin } else 201025eee848SAlexander Motin targid_len = 32; 201125eee848SAlexander Motin arc4rand(&token->body[120 + targid_len], 384 - targid_len, 0); 201225eee848SAlexander Motin }; 201325eee848SAlexander Motin 201425eee848SAlexander Motin int 201525eee848SAlexander Motin ctl_populate_token(struct ctl_scsiio *ctsio) 201625eee848SAlexander Motin { 20179cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 20189cbbfd2fSAlexander Motin struct ctl_port *port = CTL_PORT(ctsio); 20199cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 202025eee848SAlexander Motin struct scsi_populate_token *cdb; 202125eee848SAlexander Motin struct scsi_populate_token_data *data; 202225eee848SAlexander Motin struct tpc_list *list, *tlist; 202325eee848SAlexander Motin struct tpc_token *token; 202432920cbfSAlexander Motin uint64_t lba; 20253eb7651aSAlexander Motin int len, lendata, lendesc; 202625eee848SAlexander Motin 202725eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_populate_token\n")); 202825eee848SAlexander Motin 202925eee848SAlexander Motin cdb = (struct scsi_populate_token *)ctsio->cdb; 203025eee848SAlexander Motin len = scsi_4btoul(cdb->length); 203125eee848SAlexander Motin 203225eee848SAlexander Motin if (len < sizeof(struct scsi_populate_token_data) || 203325eee848SAlexander Motin len > sizeof(struct scsi_populate_token_data) + 203425eee848SAlexander Motin TPC_MAX_SEGS * sizeof(struct scsi_range_desc)) { 203525eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 203625eee848SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 203725eee848SAlexander Motin goto done; 203825eee848SAlexander Motin } 203925eee848SAlexander Motin 204025eee848SAlexander Motin /* 204125eee848SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 204225eee848SAlexander Motin * malloc it and tell the caller the data buffer is here. 204325eee848SAlexander Motin */ 204425eee848SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 204525eee848SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 204625eee848SAlexander Motin ctsio->kern_data_len = len; 204725eee848SAlexander Motin ctsio->kern_total_len = len; 204825eee848SAlexander Motin ctsio->kern_rel_offset = 0; 204925eee848SAlexander Motin ctsio->kern_sg_entries = 0; 205025eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 205125eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 205225eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 205325eee848SAlexander Motin 205425eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 205525eee848SAlexander Motin } 205625eee848SAlexander Motin 205725eee848SAlexander Motin data = (struct scsi_populate_token_data *)ctsio->kern_data_ptr; 20583eb7651aSAlexander Motin lendata = scsi_2btoul(data->length); 20593eb7651aSAlexander Motin if (lendata < sizeof(struct scsi_populate_token_data) - 2 + 20603eb7651aSAlexander Motin sizeof(struct scsi_range_desc)) { 206125eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 20623eb7651aSAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 20633eb7651aSAlexander Motin goto done; 20643eb7651aSAlexander Motin } 20653eb7651aSAlexander Motin lendesc = scsi_2btoul(data->range_descriptor_length); 20663eb7651aSAlexander Motin if (lendesc < sizeof(struct scsi_range_desc) || 20673eb7651aSAlexander Motin len < sizeof(struct scsi_populate_token_data) + lendesc || 20683eb7651aSAlexander Motin lendata < sizeof(struct scsi_populate_token_data) - 2 + lendesc) { 20693eb7651aSAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 20703eb7651aSAlexander Motin /*field*/ 14, /*bit_valid*/ 0, /*bit*/ 0); 207125eee848SAlexander Motin goto done; 207225eee848SAlexander Motin } 207325eee848SAlexander Motin /* 207425eee848SAlexander Motin printf("PT(list=%u) flags=%x to=%d rt=%x len=%x\n", 207525eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), 207625eee848SAlexander Motin data->flags, scsi_4btoul(data->inactivity_timeout), 207725eee848SAlexander Motin scsi_4btoul(data->rod_type), 207825eee848SAlexander Motin scsi_2btoul(data->range_descriptor_length)); 207925eee848SAlexander Motin */ 20803eb7651aSAlexander Motin 20813eb7651aSAlexander Motin /* Validate INACTIVITY TIMEOUT field */ 20823eb7651aSAlexander Motin if (scsi_4btoul(data->inactivity_timeout) > TPC_MAX_TOKEN_TIMEOUT) { 20833eb7651aSAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 20843eb7651aSAlexander Motin /*command*/ 0, /*field*/ 4, /*bit_valid*/ 0, 20853eb7651aSAlexander Motin /*bit*/ 0); 20863eb7651aSAlexander Motin goto done; 20873eb7651aSAlexander Motin } 20883eb7651aSAlexander Motin 20893eb7651aSAlexander Motin /* Validate ROD TYPE field */ 209025eee848SAlexander Motin if ((data->flags & EC_PT_RTV) && 209125eee848SAlexander Motin scsi_4btoul(data->rod_type) != ROD_TYPE_AUR) { 209225eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 209325eee848SAlexander Motin /*field*/ 8, /*bit_valid*/ 0, /*bit*/ 0); 209425eee848SAlexander Motin goto done; 209525eee848SAlexander Motin } 209625eee848SAlexander Motin 2097e13f4248SAlexander Motin /* Validate list of ranges */ 20988fadf660SAlexander Motin if (tpc_check_ranges_l(&data->desc[0], 2099e13f4248SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 210038618bf4SAlexander Motin sizeof(struct scsi_range_desc), 210132920cbfSAlexander Motin lun->be_lun->maxlba, &lba) != 0) { 210232920cbfSAlexander Motin ctl_set_lba_out_of_range(ctsio, lba); 21038fadf660SAlexander Motin goto done; 21048fadf660SAlexander Motin } 21058fadf660SAlexander Motin if (tpc_check_ranges_x(&data->desc[0], 21068fadf660SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 21078fadf660SAlexander Motin sizeof(struct scsi_range_desc)) != 0) { 2108e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 0, 2109e13f4248SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 2110e13f4248SAlexander Motin /*bit*/ 0); 2111e13f4248SAlexander Motin goto done; 2112e13f4248SAlexander Motin } 2113e13f4248SAlexander Motin 211425eee848SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 211525eee848SAlexander Motin list->service_action = cdb->service_action; 211625eee848SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 21177ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 211825eee848SAlexander Motin list->list_id = scsi_4btoul(cdb->list_identifier); 211925eee848SAlexander Motin list->flags = data->flags; 212025eee848SAlexander Motin list->ctsio = ctsio; 212125eee848SAlexander Motin list->lun = lun; 212225eee848SAlexander Motin mtx_lock(&lun->lun_lock); 212325eee848SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 212425eee848SAlexander Motin if (tlist != NULL && !tlist->completed) { 212525eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 212625eee848SAlexander Motin free(list, M_CTL); 212725eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 212825eee848SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 212925eee848SAlexander Motin /*bit*/ 0); 213025eee848SAlexander Motin goto done; 213125eee848SAlexander Motin } 213225eee848SAlexander Motin if (tlist != NULL) { 213325eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 213425eee848SAlexander Motin free(tlist, M_CTL); 213525eee848SAlexander Motin } 213625eee848SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 213725eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 213825eee848SAlexander Motin 213925eee848SAlexander Motin token = malloc(sizeof(*token), M_CTL, M_WAITOK | M_ZERO); 214025eee848SAlexander Motin token->lun = lun->lun; 214125eee848SAlexander Motin token->blocksize = lun->be_lun->blocksize; 214225eee848SAlexander Motin token->params = ctsio->kern_data_ptr; 214325eee848SAlexander Motin token->range = &data->desc[0]; 214425eee848SAlexander Motin token->nrange = scsi_2btoul(data->range_descriptor_length) / 214525eee848SAlexander Motin sizeof(struct scsi_range_desc); 21460b060244SAlexander Motin list->cursectors = tpc_ranges_length(token->range, token->nrange); 21470b060244SAlexander Motin list->curbytes = (off_t)list->cursectors * lun->be_lun->blocksize; 214825eee848SAlexander Motin tpc_create_token(lun, port, list->curbytes, 214925eee848SAlexander Motin (struct scsi_token *)token->token); 215025eee848SAlexander Motin token->active = 0; 215125eee848SAlexander Motin token->last_active = time_uptime; 215225eee848SAlexander Motin token->timeout = scsi_4btoul(data->inactivity_timeout); 215325eee848SAlexander Motin if (token->timeout == 0) 215425eee848SAlexander Motin token->timeout = TPC_DFL_TOKEN_TIMEOUT; 215525eee848SAlexander Motin else if (token->timeout < TPC_MIN_TOKEN_TIMEOUT) 215625eee848SAlexander Motin token->timeout = TPC_MIN_TOKEN_TIMEOUT; 215725eee848SAlexander Motin memcpy(list->res_token, token->token, sizeof(list->res_token)); 215825eee848SAlexander Motin list->res_token_valid = 1; 215925eee848SAlexander Motin list->curseg = 0; 216025eee848SAlexander Motin list->completed = 1; 216125eee848SAlexander Motin list->last_active = time_uptime; 21622d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 21639602f436SAlexander Motin TAILQ_INSERT_TAIL(&softc->tpc_tokens, token, links); 21642d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 216525eee848SAlexander Motin ctl_set_success(ctsio); 216625eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 216725eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 216825eee848SAlexander Motin 216925eee848SAlexander Motin done: 21702a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 217125eee848SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 21722a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 21732a72b593SAlexander Motin } 217425eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 217525eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 217625eee848SAlexander Motin } 217725eee848SAlexander Motin 217825eee848SAlexander Motin int 217925eee848SAlexander Motin ctl_write_using_token(struct ctl_scsiio *ctsio) 218025eee848SAlexander Motin { 21819cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 21829cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 218325eee848SAlexander Motin struct scsi_write_using_token *cdb; 218425eee848SAlexander Motin struct scsi_write_using_token_data *data; 218525eee848SAlexander Motin struct tpc_list *list, *tlist; 218625eee848SAlexander Motin struct tpc_token *token; 218732920cbfSAlexander Motin uint64_t lba; 2188e13f4248SAlexander Motin int len, lendata, lendesc; 218925eee848SAlexander Motin 219025eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_write_using_token\n")); 219125eee848SAlexander Motin 219225eee848SAlexander Motin cdb = (struct scsi_write_using_token *)ctsio->cdb; 219325eee848SAlexander Motin len = scsi_4btoul(cdb->length); 219425eee848SAlexander Motin 2195e13f4248SAlexander Motin if (len < sizeof(struct scsi_write_using_token_data) || 2196e13f4248SAlexander Motin len > sizeof(struct scsi_write_using_token_data) + 219725eee848SAlexander Motin TPC_MAX_SEGS * sizeof(struct scsi_range_desc)) { 219825eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, 219925eee848SAlexander Motin /*field*/ 9, /*bit_valid*/ 0, /*bit*/ 0); 220025eee848SAlexander Motin goto done; 220125eee848SAlexander Motin } 220225eee848SAlexander Motin 220325eee848SAlexander Motin /* 220425eee848SAlexander Motin * If we've got a kernel request that hasn't been malloced yet, 220525eee848SAlexander Motin * malloc it and tell the caller the data buffer is here. 220625eee848SAlexander Motin */ 220725eee848SAlexander Motin if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) { 220825eee848SAlexander Motin ctsio->kern_data_ptr = malloc(len, M_CTL, M_WAITOK); 220925eee848SAlexander Motin ctsio->kern_data_len = len; 221025eee848SAlexander Motin ctsio->kern_total_len = len; 221125eee848SAlexander Motin ctsio->kern_rel_offset = 0; 221225eee848SAlexander Motin ctsio->kern_sg_entries = 0; 221325eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 221425eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 221525eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 221625eee848SAlexander Motin 221725eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 221825eee848SAlexander Motin } 221925eee848SAlexander Motin 222025eee848SAlexander Motin data = (struct scsi_write_using_token_data *)ctsio->kern_data_ptr; 2221e13f4248SAlexander Motin lendata = scsi_2btoul(data->length); 2222e13f4248SAlexander Motin if (lendata < sizeof(struct scsi_write_using_token_data) - 2 + 2223e13f4248SAlexander Motin sizeof(struct scsi_range_desc)) { 222425eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 2225e13f4248SAlexander Motin /*field*/ 0, /*bit_valid*/ 0, /*bit*/ 0); 2226e13f4248SAlexander Motin goto done; 2227e13f4248SAlexander Motin } 2228e13f4248SAlexander Motin lendesc = scsi_2btoul(data->range_descriptor_length); 2229e13f4248SAlexander Motin if (lendesc < sizeof(struct scsi_range_desc) || 2230e13f4248SAlexander Motin len < sizeof(struct scsi_write_using_token_data) + lendesc || 2231e13f4248SAlexander Motin lendata < sizeof(struct scsi_write_using_token_data) - 2 + lendesc) { 2232e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 0, 2233e13f4248SAlexander Motin /*field*/ 534, /*bit_valid*/ 0, /*bit*/ 0); 223425eee848SAlexander Motin goto done; 223525eee848SAlexander Motin } 223625eee848SAlexander Motin /* 223725eee848SAlexander Motin printf("WUT(list=%u) flags=%x off=%ju len=%x\n", 223825eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), 223925eee848SAlexander Motin data->flags, scsi_8btou64(data->offset_into_rod), 224025eee848SAlexander Motin scsi_2btoul(data->range_descriptor_length)); 224125eee848SAlexander Motin */ 2242e13f4248SAlexander Motin 2243e13f4248SAlexander Motin /* Validate list of ranges */ 22448fadf660SAlexander Motin if (tpc_check_ranges_l(&data->desc[0], 2245e13f4248SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 224638618bf4SAlexander Motin sizeof(struct scsi_range_desc), 224732920cbfSAlexander Motin lun->be_lun->maxlba, &lba) != 0) { 224832920cbfSAlexander Motin ctl_set_lba_out_of_range(ctsio, lba); 22498fadf660SAlexander Motin goto done; 22508fadf660SAlexander Motin } 22518fadf660SAlexander Motin if (tpc_check_ranges_x(&data->desc[0], 22528fadf660SAlexander Motin scsi_2btoul(data->range_descriptor_length) / 22538fadf660SAlexander Motin sizeof(struct scsi_range_desc)) != 0) { 2254e13f4248SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 0, 2255e13f4248SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 2256e13f4248SAlexander Motin /*bit*/ 0); 2257e13f4248SAlexander Motin goto done; 2258e13f4248SAlexander Motin } 2259e13f4248SAlexander Motin 226025eee848SAlexander Motin list = malloc(sizeof(struct tpc_list), M_CTL, M_WAITOK | M_ZERO); 226125eee848SAlexander Motin list->service_action = cdb->service_action; 226225eee848SAlexander Motin list->init_port = ctsio->io_hdr.nexus.targ_port; 22637ac58230SAlexander Motin list->init_idx = ctl_get_initindex(&ctsio->io_hdr.nexus); 226425eee848SAlexander Motin list->list_id = scsi_4btoul(cdb->list_identifier); 226525eee848SAlexander Motin list->flags = data->flags; 226625eee848SAlexander Motin list->params = ctsio->kern_data_ptr; 226725eee848SAlexander Motin list->range = &data->desc[0]; 226825eee848SAlexander Motin list->nrange = scsi_2btoul(data->range_descriptor_length) / 226925eee848SAlexander Motin sizeof(struct scsi_range_desc); 227025eee848SAlexander Motin list->offset_into_rod = scsi_8btou64(data->offset_into_rod); 227125eee848SAlexander Motin list->ctsio = ctsio; 227225eee848SAlexander Motin list->lun = lun; 227325eee848SAlexander Motin mtx_lock(&lun->lun_lock); 227425eee848SAlexander Motin tlist = tpc_find_list(lun, list->list_id, list->init_idx); 227525eee848SAlexander Motin if (tlist != NULL && !tlist->completed) { 227625eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 227725eee848SAlexander Motin free(list, M_CTL); 227825eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 227925eee848SAlexander Motin /*command*/ 0, /*field*/ 0, /*bit_valid*/ 0, 228025eee848SAlexander Motin /*bit*/ 0); 228125eee848SAlexander Motin goto done; 228225eee848SAlexander Motin } 228325eee848SAlexander Motin if (tlist != NULL) { 228425eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, tlist, links); 228525eee848SAlexander Motin free(tlist, M_CTL); 228625eee848SAlexander Motin } 228725eee848SAlexander Motin TAILQ_INSERT_TAIL(&lun->tpc_lists, list, links); 228825eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 228925eee848SAlexander Motin 229025eee848SAlexander Motin /* Block device zero ROD token -> no token. */ 229125eee848SAlexander Motin if (scsi_4btoul(data->rod_token) == ROD_TYPE_BLOCK_ZERO) { 229225eee848SAlexander Motin tpc_process(list); 229325eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 229425eee848SAlexander Motin } 229525eee848SAlexander Motin 22962d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 22979602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) { 229825eee848SAlexander Motin if (memcmp(token->token, data->rod_token, 229925eee848SAlexander Motin sizeof(data->rod_token)) == 0) 230025eee848SAlexander Motin break; 230125eee848SAlexander Motin } 230225eee848SAlexander Motin if (token != NULL) { 230325eee848SAlexander Motin token->active++; 230425eee848SAlexander Motin list->token = token; 230525eee848SAlexander Motin if (data->flags & EC_WUT_DEL_TKN) 230625eee848SAlexander Motin token->timeout = 0; 230725eee848SAlexander Motin } 23082d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 230925eee848SAlexander Motin if (token == NULL) { 231025eee848SAlexander Motin mtx_lock(&lun->lun_lock); 231125eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 231225eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 231325eee848SAlexander Motin free(list, M_CTL); 231425eee848SAlexander Motin ctl_set_sense(ctsio, /*current_error*/ 1, 231525eee848SAlexander Motin /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST, 231625eee848SAlexander Motin /*asc*/ 0x23, /*ascq*/ 0x04, SSD_ELEM_NONE); 231725eee848SAlexander Motin goto done; 231825eee848SAlexander Motin } 231925eee848SAlexander Motin 232025eee848SAlexander Motin tpc_process(list); 232125eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 232225eee848SAlexander Motin 232325eee848SAlexander Motin done: 23242a72b593SAlexander Motin if (ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) { 232525eee848SAlexander Motin free(ctsio->kern_data_ptr, M_CTL); 23262a72b593SAlexander Motin ctsio->io_hdr.flags &= ~CTL_FLAG_ALLOCATED; 23272a72b593SAlexander Motin } 232825eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 232925eee848SAlexander Motin return (CTL_RETVAL_COMPLETE); 233025eee848SAlexander Motin } 233125eee848SAlexander Motin 233225eee848SAlexander Motin int 233325eee848SAlexander Motin ctl_receive_rod_token_information(struct ctl_scsiio *ctsio) 233425eee848SAlexander Motin { 23359cbbfd2fSAlexander Motin struct ctl_lun *lun = CTL_LUN(ctsio); 233625eee848SAlexander Motin struct scsi_receive_rod_token_information *cdb; 233725eee848SAlexander Motin struct scsi_receive_copy_status_lid4_data *data; 233825eee848SAlexander Motin struct tpc_list *list; 233925eee848SAlexander Motin struct tpc_list list_copy; 234025eee848SAlexander Motin uint8_t *ptr; 234125eee848SAlexander Motin int retval; 234225eee848SAlexander Motin int alloc_len, total_len, token_len; 234325eee848SAlexander Motin uint32_t list_id; 234425eee848SAlexander Motin 234525eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_rod_token_information\n")); 234625eee848SAlexander Motin 234725eee848SAlexander Motin cdb = (struct scsi_receive_rod_token_information *)ctsio->cdb; 234825eee848SAlexander Motin retval = CTL_RETVAL_COMPLETE; 234925eee848SAlexander Motin 235025eee848SAlexander Motin list_id = scsi_4btoul(cdb->list_identifier); 235125eee848SAlexander Motin mtx_lock(&lun->lun_lock); 235225eee848SAlexander Motin list = tpc_find_list(lun, list_id, 23537ac58230SAlexander Motin ctl_get_initindex(&ctsio->io_hdr.nexus)); 235425eee848SAlexander Motin if (list == NULL) { 235525eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 235625eee848SAlexander Motin ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, 235725eee848SAlexander Motin /*command*/ 1, /*field*/ 2, /*bit_valid*/ 0, 235825eee848SAlexander Motin /*bit*/ 0); 235925eee848SAlexander Motin ctl_done((union ctl_io *)ctsio); 236025eee848SAlexander Motin return (retval); 236125eee848SAlexander Motin } 236225eee848SAlexander Motin list_copy = *list; 236325eee848SAlexander Motin if (list->completed) { 236425eee848SAlexander Motin TAILQ_REMOVE(&lun->tpc_lists, list, links); 236525eee848SAlexander Motin free(list, M_CTL); 236625eee848SAlexander Motin } 236725eee848SAlexander Motin mtx_unlock(&lun->lun_lock); 236825eee848SAlexander Motin 236925eee848SAlexander Motin token_len = list_copy.res_token_valid ? 2 + sizeof(list_copy.res_token) : 0; 237025eee848SAlexander Motin total_len = sizeof(*data) + list_copy.sense_len + 4 + token_len; 237125eee848SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 237225eee848SAlexander Motin 237325eee848SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 237425eee848SAlexander Motin ctsio->kern_sg_entries = 0; 237525eee848SAlexander Motin ctsio->kern_rel_offset = 0; 2376640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 2377640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 237825eee848SAlexander Motin 237925eee848SAlexander Motin data = (struct scsi_receive_copy_status_lid4_data *)ctsio->kern_data_ptr; 238025eee848SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + list_copy.sense_len + 238125eee848SAlexander Motin 4 + token_len, data->available_data); 238225eee848SAlexander Motin data->response_to_service_action = list_copy.service_action; 238325eee848SAlexander Motin if (list_copy.completed) { 238425eee848SAlexander Motin if (list_copy.error) 238525eee848SAlexander Motin data->copy_command_status = RCS_CCS_ERROR; 238625eee848SAlexander Motin else if (list_copy.abort) 238725eee848SAlexander Motin data->copy_command_status = RCS_CCS_ABORTED; 238825eee848SAlexander Motin else 238925eee848SAlexander Motin data->copy_command_status = RCS_CCS_COMPLETED; 239025eee848SAlexander Motin } else 239125eee848SAlexander Motin data->copy_command_status = RCS_CCS_INPROG_FG; 239225eee848SAlexander Motin scsi_ulto2b(list_copy.curops, data->operation_counter); 239325eee848SAlexander Motin scsi_ulto4b(UINT32_MAX, data->estimated_status_update_delay); 239425eee848SAlexander Motin data->transfer_count_units = RCS_TC_LBAS; 239525eee848SAlexander Motin scsi_u64to8b(list_copy.cursectors, data->transfer_count); 239625eee848SAlexander Motin scsi_ulto2b(list_copy.curseg, data->segments_processed); 239725eee848SAlexander Motin data->length_of_the_sense_data_field = list_copy.sense_len; 239825eee848SAlexander Motin data->sense_data_length = list_copy.sense_len; 239925eee848SAlexander Motin memcpy(data->sense_data, &list_copy.sense_data, list_copy.sense_len); 240025eee848SAlexander Motin 240125eee848SAlexander Motin ptr = &data->sense_data[data->length_of_the_sense_data_field]; 240225eee848SAlexander Motin scsi_ulto4b(token_len, &ptr[0]); 240325eee848SAlexander Motin if (list_copy.res_token_valid) { 240425eee848SAlexander Motin scsi_ulto2b(0, &ptr[4]); 240525eee848SAlexander Motin memcpy(&ptr[6], list_copy.res_token, sizeof(list_copy.res_token)); 240625eee848SAlexander Motin } 240725eee848SAlexander Motin /* 240825eee848SAlexander Motin printf("RRTI(list=%u) valid=%d\n", 240925eee848SAlexander Motin scsi_4btoul(cdb->list_identifier), list_copy.res_token_valid); 241025eee848SAlexander Motin */ 2411f7241cceSAlexander Motin ctl_set_success(ctsio); 241225eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 241325eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 241425eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 241525eee848SAlexander Motin return (retval); 241625eee848SAlexander Motin } 241725eee848SAlexander Motin 241825eee848SAlexander Motin int 241925eee848SAlexander Motin ctl_report_all_rod_tokens(struct ctl_scsiio *ctsio) 242025eee848SAlexander Motin { 24219cbbfd2fSAlexander Motin struct ctl_softc *softc = CTL_SOFTC(ctsio); 242225eee848SAlexander Motin struct scsi_report_all_rod_tokens *cdb; 242325eee848SAlexander Motin struct scsi_report_all_rod_tokens_data *data; 242425eee848SAlexander Motin struct tpc_token *token; 242525eee848SAlexander Motin int retval; 242625eee848SAlexander Motin int alloc_len, total_len, tokens, i; 242725eee848SAlexander Motin 242825eee848SAlexander Motin CTL_DEBUG_PRINT(("ctl_receive_rod_token_information\n")); 242925eee848SAlexander Motin 243025eee848SAlexander Motin cdb = (struct scsi_report_all_rod_tokens *)ctsio->cdb; 243125eee848SAlexander Motin retval = CTL_RETVAL_COMPLETE; 243225eee848SAlexander Motin 243325eee848SAlexander Motin tokens = 0; 24342d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 24359602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) 243625eee848SAlexander Motin tokens++; 24372d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 243825eee848SAlexander Motin if (tokens > 512) 243925eee848SAlexander Motin tokens = 512; 244025eee848SAlexander Motin 244125eee848SAlexander Motin total_len = sizeof(*data) + tokens * 96; 244225eee848SAlexander Motin alloc_len = scsi_4btoul(cdb->length); 244325eee848SAlexander Motin 244425eee848SAlexander Motin ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO); 244525eee848SAlexander Motin ctsio->kern_sg_entries = 0; 244625eee848SAlexander Motin ctsio->kern_rel_offset = 0; 2447640603fbSAlexander Motin ctsio->kern_data_len = min(total_len, alloc_len); 2448640603fbSAlexander Motin ctsio->kern_total_len = ctsio->kern_data_len; 244925eee848SAlexander Motin 245025eee848SAlexander Motin data = (struct scsi_report_all_rod_tokens_data *)ctsio->kern_data_ptr; 245125eee848SAlexander Motin i = 0; 24522d8b2876SAlexander Motin mtx_lock(&softc->tpc_lock); 24539602f436SAlexander Motin TAILQ_FOREACH(token, &softc->tpc_tokens, links) { 245425eee848SAlexander Motin if (i >= tokens) 245525eee848SAlexander Motin break; 245625eee848SAlexander Motin memcpy(&data->rod_management_token_list[i * 96], 245725eee848SAlexander Motin token->token, 96); 245825eee848SAlexander Motin i++; 245925eee848SAlexander Motin } 24602d8b2876SAlexander Motin mtx_unlock(&softc->tpc_lock); 246125eee848SAlexander Motin scsi_ulto4b(sizeof(*data) - 4 + i * 96, data->available_data); 246225eee848SAlexander Motin /* 246325eee848SAlexander Motin printf("RART tokens=%d\n", i); 246425eee848SAlexander Motin */ 2465f7241cceSAlexander Motin ctl_set_success(ctsio); 246625eee848SAlexander Motin ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; 246725eee848SAlexander Motin ctsio->be_move_done = ctl_config_move_done; 246825eee848SAlexander Motin ctl_datamove((union ctl_io *)ctsio); 246925eee848SAlexander Motin return (retval); 247025eee848SAlexander Motin } 247125eee848SAlexander Motin 2472