Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/cam.c
104970 views
1
/*-
2
* Generic utility routines for the Common Access Method layer.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 1997 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
#ifdef _KERNEL
33
#include "opt_kdtrace.h"
34
35
#include <sys/systm.h>
36
#include <sys/kernel.h>
37
#include <sys/memdesc.h>
38
#include <sys/queue.h>
39
#include <sys/sdt.h>
40
#include <sys/sysctl.h>
41
#else /* _KERNEL */
42
#include <stdlib.h>
43
#include <stdio.h>
44
#include <string.h>
45
#include <camlib.h>
46
#endif /* _KERNEL */
47
48
#include <cam/cam.h>
49
#include <cam/cam_ccb.h>
50
#include <cam/scsi/scsi_all.h>
51
#include <cam/scsi/smp_all.h>
52
#include <sys/sbuf.h>
53
54
#ifdef _KERNEL
55
#include <sys/libkern.h>
56
#include <machine/bus.h>
57
#include <cam/cam_queue.h>
58
#include <cam/cam_xpt.h>
59
60
FEATURE(scbus, "SCSI devices support");
61
62
SDT_PROVIDER_DEFINE(cam);
63
#endif
64
65
static int camstatusentrycomp(const void *key, const void *member);
66
67
const struct cam_status_entry cam_status_table[] = {
68
{ CAM_REQ_INPROG, "CCB request is in progress" },
69
{ CAM_REQ_CMP, "CCB request completed without error" },
70
{ CAM_REQ_ABORTED, "CCB request aborted by the host" },
71
{ CAM_UA_ABORT, "Unable to abort CCB request" },
72
{ CAM_REQ_CMP_ERR, "CCB request completed with an error" },
73
{ CAM_BUSY, "CAM subsystem is busy" },
74
{ CAM_REQ_INVALID, "CCB request was invalid" },
75
{ CAM_PATH_INVALID, "Supplied Path ID is invalid" },
76
{ CAM_DEV_NOT_THERE, "Device Not Present" },
77
{ CAM_UA_TERMIO, "Unable to terminate I/O CCB request" },
78
{ CAM_SEL_TIMEOUT, "Selection Timeout" },
79
{ CAM_CMD_TIMEOUT, "Command timeout" },
80
{ CAM_SCSI_STATUS_ERROR, "SCSI Status Error" },
81
{ CAM_MSG_REJECT_REC, "Message Reject Reveived" },
82
{ CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" },
83
{ CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" },
84
{ CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" },
85
{ CAM_NO_HBA, "No HBA Detected" },
86
{ CAM_DATA_RUN_ERR, "Data Overrun error" },
87
{ CAM_UNEXP_BUSFREE, "Unexpected Bus Free" },
88
{ CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" },
89
{ CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" },
90
{ CAM_PROVIDE_FAIL, "Unable to provide requested capability" },
91
{ CAM_BDR_SENT, "SCSI BDR Message Sent" },
92
{ CAM_REQ_TERMIO, "CCB request terminated by the host" },
93
{ CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" },
94
{ CAM_REQ_TOO_BIG, "The request was too large for this host" },
95
{ CAM_REQUEUE_REQ, "Unconditionally Re-queue Request" },
96
{ CAM_ATA_STATUS_ERROR, "ATA Status Error" },
97
{ CAM_SCSI_IT_NEXUS_LOST,"Initiator/Target Nexus Lost" },
98
{ CAM_SMP_STATUS_ERROR, "SMP Status Error" },
99
{ CAM_REQ_SOFTTIMEOUT, "Completed w/o error, but took too long" },
100
{ CAM_NVME_STATUS_ERROR, "NVME Status Error" },
101
{ CAM_IDE, "Initiator Detected Error Message Received" },
102
{ CAM_RESRC_UNAVAIL, "Resource Unavailable" },
103
{ CAM_UNACKED_EVENT, "Unacknowledged Event by Host" },
104
{ CAM_MESSAGE_RECV, "Message Received in Host Target Mode" },
105
{ CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" },
106
{ CAM_LUN_INVALID, "Invalid Lun" },
107
{ CAM_TID_INVALID, "Invalid Target ID" },
108
{ CAM_FUNC_NOTAVAIL, "Function Not Available" },
109
{ CAM_NO_NEXUS, "Nexus Not Established" },
110
{ CAM_IID_INVALID, "Invalid Initiator ID" },
111
{ CAM_CDB_RECVD, "CDB Received" },
112
{ CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" },
113
{ CAM_SCSI_BUSY, "SCSI Bus Busy" },
114
};
115
116
#ifdef _KERNEL
117
SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
118
"CAM Subsystem");
119
120
#ifndef CAM_DEFAULT_SORT_IO_QUEUES
121
#define CAM_DEFAULT_SORT_IO_QUEUES 1
122
#endif
123
124
int cam_sort_io_queues = CAM_DEFAULT_SORT_IO_QUEUES;
125
SYSCTL_INT(_kern_cam, OID_AUTO, sort_io_queues, CTLFLAG_RWTUN,
126
&cam_sort_io_queues, 0, "Sort IO queues to try and optimise disk access patterns");
127
#endif
128
129
void
130
cam_strvis(uint8_t *dst, const uint8_t *src, int srclen, int dstlen)
131
{
132
cam_strvis_flag(dst, src, srclen, dstlen,
133
CAM_STRVIS_FLAG_NONASCII_ESC);
134
}
135
136
void
137
cam_strvis_flag(uint8_t *dst, const uint8_t *src, int srclen, int dstlen,
138
uint32_t flags)
139
{
140
struct sbuf sb;
141
142
sbuf_new(&sb, dst, dstlen, SBUF_FIXEDLEN);
143
cam_strvis_sbuf(&sb, src, srclen, flags);
144
sbuf_finish(&sb);
145
}
146
147
void
148
cam_strvis_sbuf(struct sbuf *sb, const uint8_t *src, int srclen,
149
uint32_t flags)
150
{
151
152
/* Trim leading/trailing spaces, nulls. */
153
while (srclen > 0 && src[0] == ' ')
154
src++, srclen--;
155
while (srclen > 0
156
&& (src[srclen-1] == ' ' || src[srclen-1] == '\0'))
157
srclen--;
158
159
while (srclen > 0) {
160
if (*src < 0x20 || *src >= 0x80) {
161
/* SCSI-II Specifies that these should never occur. */
162
/* non-printable character */
163
switch (flags & CAM_STRVIS_FLAG_NONASCII_MASK) {
164
case CAM_STRVIS_FLAG_NONASCII_ESC:
165
sbuf_printf(sb, "\\%c%c%c",
166
((*src & 0300) >> 6) + '0',
167
((*src & 0070) >> 3) + '0',
168
((*src & 0007) >> 0) + '0');
169
break;
170
case CAM_STRVIS_FLAG_NONASCII_RAW:
171
/*
172
* If we run into a NUL, just transform it
173
* into a space.
174
*/
175
if (*src != 0x00)
176
sbuf_putc(sb, *src);
177
else
178
sbuf_putc(sb, ' ');
179
break;
180
case CAM_STRVIS_FLAG_NONASCII_SPC:
181
sbuf_putc(sb, ' ');
182
break;
183
case CAM_STRVIS_FLAG_NONASCII_TRIM:
184
default:
185
break;
186
}
187
} else {
188
/* normal character */
189
sbuf_putc(sb, *src);
190
}
191
src++;
192
srclen--;
193
}
194
}
195
196
/*
197
* Compare string with pattern, returning 0 on match.
198
* Short pattern matches trailing blanks in name,
199
* Shell globbing rules apply: * matches 0 or more characters,
200
* ? matchces one character, [...] denotes a set to match one char,
201
* [^...] denotes a complimented set to match one character.
202
* Spaces in str used to match anything in the pattern string
203
* but was removed because it's a bug. No current patterns require
204
* it, as far as I know, but it's impossible to know what drives
205
* returned.
206
*
207
* Each '*' generates recursion, so keep the number of * in check.
208
*/
209
int
210
cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len)
211
{
212
213
while (*pattern != '\0' && str_len > 0) {
214
if (*pattern == '*') {
215
pattern++;
216
if (*pattern == '\0')
217
return (0);
218
do {
219
if (cam_strmatch(str, pattern, str_len) == 0)
220
return (0);
221
str++;
222
str_len--;
223
} while (str_len > 0);
224
return (1);
225
} else if (*pattern == '[') {
226
int negate_range, ok;
227
uint8_t pc = UCHAR_MAX;
228
uint8_t sc;
229
230
ok = 0;
231
sc = *str++;
232
str_len--;
233
pattern++;
234
if ((negate_range = (*pattern == '^')) != 0)
235
pattern++;
236
while ((*pattern != ']') && *pattern != '\0') {
237
if (*pattern == '-') {
238
if (pattern[1] == '\0') /* Bad pattern */
239
return (1);
240
if (sc >= pc && sc <= pattern[1])
241
ok = 1;
242
pattern++;
243
} else if (*pattern == sc)
244
ok = 1;
245
pc = *pattern;
246
pattern++;
247
}
248
if (ok == negate_range)
249
return (1);
250
pattern++;
251
} else if (*pattern == '?') {
252
/*
253
* NB: || *str == ' ' of the old code is a bug and was
254
* removed. If you add it back, keep this the last if
255
* before the naked else */
256
pattern++;
257
str++;
258
str_len--;
259
} else {
260
if (*str != *pattern)
261
return (1);
262
pattern++;
263
str++;
264
str_len--;
265
}
266
}
267
268
/* '*' is allowed to match nothing, so gobble it */
269
while (*pattern == '*')
270
pattern++;
271
272
if ( *pattern != '\0') {
273
/* Pattern not fully consumed. Not a match */
274
return (1);
275
}
276
277
/* Eat trailing spaces, which get added by SAT */
278
while (str_len > 0 && *str == ' ') {
279
str++;
280
str_len--;
281
}
282
283
return (str_len);
284
}
285
286
caddr_t
287
cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
288
int entry_size, cam_quirkmatch_t *comp_func)
289
{
290
for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
291
if ((*comp_func)(target, quirk_table) == 0)
292
return (quirk_table);
293
}
294
return (NULL);
295
}
296
297
const struct cam_status_entry*
298
cam_fetch_status_entry(cam_status status)
299
{
300
status &= CAM_STATUS_MASK;
301
return (bsearch(&status, &cam_status_table,
302
nitems(cam_status_table),
303
sizeof(*cam_status_table),
304
camstatusentrycomp));
305
}
306
307
static int
308
camstatusentrycomp(const void *key, const void *member)
309
{
310
cam_status status;
311
const struct cam_status_entry *table_entry;
312
313
status = *(const cam_status *)key;
314
table_entry = (const struct cam_status_entry *)member;
315
316
return (status - table_entry->status_code);
317
}
318
319
#ifdef _KERNEL
320
char *
321
cam_error_string(union ccb *ccb, char *str, int str_len,
322
cam_error_string_flags flags,
323
cam_error_proto_flags proto_flags)
324
#else /* !_KERNEL */
325
char *
326
cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
327
int str_len, cam_error_string_flags flags,
328
cam_error_proto_flags proto_flags)
329
#endif /* _KERNEL/!_KERNEL */
330
{
331
char path_str[64];
332
struct sbuf sb;
333
334
if ((ccb == NULL)
335
|| (str == NULL)
336
|| (str_len <= 0))
337
return(NULL);
338
339
if (flags == CAM_ESF_NONE)
340
return(NULL);
341
342
switch (ccb->ccb_h.func_code) {
343
case XPT_ATA_IO:
344
switch (proto_flags & CAM_EPF_LEVEL_MASK) {
345
case CAM_EPF_NONE:
346
break;
347
case CAM_EPF_ALL:
348
case CAM_EPF_NORMAL:
349
proto_flags |= CAM_EAF_PRINT_RESULT;
350
/* FALLTHROUGH */
351
case CAM_EPF_MINIMAL:
352
proto_flags |= CAM_EAF_PRINT_STATUS;
353
/* FALLTHROUGH */
354
default:
355
break;
356
}
357
break;
358
case XPT_SCSI_IO:
359
switch (proto_flags & CAM_EPF_LEVEL_MASK) {
360
case CAM_EPF_NONE:
361
break;
362
case CAM_EPF_ALL:
363
case CAM_EPF_NORMAL:
364
proto_flags |= CAM_ESF_PRINT_SENSE;
365
/* FALLTHROUGH */
366
case CAM_EPF_MINIMAL:
367
proto_flags |= CAM_ESF_PRINT_STATUS;
368
/* FALLTHROUGH */
369
default:
370
break;
371
}
372
break;
373
case XPT_SMP_IO:
374
switch (proto_flags & CAM_EPF_LEVEL_MASK) {
375
case CAM_EPF_NONE:
376
break;
377
case CAM_EPF_ALL:
378
proto_flags |= CAM_ESMF_PRINT_FULL_CMD;
379
/* FALLTHROUGH */
380
case CAM_EPF_NORMAL:
381
case CAM_EPF_MINIMAL:
382
proto_flags |= CAM_ESMF_PRINT_STATUS;
383
/* FALLTHROUGH */
384
default:
385
break;
386
}
387
break;
388
case XPT_NVME_IO:
389
case XPT_NVME_ADMIN:
390
switch (proto_flags & CAM_EPF_LEVEL_MASK) {
391
case CAM_EPF_NONE:
392
break;
393
case CAM_EPF_ALL:
394
case CAM_EPF_NORMAL:
395
case CAM_EPF_MINIMAL:
396
proto_flags |= CAM_ENF_PRINT_STATUS;
397
/* FALLTHROUGH */
398
default:
399
break;
400
}
401
break;
402
default:
403
break;
404
}
405
#ifdef _KERNEL
406
xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str));
407
#else /* !_KERNEL */
408
cam_path_string(device, path_str, sizeof(path_str));
409
#endif /* _KERNEL/!_KERNEL */
410
411
sbuf_new(&sb, str, str_len, 0);
412
413
if (flags & CAM_ESF_COMMAND) {
414
sbuf_cat(&sb, path_str);
415
switch (ccb->ccb_h.func_code) {
416
case XPT_ATA_IO:
417
ata_command_sbuf(&ccb->ataio, &sb);
418
break;
419
case XPT_SCSI_IO:
420
#ifdef _KERNEL
421
scsi_command_string(&ccb->csio, &sb);
422
#else /* !_KERNEL */
423
scsi_command_string(device, &ccb->csio, &sb);
424
#endif /* _KERNEL/!_KERNEL */
425
break;
426
case XPT_SMP_IO:
427
smp_command_sbuf(&ccb->smpio, &sb, path_str, 79 -
428
strlen(path_str), (proto_flags &
429
CAM_ESMF_PRINT_FULL_CMD) ? 79 : 0);
430
break;
431
case XPT_NVME_IO:
432
case XPT_NVME_ADMIN:
433
nvme_command_sbuf(&ccb->nvmeio, &sb);
434
break;
435
default:
436
sbuf_printf(&sb, "CAM func %#x",
437
ccb->ccb_h.func_code);
438
break;
439
}
440
sbuf_putc(&sb, '\n');
441
}
442
443
if (flags & CAM_ESF_CAM_STATUS) {
444
cam_status status;
445
const struct cam_status_entry *entry;
446
447
sbuf_cat(&sb, path_str);
448
449
status = ccb->ccb_h.status & CAM_STATUS_MASK;
450
451
entry = cam_fetch_status_entry(status);
452
453
if (entry == NULL)
454
sbuf_printf(&sb, "CAM status: Unknown (%#x)\n",
455
ccb->ccb_h.status);
456
else
457
sbuf_printf(&sb, "CAM status: %s\n",
458
entry->status_text);
459
}
460
461
if (flags & CAM_ESF_PROTO_STATUS) {
462
463
switch (ccb->ccb_h.func_code) {
464
case XPT_ATA_IO:
465
if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
466
CAM_ATA_STATUS_ERROR)
467
break;
468
if (proto_flags & CAM_EAF_PRINT_STATUS) {
469
sbuf_cat(&sb, path_str);
470
ata_status_sbuf(&ccb->ataio, &sb);
471
sbuf_putc(&sb, '\n');
472
}
473
if (proto_flags & CAM_EAF_PRINT_RESULT) {
474
sbuf_cat(&sb, path_str);
475
sbuf_cat(&sb, "RES: ");
476
ata_res_sbuf(&ccb->ataio.res, &sb);
477
sbuf_putc(&sb, '\n');
478
}
479
480
break;
481
case XPT_SCSI_IO:
482
if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
483
CAM_SCSI_STATUS_ERROR)
484
break;
485
486
if (proto_flags & CAM_ESF_PRINT_STATUS) {
487
sbuf_cat(&sb, path_str);
488
sbuf_printf(&sb, "SCSI status: %s\n",
489
scsi_status_string(&ccb->csio));
490
}
491
492
if ((proto_flags & CAM_ESF_PRINT_SENSE)
493
&& (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
494
&& (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) {
495
#ifdef _KERNEL
496
scsi_sense_sbuf(&ccb->csio, &sb,
497
SSS_FLAG_NONE);
498
#else /* !_KERNEL */
499
scsi_sense_sbuf(device, &ccb->csio, &sb,
500
SSS_FLAG_NONE);
501
#endif /* _KERNEL/!_KERNEL */
502
}
503
break;
504
case XPT_SMP_IO:
505
if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
506
CAM_SMP_STATUS_ERROR)
507
break;
508
509
if (proto_flags & CAM_ESF_PRINT_STATUS) {
510
sbuf_cat(&sb, path_str);
511
sbuf_printf(&sb, "SMP status: %s (%#x)\n",
512
smp_error_desc(ccb->smpio.smp_response[2]),
513
ccb->smpio.smp_response[2]);
514
}
515
/* There is no SMP equivalent to SCSI sense. */
516
break;
517
case XPT_NVME_IO:
518
case XPT_NVME_ADMIN:
519
if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
520
CAM_NVME_STATUS_ERROR)
521
break;
522
523
if (proto_flags & CAM_ESF_PRINT_STATUS) {
524
sbuf_cat(&sb, path_str);
525
sbuf_cat(&sb, "NVMe status: ");
526
nvme_status_sbuf(&ccb->nvmeio, &sb);
527
sbuf_putc(&sb, '\n');
528
}
529
530
break;
531
default:
532
break;
533
}
534
}
535
536
sbuf_finish(&sb);
537
538
return(sbuf_data(&sb));
539
}
540
541
#ifdef _KERNEL
542
543
void
544
cam_error_print(union ccb *ccb, cam_error_string_flags flags,
545
cam_error_proto_flags proto_flags)
546
{
547
char str[512];
548
549
printf("%s", cam_error_string(ccb, str, sizeof(str), flags,
550
proto_flags));
551
}
552
553
#else /* !_KERNEL */
554
555
void
556
cam_error_print(struct cam_device *device, union ccb *ccb,
557
cam_error_string_flags flags, cam_error_proto_flags proto_flags,
558
FILE *ofile)
559
{
560
char str[512];
561
562
if ((device == NULL) || (ccb == NULL) || (ofile == NULL))
563
return;
564
565
fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str),
566
flags, proto_flags));
567
}
568
569
#endif /* _KERNEL/!_KERNEL */
570
571
/*
572
* Common calculate geometry fuction
573
*
574
* Caller should set ccg->volume_size and block_size.
575
* The extended parameter should be zero if extended translation
576
* should not be used.
577
*/
578
void
579
cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended)
580
{
581
uint32_t size_mb, secs_per_cylinder;
582
583
if (ccg->block_size == 0) {
584
ccg->ccb_h.status = CAM_REQ_CMP_ERR;
585
return;
586
}
587
size_mb = (1024L * 1024L) / ccg->block_size;
588
if (size_mb == 0) {
589
ccg->ccb_h.status = CAM_REQ_CMP_ERR;
590
return;
591
}
592
size_mb = ccg->volume_size / size_mb;
593
if (size_mb > 1024 && extended) {
594
ccg->heads = 255;
595
ccg->secs_per_track = 63;
596
} else {
597
ccg->heads = 64;
598
ccg->secs_per_track = 32;
599
}
600
secs_per_cylinder = ccg->heads * ccg->secs_per_track;
601
if (secs_per_cylinder == 0) {
602
ccg->ccb_h.status = CAM_REQ_CMP_ERR;
603
return;
604
}
605
ccg->cylinders = ccg->volume_size / secs_per_cylinder;
606
ccg->ccb_h.status = CAM_REQ_CMP;
607
}
608
609
#ifdef _KERNEL
610
struct memdesc
611
memdesc_ccb(union ccb *ccb)
612
{
613
struct ccb_hdr *ccb_h;
614
void *data_ptr;
615
uint32_t dxfer_len;
616
uint16_t sglist_cnt;
617
618
ccb_h = &ccb->ccb_h;
619
switch (ccb_h->func_code) {
620
case XPT_SCSI_IO: {
621
struct ccb_scsiio *csio;
622
623
csio = &ccb->csio;
624
data_ptr = csio->data_ptr;
625
dxfer_len = csio->dxfer_len;
626
sglist_cnt = csio->sglist_cnt;
627
break;
628
}
629
case XPT_CONT_TARGET_IO: {
630
struct ccb_scsiio *ctio;
631
632
ctio = &ccb->ctio;
633
data_ptr = ctio->data_ptr;
634
dxfer_len = ctio->dxfer_len;
635
sglist_cnt = ctio->sglist_cnt;
636
break;
637
}
638
case XPT_ATA_IO: {
639
struct ccb_ataio *ataio;
640
641
ataio = &ccb->ataio;
642
data_ptr = ataio->data_ptr;
643
dxfer_len = ataio->dxfer_len;
644
sglist_cnt = 0;
645
break;
646
}
647
case XPT_NVME_IO:
648
case XPT_NVME_ADMIN: {
649
struct ccb_nvmeio *nvmeio;
650
651
nvmeio = &ccb->nvmeio;
652
data_ptr = nvmeio->data_ptr;
653
dxfer_len = nvmeio->dxfer_len;
654
sglist_cnt = nvmeio->sglist_cnt;
655
break;
656
}
657
default:
658
panic("%s: Unsupported func code %d", __func__,
659
ccb_h->func_code);
660
}
661
662
switch ((ccb_h->flags & CAM_DATA_MASK)) {
663
case CAM_DATA_VADDR:
664
return (memdesc_vaddr(data_ptr, dxfer_len));
665
case CAM_DATA_PADDR:
666
return (memdesc_paddr((vm_paddr_t)(uintptr_t)data_ptr,
667
dxfer_len));
668
case CAM_DATA_SG:
669
return (memdesc_vlist(data_ptr, sglist_cnt));
670
case CAM_DATA_SG_PADDR:
671
return (memdesc_plist(data_ptr, sglist_cnt));
672
case CAM_DATA_BIO:
673
return (memdesc_bio(data_ptr));
674
default:
675
panic("%s: flags 0x%X unimplemented", __func__, ccb_h->flags);
676
}
677
}
678
679
int
680
bus_dmamap_load_ccb(bus_dma_tag_t dmat, bus_dmamap_t map, union ccb *ccb,
681
bus_dmamap_callback_t *callback, void *callback_arg,
682
int flags)
683
{
684
struct ccb_hdr *ccb_h;
685
struct memdesc mem;
686
687
ccb_h = &ccb->ccb_h;
688
if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
689
callback(callback_arg, NULL, 0, 0);
690
return (0);
691
}
692
693
mem = memdesc_ccb(ccb);
694
return (bus_dmamap_load_mem(dmat, map, &mem, callback, callback_arg,
695
flags));
696
}
697
#endif
698
699