xref: /freebsd/sys/cam/cam.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
1 /*
2  * Generic utility routines for the Common Access Method layer.
3  *
4  * Copyright (c) 1997 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 #include <sys/param.h>
31 
32 #ifdef _KERNEL
33 #include <sys/systm.h>
34 #else /* _KERNEL */
35 #include <stdlib.h>
36 #include <stdio.h>
37 #endif /* _KERNEL */
38 
39 #include <cam/cam.h>
40 #include <cam/cam_ccb.h>
41 #include <cam/scsi/scsi_all.h>
42 #include <sys/sbuf.h>
43 
44 #ifdef _KERNEL
45 #include <sys/libkern.h>
46 #include <cam/cam_xpt.h>
47 #endif
48 
49 static int	camstatusentrycomp(const void *key, const void *member);
50 
51 const struct cam_status_entry cam_status_table[] = {
52 	{ CAM_REQ_INPROG,	 "CCB request is in progress"		     },
53 	{ CAM_REQ_CMP,		 "CCB request completed without error"	     },
54 	{ CAM_REQ_ABORTED,	 "CCB request aborted by the host"	     },
55 	{ CAM_UA_ABORT,		 "Unable to abort CCB request"		     },
56 	{ CAM_REQ_CMP_ERR,	 "CCB request completed with an error"	     },
57 	{ CAM_BUSY,		 "CAM subsytem is busy"			     },
58 	{ CAM_REQ_INVALID,	 "CCB request was invalid"		     },
59 	{ CAM_PATH_INVALID,	 "Supplied Path ID is invalid"		     },
60 	{ CAM_DEV_NOT_THERE,	 "Device Not Present"			     },
61 	{ CAM_UA_TERMIO,	 "Unable to terminate I/O CCB request"	     },
62 	{ CAM_SEL_TIMEOUT,	 "Selection Timeout"			     },
63 	{ CAM_CMD_TIMEOUT,	 "Command timeout"			     },
64 	{ CAM_SCSI_STATUS_ERROR, "SCSI Status Error"			     },
65 	{ CAM_MSG_REJECT_REC,	 "Message Reject Reveived"		     },
66 	{ CAM_SCSI_BUS_RESET,	 "SCSI Bus Reset Sent/Received"		     },
67 	{ CAM_UNCOR_PARITY,	 "Uncorrectable parity/CRC error"	     },
68 	{ CAM_AUTOSENSE_FAIL,	 "Auto-Sense Retrieval Failed"		     },
69 	{ CAM_NO_HBA,		 "No HBA Detected"			     },
70 	{ CAM_DATA_RUN_ERR,	 "Data Overrun error"			     },
71 	{ CAM_UNEXP_BUSFREE,	 "Unexpected Bus Free"			     },
72 	{ CAM_SEQUENCE_FAIL,	 "Target Bus Phase Sequence Failure"	     },
73 	{ CAM_CCB_LEN_ERR,	 "CCB length supplied is inadequate"	     },
74 	{ CAM_PROVIDE_FAIL,	 "Unable to provide requested capability"    },
75 	{ CAM_BDR_SENT,		 "SCSI BDR Message Sent"		     },
76 	{ CAM_REQ_TERMIO,	 "CCB request terminated by the host"	     },
77 	{ CAM_UNREC_HBA_ERROR,	 "Unrecoverable Host Bus Adapter Error"	     },
78 	{ CAM_REQ_TOO_BIG,	 "The request was too large for this host"   },
79 	{ CAM_REQUEUE_REQ,	 "Unconditionally Re-queue Request",	     },
80 	{ CAM_IDE,		 "Initiator Detected Error Message Received" },
81 	{ CAM_RESRC_UNAVAIL,	 "Resource Unavailable"			     },
82 	{ CAM_UNACKED_EVENT,	 "Unacknowledged Event by Host"		     },
83 	{ CAM_MESSAGE_RECV,	 "Message Received in Host Target Mode"	     },
84 	{ CAM_INVALID_CDB,	 "Invalid CDB received in Host Target Mode"  },
85 	{ CAM_LUN_INVALID,	 "Invalid Lun"				     },
86 	{ CAM_TID_INVALID,	 "Invalid Target ID"			     },
87 	{ CAM_FUNC_NOTAVAIL,	 "Function Not Available"		     },
88 	{ CAM_NO_NEXUS,		 "Nexus Not Established"		     },
89 	{ CAM_IID_INVALID,	 "Invalid Initiator ID"			     },
90 	{ CAM_CDB_RECVD,	 "CDB Received"				     },
91 	{ CAM_LUN_ALRDY_ENA,	 "LUN Already Enabled for Target Mode"	     },
92 	{ CAM_SCSI_BUSY,	 "SCSI Bus Busy"			     },
93 };
94 
95 const int num_cam_status_entries =
96     sizeof(cam_status_table)/sizeof(*cam_status_table);
97 
98 void
99 cam_strvis(u_int8_t *dst, const u_int8_t *src, int srclen, int dstlen)
100 {
101 
102 	/* Trim leading/trailing spaces, nulls. */
103 	while (srclen > 0 && src[0] == ' ')
104 		src++, srclen--;
105 	while (srclen > 0
106 	    && (src[srclen-1] == ' ' || src[srclen-1] == '\0'))
107 		srclen--;
108 
109 	while (srclen > 0 && dstlen > 1) {
110 		u_int8_t *cur_pos = dst;
111 
112 		if (*src < 0x20 || *src >= 0x80) {
113 			/* SCSI-II Specifies that these should never occur. */
114 			/* non-printable character */
115 			if (dstlen > 4) {
116 				*cur_pos++ = '\\';
117 				*cur_pos++ = ((*src & 0300) >> 6) + '0';
118 				*cur_pos++ = ((*src & 0070) >> 3) + '0';
119 				*cur_pos++ = ((*src & 0007) >> 0) + '0';
120 			} else {
121 				*cur_pos++ = '?';
122 			}
123 		} else {
124 			/* normal character */
125 			*cur_pos++ = *src;
126 		}
127 		src++;
128 		srclen--;
129 		dstlen -= cur_pos - dst;
130 		dst = cur_pos;
131 	}
132 	*dst = '\0';
133 }
134 
135 /*
136  * Compare string with pattern, returning 0 on match.
137  * Short pattern matches trailing blanks in name,
138  * wildcard '*' in pattern matches rest of name,
139  * wildcard '?' matches a single non-space character.
140  */
141 int
142 cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, int str_len)
143 {
144 
145 	while (*pattern != '\0'&& str_len > 0) {
146 
147 		if (*pattern == '*') {
148 			return (0);
149 		}
150 		if ((*pattern != *str)
151 		 && (*pattern != '?' || *str == ' ')) {
152 			return (1);
153 		}
154 		pattern++;
155 		str++;
156 		str_len--;
157 	}
158 	while (str_len > 0 && *str++ == ' ')
159 		str_len--;
160 
161 	return (str_len);
162 }
163 
164 caddr_t
165 cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
166 	       int entry_size, cam_quirkmatch_t *comp_func)
167 {
168 	for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
169 		if ((*comp_func)(target, quirk_table) == 0)
170 			return (quirk_table);
171 	}
172 	return (NULL);
173 }
174 
175 const struct cam_status_entry*
176 cam_fetch_status_entry(cam_status status)
177 {
178 	status &= CAM_STATUS_MASK;
179 	return (bsearch(&status, &cam_status_table,
180 			num_cam_status_entries,
181 			sizeof(*cam_status_table),
182 			camstatusentrycomp));
183 }
184 
185 static int
186 camstatusentrycomp(const void *key, const void *member)
187 {
188 	cam_status status;
189 	const struct cam_status_entry *table_entry;
190 
191 	status = *(const cam_status *)key;
192 	table_entry = (const struct cam_status_entry *)member;
193 
194 	return (status - table_entry->status_code);
195 }
196 
197 
198 #ifdef _KERNEL
199 char *
200 cam_error_string(union ccb *ccb, char *str, int str_len,
201 		 cam_error_string_flags flags,
202 		 cam_error_proto_flags proto_flags)
203 #else /* !_KERNEL */
204 char *
205 cam_error_string(struct cam_device *device, union ccb *ccb, char *str,
206 		 int str_len, cam_error_string_flags flags,
207 		 cam_error_proto_flags proto_flags)
208 #endif /* _KERNEL/!_KERNEL */
209 {
210 	char path_str[64];
211 	struct sbuf sb;
212 
213 	if ((ccb == NULL)
214 	 || (str == NULL)
215 	 || (str_len <= 0))
216 		return(NULL);
217 
218 	if (flags == CAM_ESF_NONE)
219 		return(NULL);
220 
221 	switch (ccb->ccb_h.func_code) {
222 		case XPT_SCSI_IO:
223 			switch (proto_flags & CAM_EPF_LEVEL_MASK) {
224 			case CAM_EPF_NONE:
225 				break;
226 			case CAM_EPF_ALL:
227 			case CAM_EPF_NORMAL:
228 				proto_flags |= CAM_ESF_PRINT_SENSE;
229 				/* FALLTHROUGH */
230 			case CAM_EPF_MINIMAL:
231 				proto_flags |= CAM_ESF_PRINT_STATUS;
232 			default:
233 				break;
234 			}
235 			break;
236 		default:
237 			break;
238 	}
239 #ifdef _KERNEL
240 	xpt_path_string(ccb->csio.ccb_h.path, path_str, sizeof(path_str));
241 #else /* !_KERNEL */
242 	cam_path_string(device, path_str, sizeof(path_str));
243 #endif /* _KERNEL/!_KERNEL */
244 
245 	sbuf_new(&sb, str, str_len, 0);
246 
247 	if (flags & CAM_ESF_COMMAND) {
248 
249 		sbuf_cat(&sb, path_str);
250 
251 		switch (ccb->ccb_h.func_code) {
252 		case XPT_SCSI_IO:
253 #ifdef _KERNEL
254 			scsi_command_string(&ccb->csio, &sb);
255 #else /* !_KERNEL */
256 			scsi_command_string(device, &ccb->csio, &sb);
257 #endif /* _KERNEL/!_KERNEL */
258 			sbuf_printf(&sb, "\n");
259 
260 			break;
261 		default:
262 			break;
263 		}
264 	}
265 
266 	if (flags & CAM_ESF_CAM_STATUS) {
267 		cam_status status;
268 		const struct cam_status_entry *entry;
269 
270 		sbuf_cat(&sb, path_str);
271 
272 		status = ccb->ccb_h.status & CAM_STATUS_MASK;
273 
274 		entry = cam_fetch_status_entry(status);
275 
276 		if (entry == NULL)
277 			sbuf_printf(&sb, "CAM Status: Unknown (%#x)\n",
278 				    ccb->ccb_h.status);
279 		else
280 			sbuf_printf(&sb, "CAM Status: %s\n",
281 				    entry->status_text);
282 	}
283 
284 	if (flags & CAM_ESF_PROTO_STATUS) {
285 
286 		switch (ccb->ccb_h.func_code) {
287 		case XPT_SCSI_IO:
288 			if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
289 			     CAM_SCSI_STATUS_ERROR)
290 				break;
291 
292 			if (proto_flags & CAM_ESF_PRINT_STATUS) {
293 				sbuf_cat(&sb, path_str);
294 				/*
295 				 * Print out the SCSI status byte as long as
296 				 * the user wants some protocol output.
297 				 */
298 				sbuf_printf(&sb, "SCSI Status: %s\n",
299 					    scsi_status_string(&ccb->csio));
300 			}
301 
302 			if ((proto_flags & CAM_ESF_PRINT_SENSE)
303 			 && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
304 			 && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)) {
305 
306 #ifdef _KERNEL
307 				scsi_sense_sbuf(&ccb->csio, &sb,
308 						SSS_FLAG_NONE);
309 #else /* !_KERNEL */
310 				scsi_sense_sbuf(device, &ccb->csio, &sb,
311 						SSS_FLAG_NONE);
312 #endif /* _KERNEL/!_KERNEL */
313 			}
314 			break;
315 		default:
316 			break;
317 		}
318 	}
319 
320 	sbuf_finish(&sb);
321 
322 	return(sbuf_data(&sb));
323 }
324 
325 #ifdef _KERNEL
326 
327 void
328 cam_error_print(union ccb *ccb, cam_error_string_flags flags,
329 		cam_error_proto_flags proto_flags)
330 {
331 	char str[512];
332 
333 	printf("%s", cam_error_string(ccb, str, sizeof(str), flags,
334 	       proto_flags));
335 }
336 
337 #else /* !_KERNEL */
338 
339 void
340 cam_error_print(struct cam_device *device, union ccb *ccb,
341 		cam_error_string_flags flags, cam_error_proto_flags proto_flags,
342 		FILE *ofile)
343 {
344 	char str[512];
345 
346 	if ((device == NULL) || (ccb == NULL) || (ofile == NULL))
347 		return;
348 
349 	fprintf(ofile, "%s", cam_error_string(device, ccb, str, sizeof(str),
350 		flags, proto_flags));
351 }
352 
353 #endif /* _KERNEL/!_KERNEL */
354