cam_periph.c revision 42957
139212Sgibbs/* 239212Sgibbs * Common functions for CAM "type" (peripheral) drivers. 339212Sgibbs * 439212Sgibbs * Copyright (c) 1997, 1998 Justin T. Gibbs. 539212Sgibbs * Copyright (c) 1997, 1998 Kenneth D. Merry. 639212Sgibbs * All rights reserved. 739212Sgibbs * 839212Sgibbs * Redistribution and use in source and binary forms, with or without 939212Sgibbs * modification, are permitted provided that the following conditions 1039212Sgibbs * are met: 1139212Sgibbs * 1. Redistributions of source code must retain the above copyright 1239212Sgibbs * notice, this list of conditions, and the following disclaimer, 1339212Sgibbs * without modification, immediately at the beginning of the file. 1439212Sgibbs * 2. The name of the author may not be used to endorse or promote products 1539212Sgibbs * derived from this software without specific prior written permission. 1639212Sgibbs * 1739212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1839212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1939212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2039212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2139212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2239212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2339212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2439212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2539212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2639212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2739212Sgibbs * SUCH DAMAGE. 2839212Sgibbs * 2942957Sdillon * $Id: cam_periph.c,v 1.9 1999/01/14 06:21:54 jdp Exp $ 3039212Sgibbs */ 3139212Sgibbs 3239212Sgibbs#include <sys/param.h> 3339212Sgibbs#include <sys/systm.h> 3439212Sgibbs#include <sys/types.h> 3539212Sgibbs#include <sys/malloc.h> 3642654Sjdp#include <sys/linker_set.h> 3739212Sgibbs#include <sys/buf.h> 3839212Sgibbs#include <sys/proc.h> 3939212Sgibbs#include <sys/devicestat.h> 4039212Sgibbs#include <vm/vm.h> 4139212Sgibbs#include <vm/vm_extern.h> 4239212Sgibbs 4339212Sgibbs#include <cam/cam.h> 4439212Sgibbs#include <cam/cam_conf.h> 4539212Sgibbs#include <cam/cam_ccb.h> 4639212Sgibbs#include <cam/cam_xpt_periph.h> 4739212Sgibbs#include <cam/cam_periph.h> 4839212Sgibbs#include <cam/cam_debug.h> 4939212Sgibbs 5039212Sgibbs#include <cam/scsi/scsi_all.h> 5139212Sgibbs#include <cam/scsi/scsi_message.h> 5239212Sgibbs#include <cam/scsi/scsi_da.h> 5339212Sgibbs#include <cam/scsi/scsi_pass.h> 5439212Sgibbs 5539212Sgibbsstatic u_int camperiphnextunit(struct periph_driver *p_drv, 5639212Sgibbs u_int newunit, int wired); 5739212Sgibbsstatic u_int camperiphunit(struct periph_driver *p_drv, 5839212Sgibbs path_id_t path_id_t, 5939212Sgibbs target_id_t target, lun_id_t lun); 6039212Sgibbsstatic void camperiphdone(struct cam_periph *periph, 6139212Sgibbs union ccb *done_ccb); 6239212Sgibbsstatic void camperiphfree(struct cam_periph *periph); 6339212Sgibbs 6439212Sgibbscam_status 6540603Skencam_periph_alloc(periph_ctor_t *periph_ctor, 6640603Sken periph_oninv_t *periph_oninvalidate, 6740603Sken periph_dtor_t *periph_dtor, periph_start_t *periph_start, 6840603Sken char *name, cam_periph_type type, struct cam_path *path, 6940603Sken ac_callback_t *ac_callback, ac_code code, void *arg) 7039212Sgibbs{ 7139212Sgibbs struct periph_driver **p_drv; 7239212Sgibbs struct cam_periph *periph; 7339212Sgibbs struct cam_periph *cur_periph; 7439212Sgibbs path_id_t path_id; 7539212Sgibbs target_id_t target_id; 7639212Sgibbs lun_id_t lun_id; 7739212Sgibbs cam_status status; 7839212Sgibbs u_int init_level; 7939212Sgibbs int s; 8039212Sgibbs 8139212Sgibbs init_level = 0; 8239212Sgibbs /* 8339212Sgibbs * Handle Hot-Plug scenarios. If there is already a peripheral 8439212Sgibbs * of our type assigned to this path, we are likely waiting for 8539212Sgibbs * final close on an old, invalidated, peripheral. If this is 8639212Sgibbs * the case, queue up a deferred call to the peripheral's async 8739212Sgibbs * handler. If it looks like a mistaken re-alloation, complain. 8839212Sgibbs */ 8939212Sgibbs if ((periph = cam_periph_find(path, name)) != NULL) { 9039212Sgibbs 9139212Sgibbs if ((periph->flags & CAM_PERIPH_INVALID) != 0 9239212Sgibbs && (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) == 0) { 9339212Sgibbs periph->flags |= CAM_PERIPH_NEW_DEV_FOUND; 9439212Sgibbs periph->deferred_callback = ac_callback; 9539212Sgibbs periph->deferred_ac = code; 9639212Sgibbs return (CAM_REQ_INPROG); 9739212Sgibbs } else { 9839212Sgibbs printf("cam_periph_alloc: attempt to re-allocate " 9939212Sgibbs "valid device %s%d rejected\n", 10039212Sgibbs periph->periph_name, periph->unit_number); 10139212Sgibbs } 10239212Sgibbs return (CAM_REQ_INVALID); 10339212Sgibbs } 10439212Sgibbs 10539212Sgibbs periph = (struct cam_periph *)malloc(sizeof(*periph), M_DEVBUF, 10639212Sgibbs M_NOWAIT); 10739212Sgibbs 10839212Sgibbs if (periph == NULL) 10939212Sgibbs return (CAM_RESRC_UNAVAIL); 11039212Sgibbs 11139212Sgibbs init_level++; 11239212Sgibbs 11339212Sgibbs for (p_drv = (struct periph_driver **)periphdriver_set.ls_items; 11439212Sgibbs *p_drv != NULL; p_drv++) { 11539212Sgibbs if (strcmp((*p_drv)->driver_name, name) == 0) 11639212Sgibbs break; 11739212Sgibbs } 11839212Sgibbs 11939212Sgibbs path_id = xpt_path_path_id(path); 12039212Sgibbs target_id = xpt_path_target_id(path); 12139212Sgibbs lun_id = xpt_path_lun_id(path); 12239212Sgibbs bzero(periph, sizeof(*periph)); 12339212Sgibbs cam_init_pinfo(&periph->pinfo); 12439212Sgibbs periph->periph_start = periph_start; 12539212Sgibbs periph->periph_dtor = periph_dtor; 12640603Sken periph->periph_oninval = periph_oninvalidate; 12739212Sgibbs periph->type = type; 12839212Sgibbs periph->periph_name = name; 12939212Sgibbs periph->unit_number = camperiphunit(*p_drv, path_id, target_id, lun_id); 13039212Sgibbs periph->immediate_priority = CAM_PRIORITY_NONE; 13139212Sgibbs periph->refcount = 0; 13239212Sgibbs SLIST_INIT(&periph->ccb_list); 13339212Sgibbs status = xpt_create_path(&path, periph, path_id, target_id, lun_id); 13439212Sgibbs if (status != CAM_REQ_CMP) 13539212Sgibbs goto failure; 13639212Sgibbs 13739212Sgibbs periph->path = path; 13839212Sgibbs init_level++; 13939212Sgibbs 14039212Sgibbs status = xpt_add_periph(periph); 14139212Sgibbs 14239212Sgibbs if (status != CAM_REQ_CMP) 14339212Sgibbs goto failure; 14439212Sgibbs 14539212Sgibbs s = splsoftcam(); 14639212Sgibbs cur_periph = TAILQ_FIRST(&(*p_drv)->units); 14739212Sgibbs while (cur_periph != NULL 14839212Sgibbs && cur_periph->unit_number < periph->unit_number) 14939212Sgibbs cur_periph = TAILQ_NEXT(cur_periph, unit_links); 15039212Sgibbs 15139212Sgibbs if (cur_periph != NULL) 15239212Sgibbs TAILQ_INSERT_BEFORE(cur_periph, periph, unit_links); 15339212Sgibbs else { 15439212Sgibbs TAILQ_INSERT_TAIL(&(*p_drv)->units, periph, unit_links); 15539212Sgibbs (*p_drv)->generation++; 15639212Sgibbs } 15739212Sgibbs 15839212Sgibbs splx(s); 15939212Sgibbs 16039212Sgibbs init_level++; 16139212Sgibbs 16239212Sgibbs status = periph_ctor(periph, arg); 16339212Sgibbs 16439212Sgibbs if (status == CAM_REQ_CMP) 16539212Sgibbs init_level++; 16639212Sgibbs 16739212Sgibbsfailure: 16839212Sgibbs switch (init_level) { 16939212Sgibbs case 4: 17039212Sgibbs /* Initialized successfully */ 17139212Sgibbs break; 17239212Sgibbs case 3: 17339212Sgibbs s = splsoftcam(); 17439212Sgibbs TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links); 17539212Sgibbs splx(s); 17639212Sgibbs xpt_remove_periph(periph); 17739212Sgibbs case 2: 17839212Sgibbs xpt_free_path(periph->path); 17939212Sgibbs case 1: 18039212Sgibbs free(periph, M_DEVBUF); 18139212Sgibbs case 0: 18239212Sgibbs /* No cleanup to perform. */ 18339212Sgibbs break; 18439212Sgibbs default: 18539212Sgibbs panic("cam_periph_alloc: Unkown init level"); 18639212Sgibbs } 18739212Sgibbs return(status); 18839212Sgibbs} 18939212Sgibbs 19039212Sgibbs/* 19139212Sgibbs * Find a peripheral structure with the specified path, target, lun, 19239212Sgibbs * and (optionally) type. If the name is NULL, this function will return 19339212Sgibbs * the first peripheral driver that matches the specified path. 19439212Sgibbs */ 19539212Sgibbsstruct cam_periph * 19639212Sgibbscam_periph_find(struct cam_path *path, char *name) 19739212Sgibbs{ 19839212Sgibbs struct periph_driver **p_drv; 19939212Sgibbs struct cam_periph *periph; 20039212Sgibbs int s; 20139212Sgibbs 20239212Sgibbs for (p_drv = (struct periph_driver **)periphdriver_set.ls_items; 20339212Sgibbs *p_drv != NULL; p_drv++) { 20439212Sgibbs 20539212Sgibbs if (name != NULL && (strcmp((*p_drv)->driver_name, name) != 0)) 20639212Sgibbs continue; 20739212Sgibbs 20839212Sgibbs s = splsoftcam(); 20939212Sgibbs for (periph = TAILQ_FIRST(&(*p_drv)->units); periph != NULL; 21039212Sgibbs periph = TAILQ_NEXT(periph, unit_links)) { 21139212Sgibbs if (xpt_path_comp(periph->path, path) == 0) { 21239212Sgibbs splx(s); 21339212Sgibbs return(periph); 21439212Sgibbs } 21539212Sgibbs } 21639212Sgibbs splx(s); 21739212Sgibbs if (name != NULL) 21839212Sgibbs return(NULL); 21939212Sgibbs } 22039212Sgibbs return(NULL); 22139212Sgibbs} 22239212Sgibbs 22339212Sgibbscam_status 22439212Sgibbscam_periph_acquire(struct cam_periph *periph) 22539212Sgibbs{ 22639212Sgibbs int s; 22739212Sgibbs 22839212Sgibbs if (periph == NULL) 22939212Sgibbs return(CAM_REQ_CMP_ERR); 23039212Sgibbs 23139212Sgibbs s = splsoftcam(); 23239212Sgibbs periph->refcount++; 23339212Sgibbs splx(s); 23439212Sgibbs 23539212Sgibbs return(CAM_REQ_CMP); 23639212Sgibbs} 23739212Sgibbs 23839212Sgibbsvoid 23939212Sgibbscam_periph_release(struct cam_periph *periph) 24039212Sgibbs{ 24139212Sgibbs int s; 24239212Sgibbs 24339212Sgibbs if (periph == NULL) 24439212Sgibbs return; 24539212Sgibbs 24639212Sgibbs s = splsoftcam(); 24739212Sgibbs if ((--periph->refcount == 0) 24839212Sgibbs && (periph->flags & CAM_PERIPH_INVALID)) { 24939212Sgibbs camperiphfree(periph); 25039212Sgibbs } 25139212Sgibbs splx(s); 25239212Sgibbs 25339212Sgibbs} 25439212Sgibbs 25539212Sgibbs/* 25639212Sgibbs * Look for the next unit number that is not currently in use for this 25739212Sgibbs * peripheral type starting at "newunit". Also exclude unit numbers that 25839212Sgibbs * are reserved by for future "hardwiring" unless we already know that this 25939212Sgibbs * is a potential wired device. Only assume that the device is "wired" the 26039212Sgibbs * first time through the loop since after that we'll be looking at unit 26139212Sgibbs * numbers that did not match a wiring entry. 26239212Sgibbs */ 26339212Sgibbsstatic u_int 26439212Sgibbscamperiphnextunit(struct periph_driver *p_drv, u_int newunit, int wired) 26539212Sgibbs{ 26639212Sgibbs struct cam_periph *periph; 26739212Sgibbs struct cam_periph_config *periph_conf; 26839212Sgibbs char *periph_name; 26939212Sgibbs int s; 27039212Sgibbs 27139212Sgibbs s = splsoftcam(); 27239212Sgibbs periph_name = p_drv->driver_name; 27339212Sgibbs for (;;newunit++) { 27439212Sgibbs 27539212Sgibbs for (periph = TAILQ_FIRST(&p_drv->units); 27639212Sgibbs periph != NULL && periph->unit_number != newunit; 27739212Sgibbs periph = TAILQ_NEXT(periph, unit_links)) 27839212Sgibbs ; 27939212Sgibbs 28039212Sgibbs if (periph != NULL && periph->unit_number == newunit) { 28139212Sgibbs if (wired != 0) { 28239212Sgibbs xpt_print_path(periph->path); 28339212Sgibbs printf("Duplicate Wired Device entry!\n"); 28439212Sgibbs xpt_print_path(periph->path); 28539212Sgibbs printf("Second device will not be wired\n"); 28639212Sgibbs wired = 0; 28739212Sgibbs } 28839212Sgibbs continue; 28939212Sgibbs } 29039212Sgibbs 29139212Sgibbs for (periph_conf = cam_pinit; 29239212Sgibbs wired == 0 && periph_conf->periph_name != NULL; 29339212Sgibbs periph_conf++) { 29439212Sgibbs 29539212Sgibbs /* 29639212Sgibbs * Don't match entries like "da 4" as a wired down 29739212Sgibbs * device, but do match entries like "da 4 target 5" 29839212Sgibbs * or even "da 4 scbus 1". 29939212Sgibbs */ 30039212Sgibbs if (IS_SPECIFIED(periph_conf->periph_unit) 30139212Sgibbs && (!strcmp(periph_name, periph_conf->periph_name)) 30239212Sgibbs && (IS_SPECIFIED(periph_conf->target) 30339212Sgibbs || IS_SPECIFIED(periph_conf->pathid)) 30439212Sgibbs && (newunit == periph_conf->periph_unit)) 30539212Sgibbs break; 30639212Sgibbs } 30739212Sgibbs 30839212Sgibbs if (wired != 0 || periph_conf->periph_name == NULL) 30939212Sgibbs break; 31039212Sgibbs } 31139212Sgibbs splx(s); 31239212Sgibbs return (newunit); 31339212Sgibbs} 31439212Sgibbs 31539212Sgibbsstatic u_int 31639212Sgibbscamperiphunit(struct periph_driver *p_drv, path_id_t pathid, 31739212Sgibbs target_id_t target, lun_id_t lun) 31839212Sgibbs{ 31939212Sgibbs struct cam_periph_config *periph_conf; 32039212Sgibbs u_int unit; 32139212Sgibbs int hit; 32239212Sgibbs 32339212Sgibbs unit = 0; 32439212Sgibbs hit = 0; 32539212Sgibbs 32639212Sgibbs for (periph_conf = cam_pinit; 32739212Sgibbs periph_conf->periph_name != NULL; 32839212Sgibbs periph_conf++, hit = 0) { 32939212Sgibbs 33039212Sgibbs if (!strcmp(p_drv->driver_name, periph_conf->periph_name) 33139212Sgibbs && IS_SPECIFIED(periph_conf->periph_unit)) { 33239212Sgibbs 33339212Sgibbs if (IS_SPECIFIED(periph_conf->pathid)) { 33439212Sgibbs 33539212Sgibbs if (pathid != periph_conf->pathid) 33639212Sgibbs continue; 33739212Sgibbs hit++; 33839212Sgibbs } 33939212Sgibbs 34039212Sgibbs if (IS_SPECIFIED(periph_conf->target)) { 34139212Sgibbs 34239212Sgibbs if (target != periph_conf->target) 34339212Sgibbs continue; 34439212Sgibbs hit++; 34539212Sgibbs } 34639212Sgibbs 34739212Sgibbs if (IS_SPECIFIED(periph_conf->lun)) { 34839212Sgibbs 34939212Sgibbs if (lun != periph_conf->lun) 35039212Sgibbs continue; 35139212Sgibbs hit++; 35239212Sgibbs } 35339212Sgibbs 35439212Sgibbs if (hit != 0) { 35539212Sgibbs unit = periph_conf->periph_unit; 35639212Sgibbs break; 35739212Sgibbs } 35839212Sgibbs } 35939212Sgibbs } 36039212Sgibbs 36139212Sgibbs /* 36239212Sgibbs * Either start from 0 looking for the next unit or from 36339212Sgibbs * the unit number given in the periph_conf. This way, 36439212Sgibbs * if we have wildcard matches, we don't return the same 36539212Sgibbs * unit number twice. 36639212Sgibbs */ 36739212Sgibbs unit = camperiphnextunit(p_drv, unit, /*wired*/hit); 36839212Sgibbs 36939212Sgibbs return (unit); 37039212Sgibbs} 37139212Sgibbs 37239212Sgibbsvoid 37339212Sgibbscam_periph_invalidate(struct cam_periph *periph) 37439212Sgibbs{ 37539212Sgibbs int s; 37639212Sgibbs 37740603Sken s = splsoftcam(); 37840603Sken /* 37940603Sken * We only call this routine the first time a peripheral is 38040603Sken * invalidated. The oninvalidate() routine is always called at 38140603Sken * splsoftcam(). 38240603Sken */ 38340603Sken if (((periph->flags & CAM_PERIPH_INVALID) == 0) 38440603Sken && (periph->periph_oninval != NULL)) 38540603Sken periph->periph_oninval(periph); 38640603Sken 38739212Sgibbs periph->flags |= CAM_PERIPH_INVALID; 38839212Sgibbs periph->flags &= ~CAM_PERIPH_NEW_DEV_FOUND; 38939212Sgibbs 39039212Sgibbs if (periph->refcount == 0) 39139212Sgibbs camperiphfree(periph); 39239212Sgibbs else if (periph->refcount < 0) 39339212Sgibbs printf("cam_invalidate_periph: refcount < 0!!\n"); 39439212Sgibbs splx(s); 39539212Sgibbs} 39639212Sgibbs 39739212Sgibbsstatic void 39839212Sgibbscamperiphfree(struct cam_periph *periph) 39939212Sgibbs{ 40039212Sgibbs int s; 40139212Sgibbs struct periph_driver **p_drv; 40239212Sgibbs 40339212Sgibbs for (p_drv = (struct periph_driver **)periphdriver_set.ls_items; 40439212Sgibbs *p_drv != NULL; p_drv++) { 40539212Sgibbs if (strcmp((*p_drv)->driver_name, periph->periph_name) == 0) 40639212Sgibbs break; 40739212Sgibbs } 40839212Sgibbs 40939212Sgibbs if (periph->periph_dtor != NULL) 41039212Sgibbs periph->periph_dtor(periph); 41139212Sgibbs 41239212Sgibbs s = splsoftcam(); 41339212Sgibbs TAILQ_REMOVE(&(*p_drv)->units, periph, unit_links); 41439212Sgibbs (*p_drv)->generation++; 41539212Sgibbs splx(s); 41639212Sgibbs 41739212Sgibbs xpt_remove_periph(periph); 41839212Sgibbs 41939212Sgibbs if (periph->flags & CAM_PERIPH_NEW_DEV_FOUND) { 42039212Sgibbs union ccb ccb; 42139212Sgibbs void *arg; 42239212Sgibbs 42339212Sgibbs switch (periph->deferred_ac) { 42439212Sgibbs case AC_FOUND_DEVICE: 42539212Sgibbs ccb.ccb_h.func_code = XPT_GDEV_TYPE; 42639212Sgibbs xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1); 42739212Sgibbs xpt_action(&ccb); 42839212Sgibbs arg = &ccb; 42939212Sgibbs break; 43039212Sgibbs case AC_PATH_REGISTERED: 43139212Sgibbs ccb.ccb_h.func_code = XPT_PATH_INQ; 43239212Sgibbs xpt_setup_ccb(&ccb.ccb_h, periph->path, /*priority*/ 1); 43339212Sgibbs xpt_action(&ccb); 43439212Sgibbs arg = &ccb; 43539212Sgibbs break; 43639212Sgibbs default: 43739212Sgibbs arg = NULL; 43839212Sgibbs break; 43939212Sgibbs } 44039212Sgibbs periph->deferred_callback(NULL, periph->deferred_ac, 44139212Sgibbs periph->path, arg); 44239212Sgibbs } 44339212Sgibbs xpt_free_path(periph->path); 44439212Sgibbs free(periph, M_DEVBUF); 44539212Sgibbs} 44639212Sgibbs 44739212Sgibbs/* 44839212Sgibbs * Wait interruptibly for an exclusive lock. 44939212Sgibbs */ 45039212Sgibbsint 45139212Sgibbscam_periph_lock(struct cam_periph *periph, int priority) 45239212Sgibbs{ 45339212Sgibbs int error; 45439212Sgibbs 45539212Sgibbs while ((periph->flags & CAM_PERIPH_LOCKED) != 0) { 45639212Sgibbs periph->flags |= CAM_PERIPH_LOCK_WANTED; 45739212Sgibbs if ((error = tsleep(periph, priority, "caplck", 0)) != 0) 45839212Sgibbs return error; 45939212Sgibbs } 46039212Sgibbs 46139212Sgibbs if (cam_periph_acquire(periph) != CAM_REQ_CMP) 46239212Sgibbs return(ENXIO); 46339212Sgibbs 46439212Sgibbs periph->flags |= CAM_PERIPH_LOCKED; 46539212Sgibbs return 0; 46639212Sgibbs} 46739212Sgibbs 46839212Sgibbs/* 46939212Sgibbs * Unlock and wake up any waiters. 47039212Sgibbs */ 47139212Sgibbsvoid 47239212Sgibbscam_periph_unlock(struct cam_periph *periph) 47339212Sgibbs{ 47439212Sgibbs periph->flags &= ~CAM_PERIPH_LOCKED; 47539212Sgibbs if ((periph->flags & CAM_PERIPH_LOCK_WANTED) != 0) { 47639212Sgibbs periph->flags &= ~CAM_PERIPH_LOCK_WANTED; 47739212Sgibbs wakeup(periph); 47839212Sgibbs } 47939212Sgibbs 48039212Sgibbs cam_periph_release(periph); 48139212Sgibbs} 48239212Sgibbs 48339212Sgibbs/* 48439212Sgibbs * Map user virtual pointers into kernel virtual address space, so we can 48539212Sgibbs * access the memory. This won't work on physical pointers, for now it's 48639212Sgibbs * up to the caller to check for that. (XXX KDM -- should we do that here 48739212Sgibbs * instead?) This also only works for up to MAXPHYS memory. Since we use 48839212Sgibbs * buffers to map stuff in and out, we're limited to the buffer size. 48939212Sgibbs */ 49039212Sgibbsint 49139212Sgibbscam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) 49239212Sgibbs{ 49341877Sken int numbufs, i; 49441877Sken int flags[CAM_PERIPH_MAXMAPS]; 49539212Sgibbs u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS]; 49639212Sgibbs u_int32_t lengths[CAM_PERIPH_MAXMAPS]; 49739212Sgibbs u_int32_t dirs[CAM_PERIPH_MAXMAPS]; 49839212Sgibbs 49939212Sgibbs switch(ccb->ccb_h.func_code) { 50039212Sgibbs case XPT_DEV_MATCH: 50139212Sgibbs if (ccb->cdm.match_buf_len == 0) { 50239212Sgibbs printf("cam_periph_mapmem: invalid match buffer " 50339212Sgibbs "length 0\n"); 50439212Sgibbs return(EINVAL); 50539212Sgibbs } 50639212Sgibbs if (ccb->cdm.pattern_buf_len > 0) { 50739212Sgibbs data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns; 50839212Sgibbs lengths[0] = ccb->cdm.pattern_buf_len; 50939212Sgibbs dirs[0] = CAM_DIR_OUT; 51039212Sgibbs data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches; 51139212Sgibbs lengths[1] = ccb->cdm.match_buf_len; 51239212Sgibbs dirs[1] = CAM_DIR_IN; 51339212Sgibbs numbufs = 2; 51439212Sgibbs } else { 51539212Sgibbs data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches; 51639212Sgibbs lengths[0] = ccb->cdm.match_buf_len; 51739212Sgibbs dirs[0] = CAM_DIR_IN; 51839212Sgibbs numbufs = 1; 51939212Sgibbs } 52039212Sgibbs break; 52139212Sgibbs case XPT_SCSI_IO: 52239212Sgibbs if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 52339212Sgibbs return(0); 52439212Sgibbs 52539212Sgibbs data_ptrs[0] = &ccb->csio.data_ptr; 52641877Sken lengths[0] = ccb->csio.dxfer_len; 52739212Sgibbs dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 52839212Sgibbs numbufs = 1; 52939212Sgibbs break; 53039212Sgibbs default: 53139212Sgibbs return(EINVAL); 53239212Sgibbs break; /* NOTREACHED */ 53339212Sgibbs } 53439212Sgibbs 53539212Sgibbs /* 53641877Sken * Check the transfer length and permissions first, so we don't 53741877Sken * have to unmap any previously mapped buffers. 53839212Sgibbs */ 53939212Sgibbs for (i = 0; i < numbufs; i++) { 54039212Sgibbs 54141877Sken flags[i] = 0; 54241877Sken 54341877Sken /* 54441877Sken * The userland data pointer passed in may not be page 54541877Sken * aligned. vmapbuf() truncates the address to a page 54641877Sken * boundary, so if the address isn't page aligned, we'll 54741877Sken * need enough space for the given transfer length, plus 54841877Sken * whatever extra space is necessary to make it to the page 54941877Sken * boundary. 55041877Sken */ 55141877Sken if ((lengths[i] + 55241885Sken (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > DFLTPHYS){ 55341877Sken printf("cam_periph_mapmem: attempt to map %u bytes, " 55441885Sken "which is greater than DFLTPHYS(%d)\n", 55541877Sken lengths[i] + 55641877Sken (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK), 55741885Sken DFLTPHYS); 55841877Sken return(E2BIG); 55941877Sken } 56041877Sken 56139212Sgibbs if (dirs[i] & CAM_DIR_IN) { 56241877Sken flags[i] = B_READ; 56339212Sgibbs if (useracc(*data_ptrs[i], lengths[i], B_READ) == 0){ 56439212Sgibbs printf("cam_periph_mapmem: error, " 56539758Sbde "address %p, length %lu isn't " 56639212Sgibbs "user accessible for READ\n", 56739758Sbde (void *)*data_ptrs[i], 56839758Sbde (u_long)lengths[i]); 56939212Sgibbs return(EACCES); 57039212Sgibbs } 57139212Sgibbs } 57239212Sgibbs 57339212Sgibbs /* 57439212Sgibbs * XXX this check is really bogus, since B_WRITE currently 57539212Sgibbs * is all 0's, and so it is "set" all the time. 57639212Sgibbs */ 57739212Sgibbs if (dirs[i] & CAM_DIR_OUT) { 57841877Sken flags[i] |= B_WRITE; 57939212Sgibbs if (useracc(*data_ptrs[i], lengths[i], B_WRITE) == 0){ 58039212Sgibbs printf("cam_periph_mapmem: error, " 58139758Sbde "address %p, length %lu isn't " 58239212Sgibbs "user accessible for WRITE\n", 58339758Sbde (void *)*data_ptrs[i], 58439758Sbde (u_long)lengths[i]); 58539212Sgibbs 58639212Sgibbs return(EACCES); 58739212Sgibbs } 58839212Sgibbs } 58939212Sgibbs 59041877Sken } 59141877Sken 59241877Sken /* this keeps the current process from getting swapped */ 59341877Sken /* 59441877Sken * XXX KDM should I use P_NOSWAP instead? 59541877Sken */ 59641877Sken curproc->p_flag |= P_PHYSIO; 59741877Sken 59841877Sken for (i = 0; i < numbufs; i++) { 59939212Sgibbs /* 60039212Sgibbs * Get the buffer. 60139212Sgibbs */ 60242957Sdillon mapinfo->bp[i] = getpbuf(NULL); 60339212Sgibbs 60439212Sgibbs /* save the buffer's data address */ 60539212Sgibbs mapinfo->bp[i]->b_saveaddr = mapinfo->bp[i]->b_data; 60639212Sgibbs 60739212Sgibbs /* put our pointer in the data slot */ 60839212Sgibbs mapinfo->bp[i]->b_data = *data_ptrs[i]; 60939212Sgibbs 61041885Sken /* set the transfer length, we know it's < DFLTPHYS */ 61139212Sgibbs mapinfo->bp[i]->b_bufsize = lengths[i]; 61239212Sgibbs 61339212Sgibbs /* set the flags */ 61441877Sken mapinfo->bp[i]->b_flags = flags[i] | B_PHYS | B_BUSY; 61539212Sgibbs 61639212Sgibbs /* map the buffer into kernel memory */ 61739212Sgibbs vmapbuf(mapinfo->bp[i]); 61839212Sgibbs 61939212Sgibbs /* set our pointer to the new mapped area */ 62039212Sgibbs *data_ptrs[i] = mapinfo->bp[i]->b_data; 62139212Sgibbs 62239212Sgibbs mapinfo->num_bufs_used++; 62339212Sgibbs } 62439212Sgibbs 62539212Sgibbs return(0); 62639212Sgibbs} 62739212Sgibbs 62839212Sgibbs/* 62939212Sgibbs * Unmap memory segments mapped into kernel virtual address space by 63039212Sgibbs * cam_periph_mapmem(). 63139212Sgibbs */ 63239212Sgibbsvoid 63339212Sgibbscam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) 63439212Sgibbs{ 63539212Sgibbs int numbufs, i; 63639212Sgibbs u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS]; 63739212Sgibbs 63839212Sgibbs if (mapinfo->num_bufs_used <= 0) { 63939212Sgibbs /* allow ourselves to be swapped once again */ 64039212Sgibbs curproc->p_flag &= ~P_PHYSIO; 64139212Sgibbs return; 64239212Sgibbs } 64339212Sgibbs 64439212Sgibbs switch (ccb->ccb_h.func_code) { 64539212Sgibbs case XPT_DEV_MATCH: 64639212Sgibbs numbufs = min(mapinfo->num_bufs_used, 2); 64739212Sgibbs 64839212Sgibbs if (numbufs == 1) { 64939212Sgibbs data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches; 65039212Sgibbs } else { 65139212Sgibbs data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns; 65239212Sgibbs data_ptrs[1] = (u_int8_t **)&ccb->cdm.matches; 65339212Sgibbs } 65439212Sgibbs break; 65539212Sgibbs case XPT_SCSI_IO: 65639212Sgibbs data_ptrs[0] = &ccb->csio.data_ptr; 65739212Sgibbs numbufs = min(mapinfo->num_bufs_used, 1); 65839212Sgibbs break; 65939212Sgibbs default: 66039212Sgibbs /* allow ourselves to be swapped once again */ 66139212Sgibbs curproc->p_flag &= ~P_PHYSIO; 66239212Sgibbs return; 66339212Sgibbs break; /* NOTREACHED */ 66439212Sgibbs } 66539212Sgibbs 66639212Sgibbs for (i = 0; i < numbufs; i++) { 66739212Sgibbs /* Set the user's pointer back to the original value */ 66839212Sgibbs *data_ptrs[i] = mapinfo->bp[i]->b_saveaddr; 66939212Sgibbs 67039212Sgibbs /* unmap the buffer */ 67139212Sgibbs vunmapbuf(mapinfo->bp[i]); 67239212Sgibbs 67339212Sgibbs /* clear the flags we set above */ 67439212Sgibbs mapinfo->bp[i]->b_flags &= ~(B_PHYS|B_BUSY); 67539212Sgibbs 67639212Sgibbs /* release the buffer */ 67742957Sdillon relpbuf(mapinfo->bp[i], NULL); 67839212Sgibbs } 67939212Sgibbs 68039212Sgibbs /* allow ourselves to be swapped once again */ 68139212Sgibbs curproc->p_flag &= ~P_PHYSIO; 68239212Sgibbs} 68339212Sgibbs 68439212Sgibbsunion ccb * 68539212Sgibbscam_periph_getccb(struct cam_periph *periph, u_int32_t priority) 68639212Sgibbs{ 68739212Sgibbs struct ccb_hdr *ccb_h; 68839212Sgibbs int s; 68939212Sgibbs 69039212Sgibbs CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetccb\n")); 69139212Sgibbs 69239212Sgibbs s = splsoftcam(); 69339212Sgibbs 69439212Sgibbs while (periph->ccb_list.slh_first == NULL) { 69539212Sgibbs if (periph->immediate_priority > priority) 69639212Sgibbs periph->immediate_priority = priority; 69739212Sgibbs xpt_schedule(periph, priority); 69839212Sgibbs if ((periph->ccb_list.slh_first != NULL) 69939212Sgibbs && (periph->ccb_list.slh_first->pinfo.priority == priority)) 70039212Sgibbs break; 70139212Sgibbs tsleep(&periph->ccb_list, PRIBIO, "cgticb", 0); 70239212Sgibbs } 70339212Sgibbs 70439212Sgibbs ccb_h = periph->ccb_list.slh_first; 70539212Sgibbs SLIST_REMOVE_HEAD(&periph->ccb_list, periph_links.sle); 70639212Sgibbs splx(s); 70739212Sgibbs return ((union ccb *)ccb_h); 70839212Sgibbs} 70939212Sgibbs 71039212Sgibbsvoid 71139212Sgibbscam_periph_ccbwait(union ccb *ccb) 71239212Sgibbs{ 71339212Sgibbs int s; 71439212Sgibbs 71539212Sgibbs s = splsoftcam(); 71639212Sgibbs if ((ccb->ccb_h.pinfo.index != CAM_UNQUEUED_INDEX) 71739212Sgibbs || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)) 71839212Sgibbs tsleep(&ccb->ccb_h.cbfcnp, PRIBIO, "cbwait", 0); 71939212Sgibbs 72039212Sgibbs splx(s); 72139212Sgibbs} 72239212Sgibbs 72339212Sgibbsint 72439212Sgibbscam_periph_ioctl(struct cam_periph *periph, int cmd, caddr_t addr, 72539212Sgibbs int (*error_routine)(union ccb *ccb, 72639212Sgibbs cam_flags camflags, 72739212Sgibbs u_int32_t sense_flags)) 72839212Sgibbs{ 72939212Sgibbs union ccb *ccb; 73039212Sgibbs int error; 73139212Sgibbs int found; 73239212Sgibbs 73339212Sgibbs error = found = 0; 73439212Sgibbs 73539212Sgibbs switch(cmd){ 73639212Sgibbs case CAMGETPASSTHRU: 73739212Sgibbs ccb = cam_periph_getccb(periph, /* priority */ 1); 73839212Sgibbs xpt_setup_ccb(&ccb->ccb_h, 73939212Sgibbs ccb->ccb_h.path, 74039212Sgibbs /*priority*/1); 74139212Sgibbs ccb->ccb_h.func_code = XPT_GDEVLIST; 74239212Sgibbs 74339212Sgibbs /* 74439212Sgibbs * Basically, the point of this is that we go through 74539212Sgibbs * getting the list of devices, until we find a passthrough 74639212Sgibbs * device. In the current version of the CAM code, the 74739212Sgibbs * only way to determine what type of device we're dealing 74839212Sgibbs * with is by its name. 74939212Sgibbs */ 75039212Sgibbs while (found == 0) { 75139212Sgibbs ccb->cgdl.index = 0; 75239212Sgibbs ccb->cgdl.status = CAM_GDEVLIST_MORE_DEVS; 75339212Sgibbs while (ccb->cgdl.status == CAM_GDEVLIST_MORE_DEVS) { 75439212Sgibbs 75539212Sgibbs /* we want the next device in the list */ 75639212Sgibbs xpt_action(ccb); 75739212Sgibbs if (strncmp(ccb->cgdl.periph_name, 75839212Sgibbs "pass", 4) == 0){ 75939212Sgibbs found = 1; 76039212Sgibbs break; 76139212Sgibbs } 76239212Sgibbs } 76339212Sgibbs if ((ccb->cgdl.status == CAM_GDEVLIST_LAST_DEVICE) && 76439212Sgibbs (found == 0)) { 76539212Sgibbs ccb->cgdl.periph_name[0] = '\0'; 76639212Sgibbs ccb->cgdl.unit_number = 0; 76739212Sgibbs break; 76839212Sgibbs } 76939212Sgibbs } 77039212Sgibbs 77139212Sgibbs /* copy the result back out */ 77239212Sgibbs bcopy(ccb, addr, sizeof(union ccb)); 77339212Sgibbs 77439212Sgibbs /* and release the ccb */ 77539212Sgibbs xpt_release_ccb(ccb); 77639212Sgibbs 77739212Sgibbs break; 77839212Sgibbs default: 77939212Sgibbs error = ENOTTY; 78039212Sgibbs break; 78139212Sgibbs } 78239212Sgibbs return(error); 78339212Sgibbs} 78439212Sgibbs 78539212Sgibbsint 78639212Sgibbscam_periph_runccb(union ccb *ccb, 78739212Sgibbs int (*error_routine)(union ccb *ccb, 78839212Sgibbs cam_flags camflags, 78939212Sgibbs u_int32_t sense_flags), 79039212Sgibbs cam_flags camflags, u_int32_t sense_flags, 79139212Sgibbs struct devstat *ds) 79239212Sgibbs{ 79339212Sgibbs int error; 79439212Sgibbs 79539212Sgibbs error = 0; 79639212Sgibbs 79739212Sgibbs /* 79839212Sgibbs * If the user has supplied a stats structure, and if we understand 79939212Sgibbs * this particular type of ccb, record the transaction start. 80039212Sgibbs */ 80139212Sgibbs if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO)) 80239212Sgibbs devstat_start_transaction(ds); 80339212Sgibbs 80439212Sgibbs xpt_action(ccb); 80539212Sgibbs 80639212Sgibbs do { 80739212Sgibbs cam_periph_ccbwait(ccb); 80839212Sgibbs if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 80939212Sgibbs error = 0; 81039212Sgibbs else if (error_routine != NULL) 81139212Sgibbs error = (*error_routine)(ccb, camflags, sense_flags); 81239212Sgibbs else 81339212Sgibbs error = 0; 81439212Sgibbs 81539212Sgibbs } while (error == ERESTART); 81639212Sgibbs 81739212Sgibbs if ((ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) 81839212Sgibbs cam_release_devq(ccb->ccb_h.path, 81939212Sgibbs /* relsim_flags */0, 82039212Sgibbs /* openings */0, 82139212Sgibbs /* timeout */0, 82239212Sgibbs /* getcount_only */ FALSE); 82339212Sgibbs 82439212Sgibbs if ((ds != NULL) && (ccb->ccb_h.func_code == XPT_SCSI_IO)) 82539212Sgibbs devstat_end_transaction(ds, 82639212Sgibbs ccb->csio.dxfer_len, 82739212Sgibbs ccb->csio.tag_action & 0xf, 82839212Sgibbs ((ccb->ccb_h.flags & CAM_DIR_MASK) == 82939212Sgibbs CAM_DIR_NONE) ? DEVSTAT_NO_DATA : 83039212Sgibbs (ccb->ccb_h.flags & CAM_DIR_OUT) ? 83139212Sgibbs DEVSTAT_WRITE : 83239212Sgibbs DEVSTAT_READ); 83339212Sgibbs 83439212Sgibbs return(error); 83539212Sgibbs} 83639212Sgibbs 83739212Sgibbsu_int32_t 83839212Sgibbscam_release_devq(struct cam_path *path, u_int32_t relsim_flags, 83939212Sgibbs u_int32_t openings, u_int32_t timeout, 84039212Sgibbs int getcount_only) 84139212Sgibbs{ 84239212Sgibbs struct ccb_relsim crs; 84339212Sgibbs 84439212Sgibbs xpt_setup_ccb(&crs.ccb_h, path, 84539212Sgibbs /*priority*/1); 84639212Sgibbs crs.ccb_h.func_code = XPT_REL_SIMQ; 84739212Sgibbs crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0; 84839212Sgibbs crs.release_flags = relsim_flags; 84939212Sgibbs crs.openings = openings; 85039212Sgibbs crs.release_timeout = timeout; 85139212Sgibbs xpt_action((union ccb *)&crs); 85239212Sgibbs return (crs.qfrozen_cnt); 85339212Sgibbs} 85439212Sgibbs 85539212Sgibbs#define saved_ccb_ptr ppriv_ptr0 85639212Sgibbsstatic void 85739212Sgibbscamperiphdone(struct cam_periph *periph, union ccb *done_ccb) 85839212Sgibbs{ 85939212Sgibbs cam_status status; 86039212Sgibbs int frozen; 86139212Sgibbs int sense; 86239212Sgibbs struct scsi_start_stop_unit *scsi_cmd; 86339212Sgibbs u_int32_t relsim_flags, timeout; 86439212Sgibbs u_int32_t qfrozen_cnt; 86539212Sgibbs 86639212Sgibbs status = done_ccb->ccb_h.status; 86739212Sgibbs frozen = (status & CAM_DEV_QFRZN) != 0; 86839212Sgibbs sense = (status & CAM_AUTOSNS_VALID) != 0; 86939212Sgibbs status &= CAM_STATUS_MASK; 87039212Sgibbs 87139212Sgibbs timeout = 0; 87239212Sgibbs relsim_flags = 0; 87339212Sgibbs 87439212Sgibbs /* 87539212Sgibbs * Unfreeze the queue once if it is already frozen.. 87639212Sgibbs */ 87739212Sgibbs if (frozen != 0) { 87839212Sgibbs qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path, 87939212Sgibbs /*relsim_flags*/0, 88039212Sgibbs /*openings*/0, 88139212Sgibbs /*timeout*/0, 88239212Sgibbs /*getcount_only*/0); 88339212Sgibbs } 88439212Sgibbs 88539212Sgibbs switch (status) { 88639212Sgibbs 88739212Sgibbs case CAM_REQ_CMP: 88839212Sgibbs 88939212Sgibbs /* 89039212Sgibbs * If we have successfully taken a device from the not 89139212Sgibbs * ready to ready state, re-scan the device and re-get the 89239212Sgibbs * inquiry information. Many devices (mostly disks) don't 89339212Sgibbs * properly report their inquiry information unless they 89439212Sgibbs * are spun up. 89539212Sgibbs */ 89639212Sgibbs if (done_ccb->ccb_h.func_code == XPT_SCSI_IO) { 89739212Sgibbs scsi_cmd = (struct scsi_start_stop_unit *) 89839212Sgibbs &done_ccb->csio.cdb_io.cdb_bytes; 89939212Sgibbs 90039212Sgibbs if (scsi_cmd->opcode == START_STOP_UNIT) 90139212Sgibbs xpt_async(AC_INQ_CHANGED, 90239212Sgibbs done_ccb->ccb_h.path, NULL); 90339212Sgibbs } 90439212Sgibbs bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb, 90539212Sgibbs sizeof(union ccb)); 90639212Sgibbs 90740318Sken periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; 90840318Sken 90939212Sgibbs xpt_action(done_ccb); 91039212Sgibbs 91139212Sgibbs break; 91239212Sgibbs case CAM_SCSI_STATUS_ERROR: 91339212Sgibbs scsi_cmd = (struct scsi_start_stop_unit *) 91439212Sgibbs &done_ccb->csio.cdb_io.cdb_bytes; 91539212Sgibbs if (sense != 0) { 91639212Sgibbs struct scsi_sense_data *sense; 91739212Sgibbs int error_code, sense_key, asc, ascq; 91839212Sgibbs 91939212Sgibbs sense = &done_ccb->csio.sense_data; 92039212Sgibbs scsi_extract_sense(sense, &error_code, 92139212Sgibbs &sense_key, &asc, &ascq); 92239212Sgibbs 92339212Sgibbs /* 92439212Sgibbs * If the error is "invalid field in CDB", 92539212Sgibbs * and the load/eject flag is set, turn the 92639212Sgibbs * flag off and try again. This is just in 92739212Sgibbs * case the drive in question barfs on the 92839212Sgibbs * load eject flag. The CAM code should set 92939212Sgibbs * the load/eject flag by default for 93039212Sgibbs * removable media. 93139212Sgibbs */ 93239212Sgibbs 93339212Sgibbs /* XXX KDM 93439212Sgibbs * Should we check to see what the specific 93539212Sgibbs * scsi status is?? Or does it not matter 93639212Sgibbs * since we already know that there was an 93739212Sgibbs * error, and we know what the specific 93839212Sgibbs * error code was, and we know what the 93939212Sgibbs * opcode is.. 94039212Sgibbs */ 94139212Sgibbs if ((scsi_cmd->opcode == START_STOP_UNIT) && 94239212Sgibbs ((scsi_cmd->how & SSS_LOEJ) != 0) && 94339212Sgibbs (asc == 0x24) && (ascq == 0x00) && 94439212Sgibbs (done_ccb->ccb_h.retry_count > 0)) { 94539212Sgibbs 94639212Sgibbs scsi_cmd->how &= ~SSS_LOEJ; 94739212Sgibbs 94839212Sgibbs xpt_action(done_ccb); 94939212Sgibbs 95039212Sgibbs } else if (done_ccb->ccb_h.retry_count > 0) { 95139212Sgibbs /* 95239212Sgibbs * In this case, the error recovery 95339212Sgibbs * command failed, but we've got 95439212Sgibbs * some retries left on it. Give 95539212Sgibbs * it another try. 95639212Sgibbs */ 95739212Sgibbs 95839212Sgibbs /* set the timeout to .5 sec */ 95939212Sgibbs relsim_flags = 96039212Sgibbs RELSIM_RELEASE_AFTER_TIMEOUT; 96139212Sgibbs timeout = 500; 96239212Sgibbs 96339212Sgibbs xpt_action(done_ccb); 96439212Sgibbs 96539212Sgibbs break; 96639212Sgibbs 96739212Sgibbs } else { 96839212Sgibbs /* 96939212Sgibbs * Copy the original CCB back and 97039212Sgibbs * send it back to the caller. 97139212Sgibbs */ 97239212Sgibbs bcopy(done_ccb->ccb_h.saved_ccb_ptr, 97339212Sgibbs done_ccb, sizeof(union ccb)); 97439212Sgibbs 97540318Sken periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; 97640318Sken 97739212Sgibbs xpt_action(done_ccb); 97839212Sgibbs } 97939212Sgibbs } else { 98039212Sgibbs /* 98139212Sgibbs * Eh?? The command failed, but we don't 98239212Sgibbs * have any sense. What's up with that? 98339212Sgibbs * Fire the CCB again to return it to the 98439212Sgibbs * caller. 98539212Sgibbs */ 98639212Sgibbs bcopy(done_ccb->ccb_h.saved_ccb_ptr, 98739212Sgibbs done_ccb, sizeof(union ccb)); 98839212Sgibbs 98940318Sken periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; 99040318Sken 99139212Sgibbs xpt_action(done_ccb); 99239212Sgibbs 99339212Sgibbs } 99439212Sgibbs break; 99539212Sgibbs default: 99639212Sgibbs bcopy(done_ccb->ccb_h.saved_ccb_ptr, done_ccb, 99739212Sgibbs sizeof(union ccb)); 99839212Sgibbs 99940318Sken periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG; 100040318Sken 100139212Sgibbs xpt_action(done_ccb); 100239212Sgibbs 100339212Sgibbs break; 100439212Sgibbs } 100539212Sgibbs 100639212Sgibbs /* decrement the retry count */ 100739212Sgibbs if (done_ccb->ccb_h.retry_count > 0) 100839212Sgibbs done_ccb->ccb_h.retry_count--; 100939212Sgibbs 101039212Sgibbs qfrozen_cnt = cam_release_devq(done_ccb->ccb_h.path, 101139212Sgibbs /*relsim_flags*/relsim_flags, 101239212Sgibbs /*openings*/0, 101339212Sgibbs /*timeout*/timeout, 101439212Sgibbs /*getcount_only*/0); 101539212Sgibbs} 101639212Sgibbs 101739212Sgibbs/* 101839212Sgibbs * Generic error handler. Peripheral drivers usually filter 101939212Sgibbs * out the errors that they handle in a unique mannor, then 102039212Sgibbs * call this function. 102139212Sgibbs */ 102239212Sgibbsint 102339212Sgibbscam_periph_error(union ccb *ccb, cam_flags camflags, 102439212Sgibbs u_int32_t sense_flags, union ccb *save_ccb) 102539212Sgibbs{ 102639212Sgibbs cam_status status; 102739212Sgibbs int frozen; 102839212Sgibbs int sense; 102939212Sgibbs int error; 103039212Sgibbs int openings; 103139212Sgibbs int retry; 103239212Sgibbs u_int32_t relsim_flags; 103339212Sgibbs u_int32_t timeout; 103439212Sgibbs 103539212Sgibbs status = ccb->ccb_h.status; 103639212Sgibbs frozen = (status & CAM_DEV_QFRZN) != 0; 103739212Sgibbs sense = (status & CAM_AUTOSNS_VALID) != 0; 103839212Sgibbs status &= CAM_STATUS_MASK; 103939212Sgibbs relsim_flags = 0; 104039212Sgibbs 104139212Sgibbs 104239212Sgibbs switch (status) { 104339212Sgibbs case CAM_REQ_CMP: 104439212Sgibbs /* decrement the number of retries */ 104539212Sgibbs retry = ccb->ccb_h.retry_count > 0; 104639212Sgibbs if (retry) 104739212Sgibbs ccb->ccb_h.retry_count--; 104839212Sgibbs error = 0; 104939212Sgibbs break; 105039212Sgibbs case CAM_SCSI_STATUS_ERROR: 105139212Sgibbs 105239212Sgibbs switch (ccb->csio.scsi_status) { 105339212Sgibbs case SCSI_STATUS_OK: 105439212Sgibbs case SCSI_STATUS_COND_MET: 105539212Sgibbs case SCSI_STATUS_INTERMED: 105639212Sgibbs case SCSI_STATUS_INTERMED_COND_MET: 105739212Sgibbs error = 0; 105839212Sgibbs break; 105939212Sgibbs case SCSI_STATUS_CMD_TERMINATED: 106039212Sgibbs case SCSI_STATUS_CHECK_COND: 106139212Sgibbs if (sense != 0) { 106239212Sgibbs struct scsi_sense_data *sense; 106339212Sgibbs int error_code, sense_key, asc, ascq; 106439212Sgibbs struct cam_periph *periph; 106539212Sgibbs scsi_sense_action err_action; 106639212Sgibbs struct ccb_getdev cgd; 106739212Sgibbs 106839212Sgibbs sense = &ccb->csio.sense_data; 106939212Sgibbs scsi_extract_sense(sense, &error_code, 107039212Sgibbs &sense_key, &asc, &ascq); 107139212Sgibbs periph = xpt_path_periph(ccb->ccb_h.path); 107239212Sgibbs 107339212Sgibbs /* 107439212Sgibbs * Grab the inquiry data for this device. 107539212Sgibbs */ 107639212Sgibbs xpt_setup_ccb(&cgd.ccb_h, ccb->ccb_h.path, 107739212Sgibbs /*priority*/ 1); 107839212Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 107939212Sgibbs xpt_action((union ccb *)&cgd); 108039212Sgibbs 108139212Sgibbs err_action = scsi_error_action(asc, ascq, 108239212Sgibbs &cgd.inq_data); 108339212Sgibbs 108439212Sgibbs /* 108539212Sgibbs * Send a Test Unit Ready to the device. 108639212Sgibbs * If the 'many' flag is set, we send 120 108739212Sgibbs * test unit ready commands, one every half 108839212Sgibbs * second. Otherwise, we just send one TUR. 108939212Sgibbs * We only want to do this if the retry 109039212Sgibbs * count has not been exhausted. 109139212Sgibbs */ 109239212Sgibbs if (((err_action & SS_MASK) == SS_TUR) 109339212Sgibbs && save_ccb != NULL 109439212Sgibbs && ccb->ccb_h.retry_count > 0) { 109539212Sgibbs 109640318Sken /* 109740318Sken * Since error recovery is already 109840318Sken * in progress, don't attempt to 109940318Sken * process this error. It is probably 110040318Sken * related to the error that caused 110140318Sken * the currently active error recovery 110240318Sken * action. Also, we only have 110340318Sken * space for one saved CCB, so if we 110440318Sken * had two concurrent error recovery 110540318Sken * actions, we would end up 110640318Sken * over-writing one error recovery 110740318Sken * CCB with another one. 110840318Sken */ 110940318Sken if (periph->flags & 111040318Sken CAM_PERIPH_RECOVERY_INPROG) { 111140318Sken error = ERESTART; 111240318Sken break; 111340318Sken } 111440318Sken 111540318Sken periph->flags |= 111640318Sken CAM_PERIPH_RECOVERY_INPROG; 111740318Sken 111839212Sgibbs /* decrement the number of retries */ 111939212Sgibbs if ((err_action & 112039212Sgibbs SSQ_DECREMENT_COUNT) != 0) { 112139212Sgibbs retry = 1; 112239212Sgibbs ccb->ccb_h.retry_count--; 112339212Sgibbs } 112439212Sgibbs 112539212Sgibbs bcopy(ccb, save_ccb, sizeof(*save_ccb)); 112639212Sgibbs 112739212Sgibbs /* 112839212Sgibbs * We retry this one every half 112939212Sgibbs * second for a minute. If the 113039212Sgibbs * device hasn't become ready in a 113139212Sgibbs * minute's time, it's unlikely to 113239212Sgibbs * ever become ready. If the table 113339212Sgibbs * doesn't specify SSQ_MANY, we can 113439212Sgibbs * only try this once. Oh well. 113539212Sgibbs */ 113639212Sgibbs if ((err_action & SSQ_MANY) != 0) 113739212Sgibbs scsi_test_unit_ready(&ccb->csio, 113839212Sgibbs /*retries*/120, 113939212Sgibbs camperiphdone, 114039212Sgibbs MSG_SIMPLE_Q_TAG, 114139212Sgibbs SSD_FULL_SIZE, 114239212Sgibbs /*timeout*/5000); 114339212Sgibbs else 114439212Sgibbs scsi_test_unit_ready(&ccb->csio, 114539212Sgibbs /*retries*/1, 114639212Sgibbs camperiphdone, 114739212Sgibbs MSG_SIMPLE_Q_TAG, 114839212Sgibbs SSD_FULL_SIZE, 114939212Sgibbs /*timeout*/5000); 115039212Sgibbs 115139212Sgibbs /* release the queue after .5 sec. */ 115239212Sgibbs relsim_flags = 115339212Sgibbs RELSIM_RELEASE_AFTER_TIMEOUT; 115439212Sgibbs timeout = 500; 115539212Sgibbs /* 115639212Sgibbs * Drop the priority to 0 so that 115739212Sgibbs * we are the first to execute. Also 115839212Sgibbs * freeze the queue after this command 115939212Sgibbs * is sent so that we can restore the 116039212Sgibbs * old csio and have it queued in the 116139212Sgibbs * proper order before we let normal 116239212Sgibbs * transactions go to the drive. 116339212Sgibbs */ 116439212Sgibbs ccb->ccb_h.pinfo.priority = 0; 116539212Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 116639212Sgibbs 116739212Sgibbs /* 116839212Sgibbs * Save a pointer to the original 116939212Sgibbs * CCB in the new CCB. 117039212Sgibbs */ 117139212Sgibbs ccb->ccb_h.saved_ccb_ptr = save_ccb; 117239212Sgibbs 117339212Sgibbs error = ERESTART; 117439212Sgibbs } 117539212Sgibbs /* 117639212Sgibbs * Send a start unit command to the device, 117739212Sgibbs * and then retry the command. We only 117839212Sgibbs * want to do this if the retry count has 117939212Sgibbs * not been exhausted. If the user 118039212Sgibbs * specified 0 retries, then we follow 118139212Sgibbs * their request and do not retry. 118239212Sgibbs */ 118339212Sgibbs else if (((err_action & SS_MASK) == SS_START) 118439212Sgibbs && save_ccb != NULL 118539212Sgibbs && ccb->ccb_h.retry_count > 0) { 118639212Sgibbs int le; 118739212Sgibbs 118840318Sken /* 118940318Sken * Only one error recovery action 119040318Sken * at a time. See above. 119140318Sken */ 119240318Sken if (periph->flags & 119340318Sken CAM_PERIPH_RECOVERY_INPROG) { 119440318Sken error = ERESTART; 119540318Sken break; 119640318Sken } 119740318Sken 119840318Sken periph->flags |= 119940318Sken CAM_PERIPH_RECOVERY_INPROG; 120040318Sken 120139212Sgibbs /* decrement the number of retries */ 120239212Sgibbs retry = 1; 120339212Sgibbs ccb->ccb_h.retry_count--; 120439212Sgibbs 120539212Sgibbs /* 120639212Sgibbs * Check for removable media and 120739212Sgibbs * set load/eject flag 120839212Sgibbs * appropriately. 120939212Sgibbs */ 121039212Sgibbs if (SID_IS_REMOVABLE(&cgd.inq_data)) 121139212Sgibbs le = TRUE; 121239212Sgibbs else 121339212Sgibbs le = FALSE; 121439212Sgibbs 121539212Sgibbs /* 121639212Sgibbs * Attempt to start the drive up. 121739212Sgibbs * 121839212Sgibbs * Save the current ccb so it can 121939212Sgibbs * be restored and retried once the 122039212Sgibbs * drive is started up. 122139212Sgibbs */ 122239212Sgibbs bcopy(ccb, save_ccb, sizeof(*save_ccb)); 122339212Sgibbs 122439212Sgibbs scsi_start_stop(&ccb->csio, 122539212Sgibbs /*retries*/1, 122639212Sgibbs camperiphdone, 122739212Sgibbs MSG_SIMPLE_Q_TAG, 122839212Sgibbs /*start*/TRUE, 122939212Sgibbs /*load/eject*/le, 123039212Sgibbs /*immediate*/FALSE, 123139212Sgibbs SSD_FULL_SIZE, 123239212Sgibbs /*timeout*/50000); 123339212Sgibbs /* 123439212Sgibbs * Drop the priority to 0 so that 123539212Sgibbs * we are the first to execute. Also 123639212Sgibbs * freeze the queue after this command 123739212Sgibbs * is sent so that we can restore the 123839212Sgibbs * old csio and have it queued in the 123939212Sgibbs * proper order before we let normal 124039212Sgibbs * transactions go to the drive. 124139212Sgibbs */ 124239212Sgibbs ccb->ccb_h.pinfo.priority = 0; 124339212Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 124439212Sgibbs 124539212Sgibbs /* 124639212Sgibbs * Save a pointer to the original 124739212Sgibbs * CCB in the new CCB. 124839212Sgibbs */ 124939212Sgibbs ccb->ccb_h.saved_ccb_ptr = save_ccb; 125039212Sgibbs 125139212Sgibbs error = ERESTART; 125239212Sgibbs } else if ((sense_flags & SF_RETRY_UA) != 0) { 125339212Sgibbs /* 125439212Sgibbs * XXX KDM this is a *horrible* 125539212Sgibbs * hack. 125639212Sgibbs */ 125739212Sgibbs error = scsi_interpret_sense(ccb, 125839212Sgibbs sense_flags, 125939212Sgibbs &relsim_flags, 126039212Sgibbs &openings, 126139212Sgibbs &timeout, 126239212Sgibbs err_action); 126339212Sgibbs } 126439212Sgibbs 126539212Sgibbs /* 126639212Sgibbs * Theoretically, this code should send a 126739212Sgibbs * test unit ready to the given device, and 126839212Sgibbs * if it returns and error, send a start 126939212Sgibbs * unit command. Since we don't yet have 127039212Sgibbs * the capability to do two-command error 127139212Sgibbs * recovery, just send a start unit. 127239212Sgibbs * XXX KDM fix this! 127339212Sgibbs */ 127439212Sgibbs else if (((err_action & SS_MASK) == SS_TURSTART) 127539212Sgibbs && save_ccb != NULL 127639212Sgibbs && ccb->ccb_h.retry_count > 0) { 127739212Sgibbs int le; 127839212Sgibbs 127940318Sken /* 128040318Sken * Only one error recovery action 128140318Sken * at a time. See above. 128240318Sken */ 128340318Sken if (periph->flags & 128440318Sken CAM_PERIPH_RECOVERY_INPROG) { 128540318Sken error = ERESTART; 128640318Sken break; 128740318Sken } 128840318Sken 128940318Sken periph->flags |= 129040318Sken CAM_PERIPH_RECOVERY_INPROG; 129140318Sken 129239212Sgibbs /* decrement the number of retries */ 129339212Sgibbs retry = 1; 129439212Sgibbs ccb->ccb_h.retry_count--; 129539212Sgibbs 129639212Sgibbs /* 129739212Sgibbs * Check for removable media and 129839212Sgibbs * set load/eject flag 129939212Sgibbs * appropriately. 130039212Sgibbs */ 130139212Sgibbs if (SID_IS_REMOVABLE(&cgd.inq_data)) 130239212Sgibbs le = TRUE; 130339212Sgibbs else 130439212Sgibbs le = FALSE; 130539212Sgibbs 130639212Sgibbs /* 130739212Sgibbs * Attempt to start the drive up. 130839212Sgibbs * 130939212Sgibbs * Save the current ccb so it can 131039212Sgibbs * be restored and retried once the 131139212Sgibbs * drive is started up. 131239212Sgibbs */ 131339212Sgibbs bcopy(ccb, save_ccb, sizeof(*save_ccb)); 131439212Sgibbs 131539212Sgibbs scsi_start_stop(&ccb->csio, 131639212Sgibbs /*retries*/1, 131739212Sgibbs camperiphdone, 131839212Sgibbs MSG_SIMPLE_Q_TAG, 131939212Sgibbs /*start*/TRUE, 132039212Sgibbs /*load/eject*/le, 132139212Sgibbs /*immediate*/FALSE, 132239212Sgibbs SSD_FULL_SIZE, 132339212Sgibbs /*timeout*/50000); 132439212Sgibbs 132539212Sgibbs /* release the queue after .5 sec. */ 132639212Sgibbs relsim_flags = 132739212Sgibbs RELSIM_RELEASE_AFTER_TIMEOUT; 132839212Sgibbs timeout = 500; 132939212Sgibbs /* 133039212Sgibbs * Drop the priority to 0 so that 133139212Sgibbs * we are the first to execute. Also 133239212Sgibbs * freeze the queue after this command 133339212Sgibbs * is sent so that we can restore the 133439212Sgibbs * old csio and have it queued in the 133539212Sgibbs * proper order before we let normal 133639212Sgibbs * transactions go to the drive. 133739212Sgibbs */ 133839212Sgibbs ccb->ccb_h.pinfo.priority = 0; 133939212Sgibbs ccb->ccb_h.flags |= CAM_DEV_QFREEZE; 134039212Sgibbs 134139212Sgibbs /* 134239212Sgibbs * Save a pointer to the original 134339212Sgibbs * CCB in the new CCB. 134439212Sgibbs */ 134539212Sgibbs ccb->ccb_h.saved_ccb_ptr = save_ccb; 134639212Sgibbs 134739212Sgibbs error = ERESTART; 134839212Sgibbs } else { 134939212Sgibbs error = scsi_interpret_sense(ccb, 135039212Sgibbs sense_flags, 135139212Sgibbs &relsim_flags, 135239212Sgibbs &openings, 135339212Sgibbs &timeout, 135439212Sgibbs err_action); 135539212Sgibbs } 135639212Sgibbs } else if (ccb->csio.scsi_status == 135739212Sgibbs SCSI_STATUS_CHECK_COND) { 135839212Sgibbs /* no point in decrementing the retry count */ 135939212Sgibbs panic("cam_periph_error: scsi status of " 136039212Sgibbs "CHECK COND returned but no sense " 136139212Sgibbs "information is availible. " 136239212Sgibbs "Controller should have returned " 136339212Sgibbs "CAM_AUTOSENSE_FAILED"); 136439212Sgibbs /* NOTREACHED */ 136539212Sgibbs error = EIO; 136639212Sgibbs } else if (ccb->ccb_h.retry_count > 0) { 136739212Sgibbs /* 136839212Sgibbs * XXX KDM shouldn't there be a better 136939212Sgibbs * argument to return?? 137039212Sgibbs */ 137139212Sgibbs error = EIO; 137239212Sgibbs } else { 137339212Sgibbs /* decrement the number of retries */ 137439212Sgibbs retry = ccb->ccb_h.retry_count > 0; 137539212Sgibbs if (retry) 137639212Sgibbs ccb->ccb_h.retry_count--; 137739212Sgibbs /* 137839212Sgibbs * If it was aborted with no 137939212Sgibbs * clue as to the reason, just 138039212Sgibbs * retry it again. 138139212Sgibbs */ 138239212Sgibbs error = ERESTART; 138339212Sgibbs } 138439212Sgibbs break; 138539212Sgibbs case SCSI_STATUS_QUEUE_FULL: 138639212Sgibbs { 138739212Sgibbs /* no decrement */ 138839212Sgibbs struct ccb_getdev cgd; 138939212Sgibbs 139039212Sgibbs /* 139139212Sgibbs * First off, find out what the current 139239212Sgibbs * transaction counts are. 139339212Sgibbs */ 139439212Sgibbs xpt_setup_ccb(&cgd.ccb_h, 139539212Sgibbs ccb->ccb_h.path, 139639212Sgibbs /*priority*/1); 139739212Sgibbs cgd.ccb_h.func_code = XPT_GDEV_TYPE; 139839212Sgibbs xpt_action((union ccb *)&cgd); 139939212Sgibbs 140039212Sgibbs /* 140139212Sgibbs * If we were the only transaction active, treat 140239212Sgibbs * the QUEUE FULL as if it were a BUSY condition. 140339212Sgibbs */ 140439212Sgibbs if (cgd.dev_active != 0) { 140539212Sgibbs /* 140639212Sgibbs * Reduce the number of openings to 140739212Sgibbs * be 1 less than the amount it took 140839212Sgibbs * to get a queue full bounded by the 140939212Sgibbs * minimum allowed tag count for this 141039212Sgibbs * device. 141139212Sgibbs */ 141239212Sgibbs openings = cgd.dev_active; 141339212Sgibbs if (openings < cgd.mintags) 141439212Sgibbs openings = cgd.mintags; 141539212Sgibbs if (openings < cgd.dev_active+cgd.dev_openings) 141639212Sgibbs relsim_flags = RELSIM_ADJUST_OPENINGS; 141739212Sgibbs else { 141839212Sgibbs /* 141939212Sgibbs * Some devices report queue full for 142039212Sgibbs * temporary resource shortages. For 142139212Sgibbs * this reason, we allow a minimum 142239212Sgibbs * tag count to be entered via a 142339212Sgibbs * quirk entry to prevent the queue 142439212Sgibbs * count on these devices from falling 142539212Sgibbs * to a pessimisticly low value. We 142639212Sgibbs * still wait for the next successful 142739212Sgibbs * completion, however, before queueing 142839212Sgibbs * more transactions to the device. 142939212Sgibbs */ 143039212Sgibbs relsim_flags = 143139212Sgibbs RELSIM_RELEASE_AFTER_CMDCMPLT; 143239212Sgibbs } 143339212Sgibbs timeout = 0; 143439212Sgibbs error = ERESTART; 143539212Sgibbs break; 143639212Sgibbs } 143739212Sgibbs /* FALLTHROUGH */ 143839212Sgibbs } 143939212Sgibbs case SCSI_STATUS_BUSY: 144039212Sgibbs /* 144139212Sgibbs * Restart the queue after either another 144239212Sgibbs * command completes or a 1 second timeout. 144339212Sgibbs */ 144439212Sgibbs /* 144539212Sgibbs * XXX KDM ask JTG about this again, do we need to 144639212Sgibbs * be looking at the retry count here? 144739212Sgibbs */ 144839212Sgibbs error = ERESTART; 144939212Sgibbs relsim_flags = RELSIM_RELEASE_AFTER_TIMEOUT 145039212Sgibbs | RELSIM_RELEASE_AFTER_CMDCMPLT; 145139212Sgibbs timeout = 1000; 145239212Sgibbs break; 145339212Sgibbs case SCSI_STATUS_RESERV_CONFLICT: 145439212Sgibbs error = EIO; 145539212Sgibbs break; 145639212Sgibbs default: 145739212Sgibbs error = EIO; 145839212Sgibbs break; 145939212Sgibbs } 146039212Sgibbs break; 146139212Sgibbs case CAM_REQ_CMP_ERR: 146239212Sgibbs case CAM_AUTOSENSE_FAIL: 146339212Sgibbs case CAM_CMD_TIMEOUT: 146439212Sgibbs case CAM_UNEXP_BUSFREE: 146539212Sgibbs case CAM_UNCOR_PARITY: 146639212Sgibbs case CAM_DATA_RUN_ERR: 146739212Sgibbs /* decrement the number of retries */ 146839212Sgibbs retry = ccb->ccb_h.retry_count > 0; 146939212Sgibbs if (retry) { 147039212Sgibbs ccb->ccb_h.retry_count--; 147139212Sgibbs error = ERESTART; 147239212Sgibbs } else { 147339212Sgibbs error = EIO; 147439212Sgibbs } 147539212Sgibbs break; 147639212Sgibbs case CAM_UA_ABORT: 147739212Sgibbs case CAM_UA_TERMIO: 147839212Sgibbs case CAM_MSG_REJECT_REC: 147939212Sgibbs /* XXX Don't know that these are correct */ 148039212Sgibbs error = EIO; 148139212Sgibbs break; 148239212Sgibbs case CAM_SEL_TIMEOUT: 148339212Sgibbs { 148439513Sgibbs /* 148539513Sgibbs * XXX 148639513Sgibbs * A single selection timeout should not be enough 148739513Sgibbs * to invalidate a device. We should retry for multiple 148839513Sgibbs * seconds assuming this isn't a probe. We'll probably 148939513Sgibbs * need a special flag for that. 149039513Sgibbs */ 149139513Sgibbs#if 0 149239212Sgibbs struct cam_path *newpath; 149339212Sgibbs 149439212Sgibbs /* Should we do more if we can't create the path?? */ 149539212Sgibbs if (xpt_create_path(&newpath, xpt_path_periph(ccb->ccb_h.path), 149639212Sgibbs xpt_path_path_id(ccb->ccb_h.path), 149739212Sgibbs xpt_path_target_id(ccb->ccb_h.path), 149839212Sgibbs CAM_LUN_WILDCARD) != CAM_REQ_CMP) 149939212Sgibbs break; 150039212Sgibbs /* 150139212Sgibbs * Let peripheral drivers know that this device has gone 150239212Sgibbs * away. 150339212Sgibbs */ 150439212Sgibbs xpt_async(AC_LOST_DEVICE, newpath, NULL); 150539212Sgibbs xpt_free_path(newpath); 150639513Sgibbs#endif 150739513Sgibbs error = ENXIO; 150839212Sgibbs break; 150939212Sgibbs } 151039212Sgibbs case CAM_REQ_INVALID: 151139212Sgibbs case CAM_PATH_INVALID: 151239212Sgibbs case CAM_DEV_NOT_THERE: 151339212Sgibbs case CAM_NO_HBA: 151439212Sgibbs case CAM_PROVIDE_FAIL: 151539212Sgibbs case CAM_REQ_TOO_BIG: 151639212Sgibbs error = EINVAL; 151739212Sgibbs break; 151839212Sgibbs case CAM_SCSI_BUS_RESET: 151939212Sgibbs case CAM_BDR_SENT: 152039212Sgibbs case CAM_REQUEUE_REQ: 152139212Sgibbs /* Unconditional requeue, dammit */ 152239212Sgibbs error = ERESTART; 152339212Sgibbs break; 152439212Sgibbs case CAM_RESRC_UNAVAIL: 152539212Sgibbs case CAM_BUSY: 152639212Sgibbs /* timeout??? */ 152739212Sgibbs default: 152839212Sgibbs /* decrement the number of retries */ 152939212Sgibbs retry = ccb->ccb_h.retry_count > 0; 153039212Sgibbs if (retry) { 153139212Sgibbs ccb->ccb_h.retry_count--; 153239212Sgibbs error = ERESTART; 153339212Sgibbs } else { 153439212Sgibbs /* Check the sense codes */ 153539212Sgibbs error = EIO; 153639212Sgibbs } 153739212Sgibbs break; 153839212Sgibbs } 153939212Sgibbs 154039212Sgibbs /* Attempt a retry */ 154139212Sgibbs if (error == ERESTART || error == 0) { 154239212Sgibbs if (frozen != 0) 154339212Sgibbs ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 154439212Sgibbs 154539212Sgibbs if (error == ERESTART) 154639212Sgibbs xpt_action(ccb); 154739212Sgibbs 154839212Sgibbs if (frozen != 0) { 154939212Sgibbs cam_release_devq(ccb->ccb_h.path, 155039212Sgibbs relsim_flags, 155139212Sgibbs openings, 155239212Sgibbs timeout, 155339212Sgibbs /*getcount_only*/0); 155439212Sgibbs } 155539212Sgibbs } 155639212Sgibbs 155739212Sgibbs 155839212Sgibbs return (error); 155939212Sgibbs} 1560