1229997Sken/*- 2229997Sken * Copyright (c) 2004, 2005 Silicon Graphics International Corp. 3229997Sken * All rights reserved. 4229997Sken * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7229997Sken * are met: 8229997Sken * 1. Redistributions of source code must retain the above copyright 9229997Sken * notice, this list of conditions, and the following disclaimer, 10229997Sken * without modification. 11229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12229997Sken * substantially similar to the "NO WARRANTY" disclaimer below 13229997Sken * ("Disclaimer") and any redistribution must be conditioned upon 14229997Sken * including a substantially similar Disclaimer requirement for further 15229997Sken * binary redistribution. 16229997Sken * 17229997Sken * NO WARRANTY 18229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28229997Sken * POSSIBILITY OF SUCH DAMAGES. 29229997Sken * 30229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_internal.c#5 $ 31229997Sken */ 32229997Sken/* 33229997Sken * CTL kernel internal frontend target driver. This allows kernel-level 34229997Sken * clients to send commands into CTL. 35229997Sken * 36229997Sken * This has elements of a FETD (e.g. it has to set tag numbers, initiator, 37229997Sken * port, target, and LUN) and elements of an initiator (LUN discovery and 38229997Sken * probing, error recovery, command initiation). Even though this has some 39229997Sken * initiator type elements, this is not intended to be a full fledged 40229997Sken * initiator layer. It is only intended to send a limited number of 41229997Sken * commands to a well known target layer. 42229997Sken * 43229997Sken * To be able to fulfill the role of a full initiator layer, it would need 44229997Sken * a whole lot more functionality. 45229997Sken * 46229997Sken * Author: Ken Merry <ken@FreeBSD.org> 47229997Sken * 48229997Sken */ 49229997Sken 50229997Sken#include <sys/cdefs.h> 51229997Sken__FBSDID("$FreeBSD$"); 52229997Sken 53229997Sken#include <sys/param.h> 54229997Sken#include <sys/systm.h> 55229997Sken#include <sys/kernel.h> 56229997Sken#include <sys/types.h> 57229997Sken#include <sys/malloc.h> 58249009Strasz#include <sys/module.h> 59229997Sken#include <sys/lock.h> 60229997Sken#include <sys/mutex.h> 61229997Sken#include <sys/condvar.h> 62229997Sken#include <sys/queue.h> 63229997Sken#include <sys/sbuf.h> 64233963Sken#include <sys/sysctl.h> 65229997Sken#include <cam/scsi/scsi_all.h> 66229997Sken#include <cam/scsi/scsi_da.h> 67229997Sken#include <cam/ctl/ctl_io.h> 68229997Sken#include <cam/ctl/ctl.h> 69229997Sken#include <cam/ctl/ctl_frontend.h> 70229997Sken#include <cam/ctl/ctl_frontend_internal.h> 71229997Sken#include <cam/ctl/ctl_backend.h> 72229997Sken#include <cam/ctl/ctl_ioctl.h> 73229997Sken#include <cam/ctl/ctl_util.h> 74229997Sken#include <cam/ctl/ctl_ha.h> 75229997Sken#include <cam/ctl/ctl_private.h> 76229997Sken#include <cam/ctl/ctl_mem_pool.h> 77229997Sken#include <cam/ctl/ctl_debug.h> 78229997Sken#include <cam/ctl/ctl_scsi_all.h> 79229997Sken#include <cam/ctl/ctl_error.h> 80229997Sken 81229997Sken/* 82229997Sken * Task structure: 83229997Sken * - overall metatask, different potential metatask types (e.g. forced 84229997Sken * shutdown, gentle shutdown) 85229997Sken * - forced shutdown metatask: 86229997Sken * - states: report luns, pending, done? 87229997Sken * - list of luns pending, with the relevant I/O for that lun attached. 88229997Sken * This would allow moving ahead on LUNs with no errors, and going 89229997Sken * into error recovery on LUNs with problems. Per-LUN states might 90229997Sken * include inquiry, stop/offline, done. 91229997Sken * 92229997Sken * Use LUN enable for LUN list instead of getting it manually? We'd still 93229997Sken * need inquiry data for each LUN. 94229997Sken * 95229997Sken * How to handle processor LUN w.r.t. found/stopped counts? 96229997Sken */ 97229997Sken#ifdef oldapi 98229997Skentypedef enum { 99229997Sken CFI_TASK_NONE, 100229997Sken CFI_TASK_SHUTDOWN, 101229997Sken CFI_TASK_STARTUP 102229997Sken} cfi_tasktype; 103229997Sken 104229997Skenstruct cfi_task_startstop { 105229997Sken int total_luns; 106229997Sken int luns_complete; 107229997Sken int luns_failed; 108229997Sken cfi_cb_t callback; 109229997Sken void *callback_arg; 110229997Sken /* XXX KDM add more fields here */ 111229997Sken}; 112229997Sken 113229997Skenunion cfi_taskinfo { 114229997Sken struct cfi_task_startstop startstop; 115229997Sken}; 116229997Sken 117229997Skenstruct cfi_metatask { 118229997Sken cfi_tasktype tasktype; 119229997Sken cfi_mt_status status; 120229997Sken union cfi_taskinfo taskinfo; 121229997Sken struct ctl_mem_element *element; 122229997Sken void *cfi_context; 123229997Sken STAILQ_ENTRY(cfi_metatask) links; 124229997Sken}; 125229997Sken#endif 126229997Sken 127229997Skentypedef enum { 128229997Sken CFI_ERR_RETRY = 0x000, 129229997Sken CFI_ERR_FAIL = 0x001, 130229997Sken CFI_ERR_LUN_RESET = 0x002, 131229997Sken CFI_ERR_MASK = 0x0ff, 132229997Sken CFI_ERR_NO_DECREMENT = 0x100 133229997Sken} cfi_error_action; 134229997Sken 135229997Skentypedef enum { 136229997Sken CFI_ERR_SOFT, 137229997Sken CFI_ERR_HARD 138229997Sken} cfi_error_policy; 139229997Sken 140229997Skentypedef enum { 141229997Sken CFI_LUN_INQUIRY, 142229997Sken CFI_LUN_READCAPACITY, 143229997Sken CFI_LUN_READCAPACITY_16, 144229997Sken CFI_LUN_READY 145229997Sken} cfi_lun_state; 146229997Sken 147229997Skenstruct cfi_lun { 148229997Sken struct ctl_id target_id; 149229997Sken int lun_id; 150229997Sken struct scsi_inquiry_data inq_data; 151229997Sken uint64_t num_blocks; 152229997Sken uint32_t blocksize; 153229997Sken int blocksize_powerof2; 154229997Sken uint32_t cur_tag_num; 155229997Sken cfi_lun_state state; 156229997Sken struct ctl_mem_element *element; 157229997Sken struct cfi_softc *softc; 158229997Sken STAILQ_HEAD(, cfi_lun_io) io_list; 159229997Sken STAILQ_ENTRY(cfi_lun) links; 160229997Sken}; 161229997Sken 162229997Skenstruct cfi_lun_io { 163229997Sken struct cfi_lun *lun; 164229997Sken struct cfi_metatask *metatask; 165229997Sken cfi_error_policy policy; 166229997Sken void (*done_function)(union ctl_io *io); 167229997Sken union ctl_io *ctl_io; 168229997Sken struct cfi_lun_io *orig_lun_io; 169229997Sken STAILQ_ENTRY(cfi_lun_io) links; 170229997Sken}; 171229997Sken 172229997Skentypedef enum { 173229997Sken CFI_NONE = 0x00, 174229997Sken CFI_ONLINE = 0x01, 175229997Sken} cfi_flags; 176229997Sken 177229997Skenstruct cfi_softc { 178229997Sken struct ctl_frontend fe; 179229997Sken char fe_name[40]; 180229997Sken struct mtx lock; 181229997Sken cfi_flags flags; 182229997Sken STAILQ_HEAD(, cfi_lun) lun_list; 183229997Sken STAILQ_HEAD(, cfi_metatask) metatask_list; 184229997Sken struct ctl_mem_pool lun_pool; 185229997Sken struct ctl_mem_pool metatask_pool; 186229997Sken}; 187229997Sken 188229997SkenMALLOC_DEFINE(M_CTL_CFI, "ctlcfi", "CTL CFI"); 189229997Sken 190229997Skenstatic struct cfi_softc fetd_internal_softc; 191229997Sken 192249009Straszint cfi_init(void); 193229997Skenvoid cfi_shutdown(void) __unused; 194229997Skenstatic void cfi_online(void *arg); 195229997Skenstatic void cfi_offline(void *arg); 196229997Skenstatic int cfi_targ_enable(void *arg, struct ctl_id targ_id); 197229997Skenstatic int cfi_targ_disable(void *arg, struct ctl_id targ_id); 198229997Skenstatic int cfi_lun_enable(void *arg, struct ctl_id target_id, int lun_id); 199229997Skenstatic int cfi_lun_disable(void *arg, struct ctl_id target_id, int lun_id); 200229997Skenstatic void cfi_datamove(union ctl_io *io); 201229997Skenstatic cfi_error_action cfi_checkcond_parse(union ctl_io *io, 202229997Sken struct cfi_lun_io *lun_io); 203229997Skenstatic cfi_error_action cfi_error_parse(union ctl_io *io, 204229997Sken struct cfi_lun_io *lun_io); 205229997Skenstatic void cfi_init_io(union ctl_io *io, struct cfi_lun *lun, 206229997Sken struct cfi_metatask *metatask, cfi_error_policy policy, 207229997Sken int retries, struct cfi_lun_io *orig_lun_io, 208229997Sken void (*done_function)(union ctl_io *io)); 209229997Skenstatic void cfi_done(union ctl_io *io); 210229997Skenstatic void cfi_lun_probe_done(union ctl_io *io); 211229997Skenstatic void cfi_lun_probe(struct cfi_lun *lun, int have_lock); 212229997Skenstatic void cfi_metatask_done(struct cfi_softc *softc, 213229997Sken struct cfi_metatask *metatask); 214229997Skenstatic void cfi_metatask_bbr_errorparse(struct cfi_metatask *metatask, 215229997Sken union ctl_io *io); 216229997Skenstatic void cfi_metatask_io_done(union ctl_io *io); 217229997Skenstatic void cfi_err_recovery_done(union ctl_io *io); 218229997Skenstatic void cfi_lun_io_done(union ctl_io *io); 219229997Sken 220249009Straszstatic int cfi_module_event_handler(module_t, int /*modeventtype_t*/, void *); 221229997Sken 222249009Straszstatic moduledata_t cfi_moduledata = { 223249009Strasz "ctlcfi", 224249009Strasz cfi_module_event_handler, 225249009Strasz NULL 226249009Strasz}; 227249009Strasz 228249009StraszDECLARE_MODULE(ctlcfi, cfi_moduledata, SI_SUB_CONFIGURE, SI_ORDER_FOURTH); 229249009StraszMODULE_VERSION(ctlcfi, 1); 230249009StraszMODULE_DEPEND(ctlcfi, ctl, 1, 1, 1); 231249009Strasz 232249009Straszint 233229997Skencfi_init(void) 234229997Sken{ 235229997Sken struct cfi_softc *softc; 236229997Sken struct ctl_frontend *fe; 237229997Sken int retval; 238229997Sken 239229997Sken softc = &fetd_internal_softc; 240229997Sken 241229997Sken fe = &softc->fe; 242229997Sken 243229997Sken retval = 0; 244229997Sken 245229997Sken if (sizeof(struct cfi_lun_io) > CTL_PORT_PRIV_SIZE) { 246229997Sken printf("%s: size of struct cfi_lun_io %zd > " 247229997Sken "CTL_PORT_PRIV_SIZE %d\n", __func__, 248229997Sken sizeof(struct cfi_lun_io), 249229997Sken CTL_PORT_PRIV_SIZE); 250229997Sken } 251250131Seadler memset(softc, 0, sizeof(*softc)); 252229997Sken 253229997Sken mtx_init(&softc->lock, "CTL frontend mutex", NULL, MTX_DEF); 254229997Sken softc->flags |= CTL_FLAG_MASTER_SHELF; 255229997Sken 256229997Sken STAILQ_INIT(&softc->lun_list); 257229997Sken STAILQ_INIT(&softc->metatask_list); 258229997Sken sprintf(softc->fe_name, "CTL internal"); 259229997Sken fe->port_type = CTL_PORT_INTERNAL; 260229997Sken fe->num_requested_ctl_io = 100; 261229997Sken fe->port_name = softc->fe_name; 262229997Sken fe->port_online = cfi_online; 263229997Sken fe->port_offline = cfi_offline; 264229997Sken fe->onoff_arg = softc; 265229997Sken fe->targ_enable = cfi_targ_enable; 266229997Sken fe->targ_disable = cfi_targ_disable; 267229997Sken fe->lun_enable = cfi_lun_enable; 268229997Sken fe->lun_disable = cfi_lun_disable; 269229997Sken fe->targ_lun_arg = softc; 270229997Sken fe->fe_datamove = cfi_datamove; 271229997Sken fe->fe_done = cfi_done; 272229997Sken fe->max_targets = 15; 273229997Sken fe->max_target_id = 15; 274229997Sken 275229997Sken if (ctl_frontend_register(fe, (softc->flags & CTL_FLAG_MASTER_SHELF)) != 0) 276229997Sken { 277229997Sken printf("%s: internal frontend registration failed\n", __func__); 278229997Sken retval = 1; 279229997Sken goto bailout; 280229997Sken } 281229997Sken 282229997Sken if (ctl_init_mem_pool(&softc->lun_pool, 283229997Sken sizeof(struct cfi_lun), 284229997Sken CTL_MEM_POOL_PERM_GROW, /*grow_inc*/ 3, 285229997Sken /* initial_pool_size */ CTL_MAX_LUNS) != 0) { 286229997Sken printf("%s: can't initialize LUN memory pool\n", __func__); 287229997Sken retval = 1; 288229997Sken goto bailout_error; 289229997Sken } 290229997Sken 291229997Sken if (ctl_init_mem_pool(&softc->metatask_pool, 292229997Sken sizeof(struct cfi_metatask), 293229997Sken CTL_MEM_POOL_PERM_GROW, /*grow_inc*/ 3, 294229997Sken /*initial_pool_size*/ 10) != 0) { 295229997Sken printf("%s: can't initialize metatask memory pool\n", __func__); 296229997Sken retval = 2; 297229997Sken goto bailout_error; 298229997Sken } 299229997Skenbailout: 300229997Sken 301249009Strasz return (0); 302229997Sken 303229997Skenbailout_error: 304229997Sken 305229997Sken switch (retval) { 306229997Sken case 3: 307229997Sken ctl_shrink_mem_pool(&softc->metatask_pool); 308229997Sken /* FALLTHROUGH */ 309229997Sken case 2: 310229997Sken ctl_shrink_mem_pool(&softc->lun_pool); 311229997Sken /* FALLTHROUGH */ 312229997Sken case 1: 313229997Sken ctl_frontend_deregister(fe); 314229997Sken break; 315229997Sken default: 316229997Sken break; 317229997Sken } 318249009Strasz 319249009Strasz return (ENOMEM); 320229997Sken} 321229997Sken 322229997Skenvoid 323229997Skencfi_shutdown(void) 324229997Sken{ 325229997Sken struct cfi_softc *softc; 326229997Sken 327229997Sken softc = &fetd_internal_softc; 328229997Sken 329229997Sken /* 330229997Sken * XXX KDM need to clear out any I/O pending on each LUN. 331229997Sken */ 332229997Sken if (ctl_frontend_deregister(&softc->fe) != 0) 333229997Sken printf("%s: ctl_frontend_deregister() failed\n", __func__); 334229997Sken 335229997Sken if (ctl_shrink_mem_pool(&softc->lun_pool) != 0) 336229997Sken printf("%s: error shrinking LUN pool\n", __func__); 337229997Sken 338229997Sken if (ctl_shrink_mem_pool(&softc->metatask_pool) != 0) 339229997Sken printf("%s: error shrinking LUN pool\n", __func__); 340229997Sken} 341229997Sken 342249009Straszstatic int 343249009Straszcfi_module_event_handler(module_t mod, int what, void *arg) 344249009Strasz{ 345249009Strasz 346249009Strasz switch (what) { 347249009Strasz case MOD_LOAD: 348249009Strasz return (cfi_init()); 349249009Strasz case MOD_UNLOAD: 350249009Strasz return (EBUSY); 351249009Strasz default: 352249009Strasz return (EOPNOTSUPP); 353249009Strasz } 354249009Strasz} 355249009Strasz 356229997Skenstatic void 357229997Skencfi_online(void *arg) 358229997Sken{ 359229997Sken struct cfi_softc *softc; 360229997Sken struct cfi_lun *lun; 361229997Sken 362229997Sken softc = (struct cfi_softc *)arg; 363229997Sken 364229997Sken softc->flags |= CFI_ONLINE; 365229997Sken 366229997Sken /* 367229997Sken * Go through and kick off the probe for each lun. Should we check 368229997Sken * the LUN flags here to determine whether or not to probe it? 369229997Sken */ 370229997Sken mtx_lock(&softc->lock); 371229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) 372229997Sken cfi_lun_probe(lun, /*have_lock*/ 1); 373229997Sken mtx_unlock(&softc->lock); 374229997Sken} 375229997Sken 376229997Skenstatic void 377229997Skencfi_offline(void *arg) 378229997Sken{ 379229997Sken struct cfi_softc *softc; 380229997Sken 381229997Sken softc = (struct cfi_softc *)arg; 382229997Sken 383229997Sken softc->flags &= ~CFI_ONLINE; 384229997Sken} 385229997Sken 386229997Skenstatic int 387229997Skencfi_targ_enable(void *arg, struct ctl_id targ_id) 388229997Sken{ 389229997Sken return (0); 390229997Sken} 391229997Sken 392229997Skenstatic int 393229997Skencfi_targ_disable(void *arg, struct ctl_id targ_id) 394229997Sken{ 395229997Sken return (0); 396229997Sken} 397229997Sken 398229997Skenstatic int 399229997Skencfi_lun_enable(void *arg, struct ctl_id target_id, int lun_id) 400229997Sken{ 401229997Sken struct ctl_mem_element *element; 402229997Sken struct cfi_softc *softc; 403229997Sken struct cfi_lun *lun; 404229997Sken int found; 405229997Sken 406229997Sken softc = (struct cfi_softc *)arg; 407229997Sken 408229997Sken found = 0; 409229997Sken mtx_lock(&softc->lock); 410229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) { 411229997Sken if ((lun->target_id.id == target_id.id) 412229997Sken && (lun->lun_id == lun_id)) { 413229997Sken found = 1; 414229997Sken break; 415229997Sken } 416229997Sken } 417229997Sken mtx_unlock(&softc->lock); 418229997Sken 419229997Sken /* 420229997Sken * If we already have this target/LUN, there is no reason to add 421229997Sken * it to our lists again. 422229997Sken */ 423229997Sken if (found != 0) 424229997Sken return (0); 425229997Sken 426229997Sken element = ctl_alloc_mem_element(&softc->lun_pool, /*can_wait*/ 0); 427229997Sken 428229997Sken if (element == NULL) { 429229997Sken printf("%s: unable to allocate LUN structure\n", __func__); 430229997Sken return (1); 431229997Sken } 432229997Sken 433229997Sken lun = (struct cfi_lun *)element->bytes; 434229997Sken 435229997Sken lun->element = element; 436229997Sken lun->target_id = target_id; 437229997Sken lun->lun_id = lun_id; 438229997Sken lun->cur_tag_num = 0; 439229997Sken lun->state = CFI_LUN_INQUIRY; 440229997Sken lun->softc = softc; 441229997Sken STAILQ_INIT(&lun->io_list); 442229997Sken 443229997Sken mtx_lock(&softc->lock); 444229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, lun, links); 445229997Sken mtx_unlock(&softc->lock); 446229997Sken 447229997Sken cfi_lun_probe(lun, /*have_lock*/ 0); 448229997Sken 449229997Sken return (0); 450229997Sken} 451229997Sken 452229997Skenstatic int 453229997Skencfi_lun_disable(void *arg, struct ctl_id target_id, int lun_id) 454229997Sken{ 455229997Sken struct cfi_softc *softc; 456229997Sken struct cfi_lun *lun; 457229997Sken int found; 458229997Sken 459229997Sken softc = (struct cfi_softc *)arg; 460229997Sken 461229997Sken found = 0; 462229997Sken 463229997Sken /* 464229997Sken * XXX KDM need to do an invalidate and then a free when any 465229997Sken * pending I/O has completed. Or do we? CTL won't free a LUN 466229997Sken * while any I/O is pending. So we won't get this notification 467229997Sken * unless any I/O we have pending on a LUN has completed. 468229997Sken */ 469229997Sken mtx_lock(&softc->lock); 470229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) { 471229997Sken if ((lun->target_id.id == target_id.id) 472229997Sken && (lun->lun_id == lun_id)) { 473229997Sken found = 1; 474229997Sken break; 475229997Sken } 476229997Sken } 477229997Sken if (found != 0) 478229997Sken STAILQ_REMOVE(&softc->lun_list, lun, cfi_lun, links); 479229997Sken 480229997Sken mtx_unlock(&softc->lock); 481229997Sken 482229997Sken if (found == 0) { 483229997Sken printf("%s: can't find target %ju lun %d\n", __func__, 484229997Sken (uintmax_t)target_id.id, lun_id); 485229997Sken return (1); 486229997Sken } 487229997Sken 488229997Sken ctl_free_mem_element(lun->element); 489229997Sken 490229997Sken return (0); 491229997Sken} 492229997Sken 493229997Skenstatic void 494229997Skencfi_datamove(union ctl_io *io) 495229997Sken{ 496229997Sken struct ctl_sg_entry *ext_sglist, *kern_sglist; 497229997Sken struct ctl_sg_entry ext_entry, kern_entry; 498229997Sken int ext_sglen, ext_sg_entries, kern_sg_entries; 499229997Sken int ext_sg_start, ext_offset; 500229997Sken int len_to_copy, len_copied; 501229997Sken int kern_watermark, ext_watermark; 502229997Sken int ext_sglist_malloced; 503229997Sken struct ctl_scsiio *ctsio; 504229997Sken int i, j; 505229997Sken 506229997Sken ext_sglist_malloced = 0; 507229997Sken ext_sg_start = 0; 508229997Sken ext_offset = 0; 509229997Sken ext_sglist = NULL; 510229997Sken 511229997Sken CTL_DEBUG_PRINT(("%s\n", __func__)); 512229997Sken 513229997Sken ctsio = &io->scsiio; 514229997Sken 515229997Sken /* 516229997Sken * If this is the case, we're probably doing a BBR read and don't 517229997Sken * actually need to transfer the data. This will effectively 518229997Sken * bit-bucket the data. 519229997Sken */ 520229997Sken if (ctsio->ext_data_ptr == NULL) 521229997Sken goto bailout; 522229997Sken 523229997Sken /* 524229997Sken * To simplify things here, if we have a single buffer, stick it in 525229997Sken * a S/G entry and just make it a single entry S/G list. 526229997Sken */ 527229997Sken if (ctsio->io_hdr.flags & CTL_FLAG_EDPTR_SGLIST) { 528229997Sken int len_seen; 529229997Sken 530229997Sken ext_sglen = ctsio->ext_sg_entries * sizeof(*ext_sglist); 531229997Sken 532229997Sken ext_sglist = (struct ctl_sg_entry *)malloc(ext_sglen, M_CTL_CFI, 533229997Sken M_WAITOK); 534229997Sken ext_sglist_malloced = 1; 535229997Sken if (memcpy(ext_sglist, ctsio->ext_data_ptr, ext_sglen) != 0) { 536229997Sken ctl_set_internal_failure(ctsio, 537229997Sken /*sks_valid*/ 0, 538229997Sken /*retry_count*/ 0); 539229997Sken goto bailout; 540229997Sken } 541229997Sken ext_sg_entries = ctsio->ext_sg_entries; 542229997Sken len_seen = 0; 543229997Sken for (i = 0; i < ext_sg_entries; i++) { 544229997Sken if ((len_seen + ext_sglist[i].len) >= 545229997Sken ctsio->ext_data_filled) { 546229997Sken ext_sg_start = i; 547229997Sken ext_offset = ctsio->ext_data_filled - len_seen; 548229997Sken break; 549229997Sken } 550229997Sken len_seen += ext_sglist[i].len; 551229997Sken } 552229997Sken } else { 553229997Sken ext_sglist = &ext_entry; 554229997Sken ext_sglist->addr = ctsio->ext_data_ptr; 555229997Sken ext_sglist->len = ctsio->ext_data_len; 556229997Sken ext_sg_entries = 1; 557229997Sken ext_sg_start = 0; 558229997Sken ext_offset = ctsio->ext_data_filled; 559229997Sken } 560229997Sken 561229997Sken if (ctsio->kern_sg_entries > 0) { 562229997Sken kern_sglist = (struct ctl_sg_entry *)ctsio->kern_data_ptr; 563229997Sken kern_sg_entries = ctsio->kern_sg_entries; 564229997Sken } else { 565229997Sken kern_sglist = &kern_entry; 566229997Sken kern_sglist->addr = ctsio->kern_data_ptr; 567229997Sken kern_sglist->len = ctsio->kern_data_len; 568229997Sken kern_sg_entries = 1; 569229997Sken } 570229997Sken 571229997Sken 572229997Sken kern_watermark = 0; 573229997Sken ext_watermark = ext_offset; 574229997Sken len_copied = 0; 575229997Sken for (i = ext_sg_start, j = 0; 576229997Sken i < ext_sg_entries && j < kern_sg_entries;) { 577229997Sken uint8_t *ext_ptr, *kern_ptr; 578229997Sken 579229997Sken len_to_copy = ctl_min(ext_sglist[i].len - ext_watermark, 580229997Sken kern_sglist[j].len - kern_watermark); 581229997Sken 582229997Sken ext_ptr = (uint8_t *)ext_sglist[i].addr; 583229997Sken ext_ptr = ext_ptr + ext_watermark; 584229997Sken if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) { 585229997Sken /* 586229997Sken * XXX KDM fix this! 587229997Sken */ 588229997Sken panic("need to implement bus address support"); 589229997Sken#if 0 590229997Sken kern_ptr = bus_to_virt(kern_sglist[j].addr); 591229997Sken#endif 592229997Sken } else 593229997Sken kern_ptr = (uint8_t *)kern_sglist[j].addr; 594229997Sken kern_ptr = kern_ptr + kern_watermark; 595229997Sken 596229997Sken kern_watermark += len_to_copy; 597229997Sken ext_watermark += len_to_copy; 598229997Sken 599229997Sken if ((ctsio->io_hdr.flags & CTL_FLAG_DATA_MASK) == 600229997Sken CTL_FLAG_DATA_IN) { 601229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes to user\n", 602229997Sken __func__, len_to_copy)); 603229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__, 604229997Sken kern_ptr, ext_ptr)); 605229997Sken memcpy(ext_ptr, kern_ptr, len_to_copy); 606229997Sken } else { 607229997Sken CTL_DEBUG_PRINT(("%s: copying %d bytes from user\n", 608229997Sken __func__, len_to_copy)); 609229997Sken CTL_DEBUG_PRINT(("%s: from %p to %p\n", __func__, 610229997Sken ext_ptr, kern_ptr)); 611229997Sken memcpy(kern_ptr, ext_ptr, len_to_copy); 612229997Sken } 613229997Sken 614229997Sken len_copied += len_to_copy; 615229997Sken 616229997Sken if (ext_sglist[i].len == ext_watermark) { 617229997Sken i++; 618229997Sken ext_watermark = 0; 619229997Sken } 620229997Sken 621229997Sken if (kern_sglist[j].len == kern_watermark) { 622229997Sken j++; 623229997Sken kern_watermark = 0; 624229997Sken } 625229997Sken } 626229997Sken 627229997Sken ctsio->ext_data_filled += len_copied; 628229997Sken 629229997Sken CTL_DEBUG_PRINT(("%s: ext_sg_entries: %d, kern_sg_entries: %d\n", 630229997Sken __func__, ext_sg_entries, kern_sg_entries)); 631229997Sken CTL_DEBUG_PRINT(("%s: ext_data_len = %d, kern_data_len = %d\n", 632229997Sken __func__, ctsio->ext_data_len, ctsio->kern_data_len)); 633229997Sken 634229997Sken 635229997Sken /* XXX KDM set residual?? */ 636229997Skenbailout: 637229997Sken 638229997Sken if (ext_sglist_malloced != 0) 639229997Sken free(ext_sglist, M_CTL_CFI); 640229997Sken 641229997Sken io->scsiio.be_move_done(io); 642229997Sken 643229997Sken return; 644229997Sken} 645229997Sken 646229997Sken/* 647229997Sken * For any sort of check condition, busy, etc., we just retry. We do not 648229997Sken * decrement the retry count for unit attention type errors. These are 649229997Sken * normal, and we want to save the retry count for "real" errors. Otherwise, 650229997Sken * we could end up with situations where a command will succeed in some 651229997Sken * situations and fail in others, depending on whether a unit attention is 652229997Sken * pending. Also, some of our error recovery actions, most notably the 653229997Sken * LUN reset action, will cause a unit attention. 654229997Sken * 655229997Sken * We can add more detail here later if necessary. 656229997Sken */ 657229997Skenstatic cfi_error_action 658229997Skencfi_checkcond_parse(union ctl_io *io, struct cfi_lun_io *lun_io) 659229997Sken{ 660229997Sken cfi_error_action error_action; 661229997Sken int error_code, sense_key, asc, ascq; 662229997Sken 663229997Sken /* 664229997Sken * Default to retrying the command. 665229997Sken */ 666229997Sken error_action = CFI_ERR_RETRY; 667229997Sken 668229997Sken scsi_extract_sense_len(&io->scsiio.sense_data, 669229997Sken io->scsiio.sense_len, 670229997Sken &error_code, 671229997Sken &sense_key, 672229997Sken &asc, 673229997Sken &ascq, 674229997Sken /*show_errors*/ 1); 675229997Sken 676229997Sken switch (error_code) { 677229997Sken case SSD_DEFERRED_ERROR: 678229997Sken case SSD_DESC_DEFERRED_ERROR: 679229997Sken error_action |= CFI_ERR_NO_DECREMENT; 680229997Sken break; 681229997Sken case SSD_CURRENT_ERROR: 682229997Sken case SSD_DESC_CURRENT_ERROR: 683229997Sken default: { 684229997Sken switch (sense_key) { 685229997Sken case SSD_KEY_UNIT_ATTENTION: 686229997Sken error_action |= CFI_ERR_NO_DECREMENT; 687229997Sken break; 688229997Sken case SSD_KEY_HARDWARE_ERROR: 689229997Sken /* 690229997Sken * This is our generic "something bad happened" 691229997Sken * error code. It often isn't recoverable. 692229997Sken */ 693229997Sken if ((asc == 0x44) && (ascq == 0x00)) 694229997Sken error_action = CFI_ERR_FAIL; 695229997Sken break; 696229997Sken case SSD_KEY_NOT_READY: 697229997Sken /* 698229997Sken * If the LUN is powered down, there likely isn't 699229997Sken * much point in retrying right now. 700229997Sken */ 701229997Sken if ((asc == 0x04) && (ascq == 0x02)) 702229997Sken error_action = CFI_ERR_FAIL; 703229997Sken /* 704229997Sken * If the LUN is offline, there probably isn't much 705229997Sken * point in retrying, either. 706229997Sken */ 707229997Sken if ((asc == 0x04) && (ascq == 0x03)) 708229997Sken error_action = CFI_ERR_FAIL; 709229997Sken break; 710229997Sken } 711229997Sken } 712229997Sken } 713229997Sken 714229997Sken return (error_action); 715229997Sken} 716229997Sken 717229997Skenstatic cfi_error_action 718229997Skencfi_error_parse(union ctl_io *io, struct cfi_lun_io *lun_io) 719229997Sken{ 720229997Sken cfi_error_action error_action; 721229997Sken 722229997Sken error_action = CFI_ERR_RETRY; 723229997Sken 724229997Sken switch (io->io_hdr.io_type) { 725229997Sken case CTL_IO_SCSI: 726229997Sken switch (io->io_hdr.status & CTL_STATUS_MASK) { 727229997Sken case CTL_SCSI_ERROR: 728229997Sken switch (io->scsiio.scsi_status) { 729229997Sken case SCSI_STATUS_RESERV_CONFLICT: 730229997Sken /* 731229997Sken * For a reservation conflict, we'll usually 732229997Sken * want the hard error recovery policy, so 733229997Sken * we'll reset the LUN. 734229997Sken */ 735229997Sken if (lun_io->policy == CFI_ERR_HARD) 736229997Sken error_action = 737229997Sken CFI_ERR_LUN_RESET; 738229997Sken else 739229997Sken error_action = 740229997Sken CFI_ERR_RETRY; 741229997Sken break; 742229997Sken case SCSI_STATUS_CHECK_COND: 743229997Sken default: 744229997Sken error_action = cfi_checkcond_parse(io, lun_io); 745229997Sken break; 746229997Sken } 747229997Sken break; 748229997Sken default: 749229997Sken error_action = CFI_ERR_RETRY; 750229997Sken break; 751229997Sken } 752229997Sken break; 753229997Sken case CTL_IO_TASK: 754229997Sken /* 755229997Sken * In theory task management commands shouldn't fail... 756229997Sken */ 757229997Sken error_action = CFI_ERR_RETRY; 758229997Sken break; 759229997Sken default: 760229997Sken printf("%s: invalid ctl_io type %d\n", __func__, 761229997Sken io->io_hdr.io_type); 762229997Sken panic("%s: invalid ctl_io type %d\n", __func__, 763229997Sken io->io_hdr.io_type); 764229997Sken break; 765229997Sken } 766229997Sken 767229997Sken return (error_action); 768229997Sken} 769229997Sken 770229997Skenstatic void 771229997Skencfi_init_io(union ctl_io *io, struct cfi_lun *lun, 772229997Sken struct cfi_metatask *metatask, cfi_error_policy policy, int retries, 773229997Sken struct cfi_lun_io *orig_lun_io, 774229997Sken void (*done_function)(union ctl_io *io)) 775229997Sken{ 776229997Sken struct cfi_lun_io *lun_io; 777229997Sken 778229997Sken io->io_hdr.nexus.initid.id = 7; 779229997Sken io->io_hdr.nexus.targ_port = lun->softc->fe.targ_port; 780229997Sken io->io_hdr.nexus.targ_target.id = lun->target_id.id; 781229997Sken io->io_hdr.nexus.targ_lun = lun->lun_id; 782229997Sken io->io_hdr.retries = retries; 783229997Sken lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv; 784229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = lun_io; 785229997Sken lun_io->lun = lun; 786229997Sken lun_io->metatask = metatask; 787229997Sken lun_io->ctl_io = io; 788229997Sken lun_io->policy = policy; 789229997Sken lun_io->orig_lun_io = orig_lun_io; 790229997Sken lun_io->done_function = done_function; 791229997Sken /* 792229997Sken * We only set the tag number for SCSI I/Os. For task management 793229997Sken * commands, the tag number is only really needed for aborts, so 794229997Sken * the caller can set it if necessary. 795229997Sken */ 796229997Sken switch (io->io_hdr.io_type) { 797229997Sken case CTL_IO_SCSI: 798229997Sken io->scsiio.tag_num = lun->cur_tag_num++; 799229997Sken break; 800229997Sken case CTL_IO_TASK: 801229997Sken default: 802229997Sken break; 803229997Sken } 804229997Sken} 805229997Sken 806229997Skenstatic void 807229997Skencfi_done(union ctl_io *io) 808229997Sken{ 809229997Sken struct cfi_lun_io *lun_io; 810229997Sken struct cfi_softc *softc; 811229997Sken struct cfi_lun *lun; 812229997Sken 813229997Sken lun_io = (struct cfi_lun_io *) 814229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 815229997Sken 816229997Sken lun = lun_io->lun; 817229997Sken softc = lun->softc; 818229997Sken 819229997Sken /* 820229997Sken * Very minimal retry logic. We basically retry if we got an error 821229997Sken * back, and the retry count is greater than 0. If we ever want 822229997Sken * more sophisticated initiator type behavior, the CAM error 823229997Sken * recovery code in ../common might be helpful. 824229997Sken */ 825229997Sken if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) 826229997Sken && (io->io_hdr.retries > 0)) { 827229997Sken ctl_io_status old_status; 828229997Sken cfi_error_action error_action; 829229997Sken 830229997Sken error_action = cfi_error_parse(io, lun_io); 831229997Sken 832229997Sken switch (error_action & CFI_ERR_MASK) { 833229997Sken case CFI_ERR_FAIL: 834229997Sken goto done; 835229997Sken break; /* NOTREACHED */ 836229997Sken case CFI_ERR_LUN_RESET: { 837229997Sken union ctl_io *new_io; 838229997Sken struct cfi_lun_io *new_lun_io; 839229997Sken 840229997Sken new_io = ctl_alloc_io(softc->fe.ctl_pool_ref); 841229997Sken if (new_io == NULL) { 842229997Sken printf("%s: unable to allocate ctl_io for " 843229997Sken "error recovery\n", __func__); 844229997Sken goto done; 845229997Sken } 846229997Sken ctl_zero_io(new_io); 847229997Sken 848229997Sken new_io->io_hdr.io_type = CTL_IO_TASK; 849229997Sken new_io->taskio.task_action = CTL_TASK_LUN_RESET; 850229997Sken 851229997Sken cfi_init_io(new_io, 852229997Sken /*lun*/ lun_io->lun, 853229997Sken /*metatask*/ NULL, 854229997Sken /*policy*/ CFI_ERR_SOFT, 855229997Sken /*retries*/ 0, 856229997Sken /*orig_lun_io*/lun_io, 857229997Sken /*done_function*/ cfi_err_recovery_done); 858229997Sken 859229997Sken 860229997Sken new_lun_io = (struct cfi_lun_io *) 861229997Sken new_io->io_hdr.port_priv; 862229997Sken 863229997Sken mtx_lock(&lun->softc->lock); 864229997Sken STAILQ_INSERT_TAIL(&lun->io_list, new_lun_io, links); 865229997Sken mtx_unlock(&lun->softc->lock); 866229997Sken 867229997Sken io = new_io; 868229997Sken break; 869229997Sken } 870229997Sken case CFI_ERR_RETRY: 871229997Sken default: 872229997Sken if ((error_action & CFI_ERR_NO_DECREMENT) == 0) 873229997Sken io->io_hdr.retries--; 874229997Sken break; 875229997Sken } 876229997Sken 877229997Sken old_status = io->io_hdr.status; 878229997Sken io->io_hdr.status = CTL_STATUS_NONE; 879229997Sken#if 0 880229997Sken io->io_hdr.flags &= ~CTL_FLAG_ALREADY_DONE; 881229997Sken#endif 882229997Sken io->io_hdr.flags &= ~CTL_FLAG_ABORT; 883229997Sken io->io_hdr.flags &= ~CTL_FLAG_SENT_2OTHER_SC; 884229997Sken 885229997Sken if (ctl_queue(io) != CTL_RETVAL_COMPLETE) { 886229997Sken printf("%s: error returned from ctl_queue()!\n", 887229997Sken __func__); 888229997Sken io->io_hdr.status = old_status; 889229997Sken } else 890229997Sken return; 891229997Sken } 892229997Skendone: 893229997Sken lun_io->done_function(io); 894229997Sken} 895229997Sken 896229997Skenstatic void 897229997Skencfi_lun_probe_done(union ctl_io *io) 898229997Sken{ 899229997Sken struct cfi_lun *lun; 900229997Sken struct cfi_lun_io *lun_io; 901229997Sken 902229997Sken lun_io = (struct cfi_lun_io *) 903229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 904229997Sken lun = lun_io->lun; 905229997Sken 906229997Sken switch (lun->state) { 907229997Sken case CFI_LUN_INQUIRY: { 908229997Sken if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) { 909229997Sken /* print out something here?? */ 910229997Sken printf("%s: LUN %d probe failed because inquiry " 911229997Sken "failed\n", __func__, lun->lun_id); 912229997Sken ctl_io_error_print(io, NULL); 913229997Sken } else { 914229997Sken 915229997Sken if (SID_TYPE(&lun->inq_data) != T_DIRECT) { 916229997Sken char path_str[40]; 917229997Sken 918229997Sken lun->state = CFI_LUN_READY; 919229997Sken ctl_scsi_path_string(io, path_str, 920229997Sken sizeof(path_str)); 921229997Sken printf("%s", path_str); 922229997Sken scsi_print_inquiry(&lun->inq_data); 923229997Sken } else { 924229997Sken lun->state = CFI_LUN_READCAPACITY; 925229997Sken cfi_lun_probe(lun, /*have_lock*/ 0); 926229997Sken } 927229997Sken } 928229997Sken mtx_lock(&lun->softc->lock); 929229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 930229997Sken mtx_unlock(&lun->softc->lock); 931229997Sken ctl_free_io(io); 932229997Sken break; 933229997Sken } 934229997Sken case CFI_LUN_READCAPACITY: 935229997Sken case CFI_LUN_READCAPACITY_16: { 936229997Sken uint64_t maxlba; 937229997Sken uint32_t blocksize; 938229997Sken 939229997Sken maxlba = 0; 940229997Sken blocksize = 0; 941229997Sken 942229997Sken if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS) { 943229997Sken printf("%s: LUN %d probe failed because READ CAPACITY " 944229997Sken "failed\n", __func__, lun->lun_id); 945229997Sken ctl_io_error_print(io, NULL); 946229997Sken } else { 947229997Sken 948229997Sken if (lun->state == CFI_LUN_READCAPACITY) { 949229997Sken struct scsi_read_capacity_data *rdcap; 950229997Sken 951229997Sken rdcap = (struct scsi_read_capacity_data *) 952229997Sken io->scsiio.ext_data_ptr; 953229997Sken 954229997Sken maxlba = scsi_4btoul(rdcap->addr); 955229997Sken blocksize = scsi_4btoul(rdcap->length); 956229997Sken if (blocksize == 0) { 957229997Sken printf("%s: LUN %d has invalid " 958229997Sken "blocksize 0, probe aborted\n", 959229997Sken __func__, lun->lun_id); 960229997Sken } else if (maxlba == 0xffffffff) { 961229997Sken lun->state = CFI_LUN_READCAPACITY_16; 962229997Sken cfi_lun_probe(lun, /*have_lock*/ 0); 963229997Sken } else 964229997Sken lun->state = CFI_LUN_READY; 965229997Sken } else { 966229997Sken struct scsi_read_capacity_data_long *rdcap_long; 967229997Sken 968229997Sken rdcap_long = (struct 969229997Sken scsi_read_capacity_data_long *) 970229997Sken io->scsiio.ext_data_ptr; 971229997Sken maxlba = scsi_8btou64(rdcap_long->addr); 972229997Sken blocksize = scsi_4btoul(rdcap_long->length); 973229997Sken 974229997Sken if (blocksize == 0) { 975229997Sken printf("%s: LUN %d has invalid " 976229997Sken "blocksize 0, probe aborted\n", 977229997Sken __func__, lun->lun_id); 978229997Sken } else 979229997Sken lun->state = CFI_LUN_READY; 980229997Sken } 981229997Sken } 982229997Sken 983229997Sken if (lun->state == CFI_LUN_READY) { 984229997Sken char path_str[40]; 985229997Sken 986229997Sken lun->num_blocks = maxlba + 1; 987229997Sken lun->blocksize = blocksize; 988229997Sken 989229997Sken /* 990229997Sken * If this is true, the blocksize is a power of 2. 991229997Sken * We already checked for 0 above. 992229997Sken */ 993229997Sken if (((blocksize - 1) & blocksize) == 0) { 994229997Sken int i; 995229997Sken 996229997Sken for (i = 0; i < 32; i++) { 997229997Sken if ((blocksize & (1 << i)) != 0) { 998229997Sken lun->blocksize_powerof2 = i; 999229997Sken break; 1000229997Sken } 1001229997Sken } 1002229997Sken } 1003229997Sken ctl_scsi_path_string(io, path_str,sizeof(path_str)); 1004229997Sken printf("%s", path_str); 1005229997Sken scsi_print_inquiry(&lun->inq_data); 1006229997Sken printf("%s %ju blocks, blocksize %d\n", path_str, 1007229997Sken (uintmax_t)maxlba + 1, blocksize); 1008229997Sken } 1009229997Sken mtx_lock(&lun->softc->lock); 1010229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1011229997Sken mtx_unlock(&lun->softc->lock); 1012229997Sken free(io->scsiio.ext_data_ptr, M_CTL_CFI); 1013229997Sken ctl_free_io(io); 1014229997Sken break; 1015229997Sken } 1016229997Sken case CFI_LUN_READY: 1017229997Sken default: 1018229997Sken mtx_lock(&lun->softc->lock); 1019229997Sken /* How did we get here?? */ 1020229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1021229997Sken mtx_unlock(&lun->softc->lock); 1022229997Sken ctl_free_io(io); 1023229997Sken break; 1024229997Sken } 1025229997Sken} 1026229997Sken 1027229997Skenstatic void 1028229997Skencfi_lun_probe(struct cfi_lun *lun, int have_lock) 1029229997Sken{ 1030229997Sken 1031229997Sken if (have_lock == 0) 1032229997Sken mtx_lock(&lun->softc->lock); 1033229997Sken if ((lun->softc->flags & CFI_ONLINE) == 0) { 1034229997Sken if (have_lock == 0) 1035229997Sken mtx_unlock(&lun->softc->lock); 1036229997Sken return; 1037229997Sken } 1038229997Sken if (have_lock == 0) 1039229997Sken mtx_unlock(&lun->softc->lock); 1040229997Sken 1041229997Sken switch (lun->state) { 1042229997Sken case CFI_LUN_INQUIRY: { 1043229997Sken struct cfi_lun_io *lun_io; 1044229997Sken union ctl_io *io; 1045229997Sken 1046229997Sken io = ctl_alloc_io(lun->softc->fe.ctl_pool_ref); 1047229997Sken if (io == NULL) { 1048229997Sken printf("%s: unable to alloc ctl_io for target %ju " 1049229997Sken "lun %d probe\n", __func__, 1050229997Sken (uintmax_t)lun->target_id.id, lun->lun_id); 1051229997Sken return; 1052229997Sken } 1053229997Sken ctl_scsi_inquiry(io, 1054229997Sken /*data_ptr*/(uint8_t *)&lun->inq_data, 1055229997Sken /*data_len*/ sizeof(lun->inq_data), 1056229997Sken /*byte2*/ 0, 1057229997Sken /*page_code*/ 0, 1058229997Sken /*tag_type*/ CTL_TAG_SIMPLE, 1059229997Sken /*control*/ 0); 1060229997Sken 1061229997Sken cfi_init_io(io, 1062229997Sken /*lun*/ lun, 1063229997Sken /*metatask*/ NULL, 1064229997Sken /*policy*/ CFI_ERR_SOFT, 1065229997Sken /*retries*/ 5, 1066229997Sken /*orig_lun_io*/ NULL, 1067229997Sken /*done_function*/ 1068229997Sken cfi_lun_probe_done); 1069229997Sken 1070229997Sken lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv; 1071229997Sken 1072229997Sken if (have_lock == 0) 1073229997Sken mtx_lock(&lun->softc->lock); 1074229997Sken STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links); 1075229997Sken if (have_lock == 0) 1076229997Sken mtx_unlock(&lun->softc->lock); 1077229997Sken 1078229997Sken if (ctl_queue(io) != CTL_RETVAL_COMPLETE) { 1079229997Sken printf("%s: error returned from ctl_queue()!\n", 1080229997Sken __func__); 1081229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, 1082229997Sken cfi_lun_io, links); 1083229997Sken ctl_free_io(io); 1084229997Sken } 1085229997Sken break; 1086229997Sken } 1087229997Sken case CFI_LUN_READCAPACITY: 1088229997Sken case CFI_LUN_READCAPACITY_16: { 1089229997Sken struct cfi_lun_io *lun_io; 1090229997Sken uint8_t *dataptr; 1091229997Sken union ctl_io *io; 1092229997Sken 1093229997Sken io = ctl_alloc_io(lun->softc->fe.ctl_pool_ref); 1094229997Sken if (io == NULL) { 1095229997Sken printf("%s: unable to alloc ctl_io for target %ju " 1096229997Sken "lun %d probe\n", __func__, 1097229997Sken (uintmax_t)lun->target_id.id, lun->lun_id); 1098229997Sken return; 1099229997Sken } 1100229997Sken 1101229997Sken dataptr = malloc(sizeof(struct scsi_read_capacity_data_long), 1102229997Sken M_CTL_CFI, M_NOWAIT); 1103229997Sken if (dataptr == NULL) { 1104229997Sken printf("%s: unable to allocate SCSI read capacity " 1105229997Sken "buffer for target %ju lun %d\n", __func__, 1106229997Sken (uintmax_t)lun->target_id.id, lun->lun_id); 1107229997Sken return; 1108229997Sken } 1109229997Sken if (lun->state == CFI_LUN_READCAPACITY) { 1110229997Sken ctl_scsi_read_capacity(io, 1111229997Sken /*data_ptr*/ dataptr, 1112229997Sken /*data_len*/ 1113229997Sken sizeof(struct scsi_read_capacity_data_long), 1114229997Sken /*addr*/ 0, 1115229997Sken /*reladr*/ 0, 1116229997Sken /*pmi*/ 0, 1117229997Sken /*tag_type*/ CTL_TAG_SIMPLE, 1118229997Sken /*control*/ 0); 1119229997Sken } else { 1120229997Sken ctl_scsi_read_capacity_16(io, 1121229997Sken /*data_ptr*/ dataptr, 1122229997Sken /*data_len*/ 1123229997Sken sizeof(struct scsi_read_capacity_data_long), 1124229997Sken /*addr*/ 0, 1125229997Sken /*reladr*/ 0, 1126229997Sken /*pmi*/ 0, 1127229997Sken /*tag_type*/ CTL_TAG_SIMPLE, 1128229997Sken /*control*/ 0); 1129229997Sken } 1130229997Sken cfi_init_io(io, 1131229997Sken /*lun*/ lun, 1132229997Sken /*metatask*/ NULL, 1133229997Sken /*policy*/ CFI_ERR_SOFT, 1134229997Sken /*retries*/ 7, 1135229997Sken /*orig_lun_io*/ NULL, 1136229997Sken /*done_function*/ cfi_lun_probe_done); 1137229997Sken 1138229997Sken lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv; 1139229997Sken 1140229997Sken if (have_lock == 0) 1141229997Sken mtx_lock(&lun->softc->lock); 1142229997Sken STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links); 1143229997Sken if (have_lock == 0) 1144229997Sken mtx_unlock(&lun->softc->lock); 1145229997Sken 1146229997Sken if (ctl_queue(io) != CTL_RETVAL_COMPLETE) { 1147229997Sken printf("%s: error returned from ctl_queue()!\n", 1148229997Sken __func__); 1149229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, 1150229997Sken cfi_lun_io, links); 1151229997Sken free(dataptr, M_CTL_CFI); 1152229997Sken ctl_free_io(io); 1153229997Sken } 1154229997Sken break; 1155229997Sken } 1156229997Sken case CFI_LUN_READY: 1157229997Sken default: 1158229997Sken /* Why were we called? */ 1159229997Sken break; 1160229997Sken } 1161229997Sken} 1162229997Sken 1163229997Skenstatic void 1164229997Skencfi_metatask_done(struct cfi_softc *softc, struct cfi_metatask *metatask) 1165229997Sken{ 1166229997Sken mtx_lock(&softc->lock); 1167229997Sken STAILQ_REMOVE(&softc->metatask_list, metatask, cfi_metatask, links); 1168229997Sken mtx_unlock(&softc->lock); 1169229997Sken 1170229997Sken /* 1171229997Sken * Return status to the caller. Caller allocated storage, and is 1172229997Sken * responsible for calling cfi_free_metatask to release it once 1173229997Sken * they've seen the status. 1174229997Sken */ 1175229997Sken metatask->callback(metatask->callback_arg, metatask); 1176229997Sken} 1177229997Sken 1178229997Skenstatic void 1179229997Skencfi_metatask_bbr_errorparse(struct cfi_metatask *metatask, union ctl_io *io) 1180229997Sken{ 1181229997Sken int error_code, sense_key, asc, ascq; 1182229997Sken 1183229997Sken if (metatask->tasktype != CFI_TASK_BBRREAD) 1184229997Sken return; 1185229997Sken 1186229997Sken if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) { 1187229997Sken metatask->status = CFI_MT_SUCCESS; 1188229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_SUCCESS; 1189229997Sken return; 1190229997Sken } 1191229997Sken 1192229997Sken if ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SCSI_ERROR) { 1193229997Sken metatask->status = CFI_MT_ERROR; 1194229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_ERROR; 1195229997Sken return; 1196229997Sken } 1197229997Sken 1198229997Sken metatask->taskinfo.bbrread.scsi_status = io->scsiio.scsi_status; 1199229997Sken memcpy(&metatask->taskinfo.bbrread.sense_data, &io->scsiio.sense_data, 1200229997Sken ctl_min(sizeof(metatask->taskinfo.bbrread.sense_data), 1201229997Sken sizeof(io->scsiio.sense_data))); 1202229997Sken 1203229997Sken if (io->scsiio.scsi_status == SCSI_STATUS_RESERV_CONFLICT) { 1204229997Sken metatask->status = CFI_MT_ERROR; 1205229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_RESERV_CONFLICT; 1206229997Sken return; 1207229997Sken } 1208229997Sken 1209229997Sken if (io->scsiio.scsi_status != SCSI_STATUS_CHECK_COND) { 1210229997Sken metatask->status = CFI_MT_ERROR; 1211229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR; 1212229997Sken return; 1213229997Sken } 1214229997Sken 1215229997Sken scsi_extract_sense_len(&io->scsiio.sense_data, 1216229997Sken io->scsiio.sense_len, 1217229997Sken &error_code, 1218229997Sken &sense_key, 1219229997Sken &asc, 1220229997Sken &ascq, 1221229997Sken /*show_errors*/ 1); 1222229997Sken 1223229997Sken switch (error_code) { 1224229997Sken case SSD_DEFERRED_ERROR: 1225229997Sken case SSD_DESC_DEFERRED_ERROR: 1226229997Sken metatask->status = CFI_MT_ERROR; 1227229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR; 1228229997Sken break; 1229229997Sken case SSD_CURRENT_ERROR: 1230229997Sken case SSD_DESC_CURRENT_ERROR: 1231229997Sken default: { 1232229997Sken struct scsi_sense_data *sense; 1233229997Sken 1234229997Sken sense = &io->scsiio.sense_data; 1235229997Sken 1236229997Sken if ((asc == 0x04) && (ascq == 0x02)) { 1237229997Sken metatask->status = CFI_MT_ERROR; 1238229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_LUN_STOPPED; 1239229997Sken } else if ((asc == 0x04) && (ascq == 0x03)) { 1240229997Sken metatask->status = CFI_MT_ERROR; 1241229997Sken metatask->taskinfo.bbrread.status = 1242229997Sken CFI_BBR_LUN_OFFLINE_CTL; 1243229997Sken } else if ((asc == 0x44) && (ascq == 0x00)) { 1244229997Sken#ifdef NEEDTOPORT 1245229997Sken if (sense->sense_key_spec[0] & SSD_SCS_VALID) { 1246229997Sken uint16_t retry_count; 1247229997Sken 1248229997Sken retry_count = sense->sense_key_spec[1] << 8 | 1249229997Sken sense->sense_key_spec[2]; 1250229997Sken if (((retry_count & 0xf000) == CSC_RAIDCORE) 1251229997Sken && ((retry_count & 0x0f00) == CSC_SHELF_SW) 1252229997Sken && ((retry_count & 0xff) == 1253229997Sken RC_STS_DEVICE_OFFLINE)) { 1254229997Sken metatask->status = CFI_MT_ERROR; 1255229997Sken metatask->taskinfo.bbrread.status = 1256229997Sken CFI_BBR_LUN_OFFLINE_RC; 1257229997Sken } else { 1258229997Sken metatask->status = CFI_MT_ERROR; 1259229997Sken metatask->taskinfo.bbrread.status = 1260229997Sken CFI_BBR_SCSI_ERROR; 1261229997Sken } 1262229997Sken } else { 1263229997Sken#endif /* NEEDTOPORT */ 1264229997Sken metatask->status = CFI_MT_ERROR; 1265229997Sken metatask->taskinfo.bbrread.status = 1266229997Sken CFI_BBR_SCSI_ERROR; 1267229997Sken#ifdef NEEDTOPORT 1268229997Sken } 1269229997Sken#endif 1270229997Sken } else { 1271229997Sken metatask->status = CFI_MT_ERROR; 1272229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_SCSI_ERROR; 1273229997Sken } 1274229997Sken break; 1275229997Sken } 1276229997Sken } 1277229997Sken} 1278229997Sken 1279229997Skenstatic void 1280229997Skencfi_metatask_io_done(union ctl_io *io) 1281229997Sken{ 1282229997Sken struct cfi_lun_io *lun_io; 1283229997Sken struct cfi_metatask *metatask; 1284229997Sken struct cfi_softc *softc; 1285229997Sken struct cfi_lun *lun; 1286229997Sken 1287229997Sken lun_io = (struct cfi_lun_io *) 1288229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 1289229997Sken 1290229997Sken lun = lun_io->lun; 1291229997Sken softc = lun->softc; 1292229997Sken 1293229997Sken metatask = lun_io->metatask; 1294229997Sken 1295229997Sken switch (metatask->tasktype) { 1296229997Sken case CFI_TASK_STARTUP: 1297229997Sken case CFI_TASK_SHUTDOWN: { 1298229997Sken int failed, done, is_start; 1299229997Sken 1300229997Sken failed = 0; 1301229997Sken done = 0; 1302229997Sken if (metatask->tasktype == CFI_TASK_STARTUP) 1303229997Sken is_start = 1; 1304229997Sken else 1305229997Sken is_start = 0; 1306229997Sken 1307229997Sken mtx_lock(&softc->lock); 1308229997Sken if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) 1309229997Sken metatask->taskinfo.startstop.luns_complete++; 1310229997Sken else { 1311229997Sken metatask->taskinfo.startstop.luns_failed++; 1312229997Sken failed = 1; 1313229997Sken } 1314229997Sken if ((metatask->taskinfo.startstop.luns_complete + 1315229997Sken metatask->taskinfo.startstop.luns_failed) >= 1316229997Sken metatask->taskinfo.startstop.total_luns) 1317229997Sken done = 1; 1318229997Sken 1319229997Sken mtx_unlock(&softc->lock); 1320229997Sken 1321229997Sken if (failed != 0) { 1322229997Sken printf("%s: LUN %d %s request failed\n", __func__, 1323229997Sken lun_io->lun->lun_id, (is_start == 1) ? "start" : 1324229997Sken "stop"); 1325229997Sken ctl_io_error_print(io, &lun_io->lun->inq_data); 1326229997Sken } 1327229997Sken if (done != 0) { 1328229997Sken if (metatask->taskinfo.startstop.luns_failed > 0) 1329229997Sken metatask->status = CFI_MT_ERROR; 1330229997Sken else 1331229997Sken metatask->status = CFI_MT_SUCCESS; 1332229997Sken cfi_metatask_done(softc, metatask); 1333229997Sken } 1334229997Sken mtx_lock(&softc->lock); 1335229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1336229997Sken mtx_unlock(&softc->lock); 1337229997Sken 1338229997Sken ctl_free_io(io); 1339229997Sken break; 1340229997Sken } 1341229997Sken case CFI_TASK_BBRREAD: { 1342229997Sken /* 1343229997Sken * Translate the SCSI error into an enumeration. 1344229997Sken */ 1345229997Sken cfi_metatask_bbr_errorparse(metatask, io); 1346229997Sken 1347229997Sken mtx_lock(&softc->lock); 1348229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1349229997Sken mtx_unlock(&softc->lock); 1350229997Sken 1351229997Sken ctl_free_io(io); 1352229997Sken 1353229997Sken cfi_metatask_done(softc, metatask); 1354229997Sken break; 1355229997Sken } 1356229997Sken default: 1357229997Sken /* 1358229997Sken * This shouldn't happen. 1359229997Sken */ 1360229997Sken mtx_lock(&softc->lock); 1361229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1362229997Sken mtx_unlock(&softc->lock); 1363229997Sken 1364229997Sken ctl_free_io(io); 1365229997Sken break; 1366229997Sken } 1367229997Sken} 1368229997Sken 1369229997Skenstatic void 1370229997Skencfi_err_recovery_done(union ctl_io *io) 1371229997Sken{ 1372229997Sken struct cfi_lun_io *lun_io, *orig_lun_io; 1373229997Sken struct cfi_lun *lun; 1374229997Sken union ctl_io *orig_io; 1375229997Sken 1376229997Sken lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv; 1377229997Sken orig_lun_io = lun_io->orig_lun_io; 1378229997Sken orig_io = orig_lun_io->ctl_io; 1379229997Sken lun = lun_io->lun; 1380229997Sken 1381229997Sken if (io->io_hdr.status != CTL_SUCCESS) { 1382229997Sken printf("%s: error recovery action failed. Original " 1383229997Sken "error:\n", __func__); 1384229997Sken 1385229997Sken ctl_io_error_print(orig_lun_io->ctl_io, &lun->inq_data); 1386229997Sken 1387229997Sken printf("%s: error from error recovery action:\n", __func__); 1388229997Sken 1389229997Sken ctl_io_error_print(io, &lun->inq_data); 1390229997Sken 1391229997Sken printf("%s: trying original command again...\n", __func__); 1392229997Sken } 1393229997Sken 1394229997Sken mtx_lock(&lun->softc->lock); 1395229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1396229997Sken mtx_unlock(&lun->softc->lock); 1397229997Sken ctl_free_io(io); 1398229997Sken 1399229997Sken orig_io->io_hdr.retries--; 1400229997Sken orig_io->io_hdr.status = CTL_STATUS_NONE; 1401229997Sken 1402229997Sken if (ctl_queue(orig_io) != CTL_RETVAL_COMPLETE) { 1403229997Sken printf("%s: error returned from ctl_queue()!\n", __func__); 1404229997Sken STAILQ_REMOVE(&lun->io_list, orig_lun_io, 1405229997Sken cfi_lun_io, links); 1406229997Sken ctl_free_io(orig_io); 1407229997Sken } 1408229997Sken} 1409229997Sken 1410229997Skenstatic void 1411229997Skencfi_lun_io_done(union ctl_io *io) 1412229997Sken{ 1413229997Sken struct cfi_lun *lun; 1414229997Sken struct cfi_lun_io *lun_io; 1415229997Sken 1416229997Sken lun_io = (struct cfi_lun_io *) 1417229997Sken io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 1418229997Sken lun = lun_io->lun; 1419229997Sken 1420229997Sken if (lun_io->metatask == NULL) { 1421229997Sken printf("%s: I/O has no metatask pointer, discarding\n", 1422229997Sken __func__); 1423229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1424229997Sken ctl_free_io(io); 1425229997Sken return; 1426229997Sken } 1427229997Sken cfi_metatask_io_done(io); 1428229997Sken} 1429229997Sken 1430229997Skenvoid 1431229997Skencfi_action(struct cfi_metatask *metatask) 1432229997Sken{ 1433229997Sken struct cfi_softc *softc; 1434229997Sken 1435229997Sken softc = &fetd_internal_softc; 1436229997Sken 1437229997Sken mtx_lock(&softc->lock); 1438229997Sken 1439229997Sken STAILQ_INSERT_TAIL(&softc->metatask_list, metatask, links); 1440229997Sken 1441229997Sken if ((softc->flags & CFI_ONLINE) == 0) { 1442229997Sken mtx_unlock(&softc->lock); 1443229997Sken metatask->status = CFI_MT_PORT_OFFLINE; 1444229997Sken cfi_metatask_done(softc, metatask); 1445229997Sken return; 1446229997Sken } else 1447229997Sken mtx_unlock(&softc->lock); 1448229997Sken 1449229997Sken switch (metatask->tasktype) { 1450229997Sken case CFI_TASK_STARTUP: 1451229997Sken case CFI_TASK_SHUTDOWN: { 1452229997Sken union ctl_io *io; 1453229997Sken int da_luns, ios_allocated, do_start; 1454229997Sken struct cfi_lun *lun; 1455229997Sken STAILQ_HEAD(, ctl_io_hdr) tmp_io_list; 1456229997Sken 1457229997Sken da_luns = 0; 1458229997Sken ios_allocated = 0; 1459229997Sken STAILQ_INIT(&tmp_io_list); 1460229997Sken 1461229997Sken if (metatask->tasktype == CFI_TASK_STARTUP) 1462229997Sken do_start = 1; 1463229997Sken else 1464229997Sken do_start = 0; 1465229997Sken 1466229997Sken mtx_lock(&softc->lock); 1467229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) { 1468229997Sken if (lun->state != CFI_LUN_READY) 1469229997Sken continue; 1470229997Sken 1471229997Sken if (SID_TYPE(&lun->inq_data) != T_DIRECT) 1472229997Sken continue; 1473229997Sken da_luns++; 1474229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 1475229997Sken if (io != NULL) { 1476229997Sken ios_allocated++; 1477229997Sken STAILQ_INSERT_TAIL(&tmp_io_list, &io->io_hdr, 1478229997Sken links); 1479229997Sken } 1480229997Sken } 1481229997Sken 1482229997Sken if (ios_allocated < da_luns) { 1483229997Sken printf("%s: error allocating ctl_io for %s\n", 1484229997Sken __func__, (do_start == 1) ? "startup" : 1485229997Sken "shutdown"); 1486229997Sken da_luns = ios_allocated; 1487229997Sken } 1488229997Sken 1489229997Sken metatask->taskinfo.startstop.total_luns = da_luns; 1490229997Sken 1491229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) { 1492229997Sken struct cfi_lun_io *lun_io; 1493229997Sken 1494229997Sken if (lun->state != CFI_LUN_READY) 1495229997Sken continue; 1496229997Sken 1497229997Sken if (SID_TYPE(&lun->inq_data) != T_DIRECT) 1498229997Sken continue; 1499229997Sken 1500229997Sken io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list); 1501229997Sken if (io == NULL) 1502229997Sken break; 1503229997Sken 1504229997Sken STAILQ_REMOVE(&tmp_io_list, &io->io_hdr, ctl_io_hdr, 1505229997Sken links); 1506229997Sken 1507229997Sken ctl_scsi_start_stop(io, 1508229997Sken /*start*/ do_start, 1509229997Sken /*load_eject*/ 0, 1510229997Sken /*immediate*/ 0, 1511229997Sken /*power_conditions*/ 1512229997Sken SSS_PC_START_VALID, 1513229997Sken /*onoffline*/ 1, 1514229997Sken /*ctl_tag_type*/ CTL_TAG_ORDERED, 1515229997Sken /*control*/ 0); 1516229997Sken 1517229997Sken cfi_init_io(io, 1518229997Sken /*lun*/ lun, 1519229997Sken /*metatask*/ metatask, 1520229997Sken /*policy*/ CFI_ERR_HARD, 1521229997Sken /*retries*/ 3, 1522229997Sken /*orig_lun_io*/ NULL, 1523229997Sken /*done_function*/ cfi_lun_io_done); 1524229997Sken 1525229997Sken lun_io = (struct cfi_lun_io *) io->io_hdr.port_priv; 1526229997Sken 1527229997Sken STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links); 1528229997Sken 1529229997Sken if (ctl_queue(io) != CTL_RETVAL_COMPLETE) { 1530229997Sken printf("%s: error returned from ctl_queue()!\n", 1531229997Sken __func__); 1532229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, 1533229997Sken cfi_lun_io, links); 1534229997Sken ctl_free_io(io); 1535229997Sken metatask->taskinfo.startstop.total_luns--; 1536229997Sken } 1537229997Sken } 1538229997Sken 1539229997Sken if (STAILQ_FIRST(&tmp_io_list) != NULL) { 1540229997Sken printf("%s: error: tmp_io_list != NULL\n", __func__); 1541229997Sken for (io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list); 1542229997Sken io != NULL; 1543229997Sken io = (union ctl_io *)STAILQ_FIRST(&tmp_io_list)) { 1544229997Sken STAILQ_REMOVE(&tmp_io_list, &io->io_hdr, 1545229997Sken ctl_io_hdr, links); 1546229997Sken ctl_free_io(io); 1547229997Sken } 1548229997Sken } 1549229997Sken mtx_unlock(&softc->lock); 1550229997Sken 1551229997Sken break; 1552229997Sken } 1553229997Sken case CFI_TASK_BBRREAD: { 1554229997Sken union ctl_io *io; 1555229997Sken struct cfi_lun *lun; 1556229997Sken struct cfi_lun_io *lun_io; 1557229997Sken cfi_bbrread_status status; 1558229997Sken int req_lun_num; 1559229997Sken uint32_t num_blocks; 1560229997Sken 1561229997Sken status = CFI_BBR_SUCCESS; 1562229997Sken 1563229997Sken req_lun_num = metatask->taskinfo.bbrread.lun_num; 1564229997Sken 1565229997Sken mtx_lock(&softc->lock); 1566229997Sken STAILQ_FOREACH(lun, &softc->lun_list, links) { 1567229997Sken if (lun->lun_id != req_lun_num) 1568229997Sken continue; 1569229997Sken if (lun->state != CFI_LUN_READY) { 1570229997Sken status = CFI_BBR_LUN_UNCONFIG; 1571229997Sken break; 1572229997Sken } else 1573229997Sken break; 1574229997Sken } 1575229997Sken 1576229997Sken if (lun == NULL) 1577229997Sken status = CFI_BBR_NO_LUN; 1578229997Sken 1579229997Sken if (status != CFI_BBR_SUCCESS) { 1580229997Sken metatask->status = CFI_MT_ERROR; 1581229997Sken metatask->taskinfo.bbrread.status = status; 1582229997Sken mtx_unlock(&softc->lock); 1583229997Sken cfi_metatask_done(softc, metatask); 1584229997Sken break; 1585229997Sken } 1586229997Sken 1587229997Sken /* 1588229997Sken * Convert the number of bytes given into blocks and check 1589229997Sken * that the number of bytes is a multiple of the blocksize. 1590229997Sken * CTL will verify that the LBA is okay. 1591229997Sken */ 1592229997Sken if (lun->blocksize_powerof2 != 0) { 1593229997Sken if ((metatask->taskinfo.bbrread.len & 1594229997Sken (lun->blocksize - 1)) != 0) { 1595229997Sken metatask->status = CFI_MT_ERROR; 1596229997Sken metatask->taskinfo.bbrread.status = 1597229997Sken CFI_BBR_BAD_LEN; 1598229997Sken cfi_metatask_done(softc, metatask); 1599229997Sken break; 1600229997Sken } 1601229997Sken 1602229997Sken num_blocks = metatask->taskinfo.bbrread.len >> 1603229997Sken lun->blocksize_powerof2; 1604229997Sken } else { 1605229997Sken /* 1606229997Sken * XXX KDM this could result in floating point 1607229997Sken * division, which isn't supported in the kernel on 1608229997Sken * x86 at least. 1609229997Sken */ 1610229997Sken if ((metatask->taskinfo.bbrread.len % 1611229997Sken lun->blocksize) != 0) { 1612229997Sken metatask->status = CFI_MT_ERROR; 1613229997Sken metatask->taskinfo.bbrread.status = 1614229997Sken CFI_BBR_BAD_LEN; 1615229997Sken cfi_metatask_done(softc, metatask); 1616229997Sken break; 1617229997Sken } 1618229997Sken 1619229997Sken /* 1620229997Sken * XXX KDM this could result in floating point 1621229997Sken * division in some cases. 1622229997Sken */ 1623229997Sken num_blocks = metatask->taskinfo.bbrread.len / 1624229997Sken lun->blocksize; 1625229997Sken 1626229997Sken } 1627229997Sken 1628229997Sken io = ctl_alloc_io(softc->fe.ctl_pool_ref); 1629229997Sken if (io == NULL) { 1630229997Sken metatask->status = CFI_MT_ERROR; 1631229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_NO_MEM; 1632229997Sken mtx_unlock(&softc->lock); 1633229997Sken cfi_metatask_done(softc, metatask); 1634229997Sken break; 1635229997Sken } 1636229997Sken 1637229997Sken /* 1638229997Sken * XXX KDM need to do a read capacity to get the blocksize 1639229997Sken * for this device. 1640229997Sken */ 1641229997Sken ctl_scsi_read_write(io, 1642229997Sken /*data_ptr*/ NULL, 1643229997Sken /*data_len*/ metatask->taskinfo.bbrread.len, 1644229997Sken /*read_op*/ 1, 1645229997Sken /*byte2*/ 0, 1646229997Sken /*minimum_cdb_size*/ 0, 1647229997Sken /*lba*/ metatask->taskinfo.bbrread.lba, 1648229997Sken /*num_blocks*/ num_blocks, 1649229997Sken /*tag_type*/ CTL_TAG_SIMPLE, 1650229997Sken /*control*/ 0); 1651229997Sken 1652229997Sken cfi_init_io(io, 1653229997Sken /*lun*/ lun, 1654229997Sken /*metatask*/ metatask, 1655229997Sken /*policy*/ CFI_ERR_SOFT, 1656229997Sken /*retries*/ 3, 1657229997Sken /*orig_lun_io*/ NULL, 1658229997Sken /*done_function*/ cfi_lun_io_done); 1659229997Sken 1660229997Sken lun_io = (struct cfi_lun_io *)io->io_hdr.port_priv; 1661229997Sken 1662229997Sken STAILQ_INSERT_TAIL(&lun->io_list, lun_io, links); 1663229997Sken 1664229997Sken if (ctl_queue(io) != CTL_RETVAL_COMPLETE) { 1665229997Sken printf("%s: error returned from ctl_queue()!\n", 1666229997Sken __func__); 1667229997Sken STAILQ_REMOVE(&lun->io_list, lun_io, cfi_lun_io, links); 1668229997Sken ctl_free_io(io); 1669229997Sken metatask->status = CFI_MT_ERROR; 1670229997Sken metatask->taskinfo.bbrread.status = CFI_BBR_ERROR; 1671229997Sken mtx_unlock(&softc->lock); 1672229997Sken cfi_metatask_done(softc, metatask); 1673229997Sken break; 1674229997Sken } 1675229997Sken 1676229997Sken mtx_unlock(&softc->lock); 1677229997Sken break; 1678229997Sken } 1679229997Sken default: 1680229997Sken panic("invalid metatask type %d", metatask->tasktype); 1681229997Sken break; /* NOTREACHED */ 1682229997Sken } 1683229997Sken} 1684229997Sken 1685229997Sken#ifdef oldapi 1686229997Skenvoid 1687229997Skencfi_shutdown_shelf(cfi_cb_t callback, void *callback_arg) 1688229997Sken{ 1689229997Sken struct ctl_mem_element *element; 1690229997Sken struct cfi_softc *softc; 1691229997Sken struct cfi_metatask *metatask; 1692229997Sken 1693229997Sken softc = &fetd_internal_softc; 1694229997Sken 1695229997Sken element = ctl_alloc_mem_element(&softc->metatask_pool, /*can_wait*/ 0); 1696229997Sken if (element == NULL) { 1697229997Sken callback(callback_arg, 1698229997Sken /*status*/ CFI_MT_ERROR, 1699229997Sken /*sluns_found*/ 0, 1700229997Sken /*sluns_complete*/ 0, 1701229997Sken /*sluns_failed*/ 0); 1702229997Sken return; 1703229997Sken } 1704229997Sken 1705229997Sken metatask = (struct cfi_metatask *)element->bytes; 1706229997Sken 1707229997Sken memset(metatask, 0, sizeof(*metatask)); 1708229997Sken metatask->tasktype = CFI_TASK_SHUTDOWN; 1709229997Sken metatask->status = CFI_MT_NONE; 1710229997Sken metatask->taskinfo.startstop.callback = callback; 1711229997Sken metatask->taskinfo.startstop.callback_arg = callback_arg; 1712229997Sken metatask->element = element; 1713229997Sken 1714229997Sken cfi_action(softc, metatask); 1715229997Sken 1716229997Sken /* 1717229997Sken * - send a report luns to lun 0, get LUN list. 1718229997Sken * - send an inquiry to each lun 1719229997Sken * - send a stop/offline to each direct access LUN 1720229997Sken * - if we get a reservation conflict, reset the LUN and then 1721229997Sken * retry sending the stop/offline 1722229997Sken * - return status back to the caller 1723229997Sken */ 1724229997Sken} 1725229997Sken 1726229997Skenvoid 1727229997Skencfi_start_shelf(cfi_cb_t callback, void *callback_arg) 1728229997Sken{ 1729229997Sken struct ctl_mem_element *element; 1730229997Sken struct cfi_softc *softc; 1731229997Sken struct cfi_metatask *metatask; 1732229997Sken 1733229997Sken softc = &fetd_internal_softc; 1734229997Sken 1735229997Sken element = ctl_alloc_mem_element(&softc->metatask_pool, /*can_wait*/ 0); 1736229997Sken if (element == NULL) { 1737229997Sken callback(callback_arg, 1738229997Sken /*status*/ CFI_MT_ERROR, 1739229997Sken /*sluns_found*/ 0, 1740229997Sken /*sluns_complete*/ 0, 1741229997Sken /*sluns_failed*/ 0); 1742229997Sken return; 1743229997Sken } 1744229997Sken 1745229997Sken metatask = (struct cfi_metatask *)element->bytes; 1746229997Sken 1747229997Sken memset(metatask, 0, sizeof(*metatask)); 1748229997Sken metatask->tasktype = CFI_TASK_STARTUP; 1749229997Sken metatask->status = CFI_MT_NONE; 1750229997Sken metatask->taskinfo.startstop.callback = callback; 1751229997Sken metatask->taskinfo.startstop.callback_arg = callback_arg; 1752229997Sken metatask->element = element; 1753229997Sken 1754229997Sken cfi_action(softc, metatask); 1755229997Sken 1756229997Sken /* 1757229997Sken * - send a report luns to lun 0, get LUN list. 1758229997Sken * - send an inquiry to each lun 1759229997Sken * - send a stop/offline to each direct access LUN 1760229997Sken * - if we get a reservation conflict, reset the LUN and then 1761229997Sken * retry sending the stop/offline 1762229997Sken * - return status back to the caller 1763229997Sken */ 1764229997Sken} 1765229997Sken 1766229997Sken#endif 1767229997Sken 1768229997Skenstruct cfi_metatask * 1769229997Skencfi_alloc_metatask(int can_wait) 1770229997Sken{ 1771229997Sken struct ctl_mem_element *element; 1772229997Sken struct cfi_metatask *metatask; 1773229997Sken struct cfi_softc *softc; 1774229997Sken 1775229997Sken softc = &fetd_internal_softc; 1776229997Sken 1777229997Sken element = ctl_alloc_mem_element(&softc->metatask_pool, can_wait); 1778229997Sken if (element == NULL) 1779229997Sken return (NULL); 1780229997Sken 1781229997Sken metatask = (struct cfi_metatask *)element->bytes; 1782229997Sken memset(metatask, 0, sizeof(*metatask)); 1783229997Sken metatask->status = CFI_MT_NONE; 1784229997Sken metatask->element = element; 1785229997Sken 1786229997Sken return (metatask); 1787229997Sken} 1788229997Sken 1789229997Skenvoid 1790229997Skencfi_free_metatask(struct cfi_metatask *metatask) 1791229997Sken{ 1792229997Sken ctl_free_mem_element(metatask->element); 1793229997Sken} 1794229997Sken 1795229997Sken/* 1796229997Sken * vim: ts=8 1797229997Sken */ 1798