162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SCSI functions used by both the initiator and the target code. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/bug.h> 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/string.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <uapi/linux/pr.h> 1262306a36Sopenharmony_ci#include <asm/unaligned.h> 1362306a36Sopenharmony_ci#include <scsi/scsi_common.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Command group 3 is reserved and should never be used. */ 1862306a36Sopenharmony_ciconst unsigned char scsi_command_size_tbl[8] = { 1962306a36Sopenharmony_ci 6, 10, 10, 12, 16, 12, 10, 10 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_command_size_tbl); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI. 2462306a36Sopenharmony_ci * You may not alter any existing entry (although adding new ones is 2562306a36Sopenharmony_ci * encouraged once assigned by ANSI/INCITS T10). 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistatic const char *const scsi_device_types[] = { 2862306a36Sopenharmony_ci "Direct-Access ", 2962306a36Sopenharmony_ci "Sequential-Access", 3062306a36Sopenharmony_ci "Printer ", 3162306a36Sopenharmony_ci "Processor ", 3262306a36Sopenharmony_ci "WORM ", 3362306a36Sopenharmony_ci "CD-ROM ", 3462306a36Sopenharmony_ci "Scanner ", 3562306a36Sopenharmony_ci "Optical Device ", 3662306a36Sopenharmony_ci "Medium Changer ", 3762306a36Sopenharmony_ci "Communications ", 3862306a36Sopenharmony_ci "ASC IT8 ", 3962306a36Sopenharmony_ci "ASC IT8 ", 4062306a36Sopenharmony_ci "RAID ", 4162306a36Sopenharmony_ci "Enclosure ", 4262306a36Sopenharmony_ci "Direct-Access-RBC", 4362306a36Sopenharmony_ci "Optical card ", 4462306a36Sopenharmony_ci "Bridge controller", 4562306a36Sopenharmony_ci "Object storage ", 4662306a36Sopenharmony_ci "Automation/Drive ", 4762306a36Sopenharmony_ci "Security Manager ", 4862306a36Sopenharmony_ci "Direct-Access-ZBC", 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * scsi_device_type - Return 17-char string indicating device type. 5362306a36Sopenharmony_ci * @type: type number to look up 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ciconst char *scsi_device_type(unsigned type) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci if (type == 0x1e) 5862306a36Sopenharmony_ci return "Well-known LUN "; 5962306a36Sopenharmony_ci if (type == 0x1f) 6062306a36Sopenharmony_ci return "No Device "; 6162306a36Sopenharmony_ci if (type >= ARRAY_SIZE(scsi_device_types)) 6262306a36Sopenharmony_ci return "Unknown "; 6362306a36Sopenharmony_ci return scsi_device_types[type]; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_device_type); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cienum pr_type scsi_pr_type_to_block(enum scsi_pr_type type) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci switch (type) { 7062306a36Sopenharmony_ci case SCSI_PR_WRITE_EXCLUSIVE: 7162306a36Sopenharmony_ci return PR_WRITE_EXCLUSIVE; 7262306a36Sopenharmony_ci case SCSI_PR_EXCLUSIVE_ACCESS: 7362306a36Sopenharmony_ci return PR_EXCLUSIVE_ACCESS; 7462306a36Sopenharmony_ci case SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY: 7562306a36Sopenharmony_ci return PR_WRITE_EXCLUSIVE_REG_ONLY; 7662306a36Sopenharmony_ci case SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY: 7762306a36Sopenharmony_ci return PR_EXCLUSIVE_ACCESS_REG_ONLY; 7862306a36Sopenharmony_ci case SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS: 7962306a36Sopenharmony_ci return PR_WRITE_EXCLUSIVE_ALL_REGS; 8062306a36Sopenharmony_ci case SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS: 8162306a36Sopenharmony_ci return PR_EXCLUSIVE_ACCESS_ALL_REGS; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_pr_type_to_block); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cienum scsi_pr_type block_pr_type_to_scsi(enum pr_type type) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci switch (type) { 9162306a36Sopenharmony_ci case PR_WRITE_EXCLUSIVE: 9262306a36Sopenharmony_ci return SCSI_PR_WRITE_EXCLUSIVE; 9362306a36Sopenharmony_ci case PR_EXCLUSIVE_ACCESS: 9462306a36Sopenharmony_ci return SCSI_PR_EXCLUSIVE_ACCESS; 9562306a36Sopenharmony_ci case PR_WRITE_EXCLUSIVE_REG_ONLY: 9662306a36Sopenharmony_ci return SCSI_PR_WRITE_EXCLUSIVE_REG_ONLY; 9762306a36Sopenharmony_ci case PR_EXCLUSIVE_ACCESS_REG_ONLY: 9862306a36Sopenharmony_ci return SCSI_PR_EXCLUSIVE_ACCESS_REG_ONLY; 9962306a36Sopenharmony_ci case PR_WRITE_EXCLUSIVE_ALL_REGS: 10062306a36Sopenharmony_ci return SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS; 10162306a36Sopenharmony_ci case PR_EXCLUSIVE_ACCESS_ALL_REGS: 10262306a36Sopenharmony_ci return SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(block_pr_type_to_scsi); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/** 11062306a36Sopenharmony_ci * scsilun_to_int - convert a scsi_lun to an int 11162306a36Sopenharmony_ci * @scsilun: struct scsi_lun to be converted. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * Description: 11462306a36Sopenharmony_ci * Convert @scsilun from a struct scsi_lun to a four-byte host byte-ordered 11562306a36Sopenharmony_ci * integer, and return the result. The caller must check for 11662306a36Sopenharmony_ci * truncation before using this function. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Notes: 11962306a36Sopenharmony_ci * For a description of the LUN format, post SCSI-3 see the SCSI 12062306a36Sopenharmony_ci * Architecture Model, for SCSI-3 see the SCSI Controller Commands. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * Given a struct scsi_lun of: d2 04 0b 03 00 00 00 00, this function 12362306a36Sopenharmony_ci * returns the integer: 0x0b03d204 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * This encoding will return a standard integer LUN for LUNs smaller 12662306a36Sopenharmony_ci * than 256, which typically use a single level LUN structure with 12762306a36Sopenharmony_ci * addressing method 0. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ciu64 scsilun_to_int(struct scsi_lun *scsilun) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int i; 13262306a36Sopenharmony_ci u64 lun; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci lun = 0; 13562306a36Sopenharmony_ci for (i = 0; i < sizeof(lun); i += 2) 13662306a36Sopenharmony_ci lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) | 13762306a36Sopenharmony_ci ((u64)scsilun->scsi_lun[i + 1] << (i * 8))); 13862306a36Sopenharmony_ci return lun; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL(scsilun_to_int); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * int_to_scsilun - reverts an int into a scsi_lun 14462306a36Sopenharmony_ci * @lun: integer to be reverted 14562306a36Sopenharmony_ci * @scsilun: struct scsi_lun to be set. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * Description: 14862306a36Sopenharmony_ci * Reverts the functionality of the scsilun_to_int, which packed 14962306a36Sopenharmony_ci * an 8-byte lun value into an int. This routine unpacks the int 15062306a36Sopenharmony_ci * back into the lun value. 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Notes: 15362306a36Sopenharmony_ci * Given an integer : 0x0b03d204, this function returns a 15462306a36Sopenharmony_ci * struct scsi_lun of: d2 04 0b 03 00 00 00 00 15562306a36Sopenharmony_ci * 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_civoid int_to_scsilun(u64 lun, struct scsi_lun *scsilun) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci int i; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci for (i = 0; i < sizeof(lun); i += 2) { 16462306a36Sopenharmony_ci scsilun->scsi_lun[i] = (lun >> 8) & 0xFF; 16562306a36Sopenharmony_ci scsilun->scsi_lun[i+1] = lun & 0xFF; 16662306a36Sopenharmony_ci lun = lun >> 16; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ciEXPORT_SYMBOL(int_to_scsilun); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * scsi_normalize_sense - normalize main elements from either fixed or 17362306a36Sopenharmony_ci * descriptor sense data format into a common format. 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * @sense_buffer: byte array containing sense data returned by device 17662306a36Sopenharmony_ci * @sb_len: number of valid bytes in sense_buffer 17762306a36Sopenharmony_ci * @sshdr: pointer to instance of structure that common 17862306a36Sopenharmony_ci * elements are written to. 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Notes: 18162306a36Sopenharmony_ci * The "main elements" from sense data are: response_code, sense_key, 18262306a36Sopenharmony_ci * asc, ascq and additional_length (only for descriptor format). 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Typically this function can be called after a device has 18562306a36Sopenharmony_ci * responded to a SCSI command with the CHECK_CONDITION status. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Return value: 18862306a36Sopenharmony_ci * true if valid sense data information found, else false; 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cibool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, 19162306a36Sopenharmony_ci struct scsi_sense_hdr *sshdr) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci memset(sshdr, 0, sizeof(struct scsi_sense_hdr)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!sense_buffer || !sb_len) 19662306a36Sopenharmony_ci return false; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci sshdr->response_code = (sense_buffer[0] & 0x7f); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!scsi_sense_valid(sshdr)) 20162306a36Sopenharmony_ci return false; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (sshdr->response_code >= 0x72) { 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * descriptor format 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci if (sb_len > 1) 20862306a36Sopenharmony_ci sshdr->sense_key = (sense_buffer[1] & 0xf); 20962306a36Sopenharmony_ci if (sb_len > 2) 21062306a36Sopenharmony_ci sshdr->asc = sense_buffer[2]; 21162306a36Sopenharmony_ci if (sb_len > 3) 21262306a36Sopenharmony_ci sshdr->ascq = sense_buffer[3]; 21362306a36Sopenharmony_ci if (sb_len > 7) 21462306a36Sopenharmony_ci sshdr->additional_length = sense_buffer[7]; 21562306a36Sopenharmony_ci } else { 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * fixed format 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci if (sb_len > 2) 22062306a36Sopenharmony_ci sshdr->sense_key = (sense_buffer[2] & 0xf); 22162306a36Sopenharmony_ci if (sb_len > 7) { 22262306a36Sopenharmony_ci sb_len = min(sb_len, sense_buffer[7] + 8); 22362306a36Sopenharmony_ci if (sb_len > 12) 22462306a36Sopenharmony_ci sshdr->asc = sense_buffer[12]; 22562306a36Sopenharmony_ci if (sb_len > 13) 22662306a36Sopenharmony_ci sshdr->ascq = sense_buffer[13]; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return true; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_normalize_sense); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. 23662306a36Sopenharmony_ci * @sense_buffer: byte array of descriptor format sense data 23762306a36Sopenharmony_ci * @sb_len: number of valid bytes in sense_buffer 23862306a36Sopenharmony_ci * @desc_type: value of descriptor type to find 23962306a36Sopenharmony_ci * (e.g. 0 -> information) 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * Notes: 24262306a36Sopenharmony_ci * only valid when sense data is in descriptor format 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * Return value: 24562306a36Sopenharmony_ci * pointer to start of (first) descriptor if found else NULL 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ciconst u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, 24862306a36Sopenharmony_ci int desc_type) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci int add_sen_len, add_len, desc_len, k; 25162306a36Sopenharmony_ci const u8 * descp; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) 25462306a36Sopenharmony_ci return NULL; 25562306a36Sopenharmony_ci if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) 25662306a36Sopenharmony_ci return NULL; 25762306a36Sopenharmony_ci add_sen_len = (add_sen_len < (sb_len - 8)) ? 25862306a36Sopenharmony_ci add_sen_len : (sb_len - 8); 25962306a36Sopenharmony_ci descp = &sense_buffer[8]; 26062306a36Sopenharmony_ci for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { 26162306a36Sopenharmony_ci descp += desc_len; 26262306a36Sopenharmony_ci add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; 26362306a36Sopenharmony_ci desc_len = add_len + 2; 26462306a36Sopenharmony_ci if (descp[0] == desc_type) 26562306a36Sopenharmony_ci return descp; 26662306a36Sopenharmony_ci if (add_len < 0) // short descriptor ?? 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci return NULL; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_sense_desc_find); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * scsi_build_sense_buffer - build sense data in a buffer 27562306a36Sopenharmony_ci * @desc: Sense format (non-zero == descriptor format, 27662306a36Sopenharmony_ci * 0 == fixed format) 27762306a36Sopenharmony_ci * @buf: Where to build sense data 27862306a36Sopenharmony_ci * @key: Sense key 27962306a36Sopenharmony_ci * @asc: Additional sense code 28062306a36Sopenharmony_ci * @ascq: Additional sense code qualifier 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci **/ 28362306a36Sopenharmony_civoid scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci if (desc) { 28662306a36Sopenharmony_ci buf[0] = 0x72; /* descriptor, current */ 28762306a36Sopenharmony_ci buf[1] = key; 28862306a36Sopenharmony_ci buf[2] = asc; 28962306a36Sopenharmony_ci buf[3] = ascq; 29062306a36Sopenharmony_ci buf[7] = 0; 29162306a36Sopenharmony_ci } else { 29262306a36Sopenharmony_ci buf[0] = 0x70; /* fixed, current */ 29362306a36Sopenharmony_ci buf[2] = key; 29462306a36Sopenharmony_ci buf[7] = 0xa; 29562306a36Sopenharmony_ci buf[12] = asc; 29662306a36Sopenharmony_ci buf[13] = ascq; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_build_sense_buffer); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * scsi_set_sense_information - set the information field in a 30362306a36Sopenharmony_ci * formatted sense data buffer 30462306a36Sopenharmony_ci * @buf: Where to build sense data 30562306a36Sopenharmony_ci * @buf_len: buffer length 30662306a36Sopenharmony_ci * @info: 64-bit information value to be set 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * Return value: 30962306a36Sopenharmony_ci * 0 on success or -EINVAL for invalid sense buffer length 31062306a36Sopenharmony_ci **/ 31162306a36Sopenharmony_ciint scsi_set_sense_information(u8 *buf, int buf_len, u64 info) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci if ((buf[0] & 0x7f) == 0x72) { 31462306a36Sopenharmony_ci u8 *ucp, len; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci len = buf[7]; 31762306a36Sopenharmony_ci ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); 31862306a36Sopenharmony_ci if (!ucp) { 31962306a36Sopenharmony_ci buf[7] = len + 0xc; 32062306a36Sopenharmony_ci ucp = buf + 8 + len; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (buf_len < len + 0xc) 32462306a36Sopenharmony_ci /* Not enough room for info */ 32562306a36Sopenharmony_ci return -EINVAL; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ucp[0] = 0; 32862306a36Sopenharmony_ci ucp[1] = 0xa; 32962306a36Sopenharmony_ci ucp[2] = 0x80; /* Valid bit */ 33062306a36Sopenharmony_ci ucp[3] = 0; 33162306a36Sopenharmony_ci put_unaligned_be64(info, &ucp[4]); 33262306a36Sopenharmony_ci } else if ((buf[0] & 0x7f) == 0x70) { 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * Only set the 'VALID' bit if we can represent the value 33562306a36Sopenharmony_ci * correctly; otherwise just fill out the lower bytes and 33662306a36Sopenharmony_ci * clear the 'VALID' flag. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci if (info <= 0xffffffffUL) 33962306a36Sopenharmony_ci buf[0] |= 0x80; 34062306a36Sopenharmony_ci else 34162306a36Sopenharmony_ci buf[0] &= 0x7f; 34262306a36Sopenharmony_ci put_unaligned_be32((u32)info, &buf[3]); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_set_sense_information); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * scsi_set_sense_field_pointer - set the field pointer sense key 35162306a36Sopenharmony_ci * specific information in a formatted sense data buffer 35262306a36Sopenharmony_ci * @buf: Where to build sense data 35362306a36Sopenharmony_ci * @buf_len: buffer length 35462306a36Sopenharmony_ci * @fp: field pointer to be set 35562306a36Sopenharmony_ci * @bp: bit pointer to be set 35662306a36Sopenharmony_ci * @cd: command/data bit 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * Return value: 35962306a36Sopenharmony_ci * 0 on success or -EINVAL for invalid sense buffer length 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ciint scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci u8 *ucp, len; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if ((buf[0] & 0x7f) == 0x72) { 36662306a36Sopenharmony_ci len = buf[7]; 36762306a36Sopenharmony_ci ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2); 36862306a36Sopenharmony_ci if (!ucp) { 36962306a36Sopenharmony_ci buf[7] = len + 8; 37062306a36Sopenharmony_ci ucp = buf + 8 + len; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (buf_len < len + 8) 37462306a36Sopenharmony_ci /* Not enough room for info */ 37562306a36Sopenharmony_ci return -EINVAL; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ucp[0] = 2; 37862306a36Sopenharmony_ci ucp[1] = 6; 37962306a36Sopenharmony_ci ucp[4] = 0x80; /* Valid bit */ 38062306a36Sopenharmony_ci if (cd) 38162306a36Sopenharmony_ci ucp[4] |= 0x40; 38262306a36Sopenharmony_ci if (bp < 0x8) 38362306a36Sopenharmony_ci ucp[4] |= 0x8 | bp; 38462306a36Sopenharmony_ci put_unaligned_be16(fp, &ucp[5]); 38562306a36Sopenharmony_ci } else if ((buf[0] & 0x7f) == 0x70) { 38662306a36Sopenharmony_ci len = buf[7]; 38762306a36Sopenharmony_ci if (len < 18) 38862306a36Sopenharmony_ci buf[7] = 18; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci buf[15] = 0x80; 39162306a36Sopenharmony_ci if (cd) 39262306a36Sopenharmony_ci buf[15] |= 0x40; 39362306a36Sopenharmony_ci if (bp < 0x8) 39462306a36Sopenharmony_ci buf[15] |= 0x8 | bp; 39562306a36Sopenharmony_ci put_unaligned_be16(fp, &buf[16]); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ciEXPORT_SYMBOL(scsi_set_sense_field_pointer); 401