cam.c revision 194189
1139743Simp/*- 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 */ 28116161Sobrien 29116161Sobrien#include <sys/cdefs.h> 30116161Sobrien__FBSDID("$FreeBSD: head/sys/cam/cam.c 194189 2009-06-14 12:46:34Z ed $"); 31116161Sobrien 3239212Sgibbs#include <sys/param.h> 3374840Sken#ifdef _KERNEL 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> 40194189Sed#include <camlib.h> 4174840Sken#endif /* _KERNEL */ 4274840Sken 4339212Sgibbs#include <cam/cam.h> 4474840Sken#include <cam/cam_ccb.h> 4574840Sken#include <cam/scsi/scsi_all.h> 4674840Sken#include <sys/sbuf.h> 4739212Sgibbs 4874840Sken#ifdef _KERNEL 4974840Sken#include <sys/libkern.h> 5074840Sken#include <cam/cam_xpt.h> 5174840Sken#endif 5274840Sken 5374840Skenstatic int camstatusentrycomp(const void *key, const void *member); 5474840Sken 5574840Skenconst struct cam_status_entry cam_status_table[] = { 5674840Sken { CAM_REQ_INPROG, "CCB request is in progress" }, 5774840Sken { CAM_REQ_CMP, "CCB request completed without error" }, 5874840Sken { CAM_REQ_ABORTED, "CCB request aborted by the host" }, 5974840Sken { CAM_UA_ABORT, "Unable to abort CCB request" }, 6074840Sken { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, 6174840Sken { CAM_BUSY, "CAM subsytem is busy" }, 6274840Sken { CAM_REQ_INVALID, "CCB request was invalid" }, 6374840Sken { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, 6474840Sken { CAM_DEV_NOT_THERE, "Device Not Present" }, 6574840Sken { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, 6674840Sken { CAM_SEL_TIMEOUT, "Selection Timeout" }, 6774840Sken { CAM_CMD_TIMEOUT, "Command timeout" }, 6874840Sken { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, 6974840Sken { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, 7074840Sken { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, 7174840Sken { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, 7274840Sken { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, 7374840Sken { CAM_NO_HBA, "No HBA Detected" }, 7474840Sken { CAM_DATA_RUN_ERR, "Data Overrun error" }, 7574840Sken { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, 7674840Sken { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, 7774840Sken { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, 7874840Sken { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, 7974840Sken { CAM_BDR_SENT, "SCSI BDR Message Sent" }, 8074840Sken { CAM_REQ_TERMIO, "CCB request terminated by the host" }, 8174840Sken { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, 8274840Sken { CAM_REQ_TOO_BIG, "The request was too large for this host" }, 8374840Sken { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, 8474840Sken { CAM_IDE, "Initiator Detected Error Message Received" }, 8574840Sken { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, 8674840Sken { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, 8774840Sken { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, 8874840Sken { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, 8974840Sken { CAM_LUN_INVALID, "Invalid Lun" }, 9074840Sken { CAM_TID_INVALID, "Invalid Target ID" }, 9174840Sken { CAM_FUNC_NOTAVAIL, "Function Not Available" }, 9274840Sken { CAM_NO_NEXUS, "Nexus Not Established" }, 9374840Sken { CAM_IID_INVALID, "Invalid Initiator ID" }, 9474840Sken { CAM_CDB_RECVD, "CDB Received" }, 9574840Sken { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, 9674840Sken { CAM_SCSI_BUSY, "SCSI Bus Busy" }, 9774840Sken}; 9874840Sken 9974840Skenconst int num_cam_status_entries = 10074840Sken sizeof(cam_status_table)/sizeof(*cam_status_table); 10174840Sken 10289114Smsmith#ifdef _KERNEL 10389114SmsmithSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 10489114Smsmith#endif 10589114Smsmith 10639212Sgibbsvoid 10739212Sgibbscam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) 10839212Sgibbs{ 10939212Sgibbs 11039552Sgibbs /* Trim leading/trailing spaces, nulls. */ 11139212Sgibbs while (srclen > 0 && src[0] == ' ') 11239212Sgibbs src++, srclen--; 11339552Sgibbs while (srclen > 0 11439552Sgibbs && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) 11539212Sgibbs srclen--; 11639212Sgibbs 11739212Sgibbs while (srclen > 0 && dstlen > 1) { 11839212Sgibbs u_int8_t *cur_pos = dst; 11939212Sgibbs 12039212Sgibbs if (*src < 0x20 || *src >= 0x80) { 12139212Sgibbs /* SCSI-II Specifies that these should never occur. */ 12239212Sgibbs /* non-printable character */ 12339212Sgibbs if (dstlen > 4) { 12439212Sgibbs *cur_pos++ = '\\'; 12539212Sgibbs *cur_pos++ = ((*src & 0300) >> 6) + '0'; 12639212Sgibbs *cur_pos++ = ((*src & 0070) >> 3) + '0'; 12739212Sgibbs *cur_pos++ = ((*src & 0007) >> 0) + '0'; 12839212Sgibbs } else { 12939212Sgibbs *cur_pos++ = '?'; 13039212Sgibbs } 13139212Sgibbs } else { 13239212Sgibbs /* normal character */ 13339212Sgibbs *cur_pos++ = *src; 13439212Sgibbs } 13539212Sgibbs src++; 13639212Sgibbs srclen--; 13739212Sgibbs dstlen -= cur_pos - dst; 13839212Sgibbs dst = cur_pos; 13939212Sgibbs } 14039212Sgibbs *dst = '\0'; 14139212Sgibbs} 14239212Sgibbs 14339212Sgibbs/* 14439212Sgibbs * Compare string with pattern, returning 0 on match. 14539212Sgibbs * Short pattern matches trailing blanks in name, 14639212Sgibbs * wildcard '*' in pattern matches rest of name, 14739212Sgibbs * wildcard '?' matches a single non-space character. 14839212Sgibbs */ 14939212Sgibbsint 15039212Sgibbscam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len) 15139212Sgibbs{ 15239212Sgibbs 15339212Sgibbs while (*pattern != '\0'&& str_len > 0) { 15439212Sgibbs 15539212Sgibbs if (*pattern == '*') { 15639212Sgibbs return (0); 15739212Sgibbs } 15839212Sgibbs if ((*pattern != *str) 15939212Sgibbs && (*pattern != '?' || *str == ' ')) { 16039212Sgibbs return (1); 16139212Sgibbs } 16239212Sgibbs pattern++; 16339212Sgibbs str++; 16439212Sgibbs str_len--; 16539212Sgibbs } 16639212Sgibbs while (str_len > 0 && *str++ == ' ') 16739212Sgibbs str_len--; 16839212Sgibbs 16939212Sgibbs return (str_len); 17039212Sgibbs} 17139212Sgibbs 17239212Sgibbscaddr_t 17339212Sgibbscam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, 17439212Sgibbs int entry_size, cam_quirkmatch_t *comp_func) 17539212Sgibbs{ 17639212Sgibbs for (; num_entries > 0; num_entries--, quirk_table += entry_size) { 17739212Sgibbs if ((*comp_func)(target, quirk_table) == 0) 17839212Sgibbs return (quirk_table); 17939212Sgibbs } 18039212Sgibbs return (NULL); 18139212Sgibbs} 18274840Sken 18374840Skenconst struct cam_status_entry* 18474840Skencam_fetch_status_entry(cam_status status) 18574840Sken{ 18674840Sken status &= CAM_STATUS_MASK; 18774840Sken return (bsearch(&status, &cam_status_table, 18874840Sken num_cam_status_entries, 18974840Sken sizeof(*cam_status_table), 19074840Sken camstatusentrycomp)); 19174840Sken} 19274840Sken 19374840Skenstatic int 19474840Skencamstatusentrycomp(const void *key, const void *member) 19574840Sken{ 19674840Sken cam_status status; 19774840Sken const struct cam_status_entry *table_entry; 19874840Sken 19974840Sken status = *(const cam_status *)key; 20074840Sken table_entry = (const struct cam_status_entry *)member; 20174840Sken 20274840Sken return (status - table_entry->status_code); 20374840Sken} 20474840Sken 20574840Sken 20674840Sken#ifdef _KERNEL 20774840Skenchar * 20874840Skencam_error_string(union ccb *ccb, char *str, int str_len, 20974840Sken cam_error_string_flags flags, 21074840Sken cam_error_proto_flags proto_flags) 21174840Sken#else /* !_KERNEL */ 21274840Skenchar * 21374840Skencam_error_string(struct cam_device *device, union ccb *ccb, char *str, 21474840Sken int str_len, cam_error_string_flags flags, 21574840Sken cam_error_proto_flags proto_flags) 21674840Sken#endif /* _KERNEL/!_KERNEL */ 21774840Sken{ 21874840Sken char path_str[64]; 21974840Sken struct sbuf sb; 22074840Sken 22174840Sken if ((ccb == NULL) 22274840Sken || (str == NULL) 22374840Sken || (str_len <= 0)) 22474840Sken return(NULL); 22574840Sken 22674840Sken if (flags == CAM_ESF_NONE) 22774840Sken return(NULL); 22874840Sken 22974840Sken switch (ccb->ccb_h.func_code) { 23074840Sken case XPT_SCSI_IO: 23174840Sken switch (proto_flags & CAM_EPF_LEVEL_MASK) { 23274840Sken case CAM_EPF_NONE: 23374840Sken break; 23474840Sken case CAM_EPF_ALL: 23574840Sken case CAM_EPF_NORMAL: 23674840Sken proto_flags |= CAM_ESF_PRINT_SENSE; 23774840Sken /* FALLTHROUGH */ 23874840Sken case CAM_EPF_MINIMAL: 23974840Sken proto_flags |= CAM_ESF_PRINT_STATUS; 240115562Sphk /* FALLTHROUGH */ 24174840Sken default: 24274840Sken break; 24374840Sken } 24474840Sken break; 24574840Sken default: 24674840Sken break; 24774840Sken } 24874840Sken#ifdef _KERNEL 24974840Sken xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); 25074840Sken#else /* !_KERNEL */ 25174840Sken cam_path_string(device, path_str, sizeof(path_str)); 25274840Sken#endif /* _KERNEL/!_KERNEL */ 25374840Sken 25474840Sken sbuf_new(&sb, str, str_len, 0); 25574840Sken 25674840Sken if (flags & CAM_ESF_COMMAND) { 25774840Sken 25874840Sken sbuf_cat(&sb, path_str); 25974840Sken 26074840Sken switch (ccb->ccb_h.func_code) { 26174840Sken case XPT_SCSI_IO: 26274840Sken#ifdef _KERNEL 26374840Sken scsi_command_string(&ccb->csio, &sb); 26474840Sken#else /* !_KERNEL */ 26574840Sken scsi_command_string(device, &ccb->csio, &sb); 26674840Sken#endif /* _KERNEL/!_KERNEL */ 26774840Sken sbuf_printf(&sb, "\n"); 26874840Sken 26974840Sken break; 27074840Sken default: 27174840Sken break; 27274840Sken } 27374840Sken } 27474840Sken 27574840Sken if (flags & CAM_ESF_CAM_STATUS) { 27674840Sken cam_status status; 27774840Sken const struct cam_status_entry *entry; 27874840Sken 27974840Sken sbuf_cat(&sb, path_str); 28074840Sken 28174840Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 28274840Sken 28374840Sken entry = cam_fetch_status_entry(status); 28474840Sken 28574840Sken if (entry == NULL) 28674840Sken sbuf_printf(&sb, "CAM Status: Unknown (%#x)\n", 28774840Sken ccb->ccb_h.status); 28874840Sken else 28974840Sken sbuf_printf(&sb, "CAM Status: %s\n", 29074840Sken entry->status_text); 29174840Sken } 29274840Sken 29374840Sken if (flags & CAM_ESF_PROTO_STATUS) { 29474840Sken 29574840Sken switch (ccb->ccb_h.func_code) { 29674840Sken case XPT_SCSI_IO: 29774840Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 29874840Sken CAM_SCSI_STATUS_ERROR) 29974840Sken break; 30074840Sken 30174840Sken if (proto_flags & CAM_ESF_PRINT_STATUS) { 30274840Sken sbuf_cat(&sb, path_str); 30374840Sken /* 30474840Sken * Print out the SCSI status byte as long as 30574840Sken * the user wants some protocol output. 30674840Sken */ 30774840Sken sbuf_printf(&sb, "SCSI Status: %s\n", 30874840Sken scsi_status_string(&ccb->csio)); 30974840Sken } 31074840Sken 31174840Sken if ((proto_flags & CAM_ESF_PRINT_SENSE) 31274840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 31374840Sken && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { 31474840Sken 31574840Sken#ifdef _KERNEL 31674840Sken scsi_sense_sbuf(&ccb->csio, &sb, 31774840Sken SSS_FLAG_NONE); 31874840Sken#else /* !_KERNEL */ 31974840Sken scsi_sense_sbuf(device, &ccb->csio, &sb, 32074840Sken SSS_FLAG_NONE); 32174840Sken#endif /* _KERNEL/!_KERNEL */ 32274840Sken } 32374840Sken break; 32474840Sken default: 32574840Sken break; 32674840Sken } 32774840Sken } 32874840Sken 32974840Sken sbuf_finish(&sb); 33074840Sken 33174840Sken return(sbuf_data(&sb)); 33274840Sken} 33374840Sken 33474840Sken#ifdef _KERNEL 33574840Sken 33674840Skenvoid 33774840Skencam_error_print(union ccb *ccb, cam_error_string_flags flags, 33874840Sken cam_error_proto_flags proto_flags) 33974840Sken{ 34074840Sken char str[512]; 34174840Sken 34274840Sken printf("%s", cam_error_string(ccb, str, sizeof(str), flags, 34374840Sken proto_flags)); 34474840Sken} 34574840Sken 34674840Sken#else /* !_KERNEL */ 34774840Sken 34874840Skenvoid 34974840Skencam_error_print(struct cam_device *device, union ccb *ccb, 35074840Sken cam_error_string_flags flags, cam_error_proto_flags proto_flags, 35174840Sken FILE *ofile) 35274840Sken{ 35374840Sken char str[512]; 35474840Sken 35574840Sken if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) 35674840Sken return; 35774840Sken 35874840Sken fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), 35974840Sken flags, proto_flags)); 36074840Sken} 36174840Sken 36274840Sken#endif /* _KERNEL/!_KERNEL */ 363116350Snjl 364116350Snjl/* 365116350Snjl * Common calculate geometry fuction 366116350Snjl * 367116350Snjl * Caller should set ccg->volume_size and block_size. 368116350Snjl * The extended parameter should be zero if extended translation 369116350Snjl * should not be used. 370116350Snjl */ 371116350Snjlvoid 372116350Snjlcam_calc_geometry(struct ccb_calc_geometry *ccg, int extended) 373116350Snjl{ 374116350Snjl uint32_t size_mb, secs_per_cylinder; 375116350Snjl 376157854Smjacob if (ccg->block_size == 0) { 377157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 378157854Smjacob return; 379157854Smjacob } 380157854Smjacob size_mb = (1024L * 1024L) / ccg->block_size; 381157854Smjacob if (size_mb == 0) { 382157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 383157854Smjacob return; 384157854Smjacob } 385157854Smjacob size_mb = ccg->volume_size / size_mb; 386116350Snjl if (size_mb > 1024 && extended) { 387116350Snjl ccg->heads = 255; 388116350Snjl ccg->secs_per_track = 63; 389116350Snjl } else { 390116350Snjl ccg->heads = 64; 391116350Snjl ccg->secs_per_track = 32; 392116350Snjl } 393116350Snjl secs_per_cylinder = ccg->heads * ccg->secs_per_track; 394157854Smjacob if (secs_per_cylinder == 0) { 395157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 396157854Smjacob return; 397157854Smjacob } 398116350Snjl ccg->cylinders = ccg->volume_size / secs_per_cylinder; 399116350Snjl ccg->ccb_h.status = CAM_REQ_CMP; 400116350Snjl} 401