| File: | cam/scsi/scsi_target.c |
| Warning: | line 924, column 10 Copies out a struct with a union element with different sizes |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /*- | |||
| 2 | * Generic SCSI Target Kernel Mode Driver | |||
| 3 | * | |||
| 4 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | |||
| 5 | * | |||
| 6 | * Copyright (c) 2002 Nate Lawson. | |||
| 7 | * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs. | |||
| 8 | * All rights reserved. | |||
| 9 | * | |||
| 10 | * Redistribution and use in source and binary forms, with or without | |||
| 11 | * modification, are permitted provided that the following conditions | |||
| 12 | * are met: | |||
| 13 | * 1. Redistributions of source code must retain the above copyright | |||
| 14 | * notice, this list of conditions, and the following disclaimer, | |||
| 15 | * without modification, immediately at the beginning of the file. | |||
| 16 | * 2. The name of the author may not be used to endorse or promote products | |||
| 17 | * derived from this software without specific prior written permission. | |||
| 18 | * | |||
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||
| 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | |||
| 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 29 | * SUCH DAMAGE. | |||
| 30 | */ | |||
| 31 | ||||
| 32 | #include <sys/cdefs.h> | |||
| 33 | __FBSDID("$FreeBSD$")__asm__(".ident\t\"" "$FreeBSD$" "\""); | |||
| 34 | ||||
| 35 | ||||
| 36 | #include <sys/param.h> | |||
| 37 | #include <sys/systm.h> | |||
| 38 | #include <sys/kernel.h> | |||
| 39 | #include <sys/conf.h> | |||
| 40 | #include <sys/malloc.h> | |||
| 41 | #include <sys/poll.h> | |||
| 42 | #include <sys/vnode.h> | |||
| 43 | #include <sys/lock.h> | |||
| 44 | #include <sys/mutex.h> | |||
| 45 | #include <sys/devicestat.h> | |||
| 46 | #include <sys/proc.h> | |||
| 47 | /* Includes to support callout */ | |||
| 48 | #include <sys/types.h> | |||
| 49 | #include <sys/systm.h> | |||
| 50 | ||||
| 51 | #include <cam/cam.h> | |||
| 52 | #include <cam/cam_ccb.h> | |||
| 53 | #include <cam/cam_periph.h> | |||
| 54 | #include <cam/cam_xpt_periph.h> | |||
| 55 | #include <cam/cam_sim.h> | |||
| 56 | #include <cam/scsi/scsi_targetio.h> | |||
| 57 | ||||
| 58 | ||||
| 59 | /* Transaction information attached to each CCB sent by the user */ | |||
| 60 | struct targ_cmd_descr { | |||
| 61 | struct cam_periph_map_info mapinfo; | |||
| 62 | TAILQ_ENTRY(targ_cmd_descr)struct { struct targ_cmd_descr *tqe_next; struct targ_cmd_descr **tqe_prev; } tqe; | |||
| 63 | union ccb *user_ccb; | |||
| 64 | int priority; | |||
| 65 | int func_code; | |||
| 66 | }; | |||
| 67 | ||||
| 68 | /* Offset into the private CCB area for storing our descriptor */ | |||
| 69 | #define targ_descrperiph_priv.entries[1].ptr periph_priv.entries[1].ptr | |||
| 70 | ||||
| 71 | TAILQ_HEAD(descr_queue, targ_cmd_descr)struct descr_queue { struct targ_cmd_descr *tqh_first; struct targ_cmd_descr **tqh_last; }; | |||
| 72 | ||||
| 73 | typedef enum { | |||
| 74 | TARG_STATE_RESV = 0x00, /* Invalid state */ | |||
| 75 | TARG_STATE_OPENED = 0x01, /* Device opened, softc initialized */ | |||
| 76 | TARG_STATE_LUN_ENABLED = 0x02 /* Device enabled for a path */ | |||
| 77 | } targ_state; | |||
| 78 | ||||
| 79 | /* Per-instance device software context */ | |||
| 80 | struct targ_softc { | |||
| 81 | /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ | |||
| 82 | struct ccb_queue pending_ccb_queue; | |||
| 83 | ||||
| 84 | /* Command descriptors awaiting CTIO resources from the XPT */ | |||
| 85 | struct descr_queue work_queue; | |||
| 86 | ||||
| 87 | /* Command descriptors that have been aborted back to the user. */ | |||
| 88 | struct descr_queue abort_queue; | |||
| 89 | ||||
| 90 | /* | |||
| 91 | * Queue of CCBs that have been copied out to userland, but our | |||
| 92 | * userland daemon has not yet seen. | |||
| 93 | */ | |||
| 94 | struct ccb_queue user_ccb_queue; | |||
| 95 | ||||
| 96 | struct cam_periph *periph; | |||
| 97 | struct cam_path *path; | |||
| 98 | targ_state state; | |||
| 99 | u_int maxio; | |||
| 100 | struct selinfo read_select; | |||
| 101 | struct devstat device_stats; | |||
| 102 | }; | |||
| 103 | ||||
| 104 | static d_open_t targopen; | |||
| 105 | static d_read_t targread; | |||
| 106 | static d_write_t targwrite; | |||
| 107 | static d_ioctl_t targioctl; | |||
| 108 | static d_poll_t targpoll; | |||
| 109 | static d_kqfilter_t targkqfilter; | |||
| 110 | static void targreadfiltdetach(struct knote *kn); | |||
| 111 | static int targreadfilt(struct knote *kn, long hint); | |||
| 112 | static struct filterops targread_filtops = { | |||
| 113 | .f_isfd = 1, | |||
| 114 | .f_detach = targreadfiltdetach, | |||
| 115 | .f_event = targreadfilt, | |||
| 116 | }; | |||
| 117 | ||||
| 118 | static struct cdevsw targ_cdevsw = { | |||
| 119 | .d_version = D_VERSION0x17122009, | |||
| 120 | .d_flags = D_NEEDGIANT0x00400000, | |||
| 121 | .d_open = targopen, | |||
| 122 | .d_read = targread, | |||
| 123 | .d_write = targwrite, | |||
| 124 | .d_ioctl = targioctl, | |||
| 125 | .d_poll = targpoll, | |||
| 126 | .d_name = "targ", | |||
| 127 | .d_kqfilter = targkqfilter | |||
| 128 | }; | |||
| 129 | ||||
| 130 | static cam_status targendislun(struct cam_path *path, int enable, | |||
| 131 | int grp6_len, int grp7_len); | |||
| 132 | static cam_status targenable(struct targ_softc *softc, | |||
| 133 | struct cam_path *path, | |||
| 134 | int grp6_len, int grp7_len); | |||
| 135 | static cam_status targdisable(struct targ_softc *softc); | |||
| 136 | static periph_ctor_t targctor; | |||
| 137 | static periph_dtor_t targdtor; | |||
| 138 | static periph_start_t targstart; | |||
| 139 | static int targusermerge(struct targ_softc *softc, | |||
| 140 | struct targ_cmd_descr *descr, | |||
| 141 | union ccb *ccb); | |||
| 142 | static int targsendccb(struct targ_softc *softc, union ccb *ccb, | |||
| 143 | struct targ_cmd_descr *descr); | |||
| 144 | static void targdone(struct cam_periph *periph, | |||
| 145 | union ccb *done_ccb); | |||
| 146 | static int targreturnccb(struct targ_softc *softc, | |||
| 147 | union ccb *ccb); | |||
| 148 | static union ccb * targgetccb(struct targ_softc *softc, xpt_opcode type, | |||
| 149 | int priority); | |||
| 150 | static void targfreeccb(struct targ_softc *softc, union ccb *ccb); | |||
| 151 | static struct targ_cmd_descr * | |||
| 152 | targgetdescr(struct targ_softc *softc); | |||
| 153 | static periph_init_t targinit; | |||
| 154 | static void targasync(void *callback_arg, u_int32_t code, | |||
| 155 | struct cam_path *path, void *arg); | |||
| 156 | static void abort_all_pending(struct targ_softc *softc); | |||
| 157 | static void notify_user(struct targ_softc *softc); | |||
| 158 | static int targcamstatus(cam_status status); | |||
| 159 | static size_t targccblen(xpt_opcode func_code); | |||
| 160 | ||||
| 161 | static struct periph_driver targdriver = | |||
| 162 | { | |||
| 163 | targinit, "targ", | |||
| 164 | TAILQ_HEAD_INITIALIZER(targdriver.units){ ((void *)0), &(targdriver.units).tqh_first, }, /* generation */ 0 | |||
| 165 | }; | |||
| 166 | PERIPHDRIVER_DECLARE(targ, targdriver)static int targ_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: periphdriver_register(data); break ; case MOD_UNLOAD: return (periphdriver_unregister(data)); default : return 45; } return 0; } static moduledata_t targ_mod = { "targ" , targ_modevent, (void *)&targdriver }; static struct mod_depend _targ_depend_on_kernel __attribute__((__section__(".data"))) = { 1300006, 1300006, 1300006 }; static struct mod_metadata _mod_metadata_md_targ_on_kernel = { 1, 1, &_targ_depend_on_kernel, "kernel" }; __asm__(".globl " "__start_set_modmetadata_set"); __asm__(".globl " "__stop_set_modmetadata_set" ); static void const * const __set_modmetadata_set_sym__mod_metadata_md_targ_on_kernel __attribute__((__section__("set_" "modmetadata_set"))) __attribute__ ((__used__)) = &(_mod_metadata_md_targ_on_kernel); static struct mod_metadata _mod_metadata_md_targ = { 1, 2, &targ_mod , "targ" }; __asm__(".globl " "__start_set_modmetadata_set"); __asm__(".globl " "__stop_set_modmetadata_set"); static void const * const __set_modmetadata_set_sym__mod_metadata_md_targ __attribute__((__section__("set_" "modmetadata_set"))) __attribute__ ((__used__)) = &(_mod_metadata_md_targ); static struct sysinit targmodule_sys_init = { SI_SUB_DRIVERS, SI_ORDER_ANY, (sysinit_cfunc_t )(sysinit_nfunc_t)module_register_init, ((void *)(&targ_mod )) }; __asm__(".globl " "__start_set_sysinit_set"); __asm__(".globl " "__stop_set_sysinit_set"); static void const * __set_sysinit_set_sym_targmodule_sys_init __attribute__((__section__("set_" "sysinit_set"))) __attribute__ ((__used__)) = &(targmodule_sys_init); struct __hack; static struct mod_depend _targ_depend_on_cam __attribute__((__section__ (".data"))) = { 1, 1, 1 }; static struct mod_metadata _mod_metadata_md_targ_on_cam = { 1, 1, &_targ_depend_on_cam, "cam" }; __asm__(".globl " "__start_set_modmetadata_set"); __asm__(".globl " "__stop_set_modmetadata_set" ); static void const * const __set_modmetadata_set_sym__mod_metadata_md_targ_on_cam __attribute__((__section__("set_" "modmetadata_set"))) __attribute__ ((__used__)) = &(_mod_metadata_md_targ_on_cam); | |||
| 167 | ||||
| 168 | static MALLOC_DEFINE(M_TARG, "TARG", "TARG data")struct malloc_type M_TARG[1] = { { ((void *)0), 877983977, "TARG" , ((void *)0) } }; static struct sysinit M_TARG_init_sys_init = { SI_SUB_KMEM, SI_ORDER_THIRD, (sysinit_cfunc_t)(sysinit_nfunc_t )malloc_init, ((void *)(M_TARG)) }; __asm__(".globl " "__start_set_sysinit_set" ); __asm__(".globl " "__stop_set_sysinit_set"); static void const * __set_sysinit_set_sym_M_TARG_init_sys_init __attribute__(( __section__("set_" "sysinit_set"))) __attribute__((__used__)) = &(M_TARG_init_sys_init); static struct sysinit M_TARG_uninit_sys_uninit = { SI_SUB_KMEM, SI_ORDER_ANY, (sysinit_cfunc_t)(sysinit_nfunc_t )malloc_uninit, ((void *)(M_TARG)) }; __asm__(".globl " "__start_set_sysuninit_set" ); __asm__(".globl " "__stop_set_sysuninit_set"); static void const * __set_sysuninit_set_sym_M_TARG_uninit_sys_uninit __attribute__ ((__section__("set_" "sysuninit_set"))) __attribute__((__used__ )) = &(M_TARG_uninit_sys_uninit); | |||
| 169 | ||||
| 170 | /* Disable LUN if enabled and teardown softc */ | |||
| 171 | static void | |||
| 172 | targcdevdtor(void *data) | |||
| 173 | { | |||
| 174 | struct targ_softc *softc; | |||
| 175 | struct cam_periph *periph; | |||
| 176 | ||||
| 177 | softc = data; | |||
| 178 | if (softc->periph == NULL((void *)0)) { | |||
| 179 | printf("%s: destroying non-enabled target\n", __func__); | |||
| 180 | free(softc, M_TARG); | |||
| 181 | return; | |||
| 182 | } | |||
| 183 | ||||
| 184 | /* | |||
| 185 | * Acquire a hold on the periph so that it doesn't go away before | |||
| 186 | * we are ready at the end of the function. | |||
| 187 | */ | |||
| 188 | periph = softc->periph; | |||
| 189 | cam_periph_acquire(periph); | |||
| 190 | cam_periph_lock(periph)__mtx_lock_flags(&((((xpt_path_mtx((periph)->path))))) ->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (190)); | |||
| 191 | (void)targdisable(softc); | |||
| 192 | if (softc->periph != NULL((void *)0)) { | |||
| 193 | cam_periph_invalidate(softc->periph); | |||
| 194 | softc->periph = NULL((void *)0); | |||
| 195 | } | |||
| 196 | cam_periph_unlock(periph)__mtx_unlock_flags(&((((xpt_path_mtx((periph)->path))) ))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (196)); | |||
| 197 | cam_periph_release(periph); | |||
| 198 | free(softc, M_TARG); | |||
| 199 | } | |||
| 200 | ||||
| 201 | /* | |||
| 202 | * Create softc and initialize it. There is no locking here because a | |||
| 203 | * periph doesn't get created until an ioctl is issued to do so, and | |||
| 204 | * that can't happen until this method returns. | |||
| 205 | */ | |||
| 206 | static int | |||
| 207 | targopen(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
| 208 | { | |||
| 209 | struct targ_softc *softc; | |||
| 210 | ||||
| 211 | /* Allocate its softc, initialize it */ | |||
| 212 | softc = malloc(sizeof(*softc), M_TARG, | |||
| 213 | M_WAITOK0x0002 | M_ZERO0x0100); | |||
| 214 | softc->state = TARG_STATE_OPENED; | |||
| 215 | softc->periph = NULL((void *)0); | |||
| 216 | softc->path = NULL((void *)0); | |||
| 217 | ||||
| 218 | TAILQ_INIT(&softc->pending_ccb_queue)do { (((&softc->pending_ccb_queue))->tqh_first) = ( (void *)0); (&softc->pending_ccb_queue)->tqh_last = &(((&softc->pending_ccb_queue))->tqh_first); ; } while (0); | |||
| 219 | TAILQ_INIT(&softc->work_queue)do { (((&softc->work_queue))->tqh_first) = ((void * )0); (&softc->work_queue)->tqh_last = &(((& softc->work_queue))->tqh_first); ; } while (0); | |||
| 220 | TAILQ_INIT(&softc->abort_queue)do { (((&softc->abort_queue))->tqh_first) = ((void * )0); (&softc->abort_queue)->tqh_last = &(((& softc->abort_queue))->tqh_first); ; } while (0); | |||
| 221 | TAILQ_INIT(&softc->user_ccb_queue)do { (((&softc->user_ccb_queue))->tqh_first) = ((void *)0); (&softc->user_ccb_queue)->tqh_last = &(( (&softc->user_ccb_queue))->tqh_first); ; } while (0 ); | |||
| 222 | knlist_init_mtx(&softc->read_select.si_note, NULL((void *)0)); | |||
| 223 | ||||
| 224 | devfs_set_cdevpriv(softc, targcdevdtor); | |||
| 225 | return (0); | |||
| 226 | } | |||
| 227 | ||||
| 228 | /* Enable/disable LUNs, set debugging level */ | |||
| 229 | static int | |||
| 230 | targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) | |||
| 231 | { | |||
| 232 | struct targ_softc *softc; | |||
| 233 | cam_status status; | |||
| 234 | ||||
| 235 | devfs_get_cdevpriv((void **)&softc); | |||
| 236 | ||||
| 237 | switch (cmd) { | |||
| 238 | case TARGIOCENABLE((unsigned long) ((0x80000000) | (((sizeof(struct ioc_enable_lun )) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((5)))): | |||
| 239 | { | |||
| 240 | struct ioc_enable_lun *new_lun; | |||
| 241 | struct cam_path *path; | |||
| 242 | ||||
| 243 | new_lun = (struct ioc_enable_lun *)addr; | |||
| 244 | status = xpt_create_path(&path, /*periph*/NULL((void *)0), | |||
| 245 | new_lun->path_id, | |||
| 246 | new_lun->target_id, | |||
| 247 | new_lun->lun_id); | |||
| 248 | if (status != CAM_REQ_CMP) { | |||
| 249 | printf("Couldn't create path, status %#x\n", status); | |||
| 250 | break; | |||
| 251 | } | |||
| 252 | xpt_path_lock(path)__mtx_lock_flags(&((((xpt_path_mtx(path)))))->mtx_lock , ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c"), (252)); | |||
| 253 | status = targenable(softc, path, new_lun->grp6_len, | |||
| 254 | new_lun->grp7_len); | |||
| 255 | xpt_path_unlock(path)__mtx_unlock_flags(&((((xpt_path_mtx(path)))))->mtx_lock , ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c"), (255)); | |||
| 256 | xpt_free_path(path); | |||
| 257 | break; | |||
| 258 | } | |||
| 259 | case TARGIOCDISABLE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((6)))): | |||
| 260 | if (softc->periph == NULL((void *)0)) { | |||
| 261 | status = CAM_DEV_NOT_THERE; | |||
| 262 | break; | |||
| 263 | } | |||
| 264 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (264)); | |||
| 265 | status = targdisable(softc); | |||
| 266 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (266)); | |||
| 267 | break; | |||
| 268 | case TARGIOCDEBUG((unsigned long) ((0x80000000) | (((sizeof(int)) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((7)))): | |||
| 269 | { | |||
| 270 | struct ccb_debug cdbg; | |||
| 271 | ||||
| 272 | /* If no periph available, disallow debugging changes */ | |||
| 273 | if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { | |||
| 274 | status = CAM_DEV_NOT_THERE; | |||
| 275 | break; | |||
| 276 | } | |||
| 277 | bzero(&cdbg, sizeof cdbg)__builtin_memset((&cdbg), 0, (sizeof cdbg)); | |||
| 278 | if (*((int *)addr) != 0) | |||
| 279 | cdbg.flags = CAM_DEBUG_PERIPH; | |||
| 280 | else | |||
| 281 | cdbg.flags = CAM_DEBUG_NONE; | |||
| 282 | xpt_setup_ccb(&cdbg.ccb_h, softc->path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
| 283 | cdbg.ccb_h.func_code = XPT_DEBUG; | |||
| 284 | cdbg.ccb_h.cbfcnp = targdone; | |||
| 285 | xpt_action((union ccb *)&cdbg); | |||
| 286 | status = cdbg.ccb_h.status & CAM_STATUS_MASK; | |||
| 287 | break; | |||
| 288 | } | |||
| 289 | default: | |||
| 290 | status = CAM_PROVIDE_FAIL; | |||
| 291 | break; | |||
| 292 | } | |||
| 293 | ||||
| 294 | return (targcamstatus(status)); | |||
| 295 | } | |||
| 296 | ||||
| 297 | /* Writes are always ready, reads wait for user_ccb_queue or abort_queue */ | |||
| 298 | static int | |||
| 299 | targpoll(struct cdev *dev, int poll_events, struct thread *td) | |||
| 300 | { | |||
| 301 | struct targ_softc *softc; | |||
| 302 | int revents; | |||
| 303 | ||||
| 304 | devfs_get_cdevpriv((void **)&softc); | |||
| 305 | ||||
| 306 | /* Poll for write() is always ok. */ | |||
| 307 | revents = poll_events & (POLLOUT0x0004 | POLLWRNORM0x0004); | |||
| 308 | if ((poll_events & (POLLIN0x0001 | POLLRDNORM0x0040)) != 0) { | |||
| 309 | /* Poll for read() depends on user and abort queues. */ | |||
| 310 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (310)); | |||
| 311 | if (!TAILQ_EMPTY(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first == ((void *)0) ) || | |||
| 312 | !TAILQ_EMPTY(&softc->abort_queue)((&softc->abort_queue)->tqh_first == ((void *)0))) { | |||
| 313 | revents |= poll_events & (POLLIN0x0001 | POLLRDNORM0x0040); | |||
| 314 | } | |||
| 315 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (315)); | |||
| 316 | /* Only sleep if the user didn't poll for write. */ | |||
| 317 | if (revents == 0) | |||
| 318 | selrecord(td, &softc->read_select); | |||
| 319 | } | |||
| 320 | ||||
| 321 | return (revents); | |||
| 322 | } | |||
| 323 | ||||
| 324 | static int | |||
| 325 | targkqfilter(struct cdev *dev, struct knote *kn) | |||
| 326 | { | |||
| 327 | struct targ_softc *softc; | |||
| 328 | ||||
| 329 | devfs_get_cdevpriv((void **)&softc); | |||
| 330 | kn->kn_hook = (caddr_t)softc; | |||
| 331 | kn->kn_fop = &targread_filtops; | |||
| 332 | knlist_add(&softc->read_select.si_note, kn, 0); | |||
| 333 | return (0); | |||
| 334 | } | |||
| 335 | ||||
| 336 | static void | |||
| 337 | targreadfiltdetach(struct knote *kn) | |||
| 338 | { | |||
| 339 | struct targ_softc *softc; | |||
| 340 | ||||
| 341 | softc = (struct targ_softc *)kn->kn_hook; | |||
| 342 | knlist_remove(&softc->read_select.si_note, kn, 0); | |||
| 343 | } | |||
| 344 | ||||
| 345 | /* Notify the user's kqueue when the user queue or abort queue gets a CCB */ | |||
| 346 | static int | |||
| 347 | targreadfilt(struct knote *kn, long hint) | |||
| 348 | { | |||
| 349 | struct targ_softc *softc; | |||
| 350 | int retval; | |||
| 351 | ||||
| 352 | softc = (struct targ_softc *)kn->kn_hook; | |||
| 353 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (353)); | |||
| 354 | retval = !TAILQ_EMPTY(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first == ((void *)0) ) || | |||
| 355 | !TAILQ_EMPTY(&softc->abort_queue)((&softc->abort_queue)->tqh_first == ((void *)0)); | |||
| 356 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (356)); | |||
| 357 | return (retval); | |||
| 358 | } | |||
| 359 | ||||
| 360 | /* Send the HBA the enable/disable message */ | |||
| 361 | static cam_status | |||
| 362 | targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) | |||
| 363 | { | |||
| 364 | struct ccb_en_lun en_ccb; | |||
| 365 | cam_status status; | |||
| 366 | ||||
| 367 | /* Tell the lun to begin answering selects */ | |||
| 368 | xpt_setup_ccb(&en_ccb.ccb_h, path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
| 369 | en_ccb.ccb_h.func_code = XPT_EN_LUN; | |||
| 370 | /* Don't need support for any vendor specific commands */ | |||
| 371 | en_ccb.grp6_len = grp6_len; | |||
| 372 | en_ccb.grp7_len = grp7_len; | |||
| 373 | en_ccb.enable = enable ? 1 : 0; | |||
| 374 | xpt_action((union ccb *)&en_ccb); | |||
| 375 | status = en_ccb.ccb_h.status & CAM_STATUS_MASK; | |||
| 376 | if (status != CAM_REQ_CMP) { | |||
| 377 | xpt_print(path, "%sable lun CCB rejected, status %#x\n", | |||
| 378 | enable ? "en" : "dis", status); | |||
| 379 | } | |||
| 380 | return (status); | |||
| 381 | } | |||
| 382 | ||||
| 383 | /* Enable target mode on a LUN, given its path */ | |||
| 384 | static cam_status | |||
| 385 | targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len, | |||
| 386 | int grp7_len) | |||
| 387 | { | |||
| 388 | struct cam_periph *periph; | |||
| 389 | struct ccb_pathinq cpi; | |||
| 390 | cam_status status; | |||
| 391 | ||||
| 392 | if ((softc->state & TARG_STATE_LUN_ENABLED) != 0) | |||
| 393 | return (CAM_LUN_ALRDY_ENA); | |||
| 394 | ||||
| 395 | /* Make sure SIM supports target mode */ | |||
| 396 | xpt_path_inq(&cpi, path); | |||
| 397 | status = cpi.ccb_h.status & CAM_STATUS_MASK; | |||
| 398 | if (status != CAM_REQ_CMP) { | |||
| 399 | printf("pathinq failed, status %#x\n", status); | |||
| 400 | goto enable_fail; | |||
| 401 | } | |||
| 402 | if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { | |||
| 403 | printf("controller does not support target mode\n"); | |||
| 404 | status = CAM_FUNC_NOTAVAIL; | |||
| 405 | goto enable_fail; | |||
| 406 | } | |||
| 407 | if (cpi.maxio == 0) | |||
| 408 | softc->maxio = DFLTPHYS(64 * 1024); /* traditional default */ | |||
| 409 | else if (cpi.maxio > MAXPHYS(128 * 1024)) | |||
| 410 | softc->maxio = MAXPHYS(128 * 1024); /* for safety */ | |||
| 411 | else | |||
| 412 | softc->maxio = cpi.maxio; /* real value */ | |||
| 413 | ||||
| 414 | /* Destroy any periph on our path if it is disabled */ | |||
| 415 | periph = cam_periph_find(path, "targ"); | |||
| 416 | if (periph != NULL((void *)0)) { | |||
| 417 | struct targ_softc *del_softc; | |||
| 418 | ||||
| 419 | del_softc = (struct targ_softc *)periph->softc; | |||
| 420 | if ((del_softc->state & TARG_STATE_LUN_ENABLED) == 0) { | |||
| 421 | cam_periph_invalidate(del_softc->periph); | |||
| 422 | del_softc->periph = NULL((void *)0); | |||
| 423 | } else { | |||
| 424 | printf("Requested path still in use by targ%d\n", | |||
| 425 | periph->unit_number); | |||
| 426 | status = CAM_LUN_ALRDY_ENA; | |||
| 427 | goto enable_fail; | |||
| 428 | } | |||
| 429 | } | |||
| 430 | ||||
| 431 | /* Create a periph instance attached to this path */ | |||
| 432 | status = cam_periph_alloc(targctor, NULL((void *)0), targdtor, targstart, | |||
| 433 | "targ", CAM_PERIPH_BIO, path, targasync, 0, softc); | |||
| 434 | if (status != CAM_REQ_CMP) { | |||
| 435 | printf("cam_periph_alloc failed, status %#x\n", status); | |||
| 436 | goto enable_fail; | |||
| 437 | } | |||
| 438 | ||||
| 439 | /* Ensure that the periph now exists. */ | |||
| 440 | if (cam_periph_find(path, "targ") == NULL((void *)0)) { | |||
| 441 | panic("targenable: succeeded but no periph?"); | |||
| 442 | /* NOTREACHED */ | |||
| 443 | } | |||
| 444 | ||||
| 445 | /* Send the enable lun message */ | |||
| 446 | status = targendislun(path, /*enable*/1, grp6_len, grp7_len); | |||
| 447 | if (status != CAM_REQ_CMP) { | |||
| 448 | printf("enable lun failed, status %#x\n", status); | |||
| 449 | goto enable_fail; | |||
| 450 | } | |||
| 451 | softc->state |= TARG_STATE_LUN_ENABLED; | |||
| 452 | ||||
| 453 | enable_fail: | |||
| 454 | return (status); | |||
| 455 | } | |||
| 456 | ||||
| 457 | /* Disable this softc's target instance if enabled */ | |||
| 458 | static cam_status | |||
| 459 | targdisable(struct targ_softc *softc) | |||
| 460 | { | |||
| 461 | cam_status status; | |||
| 462 | ||||
| 463 | if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) | |||
| 464 | return (CAM_REQ_CMP); | |||
| 465 | ||||
| 466 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targdisable\n"))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targdisable\n"); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 467 | ||||
| 468 | /* Abort any ccbs pending on the controller */ | |||
| 469 | abort_all_pending(softc); | |||
| 470 | ||||
| 471 | /* Disable this lun */ | |||
| 472 | status = targendislun(softc->path, /*enable*/0, | |||
| 473 | /*grp6_len*/0, /*grp7_len*/0); | |||
| 474 | if (status == CAM_REQ_CMP) | |||
| 475 | softc->state &= ~TARG_STATE_LUN_ENABLED; | |||
| 476 | else | |||
| 477 | printf("Disable lun failed, status %#x\n", status); | |||
| 478 | ||||
| 479 | return (status); | |||
| 480 | } | |||
| 481 | ||||
| 482 | /* Initialize a periph (called from cam_periph_alloc) */ | |||
| 483 | static cam_status | |||
| 484 | targctor(struct cam_periph *periph, void *arg) | |||
| 485 | { | |||
| 486 | struct targ_softc *softc; | |||
| 487 | ||||
| 488 | /* Store pointer to softc for periph-driven routines */ | |||
| 489 | softc = (struct targ_softc *)arg; | |||
| 490 | periph->softc = softc; | |||
| 491 | softc->periph = periph; | |||
| 492 | softc->path = periph->path; | |||
| 493 | return (CAM_REQ_CMP); | |||
| 494 | } | |||
| 495 | ||||
| 496 | static void | |||
| 497 | targdtor(struct cam_periph *periph) | |||
| 498 | { | |||
| 499 | struct targ_softc *softc; | |||
| 500 | struct ccb_hdr *ccb_h; | |||
| 501 | struct targ_cmd_descr *descr; | |||
| 502 | ||||
| 503 | softc = (struct targ_softc *)periph->softc; | |||
| 504 | ||||
| 505 | /* | |||
| 506 | * targdisable() aborts CCBs back to the user and leaves them | |||
| 507 | * on user_ccb_queue and abort_queue in case the user is still | |||
| 508 | * interested in them. We free them now. | |||
| 509 | */ | |||
| 510 | while ((ccb_h = TAILQ_FIRST(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first)) != NULL((void *)0)) { | |||
| 511 | TAILQ_REMOVE(&softc->user_ccb_queue, ccb_h, periph_links.tqe)do { ; ; do { if ((((ccb_h))->periph_links.tqe.tqe_next) != ((void *)0) && (((ccb_h))->periph_links.tqe.tqe_next )->periph_links.tqe.tqe_prev != &((ccb_h)->periph_links .tqe.tqe_next)) panic("Bad link elm %p next->prev != elm", (ccb_h)); } while (0); do { if (*(ccb_h)->periph_links.tqe .tqe_prev != (ccb_h)) panic("Bad link elm %p prev->next != elm" , (ccb_h)); } while (0); if (((((ccb_h))->periph_links.tqe .tqe_next)) != ((void *)0)) (((ccb_h))->periph_links.tqe.tqe_next )->periph_links.tqe.tqe_prev = (ccb_h)->periph_links.tqe .tqe_prev; else { (&softc->user_ccb_queue)->tqh_last = (ccb_h)->periph_links.tqe.tqe_prev; ; } *(ccb_h)->periph_links .tqe.tqe_prev = (((ccb_h))->periph_links.tqe.tqe_next); ; ; ; } while (0); | |||
| 512 | targfreeccb(softc, (union ccb *)ccb_h); | |||
| 513 | } | |||
| 514 | while ((descr = TAILQ_FIRST(&softc->abort_queue)((&softc->abort_queue)->tqh_first)) != NULL((void *)0)) { | |||
| 515 | TAILQ_REMOVE(&softc->abort_queue, descr, tqe)do { ; ; do { if ((((descr))->tqe.tqe_next) != ((void *)0) && (((descr))->tqe.tqe_next)->tqe.tqe_prev != & ((descr)->tqe.tqe_next)) panic("Bad link elm %p next->prev != elm" , (descr)); } while (0); do { if (*(descr)->tqe.tqe_prev != (descr)) panic("Bad link elm %p prev->next != elm", (descr )); } while (0); if (((((descr))->tqe.tqe_next)) != ((void *)0)) (((descr))->tqe.tqe_next)->tqe.tqe_prev = (descr )->tqe.tqe_prev; else { (&softc->abort_queue)->tqh_last = (descr)->tqe.tqe_prev; ; } *(descr)->tqe.tqe_prev = ( ((descr))->tqe.tqe_next); ; ; ; } while (0); | |||
| 516 | free(descr, M_TARG); | |||
| 517 | } | |||
| 518 | ||||
| 519 | softc->periph = NULL((void *)0); | |||
| 520 | softc->path = NULL((void *)0); | |||
| 521 | periph->softc = NULL((void *)0); | |||
| 522 | } | |||
| 523 | ||||
| 524 | /* Receive CCBs from user mode proc and send them to the HBA */ | |||
| 525 | static int | |||
| 526 | targwrite(struct cdev *dev, struct uio *uio, int ioflag) | |||
| 527 | { | |||
| 528 | union ccb *user_ccb; | |||
| 529 | struct targ_softc *softc; | |||
| 530 | struct targ_cmd_descr *descr; | |||
| 531 | int write_len, error; | |||
| 532 | int func_code, priority; | |||
| 533 | ||||
| 534 | devfs_get_cdevpriv((void **)&softc); | |||
| 535 | write_len = error = 0; | |||
| 536 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("write - uio_resid %zd\n", uio-> uio_resid); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| ||||
| 537 | ("write - uio_resid %zd\n", uio->uio_resid))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("write - uio_resid %zd\n", uio-> uio_resid); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 538 | while (uio->uio_resid >= sizeof(user_ccb) && error == 0) { | |||
| 539 | union ccb *ccb; | |||
| 540 | ||||
| 541 | error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); | |||
| 542 | if (error != 0) { | |||
| 543 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("write - uiomove failed (%d)\n", error ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 544 | ("write - uiomove failed (%d)\n", error))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("write - uiomove failed (%d)\n", error ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 545 | break; | |||
| 546 | } | |||
| 547 | priority = fuword32(&user_ccb->ccb_h.pinfo.priority); | |||
| 548 | if (priority == CAM_PRIORITY_NONE(u_int32_t)-1) { | |||
| 549 | error = EINVAL22; | |||
| 550 | break; | |||
| 551 | } | |||
| 552 | func_code = fuword32(&user_ccb->ccb_h.func_code); | |||
| 553 | switch (func_code) { | |||
| 554 | case XPT_ACCEPT_TARGET_IO: | |||
| 555 | case XPT_IMMED_NOTIFY: | |||
| 556 | case XPT_IMMEDIATE_NOTIFY: | |||
| 557 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (557)); | |||
| 558 | ccb = targgetccb(softc, func_code, priority); | |||
| 559 | descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr; | |||
| 560 | descr->user_ccb = user_ccb; | |||
| 561 | descr->func_code = func_code; | |||
| 562 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sent ATIO/INOT (%p)\n", user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 563 | ("Sent ATIO/INOT (%p)\n", user_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sent ATIO/INOT (%p)\n", user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 564 | xpt_action(ccb); | |||
| 565 | TAILQ_INSERT_TAIL(&softc->pending_ccb_queue,do { do { if (*(&softc->pending_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->pending_ccb_queue)); } while (0); (((&ccb ->ccb_h))->periph_links.tqe.tqe_next) = ((void *)0); (& ccb->ccb_h)->periph_links.tqe.tqe_prev = (&softc-> pending_ccb_queue)->tqh_last; *(&softc->pending_ccb_queue )->tqh_last = (&ccb->ccb_h); (&softc->pending_ccb_queue )->tqh_last = &(((&ccb->ccb_h))->periph_links .tqe.tqe_next); ; ; } while (0) | |||
| 566 | &ccb->ccb_h,do { do { if (*(&softc->pending_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->pending_ccb_queue)); } while (0); (((&ccb ->ccb_h))->periph_links.tqe.tqe_next) = ((void *)0); (& ccb->ccb_h)->periph_links.tqe.tqe_prev = (&softc-> pending_ccb_queue)->tqh_last; *(&softc->pending_ccb_queue )->tqh_last = (&ccb->ccb_h); (&softc->pending_ccb_queue )->tqh_last = &(((&ccb->ccb_h))->periph_links .tqe.tqe_next); ; ; } while (0) | |||
| 567 | periph_links.tqe)do { do { if (*(&softc->pending_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->pending_ccb_queue)); } while (0); (((&ccb ->ccb_h))->periph_links.tqe.tqe_next) = ((void *)0); (& ccb->ccb_h)->periph_links.tqe.tqe_prev = (&softc-> pending_ccb_queue)->tqh_last; *(&softc->pending_ccb_queue )->tqh_last = (&ccb->ccb_h); (&softc->pending_ccb_queue )->tqh_last = &(((&ccb->ccb_h))->periph_links .tqe.tqe_next); ; ; } while (0); | |||
| 568 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (568)); | |||
| 569 | break; | |||
| 570 | default: | |||
| 571 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (571)); | |||
| 572 | if ((func_code & XPT_FC_QUEUED) != 0) { | |||
| 573 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending queued ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; } | |||
| 574 | ("Sending queued ccb %#x (%p)\n",if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending queued ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; } | |||
| 575 | func_code, user_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending queued ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; }; | |||
| 576 | descr = targgetdescr(softc); | |||
| 577 | descr->user_ccb = user_ccb; | |||
| 578 | descr->priority = priority; | |||
| 579 | descr->func_code = func_code; | |||
| 580 | TAILQ_INSERT_TAIL(&softc->work_queue,do { do { if (*(&softc->work_queue)->tqh_last != (( void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL", ( &softc->work_queue)); } while (0); (((descr))->tqe. tqe_next) = ((void *)0); (descr)->tqe.tqe_prev = (&softc ->work_queue)->tqh_last; *(&softc->work_queue)-> tqh_last = (descr); (&softc->work_queue)->tqh_last = &(((descr))->tqe.tqe_next); ; ; } while (0) | |||
| 581 | descr, tqe)do { do { if (*(&softc->work_queue)->tqh_last != (( void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL", ( &softc->work_queue)); } while (0); (((descr))->tqe. tqe_next) = ((void *)0); (descr)->tqe.tqe_prev = (&softc ->work_queue)->tqh_last; *(&softc->work_queue)-> tqh_last = (descr); (&softc->work_queue)->tqh_last = &(((descr))->tqe.tqe_next); ; ; } while (0); | |||
| 582 | xpt_schedule(softc->periph, priority); | |||
| 583 | } else { | |||
| 584 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending inline ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; } | |||
| 585 | ("Sending inline ccb %#x (%p)\n",if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending inline ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; } | |||
| 586 | func_code, user_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Sending inline ccb %#x (%p)\n", func_code , user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay) ; }; | |||
| 587 | ccb = targgetccb(softc, func_code, priority); | |||
| 588 | descr = (struct targ_cmd_descr *) | |||
| 589 | ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr; | |||
| 590 | descr->user_ccb = user_ccb; | |||
| 591 | descr->priority = priority; | |||
| 592 | descr->func_code = func_code; | |||
| 593 | if (targusermerge(softc, descr, ccb) != EFAULT14) | |||
| 594 | targsendccb(softc, ccb, descr); | |||
| 595 | targreturnccb(softc, ccb); | |||
| 596 | } | |||
| 597 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (597)); | |||
| 598 | break; | |||
| 599 | } | |||
| 600 | write_len += sizeof(user_ccb); | |||
| 601 | } | |||
| 602 | ||||
| 603 | /* | |||
| 604 | * If we've successfully taken in some amount of | |||
| 605 | * data, return success for that data first. If | |||
| 606 | * an error is persistent, it will be reported | |||
| 607 | * on the next write. | |||
| 608 | */ | |||
| 609 | if (error != 0 && write_len == 0) | |||
| 610 | return (error); | |||
| 611 | if (write_len == 0 && uio->uio_resid != 0) | |||
| 612 | return (ENOSPC28); | |||
| 613 | return (0); | |||
| 614 | } | |||
| 615 | ||||
| 616 | /* Process requests (descrs) via the periph-supplied CCBs */ | |||
| 617 | static void | |||
| 618 | targstart(struct cam_periph *periph, union ccb *start_ccb) | |||
| 619 | { | |||
| 620 | struct targ_softc *softc; | |||
| 621 | struct targ_cmd_descr *descr, *next_descr; | |||
| 622 | int error; | |||
| 623 | ||||
| 624 | softc = (struct targ_softc *)periph->softc; | |||
| 625 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targstart %p\n", start_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targstart %p\n", start_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 626 | ||||
| 627 | descr = TAILQ_FIRST(&softc->work_queue)((&softc->work_queue)->tqh_first); | |||
| 628 | if (descr == NULL((void *)0)) { | |||
| 629 | xpt_release_ccb(start_ccb); | |||
| 630 | } else { | |||
| 631 | TAILQ_REMOVE(&softc->work_queue, descr, tqe)do { ; ; do { if ((((descr))->tqe.tqe_next) != ((void *)0) && (((descr))->tqe.tqe_next)->tqe.tqe_prev != & ((descr)->tqe.tqe_next)) panic("Bad link elm %p next->prev != elm" , (descr)); } while (0); do { if (*(descr)->tqe.tqe_prev != (descr)) panic("Bad link elm %p prev->next != elm", (descr )); } while (0); if (((((descr))->tqe.tqe_next)) != ((void *)0)) (((descr))->tqe.tqe_next)->tqe.tqe_prev = (descr )->tqe.tqe_prev; else { (&softc->work_queue)->tqh_last = (descr)->tqe.tqe_prev; ; } *(descr)->tqe.tqe_prev = ( ((descr))->tqe.tqe_next); ; ; ; } while (0); | |||
| 632 | next_descr = TAILQ_FIRST(&softc->work_queue)((&softc->work_queue)->tqh_first); | |||
| 633 | ||||
| 634 | /* Initiate a transaction using the descr and supplied CCB */ | |||
| 635 | error = targusermerge(softc, descr, start_ccb); | |||
| 636 | if (error == 0) | |||
| 637 | error = targsendccb(softc, start_ccb, descr); | |||
| 638 | if (error != 0) { | |||
| 639 | xpt_print(periph->path, | |||
| 640 | "targsendccb failed, err %d\n", error); | |||
| 641 | xpt_release_ccb(start_ccb); | |||
| 642 | suword(&descr->user_ccb->ccb_h.status, | |||
| 643 | CAM_REQ_CMP_ERR); | |||
| 644 | TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe)do { do { if (*(&softc->abort_queue)->tqh_last != ( (void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL", ( &softc->abort_queue)); } while (0); (((descr))->tqe .tqe_next) = ((void *)0); (descr)->tqe.tqe_prev = (&softc ->abort_queue)->tqh_last; *(&softc->abort_queue) ->tqh_last = (descr); (&softc->abort_queue)->tqh_last = &(((descr))->tqe.tqe_next); ; ; } while (0); | |||
| 645 | notify_user(softc); | |||
| 646 | } | |||
| 647 | ||||
| 648 | /* If we have more work to do, stay scheduled */ | |||
| 649 | if (next_descr != NULL((void *)0)) | |||
| 650 | xpt_schedule(periph, next_descr->priority); | |||
| 651 | } | |||
| 652 | } | |||
| 653 | ||||
| 654 | static int | |||
| 655 | targusermerge(struct targ_softc *softc, struct targ_cmd_descr *descr, | |||
| 656 | union ccb *ccb) | |||
| 657 | { | |||
| 658 | struct ccb_hdr *u_ccbh, *k_ccbh; | |||
| 659 | size_t ccb_len; | |||
| 660 | int error; | |||
| 661 | ||||
| 662 | u_ccbh = &descr->user_ccb->ccb_h; | |||
| 663 | k_ccbh = &ccb->ccb_h; | |||
| 664 | ||||
| 665 | /* | |||
| 666 | * There are some fields in the CCB header that need to be | |||
| 667 | * preserved, the rest we get from the user ccb. (See xpt_merge_ccb) | |||
| 668 | */ | |||
| 669 | xpt_setup_ccb(k_ccbh, softc->path, descr->priority); | |||
| 670 | k_ccbh->retry_count = fuword32(&u_ccbh->retry_count); | |||
| 671 | k_ccbh->func_code = descr->func_code; | |||
| 672 | k_ccbh->flags = fuword32(&u_ccbh->flags); | |||
| 673 | k_ccbh->timeout = fuword32(&u_ccbh->timeout); | |||
| 674 | ccb_len = targccblen(k_ccbh->func_code) - sizeof(struct ccb_hdr); | |||
| 675 | error = copyin(u_ccbh + 1, k_ccbh + 1, ccb_len); | |||
| 676 | if (error != 0) { | |||
| 677 | k_ccbh->status = CAM_REQ_CMP_ERR; | |||
| 678 | return (error); | |||
| 679 | } | |||
| 680 | ||||
| 681 | /* Translate usermode abort_ccb pointer to its kernel counterpart */ | |||
| 682 | if (k_ccbh->func_code == XPT_ABORT) { | |||
| 683 | struct ccb_abort *cab; | |||
| 684 | struct ccb_hdr *ccb_h; | |||
| 685 | ||||
| 686 | cab = (struct ccb_abort *)ccb; | |||
| 687 | TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue,for ((ccb_h) = (((&softc->pending_ccb_queue))->tqh_first ); (ccb_h); (ccb_h) = (((ccb_h))->periph_links.tqe.tqe_next )) | |||
| 688 | periph_links.tqe)for ((ccb_h) = (((&softc->pending_ccb_queue))->tqh_first ); (ccb_h); (ccb_h) = (((ccb_h))->periph_links.tqe.tqe_next )) { | |||
| 689 | struct targ_cmd_descr *ab_descr; | |||
| 690 | ||||
| 691 | ab_descr = (struct targ_cmd_descr *)ccb_h->targ_descrperiph_priv.entries[1].ptr; | |||
| 692 | if (ab_descr->user_ccb == cab->abort_ccb) { | |||
| 693 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Changing abort for %p to %p\n", cab ->abort_ccb, ccb_h); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); } | |||
| 694 | ("Changing abort for %p to %p\n",if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Changing abort for %p to %p\n", cab ->abort_ccb, ccb_h); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); } | |||
| 695 | cab->abort_ccb, ccb_h))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Changing abort for %p to %p\n", cab ->abort_ccb, ccb_h); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); }; | |||
| 696 | cab->abort_ccb = (union ccb *)ccb_h; | |||
| 697 | break; | |||
| 698 | } | |||
| 699 | } | |||
| 700 | /* CCB not found, set appropriate status */ | |||
| 701 | if (ccb_h == NULL((void *)0)) { | |||
| 702 | k_ccbh->status = CAM_PATH_INVALID; | |||
| 703 | error = ESRCH3; | |||
| 704 | } | |||
| 705 | } | |||
| 706 | ||||
| 707 | return (error); | |||
| 708 | } | |||
| 709 | ||||
| 710 | /* Build and send a kernel CCB formed from descr->user_ccb */ | |||
| 711 | static int | |||
| 712 | targsendccb(struct targ_softc *softc, union ccb *ccb, | |||
| 713 | struct targ_cmd_descr *descr) | |||
| 714 | { | |||
| 715 | struct cam_periph_map_info *mapinfo; | |||
| 716 | struct ccb_hdr *ccb_h; | |||
| 717 | int error; | |||
| 718 | ||||
| 719 | ccb_h = &ccb->ccb_h; | |||
| 720 | mapinfo = &descr->mapinfo; | |||
| 721 | mapinfo->num_bufs_used = 0; | |||
| 722 | ||||
| 723 | /* | |||
| 724 | * There's no way for the user to have a completion | |||
| 725 | * function, so we put our own completion function in here. | |||
| 726 | * We also stash in a reference to our descriptor so targreturnccb() | |||
| 727 | * can find our mapping info. | |||
| 728 | */ | |||
| 729 | ccb_h->cbfcnp = targdone; | |||
| 730 | ccb_h->targ_descrperiph_priv.entries[1].ptr = descr; | |||
| 731 | ||||
| 732 | if ((ccb_h->func_code == XPT_CONT_TARGET_IO) || | |||
| 733 | (ccb_h->func_code == XPT_DEV_MATCH)) { | |||
| 734 | ||||
| 735 | error = cam_periph_mapmem(ccb, mapinfo, softc->maxio); | |||
| 736 | ||||
| 737 | /* | |||
| 738 | * cam_periph_mapmem returned an error, we can't continue. | |||
| 739 | * Return the error to the user. | |||
| 740 | */ | |||
| 741 | if (error) { | |||
| 742 | ccb_h->status = CAM_REQ_CMP_ERR; | |||
| 743 | mapinfo->num_bufs_used = 0; | |||
| 744 | return (error); | |||
| 745 | } | |||
| 746 | } | |||
| 747 | ||||
| 748 | /* | |||
| 749 | * Once queued on the pending CCB list, this CCB will be protected | |||
| 750 | * by our error recovery handler. | |||
| 751 | */ | |||
| 752 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("sendccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("sendccb %p\n", ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 753 | if (XPT_FC_IS_QUEUED(ccb)(((ccb)->ccb_h.func_code & XPT_FC_QUEUED) != 0)) { | |||
| 754 | TAILQ_INSERT_TAIL(&softc->pending_ccb_queue, ccb_h,do { do { if (*(&softc->pending_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->pending_ccb_queue)); } while (0); (((ccb_h) )->periph_links.tqe.tqe_next) = ((void *)0); (ccb_h)->periph_links .tqe.tqe_prev = (&softc->pending_ccb_queue)->tqh_last ; *(&softc->pending_ccb_queue)->tqh_last = (ccb_h); (&softc->pending_ccb_queue)->tqh_last = &(((ccb_h ))->periph_links.tqe.tqe_next); ; ; } while (0) | |||
| 755 | periph_links.tqe)do { do { if (*(&softc->pending_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->pending_ccb_queue)); } while (0); (((ccb_h) )->periph_links.tqe.tqe_next) = ((void *)0); (ccb_h)->periph_links .tqe.tqe_prev = (&softc->pending_ccb_queue)->tqh_last ; *(&softc->pending_ccb_queue)->tqh_last = (ccb_h); (&softc->pending_ccb_queue)->tqh_last = &(((ccb_h ))->periph_links.tqe.tqe_next); ; ; } while (0); | |||
| 756 | } | |||
| 757 | xpt_action(ccb); | |||
| 758 | ||||
| 759 | return (0); | |||
| 760 | } | |||
| 761 | ||||
| 762 | /* Completion routine for CCBs (called at splsoftcam) */ | |||
| 763 | static void | |||
| 764 | targdone(struct cam_periph *periph, union ccb *done_ccb) | |||
| 765 | { | |||
| 766 | struct targ_softc *softc; | |||
| 767 | cam_status status; | |||
| 768 | ||||
| 769 | CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("targdone %p\n", done_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, periph->path) >= 0) && (xpt_path_comp(cam_dpath, periph->path) < 2)) { xpt_print_path (periph->path); printf ("targdone %p\n", done_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 770 | softc = (struct targ_softc *)periph->softc; | |||
| 771 | TAILQ_REMOVE(&softc->pending_ccb_queue, &done_ccb->ccb_h,do { ; ; do { if ((((&done_ccb->ccb_h))->periph_links .tqe.tqe_next) != ((void *)0) && (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next)->periph_links.tqe.tqe_prev != &((&done_ccb->ccb_h)->periph_links.tqe.tqe_next )) panic("Bad link elm %p next->prev != elm", (&done_ccb ->ccb_h)); } while (0); do { if (*(&done_ccb->ccb_h )->periph_links.tqe.tqe_prev != (&done_ccb->ccb_h)) panic("Bad link elm %p prev->next != elm", (&done_ccb ->ccb_h)); } while (0); if (((((&done_ccb->ccb_h))-> periph_links.tqe.tqe_next)) != ((void *)0)) (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next)->periph_links.tqe.tqe_prev = (&done_ccb->ccb_h)->periph_links.tqe.tqe_prev; else { (&softc->pending_ccb_queue)->tqh_last = (&done_ccb ->ccb_h)->periph_links.tqe.tqe_prev; ; } *(&done_ccb ->ccb_h)->periph_links.tqe.tqe_prev = (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next); ; ; ; } while (0) | |||
| 772 | periph_links.tqe)do { ; ; do { if ((((&done_ccb->ccb_h))->periph_links .tqe.tqe_next) != ((void *)0) && (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next)->periph_links.tqe.tqe_prev != &((&done_ccb->ccb_h)->periph_links.tqe.tqe_next )) panic("Bad link elm %p next->prev != elm", (&done_ccb ->ccb_h)); } while (0); do { if (*(&done_ccb->ccb_h )->periph_links.tqe.tqe_prev != (&done_ccb->ccb_h)) panic("Bad link elm %p prev->next != elm", (&done_ccb ->ccb_h)); } while (0); if (((((&done_ccb->ccb_h))-> periph_links.tqe.tqe_next)) != ((void *)0)) (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next)->periph_links.tqe.tqe_prev = (&done_ccb->ccb_h)->periph_links.tqe.tqe_prev; else { (&softc->pending_ccb_queue)->tqh_last = (&done_ccb ->ccb_h)->periph_links.tqe.tqe_prev; ; } *(&done_ccb ->ccb_h)->periph_links.tqe.tqe_prev = (((&done_ccb-> ccb_h))->periph_links.tqe.tqe_next); ; ; ; } while (0); | |||
| 773 | status = done_ccb->ccb_h.status & CAM_STATUS_MASK; | |||
| 774 | ||||
| 775 | /* If we're no longer enabled, throw away CCB */ | |||
| 776 | if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { | |||
| 777 | targfreeccb(softc, done_ccb); | |||
| 778 | return; | |||
| 779 | } | |||
| 780 | /* abort_all_pending() waits for pending queue to be empty */ | |||
| 781 | if (TAILQ_EMPTY(&softc->pending_ccb_queue)((&softc->pending_ccb_queue)->tqh_first == ((void * )0))) | |||
| 782 | wakeup(&softc->pending_ccb_queue); | |||
| 783 | ||||
| 784 | switch (done_ccb->ccb_h.func_code) { | |||
| 785 | /* All FC_*_QUEUED CCBs go back to userland */ | |||
| 786 | case XPT_IMMED_NOTIFY: | |||
| 787 | case XPT_IMMEDIATE_NOTIFY: | |||
| 788 | case XPT_ACCEPT_TARGET_IO: | |||
| 789 | case XPT_CONT_TARGET_IO: | |||
| 790 | TAILQ_INSERT_TAIL(&softc->user_ccb_queue, &done_ccb->ccb_h,do { do { if (*(&softc->user_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->user_ccb_queue)); } while (0); (((&done_ccb ->ccb_h))->periph_links.tqe.tqe_next) = ((void *)0); (& done_ccb->ccb_h)->periph_links.tqe.tqe_prev = (&softc ->user_ccb_queue)->tqh_last; *(&softc->user_ccb_queue )->tqh_last = (&done_ccb->ccb_h); (&softc->user_ccb_queue )->tqh_last = &(((&done_ccb->ccb_h))->periph_links .tqe.tqe_next); ; ; } while (0) | |||
| 791 | periph_links.tqe)do { do { if (*(&softc->user_ccb_queue)->tqh_last != ((void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL" , (&softc->user_ccb_queue)); } while (0); (((&done_ccb ->ccb_h))->periph_links.tqe.tqe_next) = ((void *)0); (& done_ccb->ccb_h)->periph_links.tqe.tqe_prev = (&softc ->user_ccb_queue)->tqh_last; *(&softc->user_ccb_queue )->tqh_last = (&done_ccb->ccb_h); (&softc->user_ccb_queue )->tqh_last = &(((&done_ccb->ccb_h))->periph_links .tqe.tqe_next); ; ; } while (0); | |||
| 792 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (792)); | |||
| 793 | notify_user(softc); | |||
| 794 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (794)); | |||
| 795 | break; | |||
| 796 | default: | |||
| 797 | panic("targdone: impossible xpt opcode %#x", | |||
| 798 | done_ccb->ccb_h.func_code); | |||
| 799 | /* NOTREACHED */ | |||
| 800 | } | |||
| 801 | } | |||
| 802 | ||||
| 803 | /* Return CCBs to the user from the user queue and abort queue */ | |||
| 804 | static int | |||
| 805 | targread(struct cdev *dev, struct uio *uio, int ioflag) | |||
| 806 | { | |||
| 807 | struct descr_queue *abort_queue; | |||
| 808 | struct targ_cmd_descr *user_descr; | |||
| 809 | struct targ_softc *softc; | |||
| 810 | struct ccb_queue *user_queue; | |||
| 811 | struct ccb_hdr *ccb_h; | |||
| 812 | union ccb *user_ccb; | |||
| 813 | int read_len, error; | |||
| 814 | ||||
| 815 | error = 0; | |||
| 816 | read_len = 0; | |||
| 817 | devfs_get_cdevpriv((void **)&softc); | |||
| 818 | user_queue = &softc->user_ccb_queue; | |||
| 819 | abort_queue = &softc->abort_queue; | |||
| 820 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targread\n"))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread\n"); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 821 | ||||
| 822 | /* If no data is available, wait or return immediately */ | |||
| 823 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (823)); | |||
| 824 | ccb_h = TAILQ_FIRST(user_queue)((user_queue)->tqh_first); | |||
| 825 | user_descr = TAILQ_FIRST(abort_queue)((abort_queue)->tqh_first); | |||
| 826 | while (ccb_h == NULL((void *)0) && user_descr == NULL((void *)0)) { | |||
| 827 | if ((ioflag & IO_NDELAY0x0004) == 0) { | |||
| 828 | error = cam_periph_sleep(softc->periph, user_queue,_sleep((((user_queue))), &(xpt_path_mtx((softc->periph )->path))->lock_object, (((((80) + 12) | 0x100))), ((("targrd" ))), tick_sbt * (((0))), 0, 0x0100) | |||
| 829 | PRIBIO | PCATCH, "targrd", 0)_sleep((((user_queue))), &(xpt_path_mtx((softc->periph )->path))->lock_object, (((((80) + 12) | 0x100))), ((("targrd" ))), tick_sbt * (((0))), 0, 0x0100); | |||
| 830 | ccb_h = TAILQ_FIRST(user_queue)((user_queue)->tqh_first); | |||
| 831 | user_descr = TAILQ_FIRST(abort_queue)((abort_queue)->tqh_first); | |||
| 832 | if (error != 0) { | |||
| 833 | if (error == ERESTART(-1)) { | |||
| 834 | continue; | |||
| 835 | } else { | |||
| 836 | goto read_fail; | |||
| 837 | } | |||
| 838 | } | |||
| 839 | } else { | |||
| 840 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (840)); | |||
| 841 | return (EAGAIN35); | |||
| 842 | } | |||
| 843 | } | |||
| 844 | ||||
| 845 | /* Data is available so fill the user's buffer */ | |||
| 846 | while (ccb_h != NULL((void *)0)) { | |||
| 847 | struct targ_cmd_descr *descr; | |||
| 848 | ||||
| 849 | if (uio->uio_resid < sizeof(user_ccb)) | |||
| 850 | break; | |||
| 851 | TAILQ_REMOVE(user_queue, ccb_h, periph_links.tqe)do { ; ; do { if ((((ccb_h))->periph_links.tqe.tqe_next) != ((void *)0) && (((ccb_h))->periph_links.tqe.tqe_next )->periph_links.tqe.tqe_prev != &((ccb_h)->periph_links .tqe.tqe_next)) panic("Bad link elm %p next->prev != elm", (ccb_h)); } while (0); do { if (*(ccb_h)->periph_links.tqe .tqe_prev != (ccb_h)) panic("Bad link elm %p prev->next != elm" , (ccb_h)); } while (0); if (((((ccb_h))->periph_links.tqe .tqe_next)) != ((void *)0)) (((ccb_h))->periph_links.tqe.tqe_next )->periph_links.tqe.tqe_prev = (ccb_h)->periph_links.tqe .tqe_prev; else { (user_queue)->tqh_last = (ccb_h)->periph_links .tqe.tqe_prev; ; } *(ccb_h)->periph_links.tqe.tqe_prev = ( ((ccb_h))->periph_links.tqe.tqe_next); ; ; ; } while (0); | |||
| 852 | descr = (struct targ_cmd_descr *)ccb_h->targ_descrperiph_priv.entries[1].ptr; | |||
| 853 | user_ccb = descr->user_ccb; | |||
| 854 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread ccb %p (%p)\n", ccb_h, user_ccb ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 855 | ("targread ccb %p (%p)\n", ccb_h, user_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread ccb %p (%p)\n", ccb_h, user_ccb ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 856 | error = targreturnccb(softc, (union ccb *)ccb_h); | |||
| 857 | if (error != 0) | |||
| 858 | goto read_fail; | |||
| 859 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (859)); | |||
| 860 | error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); | |||
| 861 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (861)); | |||
| 862 | if (error != 0) | |||
| 863 | goto read_fail; | |||
| 864 | read_len += sizeof(user_ccb); | |||
| 865 | ||||
| 866 | ccb_h = TAILQ_FIRST(user_queue)((user_queue)->tqh_first); | |||
| 867 | } | |||
| 868 | ||||
| 869 | /* Flush out any aborted descriptors */ | |||
| 870 | while (user_descr != NULL((void *)0)) { | |||
| 871 | if (uio->uio_resid < sizeof(user_ccb)) | |||
| 872 | break; | |||
| 873 | TAILQ_REMOVE(abort_queue, user_descr, tqe)do { ; ; do { if ((((user_descr))->tqe.tqe_next) != ((void *)0) && (((user_descr))->tqe.tqe_next)->tqe.tqe_prev != &((user_descr)->tqe.tqe_next)) panic("Bad link elm %p next->prev != elm" , (user_descr)); } while (0); do { if (*(user_descr)->tqe. tqe_prev != (user_descr)) panic("Bad link elm %p prev->next != elm" , (user_descr)); } while (0); if (((((user_descr))->tqe.tqe_next )) != ((void *)0)) (((user_descr))->tqe.tqe_next)->tqe. tqe_prev = (user_descr)->tqe.tqe_prev; else { (abort_queue )->tqh_last = (user_descr)->tqe.tqe_prev; ; } *(user_descr )->tqe.tqe_prev = (((user_descr))->tqe.tqe_next); ; ; ; } while (0); | |||
| 874 | user_ccb = user_descr->user_ccb; | |||
| 875 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread aborted descr %p (%p)\n", user_descr, user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); } | |||
| 876 | ("targread aborted descr %p (%p)\n",if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread aborted descr %p (%p)\n", user_descr, user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); } | |||
| 877 | user_descr, user_ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targread aborted descr %p (%p)\n", user_descr, user_ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay ); }; | |||
| 878 | suword(&user_ccb->ccb_h.status, CAM_REQ_ABORTED); | |||
| 879 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (879)); | |||
| 880 | error = uiomove((caddr_t)&user_ccb, sizeof(user_ccb), uio); | |||
| 881 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (881)); | |||
| 882 | if (error != 0) | |||
| 883 | goto read_fail; | |||
| 884 | read_len += sizeof(user_ccb); | |||
| 885 | ||||
| 886 | user_descr = TAILQ_FIRST(abort_queue)((abort_queue)->tqh_first); | |||
| 887 | } | |||
| 888 | ||||
| 889 | /* | |||
| 890 | * If we've successfully read some amount of data, don't report an | |||
| 891 | * error. If the error is persistent, it will be reported on the | |||
| 892 | * next read(). | |||
| 893 | */ | |||
| 894 | if (read_len == 0 && uio->uio_resid != 0) | |||
| 895 | error = ENOSPC28; | |||
| 896 | ||||
| 897 | read_fail: | |||
| 898 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (898)); | |||
| 899 | return (error); | |||
| 900 | } | |||
| 901 | ||||
| 902 | /* Copy completed ccb back to the user */ | |||
| 903 | static int | |||
| 904 | targreturnccb(struct targ_softc *softc, union ccb *ccb) | |||
| 905 | { | |||
| 906 | struct targ_cmd_descr *descr; | |||
| 907 | struct ccb_hdr *u_ccbh; | |||
| 908 | size_t ccb_len; | |||
| 909 | int error; | |||
| 910 | ||||
| 911 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("targreturnccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("targreturnccb %p\n", ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 912 | descr = (struct targ_cmd_descr *)ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr; | |||
| 913 | u_ccbh = &descr->user_ccb->ccb_h; | |||
| 914 | ||||
| 915 | /* Copy out the central portion of the ccb_hdr */ | |||
| 916 | copyout(&ccb->ccb_h.retry_count, &u_ccbh->retry_count, | |||
| 917 | offsetof(struct ccb_hdr, periph_priv)__builtin_offsetof(struct ccb_hdr, periph_priv) - | |||
| 918 | offsetof(struct ccb_hdr, retry_count)__builtin_offsetof(struct ccb_hdr, retry_count)); | |||
| 919 | ||||
| 920 | /* Copy out the rest of the ccb (after the ccb_hdr) */ | |||
| 921 | ccb_len = targccblen(ccb->ccb_h.func_code) - sizeof(struct ccb_hdr); | |||
| 922 | if (descr->mapinfo.num_bufs_used != 0) | |||
| 923 | cam_periph_unmapmem(ccb, &descr->mapinfo); | |||
| 924 | error = copyout(&ccb->ccb_h + 1, u_ccbh + 1, ccb_len); | |||
| ||||
| 925 | if (error != 0) { | |||
| 926 | xpt_print(softc->path, | |||
| 927 | "targreturnccb - CCB copyout failed (%d)\n", error); | |||
| 928 | } | |||
| 929 | /* Free CCB or send back to devq. */ | |||
| 930 | targfreeccb(softc, ccb); | |||
| 931 | ||||
| 932 | return (error); | |||
| 933 | } | |||
| 934 | ||||
| 935 | static union ccb * | |||
| 936 | targgetccb(struct targ_softc *softc, xpt_opcode type, int priority) | |||
| 937 | { | |||
| 938 | union ccb *ccb; | |||
| 939 | int ccb_len; | |||
| 940 | ||||
| 941 | ccb_len = targccblen(type); | |||
| 942 | ccb = malloc(ccb_len, M_TARG, M_NOWAIT0x0001); | |||
| 943 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("getccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("getccb %p\n", ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 944 | if (ccb == NULL((void *)0)) { | |||
| 945 | return (ccb); | |||
| 946 | } | |||
| 947 | xpt_setup_ccb(&ccb->ccb_h, softc->path, priority); | |||
| 948 | ccb->ccb_h.func_code = type; | |||
| 949 | ccb->ccb_h.cbfcnp = targdone; | |||
| 950 | ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr = targgetdescr(softc); | |||
| 951 | if (ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr == NULL((void *)0)) { | |||
| 952 | free (ccb, M_TARG); | |||
| 953 | ccb = NULL((void *)0); | |||
| 954 | } | |||
| 955 | return (ccb); | |||
| 956 | } | |||
| 957 | ||||
| 958 | static void | |||
| 959 | targfreeccb(struct targ_softc *softc, union ccb *ccb) | |||
| 960 | { | |||
| 961 | CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("targfreeccb descr %p and\n",if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("targfreeccb descr %p and\n" , ccb->ccb_h.periph_priv.entries[1].ptr); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 962 | ccb->ccb_h.targ_descr))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("targfreeccb descr %p and\n" , ccb->ccb_h.periph_priv.entries[1].ptr); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 963 | free(ccb->ccb_h.targ_descrperiph_priv.entries[1].ptr, M_TARG); | |||
| 964 | ||||
| 965 | switch (ccb->ccb_h.func_code) { | |||
| 966 | case XPT_ACCEPT_TARGET_IO: | |||
| 967 | case XPT_IMMED_NOTIFY: | |||
| 968 | case XPT_IMMEDIATE_NOTIFY: | |||
| 969 | CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH, ("freeing ccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("freeing ccb %p\n" , ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 970 | free(ccb, M_TARG); | |||
| 971 | break; | |||
| 972 | default: | |||
| 973 | /* Send back CCB if we got it from the periph */ | |||
| 974 | if (XPT_FC_IS_QUEUED(ccb)(((ccb)->ccb_h.func_code & XPT_FC_QUEUED) != 0)) { | |||
| 975 | CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("returning queued ccb %p\n" , ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 976 | ("returning queued ccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("returning queued ccb %p\n" , ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 977 | xpt_release_ccb(ccb); | |||
| 978 | } else { | |||
| 979 | CAM_DEBUG_PRINT(CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("freeing ccb %p\n" , ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 980 | ("freeing ccb %p\n", ccb))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags)) { printf("cam_debug: "); printf ("freeing ccb %p\n" , ccb); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 981 | free(ccb, M_TARG); | |||
| 982 | } | |||
| 983 | break; | |||
| 984 | } | |||
| 985 | } | |||
| 986 | ||||
| 987 | static struct targ_cmd_descr * | |||
| 988 | targgetdescr(struct targ_softc *softc) | |||
| 989 | { | |||
| 990 | struct targ_cmd_descr *descr; | |||
| 991 | ||||
| 992 | descr = malloc(sizeof(*descr), M_TARG, | |||
| 993 | M_NOWAIT0x0001); | |||
| 994 | if (descr) { | |||
| 995 | descr->mapinfo.num_bufs_used = 0; | |||
| 996 | } | |||
| 997 | return (descr); | |||
| 998 | } | |||
| 999 | ||||
| 1000 | static void | |||
| 1001 | targinit(void) | |||
| 1002 | { | |||
| 1003 | struct cdev *dev; | |||
| 1004 | ||||
| 1005 | /* Add symbolic link to targ0 for compatibility. */ | |||
| 1006 | dev = make_dev(&targ_cdevsw, 0, UID_ROOT0, GID_WHEEL0, 0600, "targ"); | |||
| 1007 | make_dev_alias(dev, "targ0"); | |||
| 1008 | } | |||
| 1009 | ||||
| 1010 | static void | |||
| 1011 | targasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) | |||
| 1012 | { | |||
| 1013 | /* All events are handled in usermode by INOTs */ | |||
| 1014 | panic("targasync() called, should be an INOT instead"); | |||
| 1015 | } | |||
| 1016 | ||||
| 1017 | /* Cancel all pending requests and CCBs awaiting work. */ | |||
| 1018 | static void | |||
| 1019 | abort_all_pending(struct targ_softc *softc) | |||
| 1020 | { | |||
| 1021 | struct targ_cmd_descr *descr; | |||
| 1022 | struct ccb_abort cab; | |||
| 1023 | struct ccb_hdr *ccb_h; | |||
| 1024 | ||||
| 1025 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH, ("abort_all_pending\n"))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("abort_all_pending\n"); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 1026 | ||||
| 1027 | /* First abort the descriptors awaiting resources */ | |||
| 1028 | while ((descr = TAILQ_FIRST(&softc->work_queue)((&softc->work_queue)->tqh_first)) != NULL((void *)0)) { | |||
| 1029 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Aborting descr from workq %p\n", descr ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 1030 | ("Aborting descr from workq %p\n", descr))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Aborting descr from workq %p\n", descr ); if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 1031 | TAILQ_REMOVE(&softc->work_queue, descr, tqe)do { ; ; do { if ((((descr))->tqe.tqe_next) != ((void *)0) && (((descr))->tqe.tqe_next)->tqe.tqe_prev != & ((descr)->tqe.tqe_next)) panic("Bad link elm %p next->prev != elm" , (descr)); } while (0); do { if (*(descr)->tqe.tqe_prev != (descr)) panic("Bad link elm %p prev->next != elm", (descr )); } while (0); if (((((descr))->tqe.tqe_next)) != ((void *)0)) (((descr))->tqe.tqe_next)->tqe.tqe_prev = (descr )->tqe.tqe_prev; else { (&softc->work_queue)->tqh_last = (descr)->tqe.tqe_prev; ; } *(descr)->tqe.tqe_prev = ( ((descr))->tqe.tqe_next); ; ; ; } while (0); | |||
| 1032 | TAILQ_INSERT_TAIL(&softc->abort_queue, descr, tqe)do { do { if (*(&softc->abort_queue)->tqh_last != ( (void *)0)) panic("Bad tailq NEXT(%p->tqh_last) != NULL", ( &softc->abort_queue)); } while (0); (((descr))->tqe .tqe_next) = ((void *)0); (descr)->tqe.tqe_prev = (&softc ->abort_queue)->tqh_last; *(&softc->abort_queue) ->tqh_last = (descr); (&softc->abort_queue)->tqh_last = &(((descr))->tqe.tqe_next); ; ; } while (0); | |||
| 1033 | } | |||
| 1034 | ||||
| 1035 | /* | |||
| 1036 | * Then abort all pending CCBs. | |||
| 1037 | * targdone() will return the aborted CCB via user_ccb_queue | |||
| 1038 | */ | |||
| 1039 | xpt_setup_ccb(&cab.ccb_h, softc->path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
| 1040 | cab.ccb_h.func_code = XPT_ABORT; | |||
| 1041 | cab.ccb_h.status = CAM_REQ_CMP_ERR; | |||
| 1042 | TAILQ_FOREACH(ccb_h, &softc->pending_ccb_queue, periph_links.tqe)for ((ccb_h) = (((&softc->pending_ccb_queue))->tqh_first ); (ccb_h); (ccb_h) = (((ccb_h))->periph_links.tqe.tqe_next )) { | |||
| 1043 | CAM_DEBUG(softc->path, CAM_DEBUG_PERIPH,if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Aborting pending CCB %p\n", ccb_h) ; if (cam_debug_delay != 0) DELAY(cam_debug_delay); } | |||
| 1044 | ("Aborting pending CCB %p\n", ccb_h))if (((CAM_DEBUG_PERIPH) & ((CAM_DEBUG_INFO | CAM_DEBUG_CDB | CAM_DEBUG_PERIPH | CAM_DEBUG_PROBE | CAM_DEBUG_NONE)) & cam_dflags) && (cam_dpath != ((void *)0)) && (xpt_path_comp(cam_dpath, softc->path) >= 0) && (xpt_path_comp(cam_dpath, softc->path) < 2)) { xpt_print_path (softc->path); printf ("Aborting pending CCB %p\n", ccb_h) ; if (cam_debug_delay != 0) DELAY(cam_debug_delay); }; | |||
| 1045 | cab.abort_ccb = (union ccb *)ccb_h; | |||
| 1046 | xpt_action((union ccb *)&cab); | |||
| 1047 | if (cab.ccb_h.status != CAM_REQ_CMP) { | |||
| 1048 | xpt_print(cab.ccb_h.path, | |||
| 1049 | "Unable to abort CCB, status %#x\n", | |||
| 1050 | cab.ccb_h.status); | |||
| 1051 | } | |||
| 1052 | } | |||
| 1053 | ||||
| 1054 | /* If we aborted at least one pending CCB ok, wait for it. */ | |||
| 1055 | if (cab.ccb_h.status == CAM_REQ_CMP) { | |||
| 1056 | cam_periph_sleep(softc->periph, &softc->pending_ccb_queue,_sleep((((&softc->pending_ccb_queue))), &(xpt_path_mtx ((softc->periph)->path))->lock_object, (((((80) + 12 ) | 0x100))), ((("tgabrt"))), tick_sbt * (((0))), 0, 0x0100) | |||
| 1057 | PRIBIO | PCATCH, "tgabrt", 0)_sleep((((&softc->pending_ccb_queue))), &(xpt_path_mtx ((softc->periph)->path))->lock_object, (((((80) + 12 ) | 0x100))), ((("tgabrt"))), tick_sbt * (((0))), 0, 0x0100); | |||
| 1058 | } | |||
| 1059 | ||||
| 1060 | /* If we aborted anything from the work queue, wakeup user. */ | |||
| 1061 | if (!TAILQ_EMPTY(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first == ((void *)0) ) | |||
| 1062 | || !TAILQ_EMPTY(&softc->abort_queue)((&softc->abort_queue)->tqh_first == ((void *)0))) { | |||
| 1063 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (1063)); | |||
| 1064 | notify_user(softc); | |||
| 1065 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/root/freebsd/sys/cam/scsi/scsi_target.c" ), (1065)); | |||
| 1066 | } | |||
| 1067 | } | |||
| 1068 | ||||
| 1069 | /* Notify the user that data is ready */ | |||
| 1070 | static void | |||
| 1071 | notify_user(struct targ_softc *softc) | |||
| 1072 | { | |||
| 1073 | /* | |||
| 1074 | * Notify users sleeping via poll(), kqueue(), and | |||
| 1075 | * blocking read(). | |||
| 1076 | */ | |||
| 1077 | selwakeuppri(&softc->read_select, PRIBIO((80) + 12)); | |||
| 1078 | KNOTE_UNLOCKED(&softc->read_select.si_note, 0)knote(&softc->read_select.si_note, 0, 0); | |||
| 1079 | wakeup(&softc->user_ccb_queue); | |||
| 1080 | } | |||
| 1081 | ||||
| 1082 | /* Convert CAM status to errno values */ | |||
| 1083 | static int | |||
| 1084 | targcamstatus(cam_status status) | |||
| 1085 | { | |||
| 1086 | switch (status & CAM_STATUS_MASK) { | |||
| 1087 | case CAM_REQ_CMP: /* CCB request completed without error */ | |||
| 1088 | return (0); | |||
| 1089 | case CAM_REQ_INPROG: /* CCB request is in progress */ | |||
| 1090 | return (EINPROGRESS36); | |||
| 1091 | case CAM_REQ_CMP_ERR: /* CCB request completed with an error */ | |||
| 1092 | return (EIO5); | |||
| 1093 | case CAM_PROVIDE_FAIL: /* Unable to provide requested capability */ | |||
| 1094 | return (ENOTTY25); | |||
| 1095 | case CAM_FUNC_NOTAVAIL: /* The requested function is not available */ | |||
| 1096 | return (ENOTSUP45); | |||
| 1097 | case CAM_LUN_ALRDY_ENA: /* LUN is already enabled for target mode */ | |||
| 1098 | return (EADDRINUSE48); | |||
| 1099 | case CAM_PATH_INVALID: /* Supplied Path ID is invalid */ | |||
| 1100 | case CAM_DEV_NOT_THERE: /* SCSI Device Not Installed/there */ | |||
| 1101 | return (ENOENT2); | |||
| 1102 | case CAM_REQ_ABORTED: /* CCB request aborted by the host */ | |||
| 1103 | return (ECANCELED85); | |||
| 1104 | case CAM_CMD_TIMEOUT: /* Command timeout */ | |||
| 1105 | return (ETIMEDOUT60); | |||
| 1106 | case CAM_REQUEUE_REQ: /* Requeue to preserve transaction ordering */ | |||
| 1107 | return (EAGAIN35); | |||
| 1108 | case CAM_REQ_INVALID: /* CCB request was invalid */ | |||
| 1109 | return (EINVAL22); | |||
| 1110 | case CAM_RESRC_UNAVAIL: /* Resource Unavailable */ | |||
| 1111 | return (ENOMEM12); | |||
| 1112 | case CAM_BUSY: /* CAM subsystem is busy */ | |||
| 1113 | case CAM_UA_ABORT: /* Unable to abort CCB request */ | |||
| 1114 | return (EBUSY16); | |||
| 1115 | default: | |||
| 1116 | return (ENXIO6); | |||
| 1117 | } | |||
| 1118 | } | |||
| 1119 | ||||
| 1120 | static size_t | |||
| 1121 | targccblen(xpt_opcode func_code) | |||
| 1122 | { | |||
| 1123 | int len; | |||
| 1124 | ||||
| 1125 | /* Codes we expect to see as a target */ | |||
| 1126 | switch (func_code) { | |||
| 1127 | case XPT_CONT_TARGET_IO: | |||
| 1128 | case XPT_SCSI_IO: | |||
| 1129 | len = sizeof(struct ccb_scsiio); | |||
| 1130 | break; | |||
| 1131 | case XPT_ACCEPT_TARGET_IO: | |||
| 1132 | len = sizeof(struct ccb_accept_tio); | |||
| 1133 | break; | |||
| 1134 | case XPT_IMMED_NOTIFY: | |||
| 1135 | len = sizeof(struct ccb_immed_notify); | |||
| 1136 | break; | |||
| 1137 | case XPT_IMMEDIATE_NOTIFY: | |||
| 1138 | len = sizeof(struct ccb_immediate_notify); | |||
| 1139 | break; | |||
| 1140 | case XPT_REL_SIMQ: | |||
| 1141 | len = sizeof(struct ccb_relsim); | |||
| 1142 | break; | |||
| 1143 | case XPT_PATH_INQ: | |||
| 1144 | len = sizeof(struct ccb_pathinq); | |||
| 1145 | break; | |||
| 1146 | case XPT_DEBUG: | |||
| 1147 | len = sizeof(struct ccb_debug); | |||
| 1148 | break; | |||
| 1149 | case XPT_ABORT: | |||
| 1150 | len = sizeof(struct ccb_abort); | |||
| 1151 | break; | |||
| 1152 | case XPT_EN_LUN: | |||
| 1153 | len = sizeof(struct ccb_en_lun); | |||
| 1154 | break; | |||
| 1155 | default: | |||
| 1156 | len = sizeof(union ccb); | |||
| 1157 | break; | |||
| 1158 | } | |||
| 1159 | ||||
| 1160 | return (len); | |||
| 1161 | } |