cam.c revision 115562
139212Sgibbs/* 239212Sgibbs * Generic utility routines for the Common Access Method layer. 339212Sgibbs * 439212Sgibbs * Copyright (c) 1997 Justin T. Gibbs. 539212Sgibbs * All rights reserved. 639212Sgibbs * 739212Sgibbs * Redistribution and use in source and binary forms, with or without 839212Sgibbs * modification, are permitted provided that the following conditions 939212Sgibbs * are met: 1039212Sgibbs * 1. Redistributions of source code must retain the above copyright 1139212Sgibbs * notice, this list of conditions, and the following disclaimer, 1239212Sgibbs * without modification, immediately at the beginning of the file. 1339212Sgibbs * 2. The name of the author may not be used to endorse or promote products 1439212Sgibbs * derived from this software without specific prior written permission. 1539212Sgibbs * 1639212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2039212Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639212Sgibbs * SUCH DAMAGE. 2739212Sgibbs * 2850477Speter * $FreeBSD: head/sys/cam/cam.c 115562 2003-05-31 20:46:21Z phk $ 2939212Sgibbs */ 3039212Sgibbs#include <sys/param.h> 3139212Sgibbs 3274840Sken#ifdef _KERNEL 3389114Smsmith#include <sys/param.h> 3474840Sken#include <sys/systm.h> 3589114Smsmith#include <sys/kernel.h> 3689114Smsmith#include <sys/sysctl.h> 3774840Sken#else /* _KERNEL */ 3874840Sken#include <stdlib.h> 3974840Sken#include <stdio.h> 4074840Sken#endif /* _KERNEL */ 4174840Sken 4239212Sgibbs#include <cam/cam.h> 4374840Sken#include <cam/cam_ccb.h> 4474840Sken#include <cam/scsi/scsi_all.h> 4574840Sken#include <sys/sbuf.h> 4639212Sgibbs 4774840Sken#ifdef _KERNEL 4874840Sken#include <sys/libkern.h> 4974840Sken#include <cam/cam_xpt.h> 5074840Sken#endif 5174840Sken 5274840Skenstatic int camstatusentrycomp(const void *key, const void *member); 5374840Sken 5474840Skenconst struct cam_status_entry cam_status_table[] = { 5574840Sken { CAM_REQ_INPROG, "CCB request is in progress" }, 5674840Sken { CAM_REQ_CMP, "CCB request completed without error" }, 5774840Sken { CAM_REQ_ABORTED, "CCB request aborted by the host" }, 5874840Sken { CAM_UA_ABORT, "Unable to abort CCB request" }, 5974840Sken { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, 6074840Sken { CAM_BUSY, "CAM subsytem is busy" }, 6174840Sken { CAM_REQ_INVALID, "CCB request was invalid" }, 6274840Sken { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, 6374840Sken { CAM_DEV_NOT_THERE, "Device Not Present" }, 6474840Sken { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, 6574840Sken { CAM_SEL_TIMEOUT, "Selection Timeout" }, 6674840Sken { CAM_CMD_TIMEOUT, "Command timeout" }, 6774840Sken { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, 6874840Sken { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, 6974840Sken { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, 7074840Sken { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, 7174840Sken { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, 7274840Sken { CAM_NO_HBA, "No HBA Detected" }, 7374840Sken { CAM_DATA_RUN_ERR, "Data Overrun error" }, 7474840Sken { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, 7574840Sken { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, 7674840Sken { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, 7774840Sken { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, 7874840Sken { CAM_BDR_SENT, "SCSI BDR Message Sent" }, 7974840Sken { CAM_REQ_TERMIO, "CCB request terminated by the host" }, 8074840Sken { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, 8174840Sken { CAM_REQ_TOO_BIG, "The request was too large for this host" }, 8274840Sken { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, 8374840Sken { CAM_IDE, "Initiator Detected Error Message Received" }, 8474840Sken { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, 8574840Sken { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, 8674840Sken { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, 8774840Sken { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, 8874840Sken { CAM_LUN_INVALID, "Invalid Lun" }, 8974840Sken { CAM_TID_INVALID, "Invalid Target ID" }, 9074840Sken { CAM_FUNC_NOTAVAIL, "Function Not Available" }, 9174840Sken { CAM_NO_NEXUS, "Nexus Not Established" }, 9274840Sken { CAM_IID_INVALID, "Invalid Initiator ID" }, 9374840Sken { CAM_CDB_RECVD, "CDB Received" }, 9474840Sken { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, 9574840Sken { CAM_SCSI_BUSY, "SCSI Bus Busy" }, 9674840Sken}; 9774840Sken 9874840Skenconst int num_cam_status_entries = 9974840Sken sizeof(cam_status_table)/sizeof(*cam_status_table); 10074840Sken 10189114Smsmith#ifdef _KERNEL 10289114SmsmithSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 10389114Smsmith#endif 10489114Smsmith 10539212Sgibbsvoid 10639212Sgibbscam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) 10739212Sgibbs{ 10839212Sgibbs 10939552Sgibbs /* Trim leading/trailing spaces, nulls. */ 11039212Sgibbs while (srclen > 0 && src[0] == ' ') 11139212Sgibbs src++, srclen--; 11239552Sgibbs while (srclen > 0 11339552Sgibbs && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) 11439212Sgibbs srclen--; 11539212Sgibbs 11639212Sgibbs while (srclen > 0 && dstlen > 1) { 11739212Sgibbs u_int8_t *cur_pos = dst; 11839212Sgibbs 11939212Sgibbs if (*src < 0x20 || *src >= 0x80) { 12039212Sgibbs /* SCSI-II Specifies that these should never occur. */ 12139212Sgibbs /* non-printable character */ 12239212Sgibbs if (dstlen > 4) { 12339212Sgibbs *cur_pos++ = '\\'; 12439212Sgibbs *cur_pos++ = ((*src & 0300) >> 6) + '0'; 12539212Sgibbs *cur_pos++ = ((*src & 0070) >> 3) + '0'; 12639212Sgibbs *cur_pos++ = ((*src & 0007) >> 0) + '0'; 12739212Sgibbs } else { 12839212Sgibbs *cur_pos++ = '?'; 12939212Sgibbs } 13039212Sgibbs } else { 13139212Sgibbs /* normal character */ 13239212Sgibbs *cur_pos++ = *src; 13339212Sgibbs } 13439212Sgibbs src++; 13539212Sgibbs srclen--; 13639212Sgibbs dstlen -= cur_pos - dst; 13739212Sgibbs dst = cur_pos; 13839212Sgibbs } 13939212Sgibbs *dst = '\0'; 14039212Sgibbs} 14139212Sgibbs 14239212Sgibbs/* 14339212Sgibbs * Compare string with pattern, returning 0 on match. 14439212Sgibbs * Short pattern matches trailing blanks in name, 14539212Sgibbs * wildcard '*' in pattern matches rest of name, 14639212Sgibbs * wildcard '?' matches a single non-space character. 14739212Sgibbs */ 14839212Sgibbsint 14939212Sgibbscam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len) 15039212Sgibbs{ 15139212Sgibbs 15239212Sgibbs while (*pattern != '\0'&& str_len > 0) { 15339212Sgibbs 15439212Sgibbs if (*pattern == '*') { 15539212Sgibbs return (0); 15639212Sgibbs } 15739212Sgibbs if ((*pattern != *str) 15839212Sgibbs && (*pattern != '?' || *str == ' ')) { 15939212Sgibbs return (1); 16039212Sgibbs } 16139212Sgibbs pattern++; 16239212Sgibbs str++; 16339212Sgibbs str_len--; 16439212Sgibbs } 16539212Sgibbs while (str_len > 0 && *str++ == ' ') 16639212Sgibbs str_len--; 16739212Sgibbs 16839212Sgibbs return (str_len); 16939212Sgibbs} 17039212Sgibbs 17139212Sgibbscaddr_t 17239212Sgibbscam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, 17339212Sgibbs int entry_size, cam_quirkmatch_t *comp_func) 17439212Sgibbs{ 17539212Sgibbs for (; num_entries > 0; num_entries--, quirk_table += entry_size) { 17639212Sgibbs if ((*comp_func)(target, quirk_table) == 0) 17739212Sgibbs return (quirk_table); 17839212Sgibbs } 17939212Sgibbs return (NULL); 18039212Sgibbs} 18174840Sken 18274840Skenconst struct cam_status_entry* 18374840Skencam_fetch_status_entry(cam_status status) 18474840Sken{ 18574840Sken status &= CAM_STATUS_MASK; 18674840Sken return (bsearch(&status, &cam_status_table, 18774840Sken num_cam_status_entries, 18874840Sken sizeof(*cam_status_table), 18974840Sken camstatusentrycomp)); 19074840Sken} 19174840Sken 19274840Skenstatic int 19374840Skencamstatusentrycomp(const void *key, const void *member) 19474840Sken{ 19574840Sken cam_status status; 19674840Sken const struct cam_status_entry *table_entry; 19774840Sken 19874840Sken status = *(const cam_status *)key; 19974840Sken table_entry = (const struct cam_status_entry *)member; 20074840Sken 20174840Sken return (status - table_entry->status_code); 20274840Sken} 20374840Sken 20474840Sken 20574840Sken#ifdef _KERNEL 20674840Skenchar * 20774840Skencam_error_string(union ccb *ccb, char *str, int str_len, 20874840Sken cam_error_string_flags flags, 20974840Sken cam_error_proto_flags proto_flags) 21074840Sken#else /* !_KERNEL */ 21174840Skenchar * 21274840Skencam_error_string(struct cam_device *device, union ccb *ccb, char *str, 21374840Sken int str_len, cam_error_string_flags flags, 21474840Sken cam_error_proto_flags proto_flags) 21574840Sken#endif /* _KERNEL/!_KERNEL */ 21674840Sken{ 21774840Sken char path_str[64]; 21874840Sken struct sbuf sb; 21974840Sken 22074840Sken if ((ccb == NULL) 22174840Sken || (str == NULL) 22274840Sken || (str_len <= 0)) 22374840Sken return(NULL); 22474840Sken 22574840Sken if (flags == CAM_ESF_NONE) 22674840Sken return(NULL); 22774840Sken 22874840Sken switch (ccb->ccb_h.func_code) { 22974840Sken case XPT_SCSI_IO: 23074840Sken switch (proto_flags & CAM_EPF_LEVEL_MASK) { 23174840Sken case CAM_EPF_NONE: 23274840Sken break; 23374840Sken case CAM_EPF_ALL: 23474840Sken case CAM_EPF_NORMAL: 23574840Sken proto_flags |= CAM_ESF_PRINT_SENSE; 23674840Sken /* FALLTHROUGH */ 23774840Sken case CAM_EPF_MINIMAL: 23874840Sken proto_flags |= CAM_ESF_PRINT_STATUS; 239115562Sphk /* FALLTHROUGH */ 24074840Sken default: 24174840Sken break; 24274840Sken } 24374840Sken break; 24474840Sken default: 24574840Sken break; 24674840Sken } 24774840Sken#ifdef _KERNEL 24874840Sken xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); 24974840Sken#else /* !_KERNEL */ 25074840Sken cam_path_string(device, path_str, sizeof(path_str)); 25174840Sken#endif /* _KERNEL/!_KERNEL */ 25274840Sken 25374840Sken sbuf_new(&sb, str, str_len, 0); 25474840Sken 25574840Sken if (flags & CAM_ESF_COMMAND) { 25674840Sken 25774840Sken sbuf_cat(&sb, path_str); 25874840Sken 25974840Sken switch (ccb->ccb_h.func_code) { 26074840Sken case XPT_SCSI_IO: 26174840Sken#ifdef _KERNEL 26274840Sken scsi_command_string(&ccb->csio, &sb); 26374840Sken#else /* !_KERNEL */ 26474840Sken scsi_command_string(device, &ccb->csio, &sb); 26574840Sken#endif /* _KERNEL/!_KERNEL */ 26674840Sken sbuf_printf(&sb, "\n"); 26774840Sken 26874840Sken break; 26974840Sken default: 27074840Sken break; 27174840Sken } 27274840Sken } 27374840Sken 27474840Sken if (flags & CAM_ESF_CAM_STATUS) { 27574840Sken cam_status status; 27674840Sken const struct cam_status_entry *entry; 27774840Sken 27874840Sken sbuf_cat(&sb, path_str); 27974840Sken 28074840Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 28174840Sken 28274840Sken entry = cam_fetch_status_entry(status); 28374840Sken 28474840Sken if (entry == NULL) 28574840Sken sbuf_printf(&sb, "CAM Status: Unknown (%#x)\n", 28674840Sken ccb->ccb_h.status); 28774840Sken else 28874840Sken sbuf_printf(&sb, "CAM Status: %s\n", 28974840Sken entry->status_text); 29074840Sken } 29174840Sken 29274840Sken if (flags & CAM_ESF_PROTO_STATUS) { 29374840Sken 29474840Sken switch (ccb->ccb_h.func_code) { 29574840Sken case XPT_SCSI_IO: 29674840Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 29774840Sken CAM_SCSI_STATUS_ERROR) 29874840Sken break; 29974840Sken 30074840Sken if (proto_flags & CAM_ESF_PRINT_STATUS) { 30174840Sken sbuf_cat(&sb, path_str); 30274840Sken /* 30374840Sken * Print out the SCSI status byte as long as 30474840Sken * the user wants some protocol output. 30574840Sken */ 30674840Sken sbuf_printf(&sb, "SCSI Status: %s\n", 30774840Sken scsi_status_string(&ccb->csio)); 30874840Sken } 30974840Sken 31074840Sken if ((proto_flags & CAM_ESF_PRINT_SENSE) 31174840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 31274840Sken && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { 31374840Sken 31474840Sken#ifdef _KERNEL 31574840Sken scsi_sense_sbuf(&ccb->csio, &sb, 31674840Sken SSS_FLAG_NONE); 31774840Sken#else /* !_KERNEL */ 31874840Sken scsi_sense_sbuf(device, &ccb->csio, &sb, 31974840Sken SSS_FLAG_NONE); 32074840Sken#endif /* _KERNEL/!_KERNEL */ 32174840Sken } 32274840Sken break; 32374840Sken default: 32474840Sken break; 32574840Sken } 32674840Sken } 32774840Sken 32874840Sken sbuf_finish(&sb); 32974840Sken 33074840Sken return(sbuf_data(&sb)); 33174840Sken} 33274840Sken 33374840Sken#ifdef _KERNEL 33474840Sken 33574840Skenvoid 33674840Skencam_error_print(union ccb *ccb, cam_error_string_flags flags, 33774840Sken cam_error_proto_flags proto_flags) 33874840Sken{ 33974840Sken char str[512]; 34074840Sken 34174840Sken printf("%s", cam_error_string(ccb, str, sizeof(str), flags, 34274840Sken proto_flags)); 34374840Sken} 34474840Sken 34574840Sken#else /* !_KERNEL */ 34674840Sken 34774840Skenvoid 34874840Skencam_error_print(struct cam_device *device, union ccb *ccb, 34974840Sken cam_error_string_flags flags, cam_error_proto_flags proto_flags, 35074840Sken FILE *ofile) 35174840Sken{ 35274840Sken char str[512]; 35374840Sken 35474840Sken if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) 35574840Sken return; 35674840Sken 35774840Sken fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), 35874840Sken flags, proto_flags)); 35974840Sken} 36074840Sken 36174840Sken#endif /* _KERNEL/!_KERNEL */ 362