Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/scsi/scsi_targ_bh.c
39482 views
1
/*-
2
* Implementation of the Target Mode 'Black Hole device' for CAM.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 1999 Justin T. Gibbs.
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions, and the following disclaimer,
14
* without modification, immediately at the beginning of the file.
15
* 2. The name of the author may not be used to endorse or promote products
16
* derived from this software without specific prior written permission.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
* SUCH DAMAGE.
29
*/
30
31
#include <sys/param.h>
32
#include <sys/queue.h>
33
#include <sys/systm.h>
34
#include <sys/kernel.h>
35
#include <sys/types.h>
36
#include <sys/bio.h>
37
#include <sys/conf.h>
38
#include <sys/devicestat.h>
39
#include <sys/malloc.h>
40
#include <sys/uio.h>
41
42
#include <cam/cam.h>
43
#include <cam/cam_ccb.h>
44
#include <cam/cam_periph.h>
45
#include <cam/cam_queue.h>
46
#include <cam/cam_xpt_periph.h>
47
#include <cam/cam_debug.h>
48
#include <cam/cam_sim.h>
49
50
#include <cam/scsi/scsi_all.h>
51
#include <cam/scsi/scsi_message.h>
52
53
static MALLOC_DEFINE(M_SCSIBH, "SCSI bh", "SCSI blackhole buffers");
54
55
typedef enum {
56
TARGBH_STATE_NORMAL,
57
TARGBH_STATE_EXCEPTION,
58
TARGBH_STATE_TEARDOWN
59
} targbh_state;
60
61
typedef enum {
62
TARGBH_FLAG_NONE = 0x00,
63
TARGBH_FLAG_LUN_ENABLED = 0x01
64
} targbh_flags;
65
66
typedef enum {
67
TARGBH_CCB_WORKQ
68
} targbh_ccb_types;
69
70
#define MAX_ACCEPT 8
71
#define MAX_IMMEDIATE 16
72
#define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */
73
74
/* Offsets into our private CCB area for storing accept information */
75
#define ccb_type ppriv_field0
76
#define ccb_descr ppriv_ptr1
77
78
/* We stick a pointer to the originating accept TIO in each continue I/O CCB */
79
#define ccb_atio ppriv_ptr1
80
81
TAILQ_HEAD(ccb_queue, ccb_hdr);
82
83
struct targbh_softc {
84
struct ccb_queue pending_queue;
85
struct ccb_queue work_queue;
86
struct ccb_queue unknown_atio_queue;
87
struct devstat device_stats;
88
targbh_state state;
89
targbh_flags flags;
90
u_int init_level;
91
u_int inq_data_len;
92
struct ccb_accept_tio *accept_tio_list;
93
struct ccb_hdr_slist immed_notify_slist;
94
};
95
96
struct targbh_cmd_desc {
97
struct ccb_accept_tio* atio_link;
98
u_int data_resid; /* How much left to transfer */
99
u_int data_increment;/* Amount to send before next disconnect */
100
void* data; /* The data. Can be from backing_store or not */
101
void* backing_store;/* Backing store allocated for this descriptor*/
102
u_int max_size; /* Size of backing_store */
103
uint32_t timeout;
104
uint8_t status; /* Status to return to initiator */
105
};
106
107
static struct scsi_inquiry_data no_lun_inq_data =
108
{
109
T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
110
/* version */2, /* format version */2
111
};
112
113
static struct scsi_sense_data_fixed no_lun_sense_data =
114
{
115
SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
116
0,
117
SSD_KEY_NOT_READY,
118
{ 0, 0, 0, 0 },
119
/*extra_len*/offsetof(struct scsi_sense_data_fixed, fru)
120
- offsetof(struct scsi_sense_data_fixed, extra_len),
121
{ 0, 0, 0, 0 },
122
/* Logical Unit Not Supported */
123
/*ASC*/0x25, /*ASCQ*/0
124
};
125
126
static const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru);
127
128
static periph_init_t targbhinit;
129
static void targbhasync(void *callback_arg, uint32_t code,
130
struct cam_path *path, void *arg);
131
static cam_status targbhenlun(struct cam_periph *periph);
132
static cam_status targbhdislun(struct cam_periph *periph);
133
static periph_ctor_t targbhctor;
134
static periph_dtor_t targbhdtor;
135
static periph_start_t targbhstart;
136
static void targbhdone(struct cam_periph *periph,
137
union ccb *done_ccb);
138
#ifdef NOTYET
139
static int targbherror(union ccb *ccb, uint32_t cam_flags,
140
uint32_t sense_flags);
141
#endif
142
static struct targbh_cmd_desc* targbhallocdescr(void);
143
static void targbhfreedescr(struct targbh_cmd_desc *buf);
144
145
static struct periph_driver targbhdriver =
146
{
147
targbhinit, "targbh",
148
TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
149
};
150
151
PERIPHDRIVER_DECLARE(targbh, targbhdriver);
152
153
static void
154
targbhinit(void)
155
{
156
cam_status status;
157
158
/*
159
* Install a global async callback. This callback will
160
* receive async callbacks like "new path registered".
161
*/
162
status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED,
163
targbhasync, NULL, NULL);
164
165
if (status != CAM_REQ_CMP) {
166
printf("targbh: Failed to attach master async callback "
167
"due to status 0x%x!\n", status);
168
}
169
}
170
171
static void
172
targbhasync(void *callback_arg, uint32_t code,
173
struct cam_path *path, void *arg)
174
{
175
struct cam_path *new_path;
176
struct ccb_pathinq *cpi;
177
path_id_t bus_path_id;
178
cam_status status;
179
180
cpi = (struct ccb_pathinq *)arg;
181
if (code == AC_PATH_REGISTERED)
182
bus_path_id = cpi->ccb_h.path_id;
183
else
184
bus_path_id = xpt_path_path_id(path);
185
/*
186
* Allocate a peripheral instance for
187
* this target instance.
188
*/
189
status = xpt_create_path(&new_path, NULL,
190
bus_path_id,
191
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
192
if (status != CAM_REQ_CMP) {
193
printf("targbhasync: Unable to create path "
194
"due to status 0x%x\n", status);
195
return;
196
}
197
198
switch (code) {
199
case AC_PATH_REGISTERED:
200
{
201
/* Only attach to controllers that support target mode */
202
if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
203
break;
204
205
status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
206
targbhstart,
207
"targbh", CAM_PERIPH_BIO,
208
new_path, targbhasync,
209
AC_PATH_REGISTERED,
210
cpi);
211
break;
212
}
213
case AC_PATH_DEREGISTERED:
214
{
215
struct cam_periph *periph;
216
217
if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
218
cam_periph_invalidate(periph);
219
break;
220
}
221
default:
222
break;
223
}
224
xpt_free_path(new_path);
225
}
226
227
/* Attempt to enable our lun */
228
static cam_status
229
targbhenlun(struct cam_periph *periph)
230
{
231
union ccb immed_ccb;
232
struct targbh_softc *softc;
233
cam_status status;
234
int i;
235
236
softc = (struct targbh_softc *)periph->softc;
237
238
if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
239
return (CAM_REQ_CMP);
240
241
memset(&immed_ccb, 0, sizeof(immed_ccb));
242
xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
243
immed_ccb.ccb_h.func_code = XPT_EN_LUN;
244
245
/* Don't need support for any vendor specific commands */
246
immed_ccb.cel.grp6_len = 0;
247
immed_ccb.cel.grp7_len = 0;
248
immed_ccb.cel.enable = 1;
249
xpt_action(&immed_ccb);
250
status = immed_ccb.ccb_h.status;
251
if (status != CAM_REQ_CMP) {
252
xpt_print(periph->path,
253
"targbhenlun - Enable Lun Rejected with status 0x%x\n",
254
status);
255
return (status);
256
}
257
258
softc->flags |= TARGBH_FLAG_LUN_ENABLED;
259
260
/*
261
* Build up a buffer of accept target I/O
262
* operations for incoming selections.
263
*/
264
for (i = 0; i < MAX_ACCEPT; i++) {
265
struct ccb_accept_tio *atio;
266
267
atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH,
268
M_ZERO | M_NOWAIT);
269
if (atio == NULL) {
270
status = CAM_RESRC_UNAVAIL;
271
break;
272
}
273
274
atio->ccb_h.ccb_descr = targbhallocdescr();
275
276
if (atio->ccb_h.ccb_descr == NULL) {
277
free(atio, M_SCSIBH);
278
status = CAM_RESRC_UNAVAIL;
279
break;
280
}
281
282
xpt_setup_ccb(&atio->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
283
atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
284
atio->ccb_h.cbfcnp = targbhdone;
285
((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
286
softc->accept_tio_list;
287
softc->accept_tio_list = atio;
288
xpt_action((union ccb *)atio);
289
status = atio->ccb_h.status;
290
if (status != CAM_REQ_INPROG)
291
break;
292
}
293
294
if (i == 0) {
295
xpt_print(periph->path,
296
"targbhenlun - Could not allocate accept tio CCBs: status "
297
"= 0x%x\n", status);
298
targbhdislun(periph);
299
return (CAM_REQ_CMP_ERR);
300
}
301
302
/*
303
* Build up a buffer of immediate notify CCBs
304
* so the SIM can tell us of asynchronous target mode events.
305
*/
306
for (i = 0; i < MAX_ACCEPT; i++) {
307
struct ccb_immediate_notify *inot;
308
309
inot = (struct ccb_immediate_notify*)malloc(sizeof(*inot),
310
M_SCSIBH, M_ZERO | M_NOWAIT);
311
312
if (inot == NULL) {
313
status = CAM_RESRC_UNAVAIL;
314
break;
315
}
316
317
xpt_setup_ccb(&inot->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
318
inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
319
inot->ccb_h.cbfcnp = targbhdone;
320
SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
321
periph_links.sle);
322
xpt_action((union ccb *)inot);
323
status = inot->ccb_h.status;
324
if (status != CAM_REQ_INPROG)
325
break;
326
}
327
328
if (i == 0) {
329
xpt_print(periph->path,
330
"targbhenlun - Could not allocate immediate notify "
331
"CCBs: status = 0x%x\n", status);
332
targbhdislun(periph);
333
return (CAM_REQ_CMP_ERR);
334
}
335
336
return (CAM_REQ_CMP);
337
}
338
339
static cam_status
340
targbhdislun(struct cam_periph *periph)
341
{
342
union ccb ccb;
343
struct targbh_softc *softc;
344
struct ccb_accept_tio* atio;
345
struct ccb_hdr *ccb_h;
346
347
softc = (struct targbh_softc *)periph->softc;
348
if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
349
return CAM_REQ_CMP;
350
351
memset(&ccb, 0, sizeof(ccb));
352
353
/* XXX Block for Continue I/O completion */
354
355
/* Kill off all ACCECPT and IMMEDIATE CCBs */
356
while ((atio = softc->accept_tio_list) != NULL) {
357
358
softc->accept_tio_list =
359
((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
360
xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
361
ccb.cab.ccb_h.func_code = XPT_ABORT;
362
ccb.cab.abort_ccb = (union ccb *)atio;
363
xpt_action(&ccb);
364
}
365
366
while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
367
SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
368
xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
369
ccb.cab.ccb_h.func_code = XPT_ABORT;
370
ccb.cab.abort_ccb = (union ccb *)ccb_h;
371
xpt_action(&ccb);
372
}
373
374
/*
375
* Dissable this lun.
376
*/
377
xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
378
ccb.cel.ccb_h.func_code = XPT_EN_LUN;
379
ccb.cel.enable = 0;
380
xpt_action(&ccb);
381
382
if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
383
printf("targbhdislun - Disabling lun on controller failed "
384
"with status 0x%x\n", ccb.cel.ccb_h.status);
385
else
386
softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
387
return (ccb.cel.ccb_h.status);
388
}
389
390
static cam_status
391
targbhctor(struct cam_periph *periph, void *arg)
392
{
393
struct targbh_softc *softc;
394
395
/* Allocate our per-instance private storage */
396
softc = (struct targbh_softc *)malloc(sizeof(*softc),
397
M_SCSIBH, M_NOWAIT);
398
if (softc == NULL) {
399
printf("targctor: unable to malloc softc\n");
400
return (CAM_REQ_CMP_ERR);
401
}
402
403
bzero(softc, sizeof(*softc));
404
TAILQ_INIT(&softc->pending_queue);
405
TAILQ_INIT(&softc->work_queue);
406
softc->accept_tio_list = NULL;
407
SLIST_INIT(&softc->immed_notify_slist);
408
softc->state = TARGBH_STATE_NORMAL;
409
periph->softc = softc;
410
softc->init_level++;
411
412
if (targbhenlun(periph) != CAM_REQ_CMP)
413
cam_periph_invalidate(periph);
414
return (CAM_REQ_CMP);
415
}
416
417
static void
418
targbhdtor(struct cam_periph *periph)
419
{
420
struct targbh_softc *softc;
421
422
softc = (struct targbh_softc *)periph->softc;
423
424
softc->state = TARGBH_STATE_TEARDOWN;
425
426
targbhdislun(periph);
427
428
switch (softc->init_level) {
429
case 0:
430
panic("targdtor - impossible init level");
431
case 1:
432
/* FALLTHROUGH */
433
default:
434
/* XXX Wait for callback of targbhdislun() */
435
cam_periph_sleep(periph, softc, PRIBIO, "targbh", hz/2);
436
free(softc, M_SCSIBH);
437
break;
438
}
439
}
440
441
static void
442
targbhstart(struct cam_periph *periph, union ccb *start_ccb)
443
{
444
struct targbh_softc *softc;
445
struct ccb_hdr *ccbh;
446
struct ccb_accept_tio *atio;
447
struct targbh_cmd_desc *desc;
448
struct ccb_scsiio *csio;
449
ccb_flags flags;
450
451
softc = (struct targbh_softc *)periph->softc;
452
453
ccbh = TAILQ_FIRST(&softc->work_queue);
454
if (ccbh == NULL) {
455
xpt_release_ccb(start_ccb);
456
} else {
457
TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
458
TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
459
periph_links.tqe);
460
atio = (struct ccb_accept_tio*)ccbh;
461
desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
462
463
/* Is this a tagged request? */
464
flags = atio->ccb_h.flags &
465
(CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
466
467
csio = &start_ccb->csio;
468
/*
469
* If we are done with the transaction, tell the
470
* controller to send status and perform a CMD_CMPLT.
471
* If we have associated sense data, see if we can
472
* send that too.
473
*/
474
if (desc->data_resid == desc->data_increment) {
475
flags |= CAM_SEND_STATUS;
476
if (atio->sense_len) {
477
csio->sense_len = atio->sense_len;
478
csio->sense_data = atio->sense_data;
479
flags |= CAM_SEND_SENSE;
480
}
481
}
482
483
cam_fill_ctio(csio,
484
/*retries*/2,
485
targbhdone,
486
flags,
487
(flags & CAM_TAG_ACTION_VALID)?
488
MSG_SIMPLE_Q_TAG : 0,
489
atio->tag_id,
490
atio->init_id,
491
desc->status,
492
/*data_ptr*/desc->data_increment == 0
493
? NULL : desc->data,
494
/*dxfer_len*/desc->data_increment,
495
/*timeout*/desc->timeout);
496
497
/* Override our wildcard attachment */
498
start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
499
start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
500
501
start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
502
start_ccb->ccb_h.ccb_atio = atio;
503
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
504
("Sending a CTIO\n"));
505
xpt_action(start_ccb);
506
/*
507
* If the queue was frozen waiting for the response
508
* to this ATIO (for instance disconnection was disallowed),
509
* then release it now that our response has been queued.
510
*/
511
if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
512
cam_release_devq(periph->path,
513
/*relsim_flags*/0,
514
/*reduction*/0,
515
/*timeout*/0,
516
/*getcount_only*/0);
517
atio->ccb_h.status &= ~CAM_DEV_QFRZN;
518
}
519
ccbh = TAILQ_FIRST(&softc->work_queue);
520
}
521
if (ccbh != NULL)
522
xpt_schedule(periph, CAM_PRIORITY_NORMAL);
523
}
524
525
static void
526
targbhdone(struct cam_periph *periph, union ccb *done_ccb)
527
{
528
struct targbh_softc *softc;
529
530
softc = (struct targbh_softc *)periph->softc;
531
532
switch (done_ccb->ccb_h.func_code) {
533
case XPT_ACCEPT_TARGET_IO:
534
{
535
struct ccb_accept_tio *atio;
536
struct targbh_cmd_desc *descr;
537
uint8_t *cdb;
538
int priority;
539
540
atio = &done_ccb->atio;
541
descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
542
cdb = atio->cdb_io.cdb_bytes;
543
if (softc->state == TARGBH_STATE_TEARDOWN
544
|| atio->ccb_h.status == CAM_REQ_ABORTED) {
545
targbhfreedescr(descr);
546
xpt_free_ccb(done_ccb);
547
return;
548
}
549
550
/*
551
* Determine the type of incoming command and
552
* setup our buffer for a response.
553
*/
554
switch (cdb[0]) {
555
case INQUIRY:
556
{
557
struct scsi_inquiry *inq;
558
559
inq = (struct scsi_inquiry *)cdb;
560
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
561
("Saw an inquiry!\n"));
562
/*
563
* Validate the command. We don't
564
* support any VPD pages, so complain
565
* if EVPD is set.
566
*/
567
if ((inq->byte2 & SI_EVPD) != 0
568
|| inq->page_code != 0) {
569
atio->ccb_h.flags &= ~CAM_DIR_MASK;
570
atio->ccb_h.flags |= CAM_DIR_NONE;
571
/*
572
* This needs to have other than a
573
* no_lun_sense_data response.
574
*/
575
bcopy(&no_lun_sense_data, &atio->sense_data,
576
min(sizeof(no_lun_sense_data),
577
sizeof(atio->sense_data)));
578
atio->sense_len = sizeof(no_lun_sense_data);
579
descr->data_resid = 0;
580
descr->data_increment = 0;
581
descr->status = SCSI_STATUS_CHECK_COND;
582
break;
583
}
584
/*
585
* Direction is always relative
586
* to the initator.
587
*/
588
atio->ccb_h.flags &= ~CAM_DIR_MASK;
589
atio->ccb_h.flags |= CAM_DIR_IN;
590
descr->data = &no_lun_inq_data;
591
descr->data_resid = MIN(sizeof(no_lun_inq_data),
592
scsi_2btoul(inq->length));
593
descr->data_increment = descr->data_resid;
594
descr->timeout = 5 * 1000;
595
descr->status = SCSI_STATUS_OK;
596
break;
597
}
598
case REQUEST_SENSE:
599
{
600
struct scsi_request_sense *rsense;
601
602
rsense = (struct scsi_request_sense *)cdb;
603
/* Refer to static sense data */
604
atio->ccb_h.flags &= ~CAM_DIR_MASK;
605
atio->ccb_h.flags |= CAM_DIR_IN;
606
descr->data = &no_lun_sense_data;
607
descr->data_resid = request_sense_size;
608
descr->data_resid = MIN(descr->data_resid,
609
SCSI_CDB6_LEN(rsense->length));
610
descr->data_increment = descr->data_resid;
611
descr->timeout = 5 * 1000;
612
descr->status = SCSI_STATUS_OK;
613
break;
614
}
615
default:
616
/* Constant CA, tell initiator */
617
/* Direction is always relative to the initator */
618
atio->ccb_h.flags &= ~CAM_DIR_MASK;
619
atio->ccb_h.flags |= CAM_DIR_NONE;
620
bcopy(&no_lun_sense_data, &atio->sense_data,
621
min(sizeof(no_lun_sense_data),
622
sizeof(atio->sense_data)));
623
atio->sense_len = sizeof (no_lun_sense_data);
624
descr->data_resid = 0;
625
descr->data_increment = 0;
626
descr->timeout = 5 * 1000;
627
descr->status = SCSI_STATUS_CHECK_COND;
628
break;
629
}
630
631
/* Queue us up to receive a Continue Target I/O ccb. */
632
if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
633
TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
634
periph_links.tqe);
635
priority = 0;
636
} else {
637
TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
638
periph_links.tqe);
639
priority = CAM_PRIORITY_NORMAL;
640
}
641
xpt_schedule(periph, priority);
642
break;
643
}
644
case XPT_CONT_TARGET_IO:
645
{
646
struct ccb_accept_tio *atio;
647
struct targbh_cmd_desc *desc;
648
649
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
650
("Received completed CTIO\n"));
651
atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
652
desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
653
654
TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
655
periph_links.tqe);
656
657
/*
658
* We could check for CAM_SENT_SENSE bein set here,
659
* but since we're not maintaining any CA/UA state,
660
* there's no point.
661
*/
662
atio->sense_len = 0;
663
done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
664
done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
665
666
/*
667
* Any errors will not change the data we return,
668
* so make sure the queue is not left frozen.
669
* XXX - At some point there may be errors that
670
* leave us in a connected state with the
671
* initiator...
672
*/
673
if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
674
printf("Releasing Queue\n");
675
cam_release_devq(done_ccb->ccb_h.path,
676
/*relsim_flags*/0,
677
/*reduction*/0,
678
/*timeout*/0,
679
/*getcount_only*/0);
680
done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
681
}
682
desc->data_resid -= desc->data_increment;
683
xpt_release_ccb(done_ccb);
684
if (softc->state != TARGBH_STATE_TEARDOWN) {
685
/*
686
* Send the original accept TIO back to the
687
* controller to handle more work.
688
*/
689
CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
690
("Returning ATIO to target\n"));
691
/* Restore wildcards */
692
atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
693
atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
694
xpt_action((union ccb *)atio);
695
break;
696
} else {
697
targbhfreedescr(desc);
698
free(atio, M_SCSIBH);
699
}
700
break;
701
}
702
case XPT_IMMEDIATE_NOTIFY:
703
{
704
int frozen;
705
706
frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
707
if (softc->state == TARGBH_STATE_TEARDOWN
708
|| done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
709
printf("Freed an immediate notify\n");
710
xpt_free_ccb(done_ccb);
711
} else {
712
/* Requeue for another immediate event */
713
xpt_action(done_ccb);
714
}
715
if (frozen != 0)
716
cam_release_devq(periph->path,
717
/*relsim_flags*/0,
718
/*opening reduction*/0,
719
/*timeout*/0,
720
/*getcount_only*/0);
721
break;
722
}
723
default:
724
panic("targbhdone: Unexpected ccb opcode");
725
break;
726
}
727
}
728
729
#ifdef NOTYET
730
static int
731
targbherror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
732
{
733
return 0;
734
}
735
#endif
736
737
static struct targbh_cmd_desc*
738
targbhallocdescr(void)
739
{
740
struct targbh_cmd_desc* descr;
741
742
/* Allocate the targbh_descr structure */
743
descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
744
M_SCSIBH, M_NOWAIT);
745
if (descr == NULL)
746
return (NULL);
747
748
bzero(descr, sizeof(*descr));
749
750
/* Allocate buffer backing store */
751
descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT);
752
if (descr->backing_store == NULL) {
753
free(descr, M_SCSIBH);
754
return (NULL);
755
}
756
descr->max_size = MAX_BUF_SIZE;
757
return (descr);
758
}
759
760
static void
761
targbhfreedescr(struct targbh_cmd_desc *descr)
762
{
763
free(descr->backing_store, M_SCSIBH);
764
free(descr, M_SCSIBH);
765
}
766
767