File: | modules/cam/../../cam/scsi/scsi_target.c |
Warning: | line 924, column 10 Copies out a struct with a union element with different sizes |
1 | /*- | |||
2 | * Generic SCSI Target Kernel Mode Driver | |||
3 | * | |||
4 | * Copyright (c) 2002 Nate Lawson. | |||
5 | * Copyright (c) 1998, 1999, 2001, 2002 Justin T. Gibbs. | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions, and the following disclaimer, | |||
13 | * without modification, immediately at the beginning of the file. | |||
14 | * 2. The name of the author may not be used to endorse or promote products | |||
15 | * derived from this software without specific prior written permission. | |||
16 | * | |||
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | |||
21 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
27 | * SUCH DAMAGE. | |||
28 | */ | |||
29 | ||||
30 | #include <sys/cdefs.h> | |||
31 | __FBSDID("$FreeBSD: releng/11.0/sys/cam/scsi/scsi_target.c 288420 2015-09-30 13:31:37Z mav $")__asm__(".ident\t\"" "$FreeBSD: releng/11.0/sys/cam/scsi/scsi_target.c 288420 2015-09-30 13:31:37Z mav $" "\""); | |||
32 | ||||
33 | ||||
34 | #include <sys/param.h> | |||
35 | #include <sys/systm.h> | |||
36 | #include <sys/kernel.h> | |||
37 | #include <sys/conf.h> | |||
38 | #include <sys/malloc.h> | |||
39 | #include <sys/poll.h> | |||
40 | #include <sys/vnode.h> | |||
41 | #include <sys/lock.h> | |||
42 | #include <sys/mutex.h> | |||
43 | #include <sys/devicestat.h> | |||
44 | #include <sys/proc.h> | |||
45 | /* Includes to support callout */ | |||
46 | #include <sys/types.h> | |||
47 | #include <sys/systm.h> | |||
48 | ||||
49 | #include <cam/cam.h> | |||
50 | #include <cam/cam_ccb.h> | |||
51 | #include <cam/cam_periph.h> | |||
52 | #include <cam/cam_xpt_periph.h> | |||
53 | #include <cam/cam_sim.h> | |||
54 | #include <cam/scsi/scsi_targetio.h> | |||
55 | ||||
56 | ||||
57 | /* Transaction information attached to each CCB sent by the user */ | |||
58 | struct targ_cmd_descr { | |||
59 | struct cam_periph_map_info mapinfo; | |||
60 | TAILQ_ENTRY(targ_cmd_descr)struct { struct targ_cmd_descr *tqe_next; struct targ_cmd_descr **tqe_prev; } tqe; | |||
61 | union ccb *user_ccb; | |||
62 | int priority; | |||
63 | int func_code; | |||
64 | }; | |||
65 | ||||
66 | /* Offset into the private CCB area for storing our descriptor */ | |||
67 | #define targ_descrperiph_priv.entries[1].ptr periph_priv.entries[1].ptr | |||
68 | ||||
69 | TAILQ_HEAD(descr_queue, targ_cmd_descr)struct descr_queue { struct targ_cmd_descr *tqh_first; struct targ_cmd_descr **tqh_last; }; | |||
70 | ||||
71 | typedef enum { | |||
72 | TARG_STATE_RESV = 0x00, /* Invalid state */ | |||
73 | TARG_STATE_OPENED = 0x01, /* Device opened, softc initialized */ | |||
74 | TARG_STATE_LUN_ENABLED = 0x02 /* Device enabled for a path */ | |||
75 | } targ_state; | |||
76 | ||||
77 | /* Per-instance device software context */ | |||
78 | struct targ_softc { | |||
79 | /* CCBs (CTIOs, ATIOs, INOTs) pending on the controller */ | |||
80 | struct ccb_queue pending_ccb_queue; | |||
81 | ||||
82 | /* Command descriptors awaiting CTIO resources from the XPT */ | |||
83 | struct descr_queue work_queue; | |||
84 | ||||
85 | /* Command descriptors that have been aborted back to the user. */ | |||
86 | struct descr_queue abort_queue; | |||
87 | ||||
88 | /* | |||
89 | * Queue of CCBs that have been copied out to userland, but our | |||
90 | * userland daemon has not yet seen. | |||
91 | */ | |||
92 | struct ccb_queue user_ccb_queue; | |||
93 | ||||
94 | struct cam_periph *periph; | |||
95 | struct cam_path *path; | |||
96 | targ_state state; | |||
97 | u_int maxio; | |||
98 | struct selinfo read_select; | |||
99 | struct devstat device_stats; | |||
100 | }; | |||
101 | ||||
102 | static d_open_t targopen; | |||
103 | static d_read_t targread; | |||
104 | static d_write_t targwrite; | |||
105 | static d_ioctl_t targioctl; | |||
106 | static d_poll_t targpoll; | |||
107 | static d_kqfilter_t targkqfilter; | |||
108 | static void targreadfiltdetach(struct knote *kn); | |||
109 | static int targreadfilt(struct knote *kn, long hint); | |||
110 | static struct filterops targread_filtops = { | |||
111 | .f_isfd = 1, | |||
112 | .f_detach = targreadfiltdetach, | |||
113 | .f_event = targreadfilt, | |||
114 | }; | |||
115 | ||||
116 | static struct cdevsw targ_cdevsw = { | |||
117 | .d_version = D_VERSION0x17122009, | |||
118 | .d_flags = D_NEEDGIANT0x00400000, | |||
119 | .d_open = targopen, | |||
120 | .d_read = targread, | |||
121 | .d_write = targwrite, | |||
122 | .d_ioctl = targioctl, | |||
123 | .d_poll = targpoll, | |||
124 | .d_name = "targ", | |||
125 | .d_kqfilter = targkqfilter | |||
126 | }; | |||
127 | ||||
128 | static cam_status targendislun(struct cam_path *path, int enable, | |||
129 | int grp6_len, int grp7_len); | |||
130 | static cam_status targenable(struct targ_softc *softc, | |||
131 | struct cam_path *path, | |||
132 | int grp6_len, int grp7_len); | |||
133 | static cam_status targdisable(struct targ_softc *softc); | |||
134 | static periph_ctor_t targctor; | |||
135 | static periph_dtor_t targdtor; | |||
136 | static periph_start_t targstart; | |||
137 | static int targusermerge(struct targ_softc *softc, | |||
138 | struct targ_cmd_descr *descr, | |||
139 | union ccb *ccb); | |||
140 | static int targsendccb(struct targ_softc *softc, union ccb *ccb, | |||
141 | struct targ_cmd_descr *descr); | |||
142 | static void targdone(struct cam_periph *periph, | |||
143 | union ccb *done_ccb); | |||
144 | static int targreturnccb(struct targ_softc *softc, | |||
145 | union ccb *ccb); | |||
146 | static union ccb * targgetccb(struct targ_softc *softc, xpt_opcode type, | |||
147 | int priority); | |||
148 | static void targfreeccb(struct targ_softc *softc, union ccb *ccb); | |||
149 | static struct targ_cmd_descr * | |||
150 | targgetdescr(struct targ_softc *softc); | |||
151 | static periph_init_t targinit; | |||
152 | static void targasync(void *callback_arg, u_int32_t code, | |||
153 | struct cam_path *path, void *arg); | |||
154 | static void abort_all_pending(struct targ_softc *softc); | |||
155 | static void notify_user(struct targ_softc *softc); | |||
156 | static int targcamstatus(cam_status status); | |||
157 | static size_t targccblen(xpt_opcode func_code); | |||
158 | ||||
159 | static struct periph_driver targdriver = | |||
160 | { | |||
161 | targinit, "targ", | |||
162 | TAILQ_HEAD_INITIALIZER(targdriver.units){ ((void *)0), &(targdriver.units).tqh_first, }, /* generation */ 0 | |||
163 | }; | |||
164 | 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: printf("targ" " module unload - not possible for this module type\n" ); return 22; 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"))) = { 1100122, 1100122, (((((1100122)+ ((100000)-1))/(100000))*(100000)) - 1) }; 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 * 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); | |||
165 | ||||
166 | 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 * 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 * const __set_sysuninit_set_sym_M_TARG_uninit_sys_uninit __attribute__((__section__("set_" "sysuninit_set"))) __attribute__ ((__used__)) = &(M_TARG_uninit_sys_uninit); | |||
167 | ||||
168 | /* Disable LUN if enabled and teardown softc */ | |||
169 | static void | |||
170 | targcdevdtor(void *data) | |||
171 | { | |||
172 | struct targ_softc *softc; | |||
173 | struct cam_periph *periph; | |||
174 | ||||
175 | softc = data; | |||
176 | if (softc->periph == NULL((void *)0)) { | |||
177 | printf("%s: destroying non-enabled target\n", __func__); | |||
178 | free(softc, M_TARG); | |||
179 | return; | |||
180 | } | |||
181 | ||||
182 | /* | |||
183 | * Acquire a hold on the periph so that it doesn't go away before | |||
184 | * we are ready at the end of the function. | |||
185 | */ | |||
186 | periph = softc->periph; | |||
187 | cam_periph_acquire(periph); | |||
188 | cam_periph_lock(periph)__mtx_lock_flags(&((((xpt_path_mtx((periph)->path))))) ->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (188)); | |||
189 | (void)targdisable(softc); | |||
190 | if (softc->periph != NULL((void *)0)) { | |||
191 | cam_periph_invalidate(softc->periph); | |||
192 | softc->periph = NULL((void *)0); | |||
193 | } | |||
194 | cam_periph_unlock(periph)__mtx_unlock_flags(&((((xpt_path_mtx((periph)->path))) ))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (194)); | |||
195 | cam_periph_release(periph); | |||
196 | free(softc, M_TARG); | |||
197 | } | |||
198 | ||||
199 | /* | |||
200 | * Create softc and initialize it. There is no locking here because a | |||
201 | * periph doesn't get created until an ioctl is issued to do so, and | |||
202 | * that can't happen until this method returns. | |||
203 | */ | |||
204 | static int | |||
205 | targopen(struct cdev *dev, int flags, int fmt, struct thread *td) | |||
206 | { | |||
207 | struct targ_softc *softc; | |||
208 | ||||
209 | /* Allocate its softc, initialize it */ | |||
210 | softc = malloc(sizeof(*softc), M_TARG, | |||
211 | M_WAITOK0x0002 | M_ZERO0x0100); | |||
212 | softc->state = TARG_STATE_OPENED; | |||
213 | softc->periph = NULL((void *)0); | |||
214 | softc->path = NULL((void *)0); | |||
215 | ||||
216 | 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); | |||
217 | 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); | |||
218 | 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); | |||
219 | 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 ); | |||
220 | knlist_init_mtx(&softc->read_select.si_note, NULL((void *)0)); | |||
221 | ||||
222 | devfs_set_cdevpriv(softc, targcdevdtor); | |||
223 | return (0); | |||
224 | } | |||
225 | ||||
226 | /* Enable/disable LUNs, set debugging level */ | |||
227 | static int | |||
228 | targioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) | |||
229 | { | |||
230 | struct targ_softc *softc; | |||
231 | cam_status status; | |||
232 | ||||
233 | devfs_get_cdevpriv((void **)&softc); | |||
234 | ||||
235 | switch (cmd) { | |||
236 | case TARGIOCENABLE((unsigned long) ((0x80000000) | (((sizeof(struct ioc_enable_lun )) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((5)))): | |||
237 | { | |||
238 | struct ioc_enable_lun *new_lun; | |||
239 | struct cam_path *path; | |||
240 | ||||
241 | new_lun = (struct ioc_enable_lun *)addr; | |||
242 | status = xpt_create_path(&path, /*periph*/NULL((void *)0), | |||
243 | new_lun->path_id, | |||
244 | new_lun->target_id, | |||
245 | new_lun->lun_id); | |||
246 | if (status != CAM_REQ_CMP) { | |||
247 | printf("Couldn't create path, status %#x\n", status); | |||
248 | break; | |||
249 | } | |||
250 | xpt_path_lock(path)__mtx_lock_flags(&((((xpt_path_mtx(path)))))->mtx_lock , ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (250)); | |||
251 | status = targenable(softc, path, new_lun->grp6_len, | |||
252 | new_lun->grp7_len); | |||
253 | xpt_path_unlock(path)__mtx_unlock_flags(&((((xpt_path_mtx(path)))))->mtx_lock , ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (253)); | |||
254 | xpt_free_path(path); | |||
255 | break; | |||
256 | } | |||
257 | case TARGIOCDISABLE((unsigned long) ((0x20000000) | (((0) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((6)))): | |||
258 | if (softc->periph == NULL((void *)0)) { | |||
259 | status = CAM_DEV_NOT_THERE; | |||
260 | break; | |||
261 | } | |||
262 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (262)); | |||
263 | status = targdisable(softc); | |||
264 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (264)); | |||
265 | break; | |||
266 | case TARGIOCDEBUG((unsigned long) ((0x80000000) | (((sizeof(int)) & ((1 << 13) - 1)) << 16) | ((('C')) << 8) | ((7)))): | |||
267 | { | |||
268 | struct ccb_debug cdbg; | |||
269 | ||||
270 | /* If no periph available, disallow debugging changes */ | |||
271 | if ((softc->state & TARG_STATE_LUN_ENABLED) == 0) { | |||
272 | status = CAM_DEV_NOT_THERE; | |||
273 | break; | |||
274 | } | |||
275 | bzero(&cdbg, sizeof cdbg); | |||
276 | if (*((int *)addr) != 0) | |||
277 | cdbg.flags = CAM_DEBUG_PERIPH; | |||
278 | else | |||
279 | cdbg.flags = CAM_DEBUG_NONE; | |||
280 | xpt_setup_ccb(&cdbg.ccb_h, softc->path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
281 | cdbg.ccb_h.func_code = XPT_DEBUG; | |||
282 | cdbg.ccb_h.cbfcnp = targdone; | |||
283 | xpt_action((union ccb *)&cdbg); | |||
284 | status = cdbg.ccb_h.status & CAM_STATUS_MASK; | |||
285 | break; | |||
286 | } | |||
287 | default: | |||
288 | status = CAM_PROVIDE_FAIL; | |||
289 | break; | |||
290 | } | |||
291 | ||||
292 | return (targcamstatus(status)); | |||
293 | } | |||
294 | ||||
295 | /* Writes are always ready, reads wait for user_ccb_queue or abort_queue */ | |||
296 | static int | |||
297 | targpoll(struct cdev *dev, int poll_events, struct thread *td) | |||
298 | { | |||
299 | struct targ_softc *softc; | |||
300 | int revents; | |||
301 | ||||
302 | devfs_get_cdevpriv((void **)&softc); | |||
303 | ||||
304 | /* Poll for write() is always ok. */ | |||
305 | revents = poll_events & (POLLOUT0x0004 | POLLWRNORM0x0004); | |||
306 | if ((poll_events & (POLLIN0x0001 | POLLRDNORM0x0040)) != 0) { | |||
307 | /* Poll for read() depends on user and abort queues. */ | |||
308 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (308)); | |||
309 | if (!TAILQ_EMPTY(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first == ((void *)0) ) || | |||
310 | !TAILQ_EMPTY(&softc->abort_queue)((&softc->abort_queue)->tqh_first == ((void *)0))) { | |||
311 | revents |= poll_events & (POLLIN0x0001 | POLLRDNORM0x0040); | |||
312 | } | |||
313 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (313)); | |||
314 | /* Only sleep if the user didn't poll for write. */ | |||
315 | if (revents == 0) | |||
316 | selrecord(td, &softc->read_select); | |||
317 | } | |||
318 | ||||
319 | return (revents); | |||
320 | } | |||
321 | ||||
322 | static int | |||
323 | targkqfilter(struct cdev *dev, struct knote *kn) | |||
324 | { | |||
325 | struct targ_softc *softc; | |||
326 | ||||
327 | devfs_get_cdevpriv((void **)&softc); | |||
328 | kn->kn_hook = (caddr_t)softc; | |||
329 | kn->kn_fop = &targread_filtops; | |||
330 | knlist_add(&softc->read_select.si_note, kn, 0); | |||
331 | return (0); | |||
332 | } | |||
333 | ||||
334 | static void | |||
335 | targreadfiltdetach(struct knote *kn) | |||
336 | { | |||
337 | struct targ_softc *softc; | |||
338 | ||||
339 | softc = (struct targ_softc *)kn->kn_hook; | |||
340 | knlist_remove(&softc->read_select.si_note, kn, 0); | |||
341 | } | |||
342 | ||||
343 | /* Notify the user's kqueue when the user queue or abort queue gets a CCB */ | |||
344 | static int | |||
345 | targreadfilt(struct knote *kn, long hint) | |||
346 | { | |||
347 | struct targ_softc *softc; | |||
348 | int retval; | |||
349 | ||||
350 | softc = (struct targ_softc *)kn->kn_hook; | |||
351 | cam_periph_lock(softc->periph)__mtx_lock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (351)); | |||
352 | retval = !TAILQ_EMPTY(&softc->user_ccb_queue)((&softc->user_ccb_queue)->tqh_first == ((void *)0) ) || | |||
353 | !TAILQ_EMPTY(&softc->abort_queue)((&softc->abort_queue)->tqh_first == ((void *)0)); | |||
354 | cam_periph_unlock(softc->periph)__mtx_unlock_flags(&((((xpt_path_mtx((softc->periph)-> path)))))->mtx_lock, ((0)), ("/usr/src/sys/modules/cam/../../cam/scsi/scsi_target.c" ), (354)); | |||
355 | return (retval); | |||
356 | } | |||
357 | ||||
358 | /* Send the HBA the enable/disable message */ | |||
359 | static cam_status | |||
360 | targendislun(struct cam_path *path, int enable, int grp6_len, int grp7_len) | |||
361 | { | |||
362 | struct ccb_en_lun en_ccb; | |||
363 | cam_status status; | |||
364 | ||||
365 | /* Tell the lun to begin answering selects */ | |||
366 | xpt_setup_ccb(&en_ccb.ccb_h, path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
367 | en_ccb.ccb_h.func_code = XPT_EN_LUN; | |||
368 | /* Don't need support for any vendor specific commands */ | |||
369 | en_ccb.grp6_len = grp6_len; | |||
370 | en_ccb.grp7_len = grp7_len; | |||
371 | en_ccb.enable = enable ? 1 : 0; | |||
372 | xpt_action((union ccb *)&en_ccb); | |||
373 | status = en_ccb.ccb_h.status & CAM_STATUS_MASK; | |||
374 | if (status != CAM_REQ_CMP) { | |||
375 | xpt_print(path, "%sable lun CCB rejected, status %#x\n", | |||
376 | enable ? "en" : "dis", status); | |||
377 | } | |||
378 | return (status); | |||
379 | } | |||
380 | ||||
381 | /* Enable target mode on a LUN, given its path */ | |||
382 | static cam_status | |||
383 | targenable(struct targ_softc *softc, struct cam_path *path, int grp6_len, | |||
384 | int grp7_len) | |||
385 | { | |||
386 | struct cam_periph *periph; | |||
387 | struct ccb_pathinq cpi; | |||
388 | cam_status status; | |||
389 | ||||
390 | if ((softc->state & TARG_STATE_LUN_ENABLED) != 0) | |||
391 | return (CAM_LUN_ALRDY_ENA); | |||
392 | ||||
393 | /* Make sure SIM supports target mode */ | |||
394 | xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL((CAM_RL_NORMAL << 8) + 0x80)); | |||
395 | cpi.ccb_h.func_code = XPT_PATH_INQ; | |||
396 | xpt_action((union ccb *)&cpi); | |||
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 { ; ; ; ; 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 { ; ; ; ; 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)), ("/usr/src/sys/modules/cam/../../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 { ; (((&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 { ; (((&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 { ; (((&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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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 { ; (((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 { ; (((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)), ("/usr/src/sys/modules/cam/../../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 { ; ; ; ; 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 { ; (((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 { ; (((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 { ; (((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 { ; ; ; ; 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 { ; ; ; ; 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 { ; (((&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 { ; (((&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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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 { ; ; ; ; 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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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 { ; ; ; ; 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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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 { ; ; ; ; 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 { ; (((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)), ("/usr/src/sys/modules/cam/../../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)), ("/usr/src/sys/modules/cam/../../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 | } |