Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/ctl/ctl_frontend_cam_sim.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009 Silicon Graphics International Corp.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions, and the following disclaimer,
12
* without modification.
13
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
14
* substantially similar to the "NO WARRANTY" disclaimer below
15
* ("Disclaimer") and any redistribution must be conditioned upon
16
* including a substantially similar Disclaimer requirement for further
17
* binary redistribution.
18
*
19
* NO WARRANTY
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
23
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
* POSSIBILITY OF SUCH DAMAGES.
31
*
32
* $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend_cam_sim.c#4 $
33
*/
34
/*
35
* CTL frontend to CAM SIM interface. This allows access to CTL LUNs via
36
* the da(4) and pass(4) drivers from inside the system.
37
*
38
* Author: Ken Merry <[email protected]>
39
*/
40
41
#include <sys/param.h>
42
#include <sys/systm.h>
43
#include <sys/kernel.h>
44
#include <sys/types.h>
45
#include <sys/malloc.h>
46
#include <sys/bus.h>
47
#include <sys/sysctl.h>
48
#include <machine/atomic.h>
49
#include <machine/bus.h>
50
#include <sys/sbuf.h>
51
52
#include <cam/cam.h>
53
#include <cam/cam_ccb.h>
54
#include <cam/cam_sim.h>
55
#include <cam/cam_xpt_sim.h>
56
#include <cam/cam_xpt.h>
57
#include <cam/cam_periph.h>
58
#include <cam/scsi/scsi_all.h>
59
#include <cam/scsi/scsi_message.h>
60
#include <cam/ctl/ctl_io.h>
61
#include <cam/ctl/ctl.h>
62
#include <cam/ctl/ctl_frontend.h>
63
#include <cam/ctl/ctl_debug.h>
64
65
#define io_ptr spriv_ptr1
66
67
struct cfcs_io {
68
union ccb *ccb;
69
};
70
71
struct cfcs_softc {
72
struct ctl_port port;
73
char port_name[32];
74
struct cam_sim *sim;
75
struct cam_devq *devq;
76
struct cam_path *path;
77
uint64_t wwnn;
78
uint64_t wwpn;
79
uint32_t cur_tag_num;
80
int online;
81
};
82
83
/*
84
* We can't handle CCBs with these flags. For the most part, we just don't
85
* handle physical addresses yet. That would require mapping things in
86
* order to do the copy.
87
*/
88
#define CFCS_BAD_CCB_FLAGS (CAM_DATA_ISPHYS | CAM_CDB_PHYS | CAM_SENSE_PTR | \
89
CAM_SENSE_PHYS)
90
91
static int cfcs_init(void);
92
static int cfcs_shutdown(void);
93
static void cfcs_poll(struct cam_sim *sim);
94
static void cfcs_online(void *arg);
95
static void cfcs_offline(void *arg);
96
static void cfcs_datamove(union ctl_io *io);
97
static void cfcs_done(union ctl_io *io);
98
void cfcs_action(struct cam_sim *sim, union ccb *ccb);
99
100
struct cfcs_softc cfcs_softc;
101
/*
102
* This is primarily intended to allow for error injection to test the CAM
103
* sense data and sense residual handling code. This sets the maximum
104
* amount of SCSI sense data that we will report to CAM.
105
*/
106
static int cfcs_max_sense = sizeof(struct scsi_sense_data);
107
108
SYSCTL_NODE(_kern_cam, OID_AUTO, ctl2cam, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
109
"CAM Target Layer SIM frontend");
110
SYSCTL_INT(_kern_cam_ctl2cam, OID_AUTO, max_sense, CTLFLAG_RW,
111
&cfcs_max_sense, 0, "Maximum sense data size");
112
113
static struct ctl_frontend cfcs_frontend =
114
{
115
.name = "camsim",
116
.init = cfcs_init,
117
.shutdown = cfcs_shutdown,
118
};
119
CTL_FRONTEND_DECLARE(ctlcfcs, cfcs_frontend);
120
121
static int
122
cfcs_init(void)
123
{
124
struct cfcs_softc *softc;
125
struct ctl_port *port;
126
int retval;
127
128
softc = &cfcs_softc;
129
bzero(softc, sizeof(*softc));
130
port = &softc->port;
131
132
port->frontend = &cfcs_frontend;
133
port->port_type = CTL_PORT_INTERNAL;
134
/* XXX KDM what should the real number be here? */
135
port->num_requested_ctl_io = 4096;
136
snprintf(softc->port_name, sizeof(softc->port_name), "camsim");
137
port->port_name = softc->port_name;
138
port->port_online = cfcs_online;
139
port->port_offline = cfcs_offline;
140
port->onoff_arg = softc;
141
port->fe_datamove = cfcs_datamove;
142
port->fe_done = cfcs_done;
143
port->targ_port = -1;
144
145
retval = ctl_port_register(port);
146
if (retval != 0) {
147
printf("%s: ctl_port_register() failed with error %d!\n",
148
__func__, retval);
149
return (retval);
150
}
151
152
/*
153
* If the CTL frontend didn't tell us what our WWNN/WWPN is, go
154
* ahead and set something random.
155
*/
156
if (port->wwnn == 0) {
157
uint64_t random_bits;
158
159
arc4rand(&random_bits, sizeof(random_bits), 0);
160
softc->wwnn = (random_bits & 0x0000000fffffff00ULL) |
161
/* Company ID */ 0x5000000000000000ULL |
162
/* NL-Port */ 0x0300;
163
softc->wwpn = softc->wwnn + port->targ_port + 1;
164
ctl_port_set_wwns(port, true, softc->wwnn, true, softc->wwpn);
165
} else {
166
softc->wwnn = port->wwnn;
167
softc->wwpn = port->wwpn;
168
}
169
170
softc->devq = cam_simq_alloc(port->num_requested_ctl_io);
171
if (softc->devq == NULL) {
172
printf("%s: error allocating devq\n", __func__);
173
retval = ENOMEM;
174
goto bailout;
175
}
176
177
softc->sim = cam_sim_alloc(cfcs_action, cfcs_poll, softc->port_name,
178
softc, /*unit*/ 0, NULL, 1,
179
port->num_requested_ctl_io, softc->devq);
180
if (softc->sim == NULL) {
181
printf("%s: error allocating SIM\n", __func__);
182
retval = ENOMEM;
183
goto bailout;
184
}
185
186
if (xpt_bus_register(softc->sim, NULL, 0) != CAM_SUCCESS) {
187
printf("%s: error registering SIM\n", __func__);
188
retval = ENOMEM;
189
goto bailout;
190
}
191
192
if (xpt_create_path(&softc->path, /*periph*/NULL,
193
cam_sim_path(softc->sim),
194
CAM_TARGET_WILDCARD,
195
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
196
printf("%s: error creating path\n", __func__);
197
xpt_bus_deregister(cam_sim_path(softc->sim));
198
retval = EINVAL;
199
goto bailout;
200
}
201
202
return (retval);
203
204
bailout:
205
if (softc->sim)
206
cam_sim_free(softc->sim, /*free_devq*/ TRUE);
207
else if (softc->devq)
208
cam_simq_free(softc->devq);
209
return (retval);
210
}
211
212
static int
213
cfcs_shutdown(void)
214
{
215
struct cfcs_softc *softc = &cfcs_softc;
216
struct ctl_port *port = &softc->port;
217
int error;
218
219
ctl_port_offline(port);
220
221
xpt_free_path(softc->path);
222
xpt_bus_deregister(cam_sim_path(softc->sim));
223
cam_sim_free(softc->sim, /*free_devq*/ TRUE);
224
225
if ((error = ctl_port_deregister(port)) != 0)
226
printf("%s: cam_sim port deregistration failed\n", __func__);
227
return (error);
228
}
229
230
static void
231
cfcs_poll(struct cam_sim *sim)
232
{
233
234
}
235
236
static void
237
cfcs_onoffline(void *arg, int online)
238
{
239
struct cfcs_softc *softc = (struct cfcs_softc *)arg;
240
union ccb *ccb;
241
242
softc->online = online;
243
244
ccb = xpt_alloc_ccb_nowait();
245
if (ccb == NULL) {
246
printf("%s: unable to allocate CCB for rescan\n", __func__);
247
return;
248
}
249
250
if (xpt_create_path(&ccb->ccb_h.path, NULL,
251
cam_sim_path(softc->sim), CAM_TARGET_WILDCARD,
252
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
253
printf("%s: can't allocate path for rescan\n", __func__);
254
xpt_free_ccb(ccb);
255
return;
256
}
257
xpt_rescan(ccb);
258
}
259
260
static void
261
cfcs_online(void *arg)
262
{
263
cfcs_onoffline(arg, /*online*/ 1);
264
}
265
266
static void
267
cfcs_offline(void *arg)
268
{
269
cfcs_onoffline(arg, /*online*/ 0);
270
}
271
272
/*
273
* This function is very similar to ctl_ioctl_do_datamove(). Is there a
274
* way to combine the functionality?
275
*
276
* XXX KDM may need to move this into a thread. We're doing a bcopy in the
277
* caller's context, which will usually be the backend. That may not be a
278
* good thing.
279
*/
280
static void
281
cfcs_datamove(union ctl_io *io)
282
{
283
union ccb *ccb;
284
bus_dma_segment_t cam_sg_entry, *cam_sglist;
285
struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
286
int cam_sg_count, ctl_sg_count, cam_sg_start;
287
int cam_sg_offset;
288
int len_to_copy;
289
int ctl_watermark, cam_watermark;
290
int i, j;
291
292
ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
293
294
/*
295
* Note that we have a check in cfcs_action() to make sure that any
296
* CCBs with "bad" flags are returned with CAM_REQ_INVALID. This
297
* is just to make sure no one removes that check without updating
298
* this code to provide the additional functionality necessary to
299
* support those modes of operation.
300
*/
301
KASSERT(((ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) == 0), ("invalid "
302
"CAM flags %#x", (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS)));
303
304
/*
305
* Simplify things on both sides by putting single buffers into a
306
* single entry S/G list.
307
*/
308
switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
309
case CAM_DATA_SG: {
310
int len_seen;
311
312
cam_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr;
313
cam_sg_count = ccb->csio.sglist_cnt;
314
cam_sg_start = cam_sg_count;
315
cam_sg_offset = 0;
316
317
for (i = 0, len_seen = 0; i < cam_sg_count; i++) {
318
if ((len_seen + cam_sglist[i].ds_len) >=
319
io->scsiio.kern_rel_offset) {
320
cam_sg_start = i;
321
cam_sg_offset = io->scsiio.kern_rel_offset -
322
len_seen;
323
break;
324
}
325
len_seen += cam_sglist[i].ds_len;
326
}
327
break;
328
}
329
case CAM_DATA_VADDR:
330
cam_sglist = &cam_sg_entry;
331
cam_sglist[0].ds_len = ccb->csio.dxfer_len;
332
cam_sglist[0].ds_addr = (bus_addr_t)(uintptr_t)ccb->csio.data_ptr;
333
cam_sg_count = 1;
334
cam_sg_start = 0;
335
cam_sg_offset = io->scsiio.kern_rel_offset;
336
break;
337
default:
338
panic("Invalid CAM flags %#x", ccb->ccb_h.flags);
339
}
340
341
if (io->scsiio.kern_sg_entries > 0) {
342
ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
343
ctl_sg_count = io->scsiio.kern_sg_entries;
344
} else {
345
ctl_sglist = &ctl_sg_entry;
346
ctl_sglist->addr = io->scsiio.kern_data_ptr;
347
ctl_sglist->len = io->scsiio.kern_data_len;
348
ctl_sg_count = 1;
349
}
350
351
ctl_watermark = 0;
352
cam_watermark = cam_sg_offset;
353
for (i = cam_sg_start, j = 0;
354
i < cam_sg_count && j < ctl_sg_count;) {
355
uint8_t *cam_ptr, *ctl_ptr;
356
357
len_to_copy = MIN(cam_sglist[i].ds_len - cam_watermark,
358
ctl_sglist[j].len - ctl_watermark);
359
360
cam_ptr = (uint8_t *)(uintptr_t)cam_sglist[i].ds_addr;
361
cam_ptr = cam_ptr + cam_watermark;
362
if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR) {
363
/*
364
* XXX KDM fix this!
365
*/
366
panic("need to implement bus address support");
367
#if 0
368
kern_ptr = bus_to_virt(kern_sglist[j].addr);
369
#endif
370
} else
371
ctl_ptr = (uint8_t *)ctl_sglist[j].addr;
372
ctl_ptr = ctl_ptr + ctl_watermark;
373
374
if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) ==
375
CTL_FLAG_DATA_IN) {
376
CTL_DEBUG_PRINT(("%s: copying %d bytes to CAM\n",
377
__func__, len_to_copy));
378
CTL_DEBUG_PRINT(("%s: from %p to %p\n", ctl_ptr,
379
__func__, cam_ptr));
380
bcopy(ctl_ptr, cam_ptr, len_to_copy);
381
} else {
382
CTL_DEBUG_PRINT(("%s: copying %d bytes from CAM\n",
383
__func__, len_to_copy));
384
CTL_DEBUG_PRINT(("%s: from %p to %p\n", cam_ptr,
385
__func__, ctl_ptr));
386
bcopy(cam_ptr, ctl_ptr, len_to_copy);
387
}
388
389
io->scsiio.ext_data_filled += len_to_copy;
390
io->scsiio.kern_data_resid -= len_to_copy;
391
392
cam_watermark += len_to_copy;
393
if (cam_sglist[i].ds_len == cam_watermark) {
394
i++;
395
cam_watermark = 0;
396
}
397
398
ctl_watermark += len_to_copy;
399
if (ctl_sglist[j].len == ctl_watermark) {
400
j++;
401
ctl_watermark = 0;
402
}
403
}
404
405
if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) {
406
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = NULL;
407
io->io_hdr.flags |= CTL_FLAG_STATUS_SENT;
408
ccb->csio.resid = ccb->csio.dxfer_len -
409
io->scsiio.ext_data_filled;
410
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
411
ccb->ccb_h.status |= CAM_REQ_CMP;
412
xpt_done(ccb);
413
}
414
415
ctl_datamove_done(io, true);
416
}
417
418
static void
419
cfcs_done(union ctl_io *io)
420
{
421
union ccb *ccb;
422
423
ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
424
if (ccb == NULL) {
425
ctl_free_io(io);
426
return;
427
}
428
429
/*
430
* At this point we should have status. If we don't, that's a bug.
431
*/
432
KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
433
("invalid CTL status %#x", io->io_hdr.status));
434
435
/*
436
* Translate CTL status to CAM status.
437
*/
438
if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
439
ccb->csio.resid = ccb->csio.dxfer_len -
440
io->scsiio.ext_data_filled;
441
}
442
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
443
switch (io->io_hdr.status & CTL_STATUS_MASK) {
444
case CTL_SUCCESS:
445
ccb->ccb_h.status |= CAM_REQ_CMP;
446
break;
447
case CTL_SCSI_ERROR:
448
ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
449
ccb->csio.scsi_status = io->scsiio.scsi_status;
450
bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data,
451
min(io->scsiio.sense_len, ccb->csio.sense_len));
452
if (ccb->csio.sense_len > io->scsiio.sense_len)
453
ccb->csio.sense_resid = ccb->csio.sense_len -
454
io->scsiio.sense_len;
455
else
456
ccb->csio.sense_resid = 0;
457
if ((ccb->csio.sense_len - ccb->csio.sense_resid) >
458
cfcs_max_sense) {
459
ccb->csio.sense_resid = ccb->csio.sense_len -
460
cfcs_max_sense;
461
}
462
break;
463
case CTL_CMD_ABORTED:
464
ccb->ccb_h.status |= CAM_REQ_ABORTED;
465
break;
466
case CTL_ERROR:
467
default:
468
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
469
break;
470
}
471
ctl_free_io(io);
472
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
473
(ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
474
xpt_freeze_devq(ccb->ccb_h.path, 1);
475
ccb->ccb_h.status |= CAM_DEV_QFRZN;
476
}
477
xpt_done(ccb);
478
}
479
480
void
481
cfcs_action(struct cam_sim *sim, union ccb *ccb)
482
{
483
struct cfcs_softc *softc;
484
int err;
485
486
softc = (struct cfcs_softc *)cam_sim_softc(sim);
487
488
switch (ccb->ccb_h.func_code) {
489
case XPT_SCSI_IO: {
490
union ctl_io *io;
491
struct ccb_scsiio *csio;
492
493
csio = &ccb->csio;
494
495
/*
496
* Catch CCB flags, like physical address flags, that
497
* indicate situations we currently can't handle.
498
*/
499
if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) {
500
ccb->ccb_h.status = CAM_REQ_INVALID;
501
printf("%s: bad CCB flags %#x (all flags %#x)\n",
502
__func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS,
503
ccb->ccb_h.flags);
504
xpt_done(ccb);
505
return;
506
}
507
508
/*
509
* If we aren't online, there are no devices to see.
510
*/
511
if (softc->online == 0) {
512
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
513
xpt_done(ccb);
514
return;
515
}
516
517
io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
518
if (io == NULL) {
519
printf("%s: can't allocate ctl_io\n", __func__);
520
ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
521
xpt_freeze_devq(ccb->ccb_h.path, 1);
522
xpt_done(ccb);
523
return;
524
}
525
ctl_zero_io(io);
526
/* Save pointers on both sides */
527
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
528
ccb->ccb_h.io_ptr = io;
529
530
/*
531
* Only SCSI I/O comes down this path, resets, etc. come
532
* down via the XPT_RESET_BUS/LUN CCBs below.
533
*/
534
io->io_hdr.io_type = CTL_IO_SCSI;
535
io->io_hdr.nexus.initid = 1;
536
io->io_hdr.nexus.targ_port = softc->port.targ_port;
537
io->io_hdr.nexus.targ_lun = ctl_decode_lun(
538
CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
539
io->scsiio.priority = csio->priority;
540
/*
541
* This tag scheme isn't the best, since we could in theory
542
* have a very long-lived I/O and tag collision, especially
543
* in a high I/O environment. But it should work well
544
* enough for now. Since we're using unsigned ints,
545
* they'll just wrap around.
546
*/
547
io->scsiio.tag_num = atomic_fetchadd_32(&softc->cur_tag_num, 1);
548
csio->tag_id = io->scsiio.tag_num;
549
switch (csio->tag_action) {
550
case CAM_TAG_ACTION_NONE:
551
io->scsiio.tag_type = CTL_TAG_UNTAGGED;
552
break;
553
case MSG_SIMPLE_TASK:
554
io->scsiio.tag_type = CTL_TAG_SIMPLE;
555
break;
556
case MSG_HEAD_OF_QUEUE_TASK:
557
io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
558
break;
559
case MSG_ORDERED_TASK:
560
io->scsiio.tag_type = CTL_TAG_ORDERED;
561
break;
562
case MSG_ACA_TASK:
563
io->scsiio.tag_type = CTL_TAG_ACA;
564
break;
565
default:
566
io->scsiio.tag_type = CTL_TAG_UNTAGGED;
567
printf("%s: unhandled tag type %#x!!\n", __func__,
568
csio->tag_action);
569
break;
570
}
571
if (csio->cdb_len > sizeof(io->scsiio.cdb)) {
572
printf("%s: WARNING: CDB len %d > ctl_io space %zd\n",
573
__func__, csio->cdb_len, sizeof(io->scsiio.cdb));
574
}
575
io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb));
576
bcopy(scsiio_cdb_ptr(csio), io->scsiio.cdb, io->scsiio.cdb_len);
577
578
ccb->ccb_h.status |= CAM_SIM_QUEUED;
579
err = ctl_queue(io);
580
if (err != CTL_RETVAL_COMPLETE) {
581
printf("%s: func %d: error %d returned by "
582
"ctl_queue()!\n", __func__,
583
ccb->ccb_h.func_code, err);
584
ctl_free_io(io);
585
ccb->ccb_h.status = CAM_REQ_INVALID;
586
xpt_done(ccb);
587
return;
588
}
589
break;
590
}
591
case XPT_ABORT: {
592
union ctl_io *io;
593
union ccb *abort_ccb;
594
595
abort_ccb = ccb->cab.abort_ccb;
596
597
if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {
598
ccb->ccb_h.status = CAM_REQ_INVALID;
599
xpt_done(ccb);
600
}
601
602
/*
603
* If we aren't online, there are no devices to talk to.
604
*/
605
if (softc->online == 0) {
606
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
607
xpt_done(ccb);
608
return;
609
}
610
611
io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
612
if (io == NULL) {
613
ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
614
xpt_freeze_devq(ccb->ccb_h.path, 1);
615
xpt_done(ccb);
616
return;
617
}
618
619
ctl_zero_io(io);
620
/* Save pointers on both sides */
621
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
622
ccb->ccb_h.io_ptr = io;
623
624
io->io_hdr.io_type = CTL_IO_TASK;
625
io->io_hdr.nexus.initid = 1;
626
io->io_hdr.nexus.targ_port = softc->port.targ_port;
627
io->io_hdr.nexus.targ_lun = ctl_decode_lun(
628
CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
629
io->taskio.task_action = CTL_TASK_ABORT_TASK;
630
io->taskio.tag_num = abort_ccb->csio.tag_id;
631
switch (abort_ccb->csio.tag_action) {
632
case CAM_TAG_ACTION_NONE:
633
io->taskio.tag_type = CTL_TAG_UNTAGGED;
634
break;
635
case MSG_SIMPLE_TASK:
636
io->taskio.tag_type = CTL_TAG_SIMPLE;
637
break;
638
case MSG_HEAD_OF_QUEUE_TASK:
639
io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
640
break;
641
case MSG_ORDERED_TASK:
642
io->taskio.tag_type = CTL_TAG_ORDERED;
643
break;
644
case MSG_ACA_TASK:
645
io->taskio.tag_type = CTL_TAG_ACA;
646
break;
647
default:
648
io->taskio.tag_type = CTL_TAG_UNTAGGED;
649
printf("%s: unhandled tag type %#x!!\n", __func__,
650
abort_ccb->csio.tag_action);
651
break;
652
}
653
err = ctl_queue(io);
654
if (err != CTL_RETVAL_COMPLETE) {
655
printf("%s func %d: error %d returned by "
656
"ctl_queue()!\n", __func__,
657
ccb->ccb_h.func_code, err);
658
ctl_free_io(io);
659
}
660
break;
661
}
662
case XPT_GET_TRAN_SETTINGS: {
663
struct ccb_trans_settings *cts;
664
struct ccb_trans_settings_scsi *scsi;
665
struct ccb_trans_settings_fc *fc;
666
667
cts = &ccb->cts;
668
scsi = &cts->proto_specific.scsi;
669
fc = &cts->xport_specific.fc;
670
671
672
cts->protocol = PROTO_SCSI;
673
cts->protocol_version = SCSI_REV_SPC2;
674
cts->transport = XPORT_FC;
675
cts->transport_version = 0;
676
677
scsi->valid = CTS_SCSI_VALID_TQ;
678
scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
679
fc->valid = CTS_FC_VALID_SPEED;
680
fc->bitrate = 800000;
681
fc->wwnn = softc->wwnn;
682
fc->wwpn = softc->wwpn;
683
fc->port = softc->port.targ_port;
684
fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN |
685
CTS_FC_VALID_PORT;
686
ccb->ccb_h.status = CAM_REQ_CMP;
687
break;
688
}
689
case XPT_SET_TRAN_SETTINGS:
690
/* XXX KDM should we actually do something here? */
691
ccb->ccb_h.status = CAM_REQ_CMP;
692
break;
693
case XPT_RESET_BUS:
694
case XPT_RESET_DEV: {
695
union ctl_io *io;
696
697
/*
698
* If we aren't online, there are no devices to talk to.
699
*/
700
if (softc->online == 0) {
701
ccb->ccb_h.status = CAM_DEV_NOT_THERE;
702
xpt_done(ccb);
703
return;
704
}
705
706
io = ctl_alloc_io_nowait(softc->port.ctl_pool_ref);
707
if (io == NULL) {
708
ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
709
xpt_freeze_devq(ccb->ccb_h.path, 1);
710
xpt_done(ccb);
711
return;
712
}
713
714
ctl_zero_io(io);
715
/* Save pointers on both sides */
716
if (ccb->ccb_h.func_code == XPT_RESET_DEV)
717
io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
718
ccb->ccb_h.io_ptr = io;
719
720
io->io_hdr.io_type = CTL_IO_TASK;
721
io->io_hdr.nexus.initid = 1;
722
io->io_hdr.nexus.targ_port = softc->port.targ_port;
723
io->io_hdr.nexus.targ_lun = ctl_decode_lun(
724
CAM_EXTLUN_BYTE_SWIZZLE(ccb->ccb_h.target_lun));
725
if (ccb->ccb_h.func_code == XPT_RESET_BUS)
726
io->taskio.task_action = CTL_TASK_BUS_RESET;
727
else
728
io->taskio.task_action = CTL_TASK_LUN_RESET;
729
730
err = ctl_queue(io);
731
if (err != CTL_RETVAL_COMPLETE) {
732
printf("%s func %d: error %d returned by "
733
"ctl_queue()!\n", __func__,
734
ccb->ccb_h.func_code, err);
735
ctl_free_io(io);
736
}
737
break;
738
}
739
case XPT_CALC_GEOMETRY:
740
cam_calc_geometry(&ccb->ccg, 1);
741
xpt_done(ccb);
742
break;
743
case XPT_PATH_INQ: {
744
struct ccb_pathinq *cpi;
745
746
cpi = &ccb->cpi;
747
748
cpi->version_num = 0;
749
cpi->hba_inquiry = PI_TAG_ABLE;
750
cpi->target_sprt = 0;
751
cpi->hba_misc = PIM_EXTLUNS;
752
cpi->hba_eng_cnt = 0;
753
cpi->max_target = 0;
754
cpi->max_lun = 1024;
755
/* Do we really have a limit? */
756
cpi->maxio = 1024 * 1024;
757
cpi->async_flags = 0;
758
cpi->hpath_id = 0;
759
cpi->initiator_id = 1;
760
761
strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
762
strlcpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN);
763
strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
764
cpi->unit_number = 0;
765
cpi->bus_id = 0;
766
cpi->base_transfer_speed = 800000;
767
cpi->protocol = PROTO_SCSI;
768
cpi->protocol_version = SCSI_REV_SPC2;
769
/*
770
* Pretend to be Fibre Channel.
771
*/
772
cpi->transport = XPORT_FC;
773
cpi->transport_version = 0;
774
cpi->xport_specific.fc.wwnn = softc->wwnn;
775
cpi->xport_specific.fc.wwpn = softc->wwpn;
776
cpi->xport_specific.fc.port = softc->port.targ_port;
777
cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000;
778
cpi->ccb_h.status = CAM_REQ_CMP;
779
break;
780
}
781
default:
782
ccb->ccb_h.status = CAM_PROVIDE_FAIL;
783
printf("%s: unsupported CCB type %#x\n", __func__,
784
ccb->ccb_h.func_code);
785
xpt_done(ccb);
786
break;
787
}
788
}
789
790