diff --git a/sys/cam/cam.c b/sys/cam/cam.c index d9cff3468da0..917197542edc 100644 --- a/sys/cam/cam.c +++ b/sys/cam/cam.c @@ -1,664 +1,692 @@ /*- * Generic utility routines for the Common Access Method layer. * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifdef _KERNEL #include #include #include #include #else /* _KERNEL */ #include #include #include #include #endif /* _KERNEL */ #include #include #include #include #include #ifdef _KERNEL #include #include #include #include FEATURE(scbus, "SCSI devices support"); #endif static int camstatusentrycomp(const void *key, const void *member); const struct cam_status_entry cam_status_table[] = { { CAM_REQ_INPROG, "CCB request is in progress" }, { CAM_REQ_CMP, "CCB request completed without error" }, { CAM_REQ_ABORTED, "CCB request aborted by the host" }, { CAM_UA_ABORT, "Unable to abort CCB request" }, { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, { CAM_BUSY, "CAM subsystem is busy" }, { CAM_REQ_INVALID, "CCB request was invalid" }, { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, { CAM_DEV_NOT_THERE, "Device Not Present" }, { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, { CAM_SEL_TIMEOUT, "Selection Timeout" }, { CAM_CMD_TIMEOUT, "Command timeout" }, { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, { CAM_NO_HBA, "No HBA Detected" }, { CAM_DATA_RUN_ERR, "Data Overrun error" }, { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, { CAM_BDR_SENT, "SCSI BDR Message Sent" }, { CAM_REQ_TERMIO, "CCB request terminated by the host" }, { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, { CAM_REQ_TOO_BIG, "The request was too large for this host" }, { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request" }, { CAM_ATA_STATUS_ERROR, "ATA Status Error" }, { CAM_SCSI_IT_NEXUS_LOST,"Initiator/Target Nexus Lost" }, { CAM_SMP_STATUS_ERROR, "SMP Status Error" }, { CAM_REQ_SOFTTIMEOUT, "Completed w/o error, but took too long" }, { CAM_NVME_STATUS_ERROR, "NVME Status Error" }, { CAM_IDE, "Initiator Detected Error Message Received" }, { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, { CAM_LUN_INVALID, "Invalid Lun" }, { CAM_TID_INVALID, "Invalid Target ID" }, { CAM_FUNC_NOTAVAIL, "Function Not Available" }, { CAM_NO_NEXUS, "Nexus Not Established" }, { CAM_IID_INVALID, "Invalid Initiator ID" }, { CAM_CDB_RECVD, "CDB Received" }, { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, { CAM_SCSI_BUSY, "SCSI Bus Busy" }, }; #ifdef _KERNEL SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "CAM Subsystem"); #ifndef CAM_DEFAULT_SORT_IO_QUEUES #define CAM_DEFAULT_SORT_IO_QUEUES 1 #endif int cam_sort_io_queues = CAM_DEFAULT_SORT_IO_QUEUES; SYSCTL_INT(_kern_cam, OID_AUTO, sort_io_queues, CTLFLAG_RWTUN, &cam_sort_io_queues, 0, "Sort IO queues to try and optimise disk access patterns"); #endif void cam_strvis(uint8_t *dst, const uint8_t *src, int srclen, int dstlen) { cam_strvis_flag(dst, src, srclen, dstlen, CAM_STRVIS_FLAG_NONASCII_ESC); } void cam_strvis_flag(uint8_t *dst, const uint8_t *src, int srclen, int dstlen, uint32_t flags) { struct sbuf sb; sbuf_new(&sb, dst, dstlen, SBUF_FIXEDLEN); cam_strvis_sbuf(&sb, src, srclen, flags); sbuf_finish(&sb); } void cam_strvis_sbuf(struct sbuf *sb, const uint8_t *src, int srclen, uint32_t flags) { /* Trim leading/trailing spaces, nulls. */ while (srclen > 0 && src[0] == ' ') src++, srclen--; while (srclen > 0 && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) srclen--; while (srclen > 0) { if (*src < 0x20 || *src >= 0x80) { /* SCSI-II Specifies that these should never occur. */ /* non-printable character */ switch (flags & CAM_STRVIS_FLAG_NONASCII_MASK) { case CAM_STRVIS_FLAG_NONASCII_ESC: sbuf_printf(sb, "\\%c%c%c", ((*src & 0300) >> 6) + '0', ((*src & 0070) >> 3) + '0', ((*src & 0007) >> 0) + '0'); break; case CAM_STRVIS_FLAG_NONASCII_RAW: /* * If we run into a NUL, just transform it * into a space. */ if (*src != 0x00) sbuf_putc(sb, *src); else sbuf_putc(sb, ' '); break; case CAM_STRVIS_FLAG_NONASCII_SPC: sbuf_putc(sb, ' '); break; case CAM_STRVIS_FLAG_NONASCII_TRIM: default: break; } } else { /* normal character */ sbuf_putc(sb, *src); } src++; srclen--; } } /* * Compare string with pattern, returning 0 on match. * Short pattern matches trailing blanks in name, * Shell globbing rules apply: * matches 0 or more characters, * ? matchces one character, [...] denotes a set to match one char, * [^...] denotes a complimented set to match one character. * Spaces in str used to match anything in the pattern string * but was removed because it's a bug. No current patterns require * it, as far as I know, but it's impossible to know what drives * returned. * * Each '*' generates recursion, so keep the number of * in check. */ int cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len) { while (*pattern != '\0' && str_len > 0) { if (*pattern == '*') { pattern++; if (*pattern == '\0') return (0); do { if (cam_strmatch(str, pattern, str_len) == 0) return (0); str++; str_len--; } while (str_len > 0); return (1); } else if (*pattern == '[') { int negate_range, ok; uint8_t pc = UCHAR_MAX; uint8_t sc; ok = 0; sc = *str++; str_len--; pattern++; if ((negate_range = (*pattern == '^')) != 0) pattern++; while ((*pattern != ']') && *pattern != '\0') { if (*pattern == '-') { if (pattern[1] == '\0') /* Bad pattern */ return (1); if (sc >= pc && sc <= pattern[1]) ok = 1; pattern++; } else if (*pattern == sc) ok = 1; pc = *pattern; pattern++; } if (ok == negate_range) return (1); pattern++; } else if (*pattern == '?') { /* * NB: || *str == ' ' of the old code is a bug and was * removed. If you add it back, keep this the last if * before the naked else */ pattern++; str++; str_len--; } else { if (*str != *pattern) return (1); pattern++; str++; str_len--; } } /* '*' is allowed to match nothing, so gobble it */ while (*pattern == '*') pattern++; if ( *pattern != '\0') { /* Pattern not fully consumed. Not a match */ return (1); } /* Eat trailing spaces, which get added by SAT */ while (str_len > 0 && *str == ' ') { str++; str_len--; } return (str_len); } caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, int entry_size, cam_quirkmatch_t *comp_func) { for (; num_entries > 0; num_entries--, quirk_table += entry_size) { if ((*comp_func)(target, quirk_table) == 0) return (quirk_table); } return (NULL); } const struct cam_status_entry* cam_fetch_status_entry(cam_status status) { status &= CAM_STATUS_MASK; return (bsearch(&status, &cam_status_table, nitems(cam_status_table), sizeof(*cam_status_table), camstatusentrycomp)); } static int camstatusentrycomp(const void *key, const void *member) { cam_status status; const struct cam_status_entry *table_entry; status = *(const cam_status *)key; table_entry = (const struct cam_status_entry *)member; return (status - table_entry->status_code); } #ifdef _KERNEL char * cam_error_string(union ccb *ccb, char *str, int str_len, cam_error_string_flags flags, cam_error_proto_flags proto_flags) #else /* !_KERNEL */ char * cam_error_string(struct cam_device *device, union ccb *ccb, char *str, int str_len, cam_error_string_flags flags, cam_error_proto_flags proto_flags) #endif /* _KERNEL/!_KERNEL */ { char path_str[64]; struct sbuf sb; if ((ccb == NULL) || (str == NULL) || (str_len <= 0)) return(NULL); if (flags == CAM_ESF_NONE) return(NULL); switch (ccb->ccb_h.func_code) { case XPT_ATA_IO: switch (proto_flags & CAM_EPF_LEVEL_MASK) { case CAM_EPF_NONE: break; case CAM_EPF_ALL: case CAM_EPF_NORMAL: proto_flags |= CAM_EAF_PRINT_RESULT; /* FALLTHROUGH */ case CAM_EPF_MINIMAL: proto_flags |= CAM_EAF_PRINT_STATUS; /* FALLTHROUGH */ default: break; } break; case XPT_SCSI_IO: switch (proto_flags & CAM_EPF_LEVEL_MASK) { case CAM_EPF_NONE: break; case CAM_EPF_ALL: case CAM_EPF_NORMAL: proto_flags |= CAM_ESF_PRINT_SENSE; /* FALLTHROUGH */ case CAM_EPF_MINIMAL: proto_flags |= CAM_ESF_PRINT_STATUS; /* FALLTHROUGH */ default: break; } break; case XPT_SMP_IO: switch (proto_flags & CAM_EPF_LEVEL_MASK) { case CAM_EPF_NONE: break; case CAM_EPF_ALL: proto_flags |= CAM_ESMF_PRINT_FULL_CMD; /* FALLTHROUGH */ case CAM_EPF_NORMAL: case CAM_EPF_MINIMAL: proto_flags |= CAM_ESMF_PRINT_STATUS; /* FALLTHROUGH */ default: break; } break; + case XPT_NVME_IO: + case XPT_NVME_ADMIN: + switch (proto_flags & CAM_EPF_LEVEL_MASK) { + case CAM_EPF_NONE: + break; + case CAM_EPF_ALL: + case CAM_EPF_NORMAL: + case CAM_EPF_MINIMAL: + proto_flags |= CAM_ENF_PRINT_STATUS; + /* FALLTHROUGH */ + default: + break; + } + break; default: break; } #ifdef _KERNEL xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); #else /* !_KERNEL */ cam_path_string(device, path_str, sizeof(path_str)); #endif /* _KERNEL/!_KERNEL */ sbuf_new(&sb, str, str_len, 0); if (flags & CAM_ESF_COMMAND) { sbuf_cat(&sb, path_str); switch (ccb->ccb_h.func_code) { case XPT_ATA_IO: ata_command_sbuf(&ccb->ataio, &sb); break; case XPT_SCSI_IO: #ifdef _KERNEL scsi_command_string(&ccb->csio, &sb); #else /* !_KERNEL */ scsi_command_string(device, &ccb->csio, &sb); #endif /* _KERNEL/!_KERNEL */ break; case XPT_SMP_IO: smp_command_sbuf(&ccb->smpio, &sb, path_str, 79 - strlen(path_str), (proto_flags & CAM_ESMF_PRINT_FULL_CMD) ? 79 : 0); break; case XPT_NVME_IO: case XPT_NVME_ADMIN: nvme_command_sbuf(&ccb->nvmeio, &sb); break; default: sbuf_printf(&sb, "CAM func %#x", ccb->ccb_h.func_code); break; } sbuf_putc(&sb, '\n'); } if (flags & CAM_ESF_CAM_STATUS) { cam_status status; const struct cam_status_entry *entry; sbuf_cat(&sb, path_str); status = ccb->ccb_h.status & CAM_STATUS_MASK; entry = cam_fetch_status_entry(status); if (entry == NULL) sbuf_printf(&sb, "CAM status: Unknown (%#x)\n", ccb->ccb_h.status); else sbuf_printf(&sb, "CAM status: %s\n", entry->status_text); } if (flags & CAM_ESF_PROTO_STATUS) { switch (ccb->ccb_h.func_code) { case XPT_ATA_IO: if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_ATA_STATUS_ERROR) break; if (proto_flags & CAM_EAF_PRINT_STATUS) { sbuf_cat(&sb, path_str); ata_status_sbuf(&ccb->ataio, &sb); sbuf_putc(&sb, '\n'); } if (proto_flags & CAM_EAF_PRINT_RESULT) { sbuf_cat(&sb, path_str); sbuf_cat(&sb, "RES: "); ata_res_sbuf(&ccb->ataio.res, &sb); sbuf_putc(&sb, '\n'); } break; case XPT_SCSI_IO: if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR) break; if (proto_flags & CAM_ESF_PRINT_STATUS) { sbuf_cat(&sb, path_str); sbuf_printf(&sb, "SCSI status: %s\n", scsi_status_string(&ccb->csio)); } if ((proto_flags & CAM_ESF_PRINT_SENSE) && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { #ifdef _KERNEL scsi_sense_sbuf(&ccb->csio, &sb, SSS_FLAG_NONE); #else /* !_KERNEL */ scsi_sense_sbuf(device, &ccb->csio, &sb, SSS_FLAG_NONE); #endif /* _KERNEL/!_KERNEL */ } break; case XPT_SMP_IO: if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SMP_STATUS_ERROR) break; if (proto_flags & CAM_ESF_PRINT_STATUS) { sbuf_cat(&sb, path_str); sbuf_printf(&sb, "SMP status: %s (%#x)\n", smp_error_desc(ccb->smpio.smp_response[2]), ccb->smpio.smp_response[2]); } /* There is no SMP equivalent to SCSI sense. */ + break; + case XPT_NVME_IO: + case XPT_NVME_ADMIN: + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != + CAM_NVME_STATUS_ERROR) + break; + + if (proto_flags & CAM_ESF_PRINT_STATUS) { + sbuf_cat(&sb, path_str); + sbuf_cat(&sb, "NVMe status: "); + nvme_status_sbuf(&ccb->nvmeio, &sb); + sbuf_putc(&sb, '\n'); + } + break; default: break; } } sbuf_finish(&sb); return(sbuf_data(&sb)); } #ifdef _KERNEL void cam_error_print(union ccb *ccb, cam_error_string_flags flags, cam_error_proto_flags proto_flags) { char str[512]; printf("%s", cam_error_string(ccb, str, sizeof(str), flags, proto_flags)); } #else /* !_KERNEL */ void cam_error_print(struct cam_device *device, union ccb *ccb, cam_error_string_flags flags, cam_error_proto_flags proto_flags, FILE *ofile) { char str[512]; if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) return; fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), flags, proto_flags)); } #endif /* _KERNEL/!_KERNEL */ /* * Common calculate geometry fuction * * Caller should set ccg->volume_size and block_size. * The extended parameter should be zero if extended translation * should not be used. */ void cam_calc_geometry(struct ccb_calc_geometry *ccg, int extended) { uint32_t size_mb, secs_per_cylinder; if (ccg->block_size == 0) { ccg->ccb_h.status = CAM_REQ_CMP_ERR; return; } size_mb = (1024L * 1024L) / ccg->block_size; if (size_mb == 0) { ccg->ccb_h.status = CAM_REQ_CMP_ERR; return; } size_mb = ccg->volume_size / size_mb; if (size_mb > 1024 && extended) { ccg->heads = 255; ccg->secs_per_track = 63; } else { ccg->heads = 64; ccg->secs_per_track = 32; } secs_per_cylinder = ccg->heads * ccg->secs_per_track; if (secs_per_cylinder == 0) { ccg->ccb_h.status = CAM_REQ_CMP_ERR; return; } ccg->cylinders = ccg->volume_size / secs_per_cylinder; ccg->ccb_h.status = CAM_REQ_CMP; } #ifdef _KERNEL struct memdesc memdesc_ccb(union ccb *ccb) { struct ccb_hdr *ccb_h; void *data_ptr; uint32_t dxfer_len; uint16_t sglist_cnt; ccb_h = &ccb->ccb_h; switch (ccb_h->func_code) { case XPT_SCSI_IO: { struct ccb_scsiio *csio; csio = &ccb->csio; data_ptr = csio->data_ptr; dxfer_len = csio->dxfer_len; sglist_cnt = csio->sglist_cnt; break; } case XPT_CONT_TARGET_IO: { struct ccb_scsiio *ctio; ctio = &ccb->ctio; data_ptr = ctio->data_ptr; dxfer_len = ctio->dxfer_len; sglist_cnt = ctio->sglist_cnt; break; } case XPT_ATA_IO: { struct ccb_ataio *ataio; ataio = &ccb->ataio; data_ptr = ataio->data_ptr; dxfer_len = ataio->dxfer_len; sglist_cnt = 0; break; } case XPT_NVME_IO: case XPT_NVME_ADMIN: { struct ccb_nvmeio *nvmeio; nvmeio = &ccb->nvmeio; data_ptr = nvmeio->data_ptr; dxfer_len = nvmeio->dxfer_len; sglist_cnt = nvmeio->sglist_cnt; break; } default: panic("%s: Unsupported func code %d", __func__, ccb_h->func_code); } switch ((ccb_h->flags & CAM_DATA_MASK)) { case CAM_DATA_VADDR: return (memdesc_vaddr(data_ptr, dxfer_len)); case CAM_DATA_PADDR: return (memdesc_paddr((vm_paddr_t)(uintptr_t)data_ptr, dxfer_len)); case CAM_DATA_SG: return (memdesc_vlist(data_ptr, sglist_cnt)); case CAM_DATA_SG_PADDR: return (memdesc_plist(data_ptr, sglist_cnt)); case CAM_DATA_BIO: return (memdesc_bio(data_ptr)); default: panic("%s: flags 0x%X unimplemented", __func__, ccb_h->flags); } } int bus_dmamap_load_ccb(bus_dma_tag_t dmat, bus_dmamap_t map, union ccb *ccb, bus_dmamap_callback_t *callback, void *callback_arg, int flags) { struct ccb_hdr *ccb_h; struct memdesc mem; ccb_h = &ccb->ccb_h; if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) { callback(callback_arg, NULL, 0, 0); return (0); } mem = memdesc_ccb(ccb); return (bus_dmamap_load_mem(dmat, map, &mem, callback, callback_arg, flags)); } #endif diff --git a/sys/cam/cam.h b/sys/cam/cam.h index 963c9798ddbc..83c1fc7b35ca 100644 --- a/sys/cam/cam.h +++ b/sys/cam/cam.h @@ -1,421 +1,426 @@ /*- * Data structures and definitions for the CAM system. * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _CAM_CAM_H #define _CAM_CAM_H 1 #ifdef _KERNEL #include "opt_cam.h" #endif #ifndef _KERNEL #include #include #endif typedef u_int path_id_t; typedef u_int target_id_t; typedef uint64_t lun_id_t; #define CAM_XPT_PATH_ID ((path_id_t)~0) #define CAM_BUS_WILDCARD ((path_id_t)~0) #define CAM_TARGET_WILDCARD ((target_id_t)~0) #define CAM_LUN_WILDCARD (~(u_int)0) #define CAM_EXTLUN_BYTE_SWIZZLE(lun) ( \ ((((uint64_t)lun) & 0xffff000000000000L) >> 48) | \ ((((uint64_t)lun) & 0x0000ffff00000000L) >> 16) | \ ((((uint64_t)lun) & 0x00000000ffff0000L) << 16) | \ ((((uint64_t)lun) & 0x000000000000ffffL) << 48)) /* * Maximum length for a CAM CDB. */ #define CAM_MAX_CDBLEN 16 /* * Definition of a CAM peripheral driver entry. Peripheral drivers instantiate * one of these for each device they wish to communicate with and pass it into * the xpt layer when they wish to schedule work on that device via the * xpt_schedule API. */ struct cam_periph; /* * Priority information for a CAM structure. */ typedef enum { CAM_RL_HOST, CAM_RL_BUS, CAM_RL_XPT, CAM_RL_DEV, CAM_RL_NORMAL, CAM_RL_VALUES } cam_rl; /* * The generation number is incremented every time a new entry is entered into * the queue giving round robin per priority level scheduling. */ typedef struct { uint32_t priority; #define CAM_PRIORITY_HOST ((CAM_RL_HOST << 8) + 0x80) #define CAM_PRIORITY_BUS ((CAM_RL_BUS << 8) + 0x80) #define CAM_PRIORITY_XPT ((CAM_RL_XPT << 8) + 0x80) #define CAM_PRIORITY_DEV ((CAM_RL_DEV << 8) + 0x80) #define CAM_PRIORITY_OOB (CAM_RL_DEV << 8) #define CAM_PRIORITY_NORMAL ((CAM_RL_NORMAL << 8) + 0x80) #define CAM_PRIORITY_NONE (uint32_t)-1 uint32_t generation; int index; #define CAM_UNQUEUED_INDEX -1 #define CAM_ACTIVE_INDEX -2 #define CAM_DONEQ_INDEX -3 #define CAM_ASYNC_INDEX -4 #define CAM_EXTRAQ_INDEX INT_MAX } cam_pinfo; /* * Macro to compare two generation numbers. It is used like this: * * if (GENERATIONCMP(a, >=, b)) * ...; * * GERERATIONCMP uses modular arithmetic to guard against wraps * wraps in the generation number. */ #define GENERATIONCMP(x, op, y) ((int32_t)((x) - (y)) op 0) /* CAM flags XXX Move to cam_periph.h ??? */ typedef enum { CAM_FLAG_NONE = 0x00, CAM_EXPECT_INQ_CHANGE = 0x01, CAM_RETRY_SELTO = 0x02 /* Retry Selection Timeouts */ } cam_flags; enum { SF_RETRY_UA = 0x01, /* Retry UNIT ATTENTION conditions. */ SF_NO_PRINT = 0x02, /* Never print error status. */ SF_QUIET_IR = 0x04, /* Be quiet about Illegal Request responses */ SF_PRINT_ALWAYS = 0x08, /* Always print error status. */ SF_NO_RECOVERY = 0x10, /* Don't do active error recovery. */ SF_NO_RETRY = 0x20, /* Don't do any retries. */ SF_RETRY_BUSY = 0x40 /* Retry BUSY status. */ }; /* CAM Status field values */ typedef enum { /* CCB request is in progress */ CAM_REQ_INPROG = 0x00, /* CCB request completed without error */ CAM_REQ_CMP = 0x01, /* CCB request aborted by the host */ CAM_REQ_ABORTED = 0x02, /* Unable to abort CCB request */ CAM_UA_ABORT = 0x03, /* CCB request completed with an error */ CAM_REQ_CMP_ERR = 0x04, /* CAM subsystem is busy */ CAM_BUSY = 0x05, /* CCB request was invalid */ CAM_REQ_INVALID = 0x06, /* Supplied Path ID is invalid */ CAM_PATH_INVALID = 0x07, /* SCSI Device Not Installed/there */ CAM_DEV_NOT_THERE = 0x08, /* Unable to terminate I/O CCB request */ CAM_UA_TERMIO = 0x09, /* Target Selection Timeout */ CAM_SEL_TIMEOUT = 0x0a, /* Command timeout */ CAM_CMD_TIMEOUT = 0x0b, /* SCSI error, look at error code in CCB */ CAM_SCSI_STATUS_ERROR = 0x0c, /* Message Reject Received */ CAM_MSG_REJECT_REC = 0x0d, /* SCSI Bus Reset Sent/Received */ CAM_SCSI_BUS_RESET = 0x0e, /* Uncorrectable parity error occurred */ CAM_UNCOR_PARITY = 0x0f, /* Autosense: request sense cmd fail */ CAM_AUTOSENSE_FAIL = 0x10, /* No HBA Detected error */ CAM_NO_HBA = 0x11, /* Data Overrun error */ CAM_DATA_RUN_ERR = 0x12, /* Unexpected Bus Free */ CAM_UNEXP_BUSFREE = 0x13, /* Target Bus Phase Sequence Failure */ CAM_SEQUENCE_FAIL = 0x14, /* CCB length supplied is inadequate */ CAM_CCB_LEN_ERR = 0x15, /* Unable to provide requested capability*/ CAM_PROVIDE_FAIL = 0x16, /* A SCSI BDR msg was sent to target */ CAM_BDR_SENT = 0x17, /* CCB request terminated by the host */ CAM_REQ_TERMIO = 0x18, /* Unrecoverable Host Bus Adapter Error */ CAM_UNREC_HBA_ERROR = 0x19, /* Request was too large for this host */ CAM_REQ_TOO_BIG = 0x1a, /* * This request should be requeued to preserve * transaction ordering. This typically occurs * when the SIM recognizes an error that should * freeze the queue and must place additional * requests for the target at the sim level * back into the XPT queue. */ CAM_REQUEUE_REQ = 0x1b, /* ATA error, look at error code in CCB */ CAM_ATA_STATUS_ERROR = 0x1c, /* Initiator/Target Nexus lost. */ CAM_SCSI_IT_NEXUS_LOST = 0x1d, /* SMP error, look at error code in CCB */ CAM_SMP_STATUS_ERROR = 0x1e, /* * Command completed without error but exceeded the soft * timeout threshold. */ CAM_REQ_SOFTTIMEOUT = 0x1f, /* * NVME error, look at errro code in CCB */ CAM_NVME_STATUS_ERROR = 0x20, /* * 0x21 - 0x32 are unassigned */ /* Initiator Detected Error */ CAM_IDE = 0x33, /* Resource Unavailable */ CAM_RESRC_UNAVAIL = 0x34, /* Unacknowledged Event by Host */ CAM_UNACKED_EVENT = 0x35, /* Message Received in Host Target Mode */ CAM_MESSAGE_RECV = 0x36, /* Invalid CDB received in Host Target Mode */ CAM_INVALID_CDB = 0x37, /* Lun supplied is invalid */ CAM_LUN_INVALID = 0x38, /* Target ID supplied is invalid */ CAM_TID_INVALID = 0x39, /* The requested function is not available */ CAM_FUNC_NOTAVAIL = 0x3a, /* Nexus is not established */ CAM_NO_NEXUS = 0x3b, /* The initiator ID is invalid */ CAM_IID_INVALID = 0x3c, /* The SCSI CDB has been received */ CAM_CDB_RECVD = 0x3d, /* The LUN is already enabled for target mode */ CAM_LUN_ALRDY_ENA = 0x3e, /* SCSI Bus Busy */ CAM_SCSI_BUSY = 0x3f, /* * Flags */ /* The DEV queue is frozen w/this err */ CAM_DEV_QFRZN = 0x40, /* Autosense data valid for target */ CAM_AUTOSNS_VALID = 0x80, /* SIM ready to take more commands */ CAM_RELEASE_SIMQ = 0x100, /* SIM has this command in its queue */ CAM_SIM_QUEUED = 0x200, /* Quality of service data is valid */ CAM_QOS_VALID = 0x400, /* Mask bits for just the status # */ CAM_STATUS_MASK = 0x3F, /* * Target Specific Adjunct Status */ /* sent sense with status */ CAM_SENT_SENSE = 0x40000000 } cam_status; typedef enum { CAM_ESF_NONE = 0x00, CAM_ESF_COMMAND = 0x01, CAM_ESF_CAM_STATUS = 0x02, CAM_ESF_PROTO_STATUS = 0x04, CAM_ESF_ALL = 0xff } cam_error_string_flags; typedef enum { CAM_EPF_NONE = 0x00, CAM_EPF_MINIMAL = 0x01, CAM_EPF_NORMAL = 0x02, CAM_EPF_ALL = 0x03, CAM_EPF_LEVEL_MASK = 0x0f /* All bits above bit 3 are protocol-specific */ } cam_error_proto_flags; typedef enum { CAM_ESF_PRINT_NONE = 0x00, CAM_ESF_PRINT_STATUS = 0x10, CAM_ESF_PRINT_SENSE = 0x20 } cam_error_scsi_flags; typedef enum { CAM_ESMF_PRINT_NONE = 0x00, CAM_ESMF_PRINT_STATUS = 0x10, CAM_ESMF_PRINT_FULL_CMD = 0x20, } cam_error_smp_flags; typedef enum { CAM_EAF_PRINT_NONE = 0x00, CAM_EAF_PRINT_STATUS = 0x10, CAM_EAF_PRINT_RESULT = 0x20 } cam_error_ata_flags; +typedef enum { + CAM_ENF_PRINT_NONE = 0x00, + CAM_ENF_PRINT_STATUS = 0x10, +} cam_error_nvme_flags; + typedef enum { CAM_STRVIS_FLAG_NONE = 0x00, CAM_STRVIS_FLAG_NONASCII_MASK = 0x03, CAM_STRVIS_FLAG_NONASCII_TRIM = 0x00, CAM_STRVIS_FLAG_NONASCII_RAW = 0x01, CAM_STRVIS_FLAG_NONASCII_SPC = 0x02, CAM_STRVIS_FLAG_NONASCII_ESC = 0x03 } cam_strvis_flags; struct cam_status_entry { cam_status status_code; const char *status_text; }; extern const struct cam_status_entry cam_status_table[]; extern const int num_cam_status_entries; #ifdef _KERNEL extern int cam_sort_io_queues; #endif union ccb; struct sbuf; #ifdef SYSCTL_DECL /* from sysctl.h */ SYSCTL_DECL(_kern_cam); #endif __BEGIN_DECLS typedef int (cam_quirkmatch_t)(caddr_t, caddr_t); caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, int entry_size, cam_quirkmatch_t *comp_func); void cam_strvis(uint8_t *dst, const uint8_t *src, int srclen, int dstlen); void cam_strvis_flag(uint8_t *dst, const uint8_t *src, int srclen, int dstlen, uint32_t flags); void cam_strvis_sbuf(struct sbuf *sb, const uint8_t *src, int srclen, uint32_t flags); int cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len); const struct cam_status_entry* cam_fetch_status_entry(cam_status status); #ifdef _KERNEL char * cam_error_string(union ccb *ccb, char *str, int str_len, cam_error_string_flags flags, cam_error_proto_flags proto_flags); void cam_error_print(union ccb *ccb, cam_error_string_flags flags, cam_error_proto_flags proto_flags); #else /* _KERNEL */ struct cam_device; char * cam_error_string(struct cam_device *device, union ccb *ccb, char *str, int str_len, cam_error_string_flags flags, cam_error_proto_flags proto_flags); void cam_error_print(struct cam_device *device, union ccb *ccb, cam_error_string_flags flags, cam_error_proto_flags proto_flags, FILE *ofile); #endif /* _KERNEL */ __END_DECLS #ifdef _KERNEL static __inline void cam_init_pinfo(cam_pinfo *pinfo) { pinfo->priority = CAM_PRIORITY_NONE; pinfo->index = CAM_UNQUEUED_INDEX; } #endif #endif /* _CAM_CAM_H */