cam.c revision 203108
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 203108 2010-01-28 08:41:30Z mav $"); 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> 50195534Sscottl#include <cam/cam_queue.h> 5174840Sken#include <cam/cam_xpt.h> 5274840Sken#endif 5374840Sken 5474840Skenstatic int camstatusentrycomp(const void *key, const void *member); 5574840Sken 5674840Skenconst struct cam_status_entry cam_status_table[] = { 5774840Sken { CAM_REQ_INPROG, "CCB request is in progress" }, 5874840Sken { CAM_REQ_CMP, "CCB request completed without error" }, 5974840Sken { CAM_REQ_ABORTED, "CCB request aborted by the host" }, 6074840Sken { CAM_UA_ABORT, "Unable to abort CCB request" }, 6174840Sken { CAM_REQ_CMP_ERR, "CCB request completed with an error" }, 6274840Sken { CAM_BUSY, "CAM subsytem is busy" }, 6374840Sken { CAM_REQ_INVALID, "CCB request was invalid" }, 6474840Sken { CAM_PATH_INVALID, "Supplied Path ID is invalid" }, 6574840Sken { CAM_DEV_NOT_THERE, "Device Not Present" }, 6674840Sken { CAM_UA_TERMIO, "Unable to terminate I/O CCB request" }, 6774840Sken { CAM_SEL_TIMEOUT, "Selection Timeout" }, 6874840Sken { CAM_CMD_TIMEOUT, "Command timeout" }, 6974840Sken { CAM_SCSI_STATUS_ERROR, "SCSI Status Error" }, 7074840Sken { CAM_MSG_REJECT_REC, "Message Reject Reveived" }, 7174840Sken { CAM_SCSI_BUS_RESET, "SCSI Bus Reset Sent/Received" }, 7274840Sken { CAM_UNCOR_PARITY, "Uncorrectable parity/CRC error" }, 7374840Sken { CAM_AUTOSENSE_FAIL, "Auto-Sense Retrieval Failed" }, 7474840Sken { CAM_NO_HBA, "No HBA Detected" }, 7574840Sken { CAM_DATA_RUN_ERR, "Data Overrun error" }, 7674840Sken { CAM_UNEXP_BUSFREE, "Unexpected Bus Free" }, 7774840Sken { CAM_SEQUENCE_FAIL, "Target Bus Phase Sequence Failure" }, 7874840Sken { CAM_CCB_LEN_ERR, "CCB length supplied is inadequate" }, 7974840Sken { CAM_PROVIDE_FAIL, "Unable to provide requested capability" }, 8074840Sken { CAM_BDR_SENT, "SCSI BDR Message Sent" }, 8174840Sken { CAM_REQ_TERMIO, "CCB request terminated by the host" }, 8274840Sken { CAM_UNREC_HBA_ERROR, "Unrecoverable Host Bus Adapter Error" }, 8374840Sken { CAM_REQ_TOO_BIG, "The request was too large for this host" }, 8474840Sken { CAM_REQUEUE_REQ, "Unconditionally Re-queue Request", }, 85195534Sscottl { CAM_ATA_STATUS_ERROR, "ATA Status Error" }, 8674840Sken { CAM_IDE, "Initiator Detected Error Message Received" }, 8774840Sken { CAM_RESRC_UNAVAIL, "Resource Unavailable" }, 8874840Sken { CAM_UNACKED_EVENT, "Unacknowledged Event by Host" }, 8974840Sken { CAM_MESSAGE_RECV, "Message Received in Host Target Mode" }, 9074840Sken { CAM_INVALID_CDB, "Invalid CDB received in Host Target Mode" }, 9174840Sken { CAM_LUN_INVALID, "Invalid Lun" }, 9274840Sken { CAM_TID_INVALID, "Invalid Target ID" }, 9374840Sken { CAM_FUNC_NOTAVAIL, "Function Not Available" }, 9474840Sken { CAM_NO_NEXUS, "Nexus Not Established" }, 9574840Sken { CAM_IID_INVALID, "Invalid Initiator ID" }, 9674840Sken { CAM_CDB_RECVD, "CDB Received" }, 9774840Sken { CAM_LUN_ALRDY_ENA, "LUN Already Enabled for Target Mode" }, 9874840Sken { CAM_SCSI_BUSY, "SCSI Bus Busy" }, 9974840Sken}; 10074840Sken 10174840Skenconst int num_cam_status_entries = 10274840Sken sizeof(cam_status_table)/sizeof(*cam_status_table); 10374840Sken 10489114Smsmith#ifdef _KERNEL 10589114SmsmithSYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem"); 10689114Smsmith#endif 10789114Smsmith 10839212Sgibbsvoid 10939212Sgibbscam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen) 11039212Sgibbs{ 11139212Sgibbs 11239552Sgibbs /* Trim leading/trailing spaces, nulls. */ 11339212Sgibbs while (srclen > 0 && src[0] == ' ') 11439212Sgibbs src++, srclen--; 11539552Sgibbs while (srclen > 0 11639552Sgibbs && (src[srclen-1] == ' ' || src[srclen-1] == '\0')) 11739212Sgibbs srclen--; 11839212Sgibbs 11939212Sgibbs while (srclen > 0 && dstlen > 1) { 12039212Sgibbs u_int8_t *cur_pos = dst; 12139212Sgibbs 12239212Sgibbs if (*src < 0x20 || *src >= 0x80) { 12339212Sgibbs /* SCSI-II Specifies that these should never occur. */ 12439212Sgibbs /* non-printable character */ 12539212Sgibbs if (dstlen > 4) { 12639212Sgibbs *cur_pos++ = '\\'; 12739212Sgibbs *cur_pos++ = ((*src & 0300) >> 6) + '0'; 12839212Sgibbs *cur_pos++ = ((*src & 0070) >> 3) + '0'; 12939212Sgibbs *cur_pos++ = ((*src & 0007) >> 0) + '0'; 13039212Sgibbs } else { 13139212Sgibbs *cur_pos++ = '?'; 13239212Sgibbs } 13339212Sgibbs } else { 13439212Sgibbs /* normal character */ 13539212Sgibbs *cur_pos++ = *src; 13639212Sgibbs } 13739212Sgibbs src++; 13839212Sgibbs srclen--; 13939212Sgibbs dstlen -= cur_pos - dst; 14039212Sgibbs dst = cur_pos; 14139212Sgibbs } 14239212Sgibbs *dst = '\0'; 14339212Sgibbs} 14439212Sgibbs 14539212Sgibbs/* 14639212Sgibbs * Compare string with pattern, returning 0 on match. 14739212Sgibbs * Short pattern matches trailing blanks in name, 14839212Sgibbs * wildcard '*' in pattern matches rest of name, 14939212Sgibbs * wildcard '?' matches a single non-space character. 15039212Sgibbs */ 15139212Sgibbsint 15239212Sgibbscam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len) 15339212Sgibbs{ 15439212Sgibbs 15539212Sgibbs while (*pattern != '\0'&& str_len > 0) { 15639212Sgibbs 15739212Sgibbs if (*pattern == '*') { 15839212Sgibbs return (0); 15939212Sgibbs } 16039212Sgibbs if ((*pattern != *str) 16139212Sgibbs && (*pattern != '?' || *str == ' ')) { 16239212Sgibbs return (1); 16339212Sgibbs } 16439212Sgibbs pattern++; 16539212Sgibbs str++; 16639212Sgibbs str_len--; 16739212Sgibbs } 168199178Smav while (str_len > 0 && *str == ' ') { 169199178Smav str++; 17039212Sgibbs str_len--; 171199178Smav } 172199178Smav if (str_len > 0 && *str == 0) 173199178Smav str_len = 0; 17439212Sgibbs 17539212Sgibbs return (str_len); 17639212Sgibbs} 17739212Sgibbs 17839212Sgibbscaddr_t 17939212Sgibbscam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, 18039212Sgibbs int entry_size, cam_quirkmatch_t *comp_func) 18139212Sgibbs{ 18239212Sgibbs for (; num_entries > 0; num_entries--, quirk_table += entry_size) { 18339212Sgibbs if ((*comp_func)(target, quirk_table) == 0) 18439212Sgibbs return (quirk_table); 18539212Sgibbs } 18639212Sgibbs return (NULL); 18739212Sgibbs} 18874840Sken 18974840Skenconst struct cam_status_entry* 19074840Skencam_fetch_status_entry(cam_status status) 19174840Sken{ 19274840Sken status &= CAM_STATUS_MASK; 19374840Sken return (bsearch(&status, &cam_status_table, 19474840Sken num_cam_status_entries, 19574840Sken sizeof(*cam_status_table), 19674840Sken camstatusentrycomp)); 19774840Sken} 19874840Sken 19974840Skenstatic int 20074840Skencamstatusentrycomp(const void *key, const void *member) 20174840Sken{ 20274840Sken cam_status status; 20374840Sken const struct cam_status_entry *table_entry; 20474840Sken 20574840Sken status = *(const cam_status *)key; 20674840Sken table_entry = (const struct cam_status_entry *)member; 20774840Sken 20874840Sken return (status - table_entry->status_code); 20974840Sken} 21074840Sken 21174840Sken 21274840Sken#ifdef _KERNEL 21374840Skenchar * 21474840Skencam_error_string(union ccb *ccb, char *str, int str_len, 21574840Sken cam_error_string_flags flags, 21674840Sken cam_error_proto_flags proto_flags) 21774840Sken#else /* !_KERNEL */ 21874840Skenchar * 21974840Skencam_error_string(struct cam_device *device, union ccb *ccb, char *str, 22074840Sken int str_len, cam_error_string_flags flags, 22174840Sken cam_error_proto_flags proto_flags) 22274840Sken#endif /* _KERNEL/!_KERNEL */ 22374840Sken{ 22474840Sken char path_str[64]; 22574840Sken struct sbuf sb; 22674840Sken 22774840Sken if ((ccb == NULL) 22874840Sken || (str == NULL) 22974840Sken || (str_len <= 0)) 23074840Sken return(NULL); 23174840Sken 23274840Sken if (flags == CAM_ESF_NONE) 23374840Sken return(NULL); 23474840Sken 23574840Sken switch (ccb->ccb_h.func_code) { 236198849Smav case XPT_ATA_IO: 237198849Smav switch (proto_flags & CAM_EPF_LEVEL_MASK) { 238198849Smav case CAM_EPF_NONE: 239198849Smav break; 240198849Smav case CAM_EPF_ALL: 241198849Smav case CAM_EPF_NORMAL: 242198849Smav proto_flags |= CAM_EAF_PRINT_RESULT; 243198849Smav /* FALLTHROUGH */ 244198849Smav case CAM_EPF_MINIMAL: 245198849Smav proto_flags |= CAM_EAF_PRINT_STATUS; 246198849Smav /* FALLTHROUGH */ 247198849Smav default: 248198849Smav break; 249198849Smav } 250198849Smav break; 25174840Sken case XPT_SCSI_IO: 25274840Sken switch (proto_flags & CAM_EPF_LEVEL_MASK) { 25374840Sken case CAM_EPF_NONE: 25474840Sken break; 25574840Sken case CAM_EPF_ALL: 25674840Sken case CAM_EPF_NORMAL: 25774840Sken proto_flags |= CAM_ESF_PRINT_SENSE; 25874840Sken /* FALLTHROUGH */ 25974840Sken case CAM_EPF_MINIMAL: 26074840Sken proto_flags |= CAM_ESF_PRINT_STATUS; 261115562Sphk /* FALLTHROUGH */ 26274840Sken default: 26374840Sken break; 26474840Sken } 26574840Sken break; 26674840Sken default: 26774840Sken break; 26874840Sken } 26974840Sken#ifdef _KERNEL 27074840Sken xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str)); 27174840Sken#else /* !_KERNEL */ 27274840Sken cam_path_string(device, path_str, sizeof(path_str)); 27374840Sken#endif /* _KERNEL/!_KERNEL */ 27474840Sken 27574840Sken sbuf_new(&sb, str, str_len, 0); 27674840Sken 27774840Sken if (flags & CAM_ESF_COMMAND) { 27874840Sken sbuf_cat(&sb, path_str); 27974840Sken switch (ccb->ccb_h.func_code) { 280198849Smav case XPT_ATA_IO: 281198849Smav ata_command_sbuf(&ccb->ataio, &sb); 282198849Smav sbuf_printf(&sb, "\n"); 283198849Smav break; 28474840Sken case XPT_SCSI_IO: 28574840Sken#ifdef _KERNEL 28674840Sken scsi_command_string(&ccb->csio, &sb); 28774840Sken#else /* !_KERNEL */ 28874840Sken scsi_command_string(device, &ccb->csio, &sb); 28974840Sken#endif /* _KERNEL/!_KERNEL */ 29074840Sken sbuf_printf(&sb, "\n"); 29174840Sken break; 29274840Sken default: 29374840Sken break; 29474840Sken } 29574840Sken } 29674840Sken 29774840Sken if (flags & CAM_ESF_CAM_STATUS) { 29874840Sken cam_status status; 29974840Sken const struct cam_status_entry *entry; 30074840Sken 30174840Sken sbuf_cat(&sb, path_str); 30274840Sken 30374840Sken status = ccb->ccb_h.status & CAM_STATUS_MASK; 30474840Sken 30574840Sken entry = cam_fetch_status_entry(status); 30674840Sken 30774840Sken if (entry == NULL) 308203108Smav sbuf_printf(&sb, "CAM status: Unknown (%#x)\n", 30974840Sken ccb->ccb_h.status); 31074840Sken else 311203108Smav sbuf_printf(&sb, "CAM status: %s\n", 31274840Sken entry->status_text); 31374840Sken } 31474840Sken 31574840Sken if (flags & CAM_ESF_PROTO_STATUS) { 31674840Sken 31774840Sken switch (ccb->ccb_h.func_code) { 318198849Smav case XPT_ATA_IO: 319198849Smav if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 320198849Smav CAM_ATA_STATUS_ERROR) 321198849Smav break; 322198849Smav if (proto_flags & CAM_EAF_PRINT_STATUS) { 323198849Smav sbuf_cat(&sb, path_str); 324198849Smav ata_status_sbuf(&ccb->ataio, &sb); 325198849Smav sbuf_printf(&sb, "\n"); 326198849Smav } 327198849Smav if (proto_flags & CAM_EAF_PRINT_RESULT) { 328198849Smav sbuf_cat(&sb, path_str); 329198849Smav ata_res_sbuf(&ccb->ataio, &sb); 330198849Smav sbuf_printf(&sb, "\n"); 331198849Smav } 332198849Smav 333198849Smav break; 33474840Sken case XPT_SCSI_IO: 33574840Sken if ((ccb->ccb_h.status & CAM_STATUS_MASK) != 33674840Sken CAM_SCSI_STATUS_ERROR) 33774840Sken break; 33874840Sken 33974840Sken if (proto_flags & CAM_ESF_PRINT_STATUS) { 34074840Sken sbuf_cat(&sb, path_str); 341203108Smav sbuf_printf(&sb, "SCSI status: %s\n", 34274840Sken scsi_status_string(&ccb->csio)); 34374840Sken } 34474840Sken 34574840Sken if ((proto_flags & CAM_ESF_PRINT_SENSE) 34674840Sken && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND) 34774840Sken && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) { 34874840Sken 34974840Sken#ifdef _KERNEL 35074840Sken scsi_sense_sbuf(&ccb->csio, &sb, 35174840Sken SSS_FLAG_NONE); 35274840Sken#else /* !_KERNEL */ 35374840Sken scsi_sense_sbuf(device, &ccb->csio, &sb, 35474840Sken SSS_FLAG_NONE); 35574840Sken#endif /* _KERNEL/!_KERNEL */ 35674840Sken } 35774840Sken break; 35874840Sken default: 35974840Sken break; 36074840Sken } 36174840Sken } 36274840Sken 36374840Sken sbuf_finish(&sb); 36474840Sken 36574840Sken return(sbuf_data(&sb)); 36674840Sken} 36774840Sken 36874840Sken#ifdef _KERNEL 36974840Sken 37074840Skenvoid 37174840Skencam_error_print(union ccb *ccb, cam_error_string_flags flags, 37274840Sken cam_error_proto_flags proto_flags) 37374840Sken{ 37474840Sken char str[512]; 37574840Sken 37674840Sken printf("%s", cam_error_string(ccb, str, sizeof(str), flags, 37774840Sken proto_flags)); 37874840Sken} 37974840Sken 38074840Sken#else /* !_KERNEL */ 38174840Sken 38274840Skenvoid 38374840Skencam_error_print(struct cam_device *device, union ccb *ccb, 38474840Sken cam_error_string_flags flags, cam_error_proto_flags proto_flags, 38574840Sken FILE *ofile) 38674840Sken{ 38774840Sken char str[512]; 38874840Sken 38974840Sken if ((device == NULL) || (ccb == NULL) || (ofile == NULL)) 39074840Sken return; 39174840Sken 39274840Sken fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str), 39374840Sken flags, proto_flags)); 39474840Sken} 39574840Sken 39674840Sken#endif /* _KERNEL/!_KERNEL */ 397116350Snjl 398116350Snjl/* 399116350Snjl * Common calculate geometry fuction 400116350Snjl * 401116350Snjl * Caller should set ccg->volume_size and block_size. 402116350Snjl * The extended parameter should be zero if extended translation 403116350Snjl * should not be used. 404116350Snjl */ 405116350Snjlvoid 406116350Snjlcam_calc_geometry(struct ccb_calc_geometry *ccg, int extended) 407116350Snjl{ 408116350Snjl uint32_t size_mb, secs_per_cylinder; 409116350Snjl 410157854Smjacob if (ccg->block_size == 0) { 411157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 412157854Smjacob return; 413157854Smjacob } 414157854Smjacob size_mb = (1024L * 1024L) / ccg->block_size; 415157854Smjacob if (size_mb == 0) { 416157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 417157854Smjacob return; 418157854Smjacob } 419157854Smjacob size_mb = ccg->volume_size / size_mb; 420116350Snjl if (size_mb > 1024 && extended) { 421116350Snjl ccg->heads = 255; 422116350Snjl ccg->secs_per_track = 63; 423116350Snjl } else { 424116350Snjl ccg->heads = 64; 425116350Snjl ccg->secs_per_track = 32; 426116350Snjl } 427116350Snjl secs_per_cylinder = ccg->heads * ccg->secs_per_track; 428157854Smjacob if (secs_per_cylinder == 0) { 429157854Smjacob ccg->ccb_h.status = CAM_REQ_CMP_ERR; 430157854Smjacob return; 431157854Smjacob } 432116350Snjl ccg->cylinders = ccg->volume_size / secs_per_cylinder; 433116350Snjl ccg->ccb_h.status = CAM_REQ_CMP; 434116350Snjl} 435