xref: /openbmc/linux/drivers/scsi/scsi_common.c (revision 12306b42)
107e38420SBart Van Assche /*
207e38420SBart Van Assche  * SCSI functions used by both the initiator and the target code.
307e38420SBart Van Assche  */
407e38420SBart Van Assche 
507e38420SBart Van Assche #include <linux/bug.h>
607e38420SBart Van Assche #include <linux/kernel.h>
707e38420SBart Van Assche #include <linux/string.h>
87708c165SSagi Grimberg #include <asm/unaligned.h>
907e38420SBart Van Assche #include <scsi/scsi_common.h>
1007e38420SBart Van Assche 
1107e38420SBart Van Assche /* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
1207e38420SBart Van Assche  * You may not alter any existing entry (although adding new ones is
1307e38420SBart Van Assche  * encouraged once assigned by ANSI/INCITS T10
1407e38420SBart Van Assche  */
1507e38420SBart Van Assche static const char *const scsi_device_types[] = {
1607e38420SBart Van Assche 	"Direct-Access    ",
1707e38420SBart Van Assche 	"Sequential-Access",
1807e38420SBart Van Assche 	"Printer          ",
1907e38420SBart Van Assche 	"Processor        ",
2007e38420SBart Van Assche 	"WORM             ",
2107e38420SBart Van Assche 	"CD-ROM           ",
2207e38420SBart Van Assche 	"Scanner          ",
2307e38420SBart Van Assche 	"Optical Device   ",
2407e38420SBart Van Assche 	"Medium Changer   ",
2507e38420SBart Van Assche 	"Communications   ",
2607e38420SBart Van Assche 	"ASC IT8          ",
2707e38420SBart Van Assche 	"ASC IT8          ",
2807e38420SBart Van Assche 	"RAID             ",
2907e38420SBart Van Assche 	"Enclosure        ",
3007e38420SBart Van Assche 	"Direct-Access-RBC",
3107e38420SBart Van Assche 	"Optical card     ",
3207e38420SBart Van Assche 	"Bridge controller",
3307e38420SBart Van Assche 	"Object storage   ",
3407e38420SBart Van Assche 	"Automation/Drive ",
3507e38420SBart Van Assche 	"Security Manager ",
3607e38420SBart Van Assche 	"Direct-Access-ZBC",
3707e38420SBart Van Assche };
3807e38420SBart Van Assche 
3907e38420SBart Van Assche /**
4007e38420SBart Van Assche  * scsi_device_type - Return 17 char string indicating device type.
4107e38420SBart Van Assche  * @type: type number to look up
4207e38420SBart Van Assche  */
4307e38420SBart Van Assche const char *scsi_device_type(unsigned type)
4407e38420SBart Van Assche {
4507e38420SBart Van Assche 	if (type == 0x1e)
4607e38420SBart Van Assche 		return "Well-known LUN   ";
4707e38420SBart Van Assche 	if (type == 0x1f)
4807e38420SBart Van Assche 		return "No Device        ";
4907e38420SBart Van Assche 	if (type >= ARRAY_SIZE(scsi_device_types))
5007e38420SBart Van Assche 		return "Unknown          ";
5107e38420SBart Van Assche 	return scsi_device_types[type];
5207e38420SBart Van Assche }
5307e38420SBart Van Assche EXPORT_SYMBOL(scsi_device_type);
5407e38420SBart Van Assche 
5507e38420SBart Van Assche /**
5607e38420SBart Van Assche  * scsilun_to_int - convert a scsi_lun to an int
5707e38420SBart Van Assche  * @scsilun:	struct scsi_lun to be converted.
5807e38420SBart Van Assche  *
5907e38420SBart Van Assche  * Description:
6007e38420SBart Van Assche  *     Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered
6107e38420SBart Van Assche  *     integer, and return the result. The caller must check for
6207e38420SBart Van Assche  *     truncation before using this function.
6307e38420SBart Van Assche  *
6407e38420SBart Van Assche  * Notes:
6507e38420SBart Van Assche  *     For a description of the LUN format, post SCSI-3 see the SCSI
6607e38420SBart Van Assche  *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.
6707e38420SBart Van Assche  *
6807e38420SBart Van Assche  *     Given a struct scsi_lun of: d2 04 0b 03 00 00 00 00, this function
6907e38420SBart Van Assche  *     returns the integer: 0x0b03d204
7007e38420SBart Van Assche  *
7107e38420SBart Van Assche  *     This encoding will return a standard integer LUN for LUNs smaller
7207e38420SBart Van Assche  *     than 256, which typically use a single level LUN structure with
7307e38420SBart Van Assche  *     addressing method 0.
7407e38420SBart Van Assche  */
7507e38420SBart Van Assche u64 scsilun_to_int(struct scsi_lun *scsilun)
7607e38420SBart Van Assche {
7707e38420SBart Van Assche 	int i;
7807e38420SBart Van Assche 	u64 lun;
7907e38420SBart Van Assche 
8007e38420SBart Van Assche 	lun = 0;
8107e38420SBart Van Assche 	for (i = 0; i < sizeof(lun); i += 2)
8207e38420SBart Van Assche 		lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
8307e38420SBart Van Assche 			     ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
8407e38420SBart Van Assche 	return lun;
8507e38420SBart Van Assche }
8607e38420SBart Van Assche EXPORT_SYMBOL(scsilun_to_int);
8707e38420SBart Van Assche 
8807e38420SBart Van Assche /**
8907e38420SBart Van Assche  * int_to_scsilun - reverts an int into a scsi_lun
9007e38420SBart Van Assche  * @lun:        integer to be reverted
9107e38420SBart Van Assche  * @scsilun:	struct scsi_lun to be set.
9207e38420SBart Van Assche  *
9307e38420SBart Van Assche  * Description:
9407e38420SBart Van Assche  *     Reverts the functionality of the scsilun_to_int, which packed
9507e38420SBart Van Assche  *     an 8-byte lun value into an int. This routine unpacks the int
9607e38420SBart Van Assche  *     back into the lun value.
9707e38420SBart Van Assche  *
9807e38420SBart Van Assche  * Notes:
9907e38420SBart Van Assche  *     Given an integer : 0x0b03d204,  this function returns a
10007e38420SBart Van Assche  *     struct scsi_lun of: d2 04 0b 03 00 00 00 00
10107e38420SBart Van Assche  *
10207e38420SBart Van Assche  */
10307e38420SBart Van Assche void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
10407e38420SBart Van Assche {
10507e38420SBart Van Assche 	int i;
10607e38420SBart Van Assche 
10707e38420SBart Van Assche 	memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
10807e38420SBart Van Assche 
10907e38420SBart Van Assche 	for (i = 0; i < sizeof(lun); i += 2) {
11007e38420SBart Van Assche 		scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
11107e38420SBart Van Assche 		scsilun->scsi_lun[i+1] = lun & 0xFF;
11207e38420SBart Van Assche 		lun = lun >> 16;
11307e38420SBart Van Assche 	}
11407e38420SBart Van Assche }
11507e38420SBart Van Assche EXPORT_SYMBOL(int_to_scsilun);
11607e38420SBart Van Assche 
11707e38420SBart Van Assche /**
11807e38420SBart Van Assche  * scsi_normalize_sense - normalize main elements from either fixed or
11907e38420SBart Van Assche  *			descriptor sense data format into a common format.
12007e38420SBart Van Assche  *
12107e38420SBart Van Assche  * @sense_buffer:	byte array containing sense data returned by device
12207e38420SBart Van Assche  * @sb_len:		number of valid bytes in sense_buffer
12307e38420SBart Van Assche  * @sshdr:		pointer to instance of structure that common
12407e38420SBart Van Assche  *			elements are written to.
12507e38420SBart Van Assche  *
12607e38420SBart Van Assche  * Notes:
12707e38420SBart Van Assche  *	The "main elements" from sense data are: response_code, sense_key,
12807e38420SBart Van Assche  *	asc, ascq and additional_length (only for descriptor format).
12907e38420SBart Van Assche  *
13007e38420SBart Van Assche  *	Typically this function can be called after a device has
13107e38420SBart Van Assche  *	responded to a SCSI command with the CHECK_CONDITION status.
13207e38420SBart Van Assche  *
13307e38420SBart Van Assche  * Return value:
13407e38420SBart Van Assche  *	true if valid sense data information found, else false;
13507e38420SBart Van Assche  */
13607e38420SBart Van Assche bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
13707e38420SBart Van Assche 			  struct scsi_sense_hdr *sshdr)
13807e38420SBart Van Assche {
13907e38420SBart Van Assche 	if (!sense_buffer || !sb_len)
14007e38420SBart Van Assche 		return false;
14107e38420SBart Van Assche 
14207e38420SBart Van Assche 	memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
14307e38420SBart Van Assche 
14407e38420SBart Van Assche 	sshdr->response_code = (sense_buffer[0] & 0x7f);
14507e38420SBart Van Assche 
14607e38420SBart Van Assche 	if (!scsi_sense_valid(sshdr))
14707e38420SBart Van Assche 		return false;
14807e38420SBart Van Assche 
14907e38420SBart Van Assche 	if (sshdr->response_code >= 0x72) {
15007e38420SBart Van Assche 		/*
15107e38420SBart Van Assche 		 * descriptor format
15207e38420SBart Van Assche 		 */
15307e38420SBart Van Assche 		if (sb_len > 1)
15407e38420SBart Van Assche 			sshdr->sense_key = (sense_buffer[1] & 0xf);
15507e38420SBart Van Assche 		if (sb_len > 2)
15607e38420SBart Van Assche 			sshdr->asc = sense_buffer[2];
15707e38420SBart Van Assche 		if (sb_len > 3)
15807e38420SBart Van Assche 			sshdr->ascq = sense_buffer[3];
15907e38420SBart Van Assche 		if (sb_len > 7)
16007e38420SBart Van Assche 			sshdr->additional_length = sense_buffer[7];
16107e38420SBart Van Assche 	} else {
16207e38420SBart Van Assche 		/*
16307e38420SBart Van Assche 		 * fixed format
16407e38420SBart Van Assche 		 */
16507e38420SBart Van Assche 		if (sb_len > 2)
16607e38420SBart Van Assche 			sshdr->sense_key = (sense_buffer[2] & 0xf);
16707e38420SBart Van Assche 		if (sb_len > 7) {
16807e38420SBart Van Assche 			sb_len = (sb_len < (sense_buffer[7] + 8)) ?
16907e38420SBart Van Assche 					 sb_len : (sense_buffer[7] + 8);
17007e38420SBart Van Assche 			if (sb_len > 12)
17107e38420SBart Van Assche 				sshdr->asc = sense_buffer[12];
17207e38420SBart Van Assche 			if (sb_len > 13)
17307e38420SBart Van Assche 				sshdr->ascq = sense_buffer[13];
17407e38420SBart Van Assche 		}
17507e38420SBart Van Assche 	}
17607e38420SBart Van Assche 
17707e38420SBart Van Assche 	return true;
17807e38420SBart Van Assche }
17907e38420SBart Van Assche EXPORT_SYMBOL(scsi_normalize_sense);
1807708c165SSagi Grimberg 
1817708c165SSagi Grimberg /**
1827708c165SSagi Grimberg  * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format.
1837708c165SSagi Grimberg  * @sense_buffer:	byte array of descriptor format sense data
1847708c165SSagi Grimberg  * @sb_len:		number of valid bytes in sense_buffer
1857708c165SSagi Grimberg  * @desc_type:		value of descriptor type to find
1867708c165SSagi Grimberg  *			(e.g. 0 -> information)
1877708c165SSagi Grimberg  *
1887708c165SSagi Grimberg  * Notes:
1897708c165SSagi Grimberg  *	only valid when sense data is in descriptor format
1907708c165SSagi Grimberg  *
1917708c165SSagi Grimberg  * Return value:
1927708c165SSagi Grimberg  *	pointer to start of (first) descriptor if found else NULL
1937708c165SSagi Grimberg  */
1947708c165SSagi Grimberg const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
1957708c165SSagi Grimberg 				int desc_type)
1967708c165SSagi Grimberg {
1977708c165SSagi Grimberg 	int add_sen_len, add_len, desc_len, k;
1987708c165SSagi Grimberg 	const u8 * descp;
1997708c165SSagi Grimberg 
2007708c165SSagi Grimberg 	if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
2017708c165SSagi Grimberg 		return NULL;
2027708c165SSagi Grimberg 	if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
2037708c165SSagi Grimberg 		return NULL;
2047708c165SSagi Grimberg 	add_sen_len = (add_sen_len < (sb_len - 8)) ?
2057708c165SSagi Grimberg 			add_sen_len : (sb_len - 8);
2067708c165SSagi Grimberg 	descp = &sense_buffer[8];
2077708c165SSagi Grimberg 	for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
2087708c165SSagi Grimberg 		descp += desc_len;
2097708c165SSagi Grimberg 		add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
2107708c165SSagi Grimberg 		desc_len = add_len + 2;
2117708c165SSagi Grimberg 		if (descp[0] == desc_type)
2127708c165SSagi Grimberg 			return descp;
2137708c165SSagi Grimberg 		if (add_len < 0) // short descriptor ??
2147708c165SSagi Grimberg 			break;
2157708c165SSagi Grimberg 	}
2167708c165SSagi Grimberg 	return NULL;
2177708c165SSagi Grimberg }
2187708c165SSagi Grimberg EXPORT_SYMBOL(scsi_sense_desc_find);
2197708c165SSagi Grimberg 
2207708c165SSagi Grimberg /**
2217708c165SSagi Grimberg  * scsi_build_sense_buffer - build sense data in a buffer
2227708c165SSagi Grimberg  * @desc:	Sense format (non zero == descriptor format,
2237708c165SSagi Grimberg  *              0 == fixed format)
2247708c165SSagi Grimberg  * @buf:	Where to build sense data
2257708c165SSagi Grimberg  * @key:	Sense key
2267708c165SSagi Grimberg  * @asc:	Additional sense code
2277708c165SSagi Grimberg  * @ascq:	Additional sense code qualifier
2287708c165SSagi Grimberg  *
2297708c165SSagi Grimberg  **/
2307708c165SSagi Grimberg void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
2317708c165SSagi Grimberg {
2327708c165SSagi Grimberg 	if (desc) {
2337708c165SSagi Grimberg 		buf[0] = 0x72;	/* descriptor, current */
2347708c165SSagi Grimberg 		buf[1] = key;
2357708c165SSagi Grimberg 		buf[2] = asc;
2367708c165SSagi Grimberg 		buf[3] = ascq;
2377708c165SSagi Grimberg 		buf[7] = 0;
2387708c165SSagi Grimberg 	} else {
2397708c165SSagi Grimberg 		buf[0] = 0x70;	/* fixed, current */
2407708c165SSagi Grimberg 		buf[2] = key;
2417708c165SSagi Grimberg 		buf[7] = 0xa;
2427708c165SSagi Grimberg 		buf[12] = asc;
2437708c165SSagi Grimberg 		buf[13] = ascq;
2447708c165SSagi Grimberg 	}
2457708c165SSagi Grimberg }
2467708c165SSagi Grimberg EXPORT_SYMBOL(scsi_build_sense_buffer);
2477708c165SSagi Grimberg 
2487708c165SSagi Grimberg /**
2497708c165SSagi Grimberg  * scsi_set_sense_information - set the information field in a
2507708c165SSagi Grimberg  *		formatted sense data buffer
2517708c165SSagi Grimberg  * @buf:	Where to build sense data
2527708c165SSagi Grimberg  * @info:	64-bit information value to be set
2537708c165SSagi Grimberg  *
2547708c165SSagi Grimberg  **/
2557708c165SSagi Grimberg void scsi_set_sense_information(u8 *buf, u64 info)
2567708c165SSagi Grimberg {
2577708c165SSagi Grimberg 	if ((buf[0] & 0x7f) == 0x72) {
2587708c165SSagi Grimberg 		u8 *ucp, len;
2597708c165SSagi Grimberg 
2607708c165SSagi Grimberg 		len = buf[7];
2617708c165SSagi Grimberg 		ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
2627708c165SSagi Grimberg 		if (!ucp) {
26312306b42SSagi Grimberg 			buf[7] = len + 0xc;
2647708c165SSagi Grimberg 			ucp = buf + 8 + len;
2657708c165SSagi Grimberg 		}
2667708c165SSagi Grimberg 		ucp[0] = 0;
2677708c165SSagi Grimberg 		ucp[1] = 0xa;
2687708c165SSagi Grimberg 		ucp[2] = 0x80; /* Valid bit */
2697708c165SSagi Grimberg 		ucp[3] = 0;
2707708c165SSagi Grimberg 		put_unaligned_be64(info, &ucp[4]);
2717708c165SSagi Grimberg 	} else if ((buf[0] & 0x7f) == 0x70) {
2727708c165SSagi Grimberg 		buf[0] |= 0x80;
2737708c165SSagi Grimberg 		put_unaligned_be64(info, &buf[3]);
2747708c165SSagi Grimberg 	}
2757708c165SSagi Grimberg }
2767708c165SSagi Grimberg EXPORT_SYMBOL(scsi_set_sense_information);
277