ctl_error.c revision 274732
1248613Sdes/*-
2248613Sdes * Copyright (c) 2003-2009 Silicon Graphics International Corp.
3248613Sdes * Copyright (c) 2011 Spectra Logic Corporation
4248613Sdes * All rights reserved.
5248613Sdes *
6248613Sdes * Redistribution and use in source and binary forms, with or without
7248613Sdes * modification, are permitted provided that the following conditions
8248613Sdes * are met:
9248613Sdes * 1. Redistributions of source code must retain the above copyright
10248613Sdes *    notice, this list of conditions, and the following disclaimer,
11248613Sdes *    without modification.
12248613Sdes * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13248613Sdes *    substantially similar to the "NO WARRANTY" disclaimer below
14248613Sdes *    ("Disclaimer") and any redistribution must be conditioned upon
15248613Sdes *    including a substantially similar Disclaimer requirement for further
16248613Sdes *    binary redistribution.
17296781Sdes *
18248613Sdes * NO WARRANTY
19248613Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20248613Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21295367Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
22248613Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23248613Sdes * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24248613Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25248613Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26248613Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27248613Sdes * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28248613Sdes * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29248613Sdes * POSSIBILITY OF SUCH DAMAGES.
30248613Sdes *
31248613Sdes * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_error.c#2 $
32248613Sdes */
33295367Sdes/*
34295367Sdes * CAM Target Layer error reporting routines.
35295367Sdes *
36248613Sdes * Author: Ken Merry <ken@FreeBSD.org>
37248613Sdes */
38248613Sdes
39295367Sdes#include <sys/cdefs.h>
40295367Sdes__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_error.c 274732 2014-11-20 01:55:12Z mav $");
41248613Sdes
42248613Sdes#include <sys/param.h>
43248613Sdes#include <sys/systm.h>
44248613Sdes#include <sys/kernel.h>
45248613Sdes#include <sys/types.h>
46248613Sdes#include <sys/malloc.h>
47248613Sdes#include <sys/lock.h>
48248613Sdes#include <sys/mutex.h>
49248613Sdes#include <sys/condvar.h>
50248613Sdes#include <sys/stddef.h>
51248613Sdes#include <sys/ctype.h>
52248613Sdes#include <sys/sysctl.h>
53248613Sdes#include <machine/stdarg.h>
54248613Sdes
55248613Sdes#include <cam/scsi/scsi_all.h>
56248613Sdes#include <cam/scsi/scsi_da.h>
57248613Sdes#include <cam/ctl/ctl_io.h>
58248613Sdes#include <cam/ctl/ctl.h>
59248613Sdes#include <cam/ctl/ctl_frontend.h>
60248613Sdes#include <cam/ctl/ctl_frontend_internal.h>
61248613Sdes#include <cam/ctl/ctl_backend.h>
62248613Sdes#include <cam/ctl/ctl_ioctl.h>
63248613Sdes#include <cam/ctl/ctl_error.h>
64248613Sdes#include <cam/ctl/ctl_ha.h>
65248613Sdes#include <cam/ctl/ctl_private.h>
66248613Sdes
67248613Sdesvoid
68248613Sdesctl_set_sense_data_va(struct scsi_sense_data *sense_data, void *lunptr,
69248613Sdes		      scsi_sense_data_type sense_format, int current_error,
70248613Sdes		      int sense_key, int asc, int ascq, va_list ap)
71248613Sdes{
72248613Sdes	struct ctl_lun *lun;
73248613Sdes
74248613Sdes	lun = (struct ctl_lun *)lunptr;
75248613Sdes
76248613Sdes	/*
77295367Sdes	 * Determine whether to return fixed or descriptor format sense
78248613Sdes	 * data.
79248613Sdes	 */
80248613Sdes	if (sense_format == SSD_TYPE_NONE) {
81248613Sdes		/*
82248613Sdes		 * If the format isn't specified, we only return descriptor
83248613Sdes		 * sense if the LUN exists and descriptor sense is turned
84248613Sdes		 * on for that LUN.
85248613Sdes		 */
86295367Sdes		if ((lun != NULL)
87248613Sdes		 && (lun->flags & CTL_LUN_SENSE_DESC))
88248613Sdes			sense_format = SSD_TYPE_DESC;
89248613Sdes		else
90248613Sdes			sense_format = SSD_TYPE_FIXED;
91248613Sdes	}
92248613Sdes
93248613Sdes	scsi_set_sense_data_va(sense_data, sense_format, current_error,
94248613Sdes			       sense_key, asc, ascq, ap);
95248613Sdes}
96248613Sdes
97248613Sdesvoid
98248613Sdesctl_set_sense_data(struct scsi_sense_data *sense_data, void *lunptr,
99248613Sdes		   scsi_sense_data_type sense_format, int current_error,
100248613Sdes		   int sense_key, int asc, int ascq, ...)
101248613Sdes{
102248613Sdes	va_list ap;
103248613Sdes
104248613Sdes	va_start(ap, ascq);
105248613Sdes	ctl_set_sense_data_va(sense_data, lunptr, sense_format, current_error,
106248613Sdes			      sense_key, asc, ascq, ap);
107248613Sdes	va_end(ap);
108248613Sdes}
109248613Sdes
110248613Sdesvoid
111248613Sdesctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key,
112248613Sdes	      int asc, int ascq, ...)
113248613Sdes{
114248613Sdes	va_list ap;
115248613Sdes	struct ctl_lun *lun;
116248613Sdes
117248613Sdes	/*
118248613Sdes	 * The LUN can't go away until all of the commands have been
119248613Sdes	 * completed.  Therefore we can safely access the LUN structure and
120248613Sdes	 * flags without the lock.
121248613Sdes	 */
122248613Sdes	lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
123248613Sdes
124248613Sdes	va_start(ap, ascq);
125248613Sdes	ctl_set_sense_data_va(&ctsio->sense_data,
126248613Sdes			      lun,
127248613Sdes			      SSD_TYPE_NONE,
128248613Sdes			      current_error,
129248613Sdes			      sense_key,
130248613Sdes			      asc,
131248613Sdes			      ascq,
132248613Sdes			      ap);
133248613Sdes	va_end(ap);
134248613Sdes
135248613Sdes	ctsio->scsi_status = SCSI_STATUS_CHECK_COND;
136248613Sdes	ctsio->sense_len = SSD_FULL_SIZE;
137248613Sdes	ctsio->io_hdr.status = CTL_SCSI_ERROR | CTL_AUTOSENSE;
138248613Sdes}
139248613Sdes
140248613Sdes/*
141248613Sdes * Transform fixed sense data into descriptor sense data.
142248613Sdes *
143248613Sdes * For simplicity's sake, we assume that both sense structures are
144248613Sdes * SSD_FULL_SIZE.  Otherwise, the logic gets more complicated.
145248613Sdes */
146248613Sdesvoid
147248613Sdesctl_sense_to_desc(struct scsi_sense_data_fixed *sense_src,
148248613Sdes		  struct scsi_sense_data_desc *sense_dest)
149248613Sdes{
150248613Sdes	struct scsi_sense_stream stream_sense;
151248613Sdes	int current_error;
152248613Sdes	uint8_t stream_bits;
153248613Sdes
154248613Sdes	bzero(sense_dest, sizeof(*sense_dest));
155248613Sdes
156248613Sdes	if ((sense_src->error_code & SSD_ERRCODE) == SSD_DEFERRED_ERROR)
157248613Sdes		current_error = 0;
158248613Sdes	else
159295367Sdes		current_error = 1;
160248613Sdes
161248613Sdes	bzero(&stream_sense, sizeof(stream_sense));
162248613Sdes
163248613Sdes	/*
164248613Sdes	 * Check to see whether any of the tape-specific bits are set.  If
165248613Sdes	 * so, we'll need a stream sense descriptor.
166248613Sdes	 */
167248613Sdes	if (sense_src->flags & (SSD_ILI|SSD_EOM|SSD_FILEMARK))
168248613Sdes		stream_bits = sense_src->flags & ~SSD_KEY;
169248613Sdes	else
170248613Sdes		stream_bits = 0;
171248613Sdes
172248613Sdes	/*
173248613Sdes	 * Utilize our sense setting routine to do the transform.  If a
174248613Sdes	 * value is set in the fixed sense data, set it in the descriptor
175248613Sdes	 * data.  Otherwise, skip it.
176248613Sdes	 */
177248613Sdes	ctl_set_sense_data((struct scsi_sense_data *)sense_dest,
178248613Sdes			   /*lun*/ NULL,
179248613Sdes			   /*sense_format*/ SSD_TYPE_DESC,
180248613Sdes			   current_error,
181248613Sdes			   /*sense_key*/ sense_src->flags & SSD_KEY,
182248613Sdes			   /*asc*/ sense_src->add_sense_code,
183248613Sdes			   /*ascq*/ sense_src->add_sense_code_qual,
184248613Sdes
185248613Sdes			   /* Information Bytes */
186248613Sdes			   (scsi_4btoul(sense_src->info) != 0) ?
187248613Sdes			   SSD_ELEM_INFO : SSD_ELEM_SKIP,
188248613Sdes			   sizeof(sense_src->info),
189248613Sdes			   sense_src->info,
190248613Sdes
191248613Sdes			   /* Command specific bytes */
192248613Sdes			   (scsi_4btoul(sense_src->cmd_spec_info) != 0) ?
193248613Sdes			   SSD_ELEM_COMMAND : SSD_ELEM_SKIP,
194295367Sdes			   sizeof(sense_src->cmd_spec_info),
195248613Sdes			   sense_src->cmd_spec_info,
196248613Sdes
197248613Sdes			   /* FRU */
198248613Sdes			   (sense_src->fru != 0) ?
199295367Sdes			   SSD_ELEM_FRU : SSD_ELEM_SKIP,
200295367Sdes			   sizeof(sense_src->fru),
201248613Sdes			   &sense_src->fru,
202248613Sdes
203248613Sdes			   /* Sense Key Specific */
204248613Sdes			   (sense_src->sense_key_spec[0] & SSD_SCS_VALID) ?
205248613Sdes			   SSD_ELEM_SKS : SSD_ELEM_SKIP,
206248613Sdes			   sizeof(sense_src->sense_key_spec),
207248613Sdes			   sense_src->sense_key_spec,
208295367Sdes
209248613Sdes			   /* Tape bits */
210248613Sdes			   (stream_bits != 0) ?
211248613Sdes			   SSD_ELEM_STREAM : SSD_ELEM_SKIP,
212295367Sdes			   sizeof(stream_bits),
213248613Sdes			   &stream_bits,
214248613Sdes
215248613Sdes			   SSD_ELEM_NONE);
216295367Sdes}
217295367Sdes
218248613Sdes/*
219248613Sdes * Transform descriptor format sense data into fixed sense data.
220248613Sdes *
221248613Sdes * Some data may be lost in translation, because there are descriptors
222248613Sdes * thant can't be represented as fixed sense data.
223248613Sdes *
224248613Sdes * For simplicity's sake, we assume that both sense structures are
225248613Sdes * SSD_FULL_SIZE.  Otherwise, the logic gets more complicated.
226295367Sdes */
227295367Sdesvoid
228295367Sdesctl_sense_to_fixed(struct scsi_sense_data_desc *sense_src,
229295367Sdes		   struct scsi_sense_data_fixed *sense_dest)
230248613Sdes{
231295367Sdes	int current_error;
232248613Sdes	uint8_t *info_ptr = NULL, *cmd_ptr = NULL, *fru_ptr = NULL;
233248613Sdes	uint8_t *sks_ptr = NULL, *stream_ptr = NULL;
234248613Sdes	int info_size = 0, cmd_size = 0, fru_size = 0;
235248613Sdes	int sks_size = 0, stream_size = 0;
236295367Sdes	int pos;
237295367Sdes
238248613Sdes	if ((sense_src->error_code & SSD_ERRCODE) == SSD_DESC_CURRENT_ERROR)
239248613Sdes		current_error = 1;
240248613Sdes	else
241248613Sdes		current_error = 0;
242248613Sdes
243248613Sdes	for (pos = 0; pos < (int)(sense_src->extra_len - 1);) {
244248613Sdes		struct scsi_sense_desc_header *header;
245248613Sdes
246248613Sdes		header = (struct scsi_sense_desc_header *)
247248613Sdes		    &sense_src->sense_desc[pos];
248264377Sdes
249248613Sdes		/*
250248613Sdes		 * See if this record goes past the end of the sense data.
251248613Sdes		 * It shouldn't, but check just in case.
252248613Sdes		 */
253248613Sdes		if ((pos + header->length + sizeof(*header)) >
254248613Sdes		     sense_src->extra_len)
255295367Sdes			break;
256248613Sdes
257248613Sdes		switch (sense_src->sense_desc[pos]) {
258248613Sdes		case SSD_DESC_INFO: {
259248613Sdes			struct scsi_sense_info *info;
260248613Sdes
261248613Sdes			info = (struct scsi_sense_info *)header;
262295367Sdes
263248613Sdes			info_ptr = info->info;
264248613Sdes			info_size = sizeof(info->info);
265248613Sdes
266248613Sdes			pos += info->length +
267248613Sdes			    sizeof(struct scsi_sense_desc_header);
268248613Sdes			break;
269248613Sdes		}
270248613Sdes		case SSD_DESC_COMMAND: {
271248613Sdes			struct scsi_sense_command *cmd;
272248613Sdes
273248613Sdes			cmd = (struct scsi_sense_command *)header;
274248613Sdes			cmd_ptr = cmd->command_info;
275248613Sdes			cmd_size = sizeof(cmd->command_info);
276248613Sdes
277295367Sdes			pos += cmd->length +
278248613Sdes			    sizeof(struct scsi_sense_desc_header);
279248613Sdes			break;
280248613Sdes		}
281248613Sdes		case SSD_DESC_FRU: {
282248613Sdes			struct scsi_sense_fru *fru;
283248613Sdes
284248613Sdes			fru = (struct scsi_sense_fru *)header;
285248613Sdes			fru_ptr = &fru->fru;
286248613Sdes			fru_size = sizeof(fru->fru);
287248613Sdes			pos += fru->length +
288248613Sdes			    sizeof(struct scsi_sense_desc_header);
289248613Sdes			break;
290248613Sdes		}
291248613Sdes		case SSD_DESC_SKS: {
292248613Sdes			struct scsi_sense_sks *sks;
293248613Sdes
294248613Sdes			sks = (struct scsi_sense_sks *)header;
295248613Sdes			sks_ptr = sks->sense_key_spec;
296248613Sdes			sks_size = sizeof(sks->sense_key_spec);
297248613Sdes
298248613Sdes			pos = sks->length +
299248613Sdes			    sizeof(struct scsi_sense_desc_header);
300248613Sdes			break;
301248613Sdes		}
302248613Sdes		case SSD_DESC_STREAM: {
303248613Sdes			struct scsi_sense_stream *stream_sense;
304248613Sdes
305248613Sdes			stream_sense = (struct scsi_sense_stream *)header;
306248613Sdes			stream_ptr = &stream_sense->byte3;
307248613Sdes			stream_size = sizeof(stream_sense->byte3);
308248613Sdes			pos = stream_sense->length +
309248613Sdes			    sizeof(struct scsi_sense_desc_header);
310248613Sdes			break;
311248613Sdes		}
312248613Sdes		default:
313248613Sdes			/*
314248613Sdes			 * We don't recognize this particular sense
315248613Sdes			 * descriptor type, so just skip it.
316295367Sdes			 */
317248613Sdes			pos += sizeof(*header) + header->length;
318248613Sdes			break;
319248613Sdes		}
320248613Sdes	}
321248613Sdes
322248613Sdes	ctl_set_sense_data((struct scsi_sense_data *)sense_dest,
323295367Sdes			   /*lun*/ NULL,
324295367Sdes			   /*sense_format*/ SSD_TYPE_FIXED,
325248613Sdes			   current_error,
326248613Sdes			   /*sense_key*/ sense_src->sense_key & SSD_KEY,
327295367Sdes			   /*asc*/ sense_src->add_sense_code,
328248613Sdes			   /*ascq*/ sense_src->add_sense_code_qual,
329248613Sdes
330295367Sdes			   /* Information Bytes */
331295367Sdes			   (info_ptr != NULL) ? SSD_ELEM_INFO : SSD_ELEM_SKIP,
332295367Sdes			   info_size,
333248613Sdes			   info_ptr,
334248613Sdes
335248613Sdes			   /* Command specific bytes */
336248613Sdes			   (cmd_ptr != NULL) ? SSD_ELEM_COMMAND : SSD_ELEM_SKIP,
337295367Sdes			   cmd_size,
338248613Sdes			   cmd_ptr,
339248613Sdes
340248613Sdes			   /* FRU */
341248613Sdes			   (fru_ptr != NULL) ? SSD_ELEM_FRU : SSD_ELEM_SKIP,
342295367Sdes			   fru_size,
343248613Sdes			   fru_ptr,
344295367Sdes
345295367Sdes			   /* Sense Key Specific */
346248613Sdes			   (sks_ptr != NULL) ? SSD_ELEM_SKS : SSD_ELEM_SKIP,
347295367Sdes			   sks_size,
348248613Sdes			   sks_ptr,
349248613Sdes
350248613Sdes			   /* Tape bits */
351295367Sdes			   (stream_ptr != NULL) ? SSD_ELEM_STREAM : SSD_ELEM_SKIP,
352248613Sdes			   stream_size,
353248613Sdes			   stream_ptr,
354248613Sdes
355248613Sdes			   SSD_ELEM_NONE);
356248613Sdes}
357248613Sdes
358248613Sdesvoid
359248613Sdesctl_set_ua(struct ctl_scsiio *ctsio, int asc, int ascq)
360248613Sdes{
361248613Sdes	ctl_set_sense(ctsio,
362248613Sdes		      /*current_error*/ 1,
363295367Sdes		      /*sense_key*/ SSD_KEY_UNIT_ATTENTION,
364248613Sdes		      asc,
365295367Sdes		      ascq,
366248613Sdes		      SSD_ELEM_NONE);
367248613Sdes}
368295367Sdes
369295367Sdesctl_ua_type
370295367Sdesctl_build_ua(ctl_ua_type *ua_type, struct scsi_sense_data *sense,
371295367Sdes	     scsi_sense_data_type sense_format)
372295367Sdes{
373295367Sdes	ctl_ua_type ua_to_build, ua_to_clear;
374248613Sdes	int asc, ascq;
375248613Sdes
376295367Sdes	if (*ua_type == CTL_UA_NONE)
377295367Sdes		return (CTL_UA_NONE);
378295367Sdes
379248613Sdes	ua_to_build = (1 << (ffs(*ua_type) - 1));
380248613Sdes	ua_to_clear = ua_to_build;
381248613Sdes
382248613Sdes	switch (ua_to_build) {
383295367Sdes	case CTL_UA_POWERON:
384248613Sdes		/* 29h/01h  POWER ON OCCURRED */
385248613Sdes		asc = 0x29;
386248613Sdes		ascq = 0x01;
387248613Sdes		ua_to_clear = ~0;
388295367Sdes		break;
389248613Sdes	case CTL_UA_BUS_RESET:
390248613Sdes		/* 29h/02h  SCSI BUS RESET OCCURRED */
391248613Sdes		asc = 0x29;
392248613Sdes		ascq = 0x02;
393248613Sdes		ua_to_clear = ~0;
394248613Sdes		break;
395248613Sdes	case CTL_UA_TARG_RESET:
396248613Sdes		/* 29h/03h  BUS DEVICE RESET FUNCTION OCCURRED*/
397248613Sdes		asc = 0x29;
398248613Sdes		ascq = 0x03;
399248613Sdes		ua_to_clear = ~0;
400295367Sdes		break;
401248613Sdes	case CTL_UA_I_T_NEXUS_LOSS:
402248613Sdes		/* 29h/07h  I_T NEXUS LOSS OCCURRED */
403295367Sdes		asc = 0x29;
404295367Sdes		ascq = 0x07;
405248613Sdes		ua_to_clear = ~0;
406295367Sdes		break;
407295367Sdes	case CTL_UA_LUN_RESET:
408295367Sdes		/* 29h/00h  POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
409248613Sdes		/*
410248613Sdes		 * Since we don't have a specific ASC/ASCQ pair for a LUN
411248613Sdes		 * reset, just return the generic reset code.
412248613Sdes		 */
413295367Sdes		asc = 0x29;
414248613Sdes		ascq = 0x00;
415248613Sdes		break;
416295367Sdes	case CTL_UA_LUN_CHANGE:
417295367Sdes		/* 3Fh/0Eh  REPORTED LUNS DATA HAS CHANGED */
418248613Sdes		asc = 0x3F;
419295367Sdes		ascq = 0x0E;
420295367Sdes		break;
421295367Sdes	case CTL_UA_MODE_CHANGE:
422295367Sdes		/* 2Ah/01h  MODE PARAMETERS CHANGED */
423248613Sdes		asc = 0x2A;
424248613Sdes		ascq = 0x01;
425248613Sdes		break;
426248613Sdes	case CTL_UA_LOG_CHANGE:
427295367Sdes		/* 2Ah/02h  LOG PARAMETERS CHANGED */
428248613Sdes		asc = 0x2A;
429295367Sdes		ascq = 0x02;
430248613Sdes		break;
431248613Sdes	case CTL_UA_LVD:
432295367Sdes		/* 29h/06h  TRANSCEIVER MODE CHANGED TO LVD */
433248613Sdes		asc = 0x29;
434248613Sdes		ascq = 0x06;
435248613Sdes		break;
436248613Sdes	case CTL_UA_SE:
437248613Sdes		/* 29h/05h  TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
438248613Sdes		asc = 0x29;
439248613Sdes		ascq = 0x05;
440248613Sdes		break;
441248613Sdes	case CTL_UA_RES_PREEMPT:
442248613Sdes		/* 2Ah/03h  RESERVATIONS PREEMPTED */
443248613Sdes		asc = 0x2A;
444295367Sdes		ascq = 0x03;
445295367Sdes		break;
446248613Sdes	case CTL_UA_RES_RELEASE:
447248613Sdes		/* 2Ah/04h  RESERVATIONS RELEASED */
448248613Sdes		asc = 0x2A;
449248613Sdes		ascq = 0x04;
450248613Sdes		break;
451248613Sdes	case CTL_UA_REG_PREEMPT:
452248613Sdes		/* 2Ah/05h  REGISTRATIONS PREEMPTED */
453248613Sdes		asc = 0x2A;
454248613Sdes		ascq = 0x05;
455248613Sdes		break;
456248613Sdes	case CTL_UA_ASYM_ACC_CHANGE:
457248613Sdes	        /* 2Ah/06n  ASYMMETRIC ACCESS STATE CHANGED */
458248613Sdes		asc = 0x2A;
459248613Sdes		ascq = 0x06;
460248613Sdes		break;
461248613Sdes	case CTL_UA_CAPACITY_CHANGED:
462248613Sdes	        /* 2Ah/09n  CAPACITY DATA HAS CHANGED */
463248613Sdes		asc = 0x2A;
464248613Sdes		ascq = 0x09;
465248613Sdes		break;
466248613Sdes	case CTL_UA_THIN_PROV_THRES:
467248613Sdes		/* 38h/07n  THIN PROVISIONING SOFT THRESHOLD REACHED */
468248613Sdes		asc = 0x38;
469248613Sdes		ascq = 0x07;
470248613Sdes		break;
471248613Sdes	default:
472248613Sdes		panic("ctl_build_ua: Unknown UA %x", ua_to_build);
473248613Sdes	}
474248613Sdes
475248613Sdes	ctl_set_sense_data(sense,
476248613Sdes			   /*lun*/ NULL,
477248613Sdes			   sense_format,
478248613Sdes			   /*current_error*/ 1,
479248613Sdes			   /*sense_key*/ SSD_KEY_UNIT_ATTENTION,
480248613Sdes			   asc,
481248613Sdes			   ascq,
482248613Sdes			   SSD_ELEM_NONE);
483248613Sdes
484248613Sdes	/* We're reporting this UA, so clear it */
485248613Sdes	*ua_type &= ~ua_to_clear;
486248613Sdes
487248613Sdes	return (ua_to_build);
488248613Sdes}
489248613Sdes
490248613Sdesvoid
491248613Sdesctl_set_overlapped_cmd(struct ctl_scsiio *ctsio)
492248613Sdes{
493248613Sdes	/* OVERLAPPED COMMANDS ATTEMPTED */
494248613Sdes	ctl_set_sense(ctsio,
495248613Sdes		      /*current_error*/ 1,
496248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
497248613Sdes		      /*asc*/ 0x4E,
498248613Sdes		      /*ascq*/ 0x00,
499248613Sdes		      SSD_ELEM_NONE);
500248613Sdes}
501248613Sdes
502248613Sdesvoid
503248613Sdesctl_set_overlapped_tag(struct ctl_scsiio *ctsio, uint8_t tag)
504248613Sdes{
505248613Sdes	/* TAGGED OVERLAPPED COMMANDS (NN = QUEUE TAG) */
506248613Sdes	ctl_set_sense(ctsio,
507248613Sdes		      /*current_error*/ 1,
508248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
509248613Sdes		      /*asc*/ 0x4D,
510248613Sdes		      /*ascq*/ tag,
511248613Sdes		      SSD_ELEM_NONE);
512248613Sdes}
513248613Sdes
514248613Sdes/*
515295367Sdes * Tell the user that there was a problem with the command or data he sent.
516248613Sdes */
517255767Sdesvoid
518255767Sdesctl_set_invalid_field(struct ctl_scsiio *ctsio, int sks_valid, int command,
519255767Sdes		      int field, int bit_valid, int bit)
520255767Sdes{
521255767Sdes	uint8_t sks[3];
522295367Sdes	int asc;
523248613Sdes
524248613Sdes	if (command != 0) {
525248613Sdes		/* "Invalid field in CDB" */
526295367Sdes		asc = 0x24;
527295367Sdes	} else {
528295367Sdes		/* "Invalid field in parameter list" */
529295367Sdes		asc = 0x26;
530295367Sdes	}
531295367Sdes
532295367Sdes	if (sks_valid) {
533295367Sdes		sks[0] = SSD_SCS_VALID;
534295367Sdes		if (command)
535295367Sdes			sks[0] |= SSD_FIELDPTR_CMD;
536295367Sdes		scsi_ulto2b(field, &sks[1]);
537295367Sdes
538295367Sdes		if (bit_valid)
539295367Sdes			sks[0] |= SSD_BITPTR_VALID | bit;
540295367Sdes	}
541295367Sdes
542295367Sdes	ctl_set_sense(ctsio,
543295367Sdes		      /*current_error*/ 1,
544295367Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
545248613Sdes		      asc,
546248613Sdes		      /*ascq*/ 0x00,
547295367Sdes		      /*type*/ (sks_valid != 0) ? SSD_ELEM_SKS : SSD_ELEM_SKIP,
548248613Sdes		      /*size*/ sizeof(sks),
549295367Sdes		      /*data*/ sks,
550248613Sdes		      SSD_ELEM_NONE);
551248613Sdes}
552248613Sdes
553248613Sdesvoid
554295367Sdesctl_set_invalid_opcode(struct ctl_scsiio *ctsio)
555295367Sdes{
556248613Sdes	struct scsi_sense_data *sense;
557295367Sdes	uint8_t sks[3];
558295367Sdes
559248613Sdes	sense = &ctsio->sense_data;
560295367Sdes
561295367Sdes	sks[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD;
562295367Sdes	scsi_ulto2b(0, &sks[1]);
563295367Sdes
564295367Sdes	/* "Invalid command operation code" */
565295367Sdes	ctl_set_sense(ctsio,
566295367Sdes		      /*current_error*/ 1,
567295367Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
568295367Sdes		      /*asc*/ 0x20,
569295367Sdes		      /*ascq*/ 0x00,
570248613Sdes		      /*type*/ SSD_ELEM_SKS,
571248613Sdes		      /*size*/ sizeof(sks),
572248613Sdes		      /*data*/ sks,
573248613Sdes		      SSD_ELEM_NONE);
574248613Sdes}
575295367Sdes
576255767Sdesvoid
577295367Sdesctl_set_param_len_error(struct ctl_scsiio *ctsio)
578248613Sdes{
579248613Sdes	/* "Parameter list length error" */
580248613Sdes	ctl_set_sense(ctsio,
581248613Sdes		      /*current_error*/ 1,
582248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
583248613Sdes		      /*asc*/ 0x1a,
584248613Sdes		      /*ascq*/ 0x00,
585248613Sdes		      SSD_ELEM_NONE);
586248613Sdes}
587248613Sdes
588248613Sdesvoid
589248613Sdesctl_set_already_locked(struct ctl_scsiio *ctsio)
590248613Sdes{
591248613Sdes	/* Vendor unique "Somebody already is locked" */
592248613Sdes	ctl_set_sense(ctsio,
593248613Sdes		      /*current_error*/ 1,
594248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
595295367Sdes		      /*asc*/ 0x81,
596248613Sdes		      /*ascq*/ 0x00,
597248613Sdes		      SSD_ELEM_NONE);
598248613Sdes}
599248613Sdes
600248613Sdesvoid
601295367Sdesctl_set_unsupported_lun(struct ctl_scsiio *ctsio)
602295367Sdes{
603295367Sdes	/* "Logical unit not supported" */
604248613Sdes	ctl_set_sense(ctsio,
605248613Sdes		      /*current_error*/ 1,
606248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
607295367Sdes		      /*asc*/ 0x25,
608295367Sdes		      /*ascq*/ 0x00,
609295367Sdes		      SSD_ELEM_NONE);
610295367Sdes}
611248613Sdes
612248613Sdesvoid
613248613Sdesctl_set_internal_failure(struct ctl_scsiio *ctsio, int sks_valid,
614248613Sdes			 uint16_t retry_count)
615295367Sdes{
616295367Sdes	uint8_t sks[3];
617248613Sdes
618295367Sdes	if (sks_valid) {
619248613Sdes		sks[0] = SSD_SCS_VALID;
620248613Sdes		sks[1] = (retry_count >> 8) & 0xff;
621248613Sdes		sks[2] = retry_count & 0xff;
622248613Sdes	}
623248613Sdes
624295367Sdes	/* "Internal target failure" */
625295367Sdes	ctl_set_sense(ctsio,
626248613Sdes		      /*current_error*/ 1,
627295367Sdes		      /*sense_key*/ SSD_KEY_HARDWARE_ERROR,
628248613Sdes		      /*asc*/ 0x44,
629295367Sdes		      /*ascq*/ 0x00,
630295367Sdes		      /*type*/ (sks_valid != 0) ? SSD_ELEM_SKS : SSD_ELEM_SKIP,
631295367Sdes		      /*size*/ sizeof(sks),
632248613Sdes		      /*data*/ sks,
633248613Sdes		      SSD_ELEM_NONE);
634248613Sdes}
635248613Sdes
636248613Sdesvoid
637248613Sdesctl_set_medium_error(struct ctl_scsiio *ctsio)
638248613Sdes{
639295367Sdes	if ((ctsio->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
640295367Sdes		/* "Unrecovered read error" */
641295367Sdes		ctl_set_sense(ctsio,
642295367Sdes			      /*current_error*/ 1,
643248613Sdes			      /*sense_key*/ SSD_KEY_MEDIUM_ERROR,
644248613Sdes			      /*asc*/ 0x11,
645295367Sdes			      /*ascq*/ 0x00,
646295367Sdes			      SSD_ELEM_NONE);
647295367Sdes	} else {
648248613Sdes		/* "Write error - auto reallocation failed" */
649248613Sdes		ctl_set_sense(ctsio,
650248613Sdes			      /*current_error*/ 1,
651248613Sdes			      /*sense_key*/ SSD_KEY_MEDIUM_ERROR,
652248613Sdes			      /*asc*/ 0x0C,
653248613Sdes			      /*ascq*/ 0x02,
654248613Sdes			      SSD_ELEM_NONE);
655295367Sdes	}
656295367Sdes}
657295367Sdes
658248613Sdesvoid
659295367Sdesctl_set_aborted(struct ctl_scsiio *ctsio)
660248613Sdes{
661248613Sdes	ctl_set_sense(ctsio,
662248613Sdes		      /*current_error*/ 1,
663248613Sdes		      /*sense_key*/ SSD_KEY_ABORTED_COMMAND,
664248613Sdes		      /*asc*/ 0x45,
665248613Sdes		      /*ascq*/ 0x00,
666248613Sdes		      SSD_ELEM_NONE);
667295367Sdes}
668295367Sdes
669248613Sdesvoid
670248613Sdesctl_set_lba_out_of_range(struct ctl_scsiio *ctsio)
671248613Sdes{
672248613Sdes	/* "Logical block address out of range" */
673248613Sdes	ctl_set_sense(ctsio,
674295367Sdes		      /*current_error*/ 1,
675295367Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
676295367Sdes		      /*asc*/ 0x21,
677248613Sdes		      /*ascq*/ 0x00,
678248613Sdes		      SSD_ELEM_NONE);
679248613Sdes}
680295367Sdes
681295367Sdesvoid
682295367Sdesctl_set_lun_stopped(struct ctl_scsiio *ctsio)
683248613Sdes{
684295367Sdes	/* "Logical unit not ready, initializing cmd. required" */
685248613Sdes	ctl_set_sense(ctsio,
686248613Sdes		      /*current_error*/ 1,
687295367Sdes		      /*sense_key*/ SSD_KEY_NOT_READY,
688248613Sdes		      /*asc*/ 0x04,
689295367Sdes		      /*ascq*/ 0x02,
690295367Sdes		      SSD_ELEM_NONE);
691295367Sdes}
692248613Sdes
693295367Sdesvoid
694295367Sdesctl_set_lun_not_ready(struct ctl_scsiio *ctsio)
695295367Sdes{
696295367Sdes	/* "Logical unit not ready, manual intervention required" */
697248613Sdes	ctl_set_sense(ctsio,
698248613Sdes		      /*current_error*/ 1,
699248613Sdes		      /*sense_key*/ SSD_KEY_NOT_READY,
700295367Sdes		      /*asc*/ 0x04,
701295367Sdes		      /*ascq*/ 0x03,
702248613Sdes		      SSD_ELEM_NONE);
703248613Sdes}
704248613Sdes
705248613Sdesvoid
706295367Sdesctl_set_illegal_pr_release(struct ctl_scsiio *ctsio)
707295367Sdes{
708248613Sdes	/* "Invalid release of persistent reservation" */
709295367Sdes	ctl_set_sense(ctsio,
710248613Sdes		      /*current_error*/ 1,
711248613Sdes		      /*sense_key*/ SSD_KEY_ILLEGAL_REQUEST,
712295367Sdes		      /*asc*/ 0x26,
713295367Sdes		      /*ascq*/ 0x04,
714295367Sdes		      SSD_ELEM_NONE);
715248613Sdes}
716248613Sdes
717248613Sdesvoid
718248613Sdesctl_set_lun_standby(struct ctl_scsiio *ctsio)
719295367Sdes{
720295367Sdes	/* "Logical unit not ready, target port in standby state" */
721248613Sdes	ctl_set_sense(ctsio,
722248613Sdes		      /*current_error*/ 1,
723295367Sdes		      /*sense_key*/ SSD_KEY_NOT_READY,
724295367Sdes		      /*asc*/ 0x04,
725295367Sdes		      /*ascq*/ 0x0b,
726296781Sdes		      SSD_ELEM_NONE);
727295367Sdes}
728295367Sdes
729295367Sdesvoid
730295367Sdesctl_set_medium_format_corrupted(struct ctl_scsiio *ctsio)
731248613Sdes{
732248613Sdes	/* "Medium format corrupted" */
733248613Sdes	ctl_set_sense(ctsio,
734295367Sdes		      /*current_error*/ 1,
735295367Sdes		      /*sense_key*/ SSD_KEY_MEDIUM_ERROR,
736248613Sdes		      /*asc*/ 0x31,
737295367Sdes		      /*ascq*/ 0x00,
738295367Sdes		      SSD_ELEM_NONE);
739295367Sdes}
740248613Sdes
741248613Sdesvoid
742248613Sdesctl_set_medium_magazine_inaccessible(struct ctl_scsiio *ctsio)
743295367Sdes{
744248613Sdes	/* "Medium magazine not accessible" */
745295367Sdes	ctl_set_sense(ctsio,
746295367Sdes		      /*current_error*/ 1,
747295367Sdes		      /*sense_key*/ SSD_KEY_NOT_READY,
748248613Sdes		      /*asc*/ 0x3b,
749295367Sdes		      /*ascq*/ 0x11,
750295367Sdes		      SSD_ELEM_NONE);
751295367Sdes}
752295367Sdes
753248613Sdesvoid
754295367Sdesctl_set_data_phase_error(struct ctl_scsiio *ctsio)
755248613Sdes{
756295367Sdes	/* "Data phase error" */
757295367Sdes	ctl_set_sense(ctsio,
758295367Sdes		      /*current_error*/ 1,
759248613Sdes		      /*sense_key*/ SSD_KEY_NOT_READY,
760295367Sdes		      /*asc*/ 0x4b,
761295367Sdes		      /*ascq*/ 0x00,
762295367Sdes		      SSD_ELEM_NONE);
763295367Sdes}
764295367Sdes
765248613Sdesvoid
766248613Sdesctl_set_reservation_conflict(struct ctl_scsiio *ctsio)
767248613Sdes{
768295367Sdes	struct scsi_sense_data *sense;
769295367Sdes
770295367Sdes	sense = &ctsio->sense_data;
771295367Sdes	memset(sense, 0, sizeof(*sense));
772248613Sdes	ctsio->scsi_status = SCSI_STATUS_RESERV_CONFLICT;
773248613Sdes	ctsio->sense_len = 0;
774295367Sdes	ctsio->io_hdr.status = CTL_SCSI_ERROR;
775296781Sdes}
776248613Sdes
777295367Sdesvoid
778295367Sdesctl_set_queue_full(struct ctl_scsiio *ctsio)
779295367Sdes{
780248613Sdes	struct scsi_sense_data *sense;
781248613Sdes
782248613Sdes	sense = &ctsio->sense_data;
783248613Sdes	memset(sense, 0, sizeof(*sense));
784248613Sdes	ctsio->scsi_status = SCSI_STATUS_QUEUE_FULL;
785295367Sdes	ctsio->sense_len = 0;
786248613Sdes	ctsio->io_hdr.status = CTL_SCSI_ERROR;
787248613Sdes}
788248613Sdes
789248613Sdesvoid
790248613Sdesctl_set_busy(struct ctl_scsiio *ctsio)
791248613Sdes{
792248613Sdes	struct scsi_sense_data *sense;
793248613Sdes
794248613Sdes	sense = &ctsio->sense_data;
795248613Sdes	memset(sense, 0, sizeof(*sense));
796248613Sdes	ctsio->scsi_status = SCSI_STATUS_BUSY;
797295367Sdes	ctsio->sense_len = 0;
798295367Sdes	ctsio->io_hdr.status = CTL_SCSI_ERROR;
799295367Sdes}
800295367Sdes
801295367Sdesvoid
802295367Sdesctl_set_task_aborted(struct ctl_scsiio *ctsio)
803248613Sdes{
804248613Sdes	struct scsi_sense_data *sense;
805248613Sdes
806295367Sdes	sense = &ctsio->sense_data;
807248613Sdes	memset(sense, 0, sizeof(*sense));
808295367Sdes	ctsio->scsi_status = SCSI_STATUS_TASK_ABORTED;
809295367Sdes	ctsio->sense_len = 0;
810295367Sdes	ctsio->io_hdr.status = CTL_CMD_ABORTED;
811295367Sdes}
812295367Sdes
813248613Sdesvoid
814295367Sdesctl_set_space_alloc_fail(struct ctl_scsiio *ctsio)
815248613Sdes{
816295367Sdes	/* "Space allocation failed write protect" */
817248613Sdes	ctl_set_sense(ctsio,
818295367Sdes		      /*current_error*/ 1,
819295367Sdes		      /*sense_key*/ SSD_KEY_DATA_PROTECT,
820248613Sdes		      /*asc*/ 0x27,
821295367Sdes		      /*ascq*/ 0x07,
822295367Sdes		      SSD_ELEM_NONE);
823295367Sdes}
824248613Sdes
825295367Sdesvoid
826248613Sdesctl_set_success(struct ctl_scsiio *ctsio)
827248613Sdes{
828295367Sdes	struct scsi_sense_data *sense;
829296781Sdes
830296781Sdes	sense = &ctsio->sense_data;
831295367Sdes	memset(sense, 0, sizeof(*sense));
832295367Sdes	ctsio->scsi_status = SCSI_STATUS_OK;
833248613Sdes	ctsio->sense_len = 0;
834295367Sdes	ctsio->io_hdr.status = CTL_SUCCESS;
835295367Sdes}
836248613Sdes