brintos

brintos / linux-shallow public Read only

0
0
Text · 10.1 KiB · e1a2a62 Raw
402 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * SCSI functions used by both the initiator and the target code.4 */5 6#include <linux/bug.h>7#include <linux/kernel.h>8#include <linux/string.h>9#include <linux/errno.h>10#include <linux/module.h>11#include <uapi/linux/pr.h>12#include <linux/unaligned.h>13#include <scsi/scsi_common.h>14 15MODULE_DESCRIPTION("SCSI functions used by both the initiator and the target code");16MODULE_LICENSE("GPL v2");17 18/* Command group 3 is reserved and should never be used.  */19const unsigned char scsi_command_size_tbl[8] = {20	6, 10, 10, 12, 16, 12, 10, 1021};22EXPORT_SYMBOL(scsi_command_size_tbl);23 24/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.25 * You may not alter any existing entry (although adding new ones is26 * encouraged once assigned by ANSI/INCITS T10).27 */28static const char *const scsi_device_types[] = {29	"Direct-Access    ",30	"Sequential-Access",31	"Printer          ",32	"Processor        ",33	"WORM             ",34	"CD-ROM           ",35	"Scanner          ",36	"Optical Device   ",37	"Medium Changer   ",38	"Communications   ",39	"ASC IT8          ",40	"ASC IT8          ",41	"RAID             ",42	"Enclosure        ",43	"Direct-Access-RBC",44	"Optical card     ",45	"Bridge controller",46	"Object storage   ",47	"Automation/Drive ",48	"Security Manager ",49	"Direct-Access-ZBC",50};51 52/**53 * scsi_device_type - Return 17-char string indicating device type.54 * @type: type number to look up55 */56const char *scsi_device_type(unsigned type)57{58	if (type == 0x1e)59		return "Well-known LUN   ";60	if (type == 0x1f)61		return "No Device        ";62	if (type >= ARRAY_SIZE(scsi_device_types))63		return "Unknown          ";64	return scsi_device_types[type];65}66EXPORT_SYMBOL(scsi_device_type);67 68enum pr_type scsi_pr_type_to_block(enum scsi_pr_type type)69{70	switch (type) {71	case SCSI_PR_WRITE_EXCLUSIVE:72		return PR_WRITE_EXCLUSIVE;73	case SCSI_PR_EXCLUSIVE_ACCESS:74		return PR_EXCLUSIVE_ACCESS;75	case SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY:76		return PR_WRITE_EXCLUSIVE_REG_ONLY;77	case SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY:78		return PR_EXCLUSIVE_ACCESS_REG_ONLY;79	case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:80		return PR_WRITE_EXCLUSIVE_ALL_REGS;81	case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:82		return PR_EXCLUSIVE_ACCESS_ALL_REGS;83	}84 85	return 0;86}87EXPORT_SYMBOL_GPL(scsi_pr_type_to_block);88 89enum scsi_pr_type block_pr_type_to_scsi(enum pr_type type)90{91	switch (type) {92	case PR_WRITE_EXCLUSIVE:93		return SCSI_PR_WRITE_EXCLUSIVE;94	case PR_EXCLUSIVE_ACCESS:95		return SCSI_PR_EXCLUSIVE_ACCESS;96	case PR_WRITE_EXCLUSIVE_REG_ONLY:97		return SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY;98	case PR_EXCLUSIVE_ACCESS_REG_ONLY:99		return SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY;100	case PR_WRITE_EXCLUSIVE_ALL_REGS:101		return SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS;102	case PR_EXCLUSIVE_ACCESS_ALL_REGS:103		return SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS;104	}105 106	return 0;107}108EXPORT_SYMBOL_GPL(block_pr_type_to_scsi);109 110/**111 * scsilun_to_int - convert a scsi_lun to an int112 * @scsilun:	struct scsi_lun to be converted.113 *114 * Description:115 *     Convert @scsilun from a struct scsi_lun to a four-byte host byte-ordered116 *     integer, and return the result. The caller must check for117 *     truncation before using this function.118 *119 * Notes:120 *     For a description of the LUN format, post SCSI-3 see the SCSI121 *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.122 *123 *     Given a struct scsi_lun of: d2 04 0b 03 00 00 00 00, this function124 *     returns the integer: 0x0b03d204125 *126 *     This encoding will return a standard integer LUN for LUNs smaller127 *     than 256, which typically use a single level LUN structure with128 *     addressing method 0.129 */130u64 scsilun_to_int(struct scsi_lun *scsilun)131{132	int i;133	u64 lun;134 135	lun = 0;136	for (i = 0; i < sizeof(lun); i += 2)137		lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |138			     ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));139	return lun;140}141EXPORT_SYMBOL(scsilun_to_int);142 143/**144 * int_to_scsilun - reverts an int into a scsi_lun145 * @lun:        integer to be reverted146 * @scsilun:	struct scsi_lun to be set.147 *148 * Description:149 *     Reverts the functionality of the scsilun_to_int, which packed150 *     an 8-byte lun value into an int. This routine unpacks the int151 *     back into the lun value.152 *153 * Notes:154 *     Given an integer : 0x0b03d204, this function returns a155 *     struct scsi_lun of: d2 04 0b 03 00 00 00 00156 *157 */158void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)159{160	int i;161 162	memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));163 164	for (i = 0; i < sizeof(lun); i += 2) {165		scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;166		scsilun->scsi_lun[i+1] = lun & 0xFF;167		lun = lun >> 16;168	}169}170EXPORT_SYMBOL(int_to_scsilun);171 172/**173 * scsi_normalize_sense - normalize main elements from either fixed or174 *			descriptor sense data format into a common format.175 *176 * @sense_buffer:	byte array containing sense data returned by device177 * @sb_len:		number of valid bytes in sense_buffer178 * @sshdr:		pointer to instance of structure that common179 *			elements are written to.180 *181 * Notes:182 *	The "main elements" from sense data are: response_code, sense_key,183 *	asc, ascq and additional_length (only for descriptor format).184 *185 *	Typically this function can be called after a device has186 *	responded to a SCSI command with the CHECK_CONDITION status.187 *188 * Return value:189 *	true if valid sense data information found, else false;190 */191bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,192			  struct scsi_sense_hdr *sshdr)193{194	memset(sshdr, 0, sizeof(struct scsi_sense_hdr));195 196	if (!sense_buffer || !sb_len)197		return false;198 199	sshdr->response_code = (sense_buffer[0] & 0x7f);200 201	if (!scsi_sense_valid(sshdr))202		return false;203 204	if (sshdr->response_code >= 0x72) {205		/*206		 * descriptor format207		 */208		if (sb_len > 1)209			sshdr->sense_key = (sense_buffer[1] & 0xf);210		if (sb_len > 2)211			sshdr->asc = sense_buffer[2];212		if (sb_len > 3)213			sshdr->ascq = sense_buffer[3];214		if (sb_len > 7)215			sshdr->additional_length = sense_buffer[7];216	} else {217		/*218		 * fixed format219		 */220		if (sb_len > 2)221			sshdr->sense_key = (sense_buffer[2] & 0xf);222		if (sb_len > 7) {223			sb_len = min(sb_len, sense_buffer[7] + 8);224			if (sb_len > 12)225				sshdr->asc = sense_buffer[12];226			if (sb_len > 13)227				sshdr->ascq = sense_buffer[13];228		}229	}230 231	return true;232}233EXPORT_SYMBOL(scsi_normalize_sense);234 235/**236 * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format.237 * @sense_buffer:	byte array of descriptor format sense data238 * @sb_len:		number of valid bytes in sense_buffer239 * @desc_type:		value of descriptor type to find240 *			(e.g. 0 -> information)241 *242 * Notes:243 *	only valid when sense data is in descriptor format244 *245 * Return value:246 *	pointer to start of (first) descriptor if found else NULL247 */248const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,249				int desc_type)250{251	int add_sen_len, add_len, desc_len, k;252	const u8 * descp;253 254	if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))255		return NULL;256	if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))257		return NULL;258	add_sen_len = (add_sen_len < (sb_len - 8)) ?259			add_sen_len : (sb_len - 8);260	descp = &sense_buffer[8];261	for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {262		descp += desc_len;263		add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;264		desc_len = add_len + 2;265		if (descp[0] == desc_type)266			return descp;267		if (add_len < 0) // short descriptor ??268			break;269	}270	return NULL;271}272EXPORT_SYMBOL(scsi_sense_desc_find);273 274/**275 * scsi_build_sense_buffer - build sense data in a buffer276 * @desc:	Sense format (non-zero == descriptor format,277 *              0 == fixed format)278 * @buf:	Where to build sense data279 * @key:	Sense key280 * @asc:	Additional sense code281 * @ascq:	Additional sense code qualifier282 *283 **/284void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)285{286	if (desc) {287		buf[0] = 0x72;	/* descriptor, current */288		buf[1] = key;289		buf[2] = asc;290		buf[3] = ascq;291		buf[7] = 0;292	} else {293		buf[0] = 0x70;	/* fixed, current */294		buf[2] = key;295		buf[7] = 0xa;296		buf[12] = asc;297		buf[13] = ascq;298	}299}300EXPORT_SYMBOL(scsi_build_sense_buffer);301 302/**303 * scsi_set_sense_information - set the information field in a304 *		formatted sense data buffer305 * @buf:	Where to build sense data306 * @buf_len:    buffer length307 * @info:	64-bit information value to be set308 *309 * Return value:310 *	0 on success or -EINVAL for invalid sense buffer length311 **/312int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)313{314	if ((buf[0] & 0x7f) == 0x72) {315		u8 *ucp, len;316 317		len = buf[7];318		ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);319		if (!ucp) {320			buf[7] = len + 0xc;321			ucp = buf + 8 + len;322		}323 324		if (buf_len < len + 0xc)325			/* Not enough room for info */326			return -EINVAL;327 328		ucp[0] = 0;329		ucp[1] = 0xa;330		ucp[2] = 0x80; /* Valid bit */331		ucp[3] = 0;332		put_unaligned_be64(info, &ucp[4]);333	} else if ((buf[0] & 0x7f) == 0x70) {334		/*335		 * Only set the 'VALID' bit if we can represent the value336		 * correctly; otherwise just fill out the lower bytes and337		 * clear the 'VALID' flag.338		 */339		if (info <= 0xffffffffUL)340			buf[0] |= 0x80;341		else342			buf[0] &= 0x7f;343		put_unaligned_be32((u32)info, &buf[3]);344	}345 346	return 0;347}348EXPORT_SYMBOL(scsi_set_sense_information);349 350/**351 * scsi_set_sense_field_pointer - set the field pointer sense key352 *		specific information in a formatted sense data buffer353 * @buf:	Where to build sense data354 * @buf_len:    buffer length355 * @fp:		field pointer to be set356 * @bp:		bit pointer to be set357 * @cd:		command/data bit358 *359 * Return value:360 *	0 on success or -EINVAL for invalid sense buffer length361 */362int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)363{364	u8 *ucp, len;365 366	if ((buf[0] & 0x7f) == 0x72) {367		len = buf[7];368		ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);369		if (!ucp) {370			buf[7] = len + 8;371			ucp = buf + 8 + len;372		}373 374		if (buf_len < len + 8)375			/* Not enough room for info */376			return -EINVAL;377 378		ucp[0] = 2;379		ucp[1] = 6;380		ucp[4] = 0x80; /* Valid bit */381		if (cd)382			ucp[4] |= 0x40;383		if (bp < 0x8)384			ucp[4] |= 0x8 | bp;385		put_unaligned_be16(fp, &ucp[5]);386	} else if ((buf[0] & 0x7f) == 0x70) {387		len = buf[7];388		if (len < 18)389			buf[7] = 18;390 391		buf[15] = 0x80;392		if (cd)393			buf[15] |= 0x40;394		if (bp < 0x8)395			buf[15] |= 0x8 | bp;396		put_unaligned_be16(fp, &buf[16]);397	}398 399	return 0;400}401EXPORT_SYMBOL(scsi_set_sense_field_pointer);402