0001
0002
0003
0004
0005
0006 #include <linux/bug.h>
0007 #include <linux/kernel.h>
0008 #include <linux/string.h>
0009 #include <linux/errno.h>
0010 #include <linux/module.h>
0011 #include <asm/unaligned.h>
0012 #include <scsi/scsi_common.h>
0013
0014 MODULE_LICENSE("GPL v2");
0015
0016
0017 const unsigned char scsi_command_size_tbl[8] = {
0018 6, 10, 10, 12, 16, 12, 10, 10
0019 };
0020 EXPORT_SYMBOL(scsi_command_size_tbl);
0021
0022
0023
0024
0025
0026 static const char *const scsi_device_types[] = {
0027 "Direct-Access ",
0028 "Sequential-Access",
0029 "Printer ",
0030 "Processor ",
0031 "WORM ",
0032 "CD-ROM ",
0033 "Scanner ",
0034 "Optical Device ",
0035 "Medium Changer ",
0036 "Communications ",
0037 "ASC IT8 ",
0038 "ASC IT8 ",
0039 "RAID ",
0040 "Enclosure ",
0041 "Direct-Access-RBC",
0042 "Optical card ",
0043 "Bridge controller",
0044 "Object storage ",
0045 "Automation/Drive ",
0046 "Security Manager ",
0047 "Direct-Access-ZBC",
0048 };
0049
0050
0051
0052
0053
0054 const char *scsi_device_type(unsigned type)
0055 {
0056 if (type == 0x1e)
0057 return "Well-known LUN ";
0058 if (type == 0x1f)
0059 return "No Device ";
0060 if (type >= ARRAY_SIZE(scsi_device_types))
0061 return "Unknown ";
0062 return scsi_device_types[type];
0063 }
0064 EXPORT_SYMBOL(scsi_device_type);
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 u64 scsilun_to_int(struct scsi_lun *scsilun)
0087 {
0088 int i;
0089 u64 lun;
0090
0091 lun = 0;
0092 for (i = 0; i < sizeof(lun); i += 2)
0093 lun = lun | (((u64)scsilun->scsi_lun[i] << ((i + 1) * 8)) |
0094 ((u64)scsilun->scsi_lun[i + 1] << (i * 8)));
0095 return lun;
0096 }
0097 EXPORT_SYMBOL(scsilun_to_int);
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 void int_to_scsilun(u64 lun, struct scsi_lun *scsilun)
0115 {
0116 int i;
0117
0118 memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun));
0119
0120 for (i = 0; i < sizeof(lun); i += 2) {
0121 scsilun->scsi_lun[i] = (lun >> 8) & 0xFF;
0122 scsilun->scsi_lun[i+1] = lun & 0xFF;
0123 lun = lun >> 16;
0124 }
0125 }
0126 EXPORT_SYMBOL(int_to_scsilun);
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147 bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
0148 struct scsi_sense_hdr *sshdr)
0149 {
0150 memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
0151
0152 if (!sense_buffer || !sb_len)
0153 return false;
0154
0155 sshdr->response_code = (sense_buffer[0] & 0x7f);
0156
0157 if (!scsi_sense_valid(sshdr))
0158 return false;
0159
0160 if (sshdr->response_code >= 0x72) {
0161
0162
0163
0164 if (sb_len > 1)
0165 sshdr->sense_key = (sense_buffer[1] & 0xf);
0166 if (sb_len > 2)
0167 sshdr->asc = sense_buffer[2];
0168 if (sb_len > 3)
0169 sshdr->ascq = sense_buffer[3];
0170 if (sb_len > 7)
0171 sshdr->additional_length = sense_buffer[7];
0172 } else {
0173
0174
0175
0176 if (sb_len > 2)
0177 sshdr->sense_key = (sense_buffer[2] & 0xf);
0178 if (sb_len > 7) {
0179 sb_len = (sb_len < (sense_buffer[7] + 8)) ?
0180 sb_len : (sense_buffer[7] + 8);
0181 if (sb_len > 12)
0182 sshdr->asc = sense_buffer[12];
0183 if (sb_len > 13)
0184 sshdr->ascq = sense_buffer[13];
0185 }
0186 }
0187
0188 return true;
0189 }
0190 EXPORT_SYMBOL(scsi_normalize_sense);
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
0206 int desc_type)
0207 {
0208 int add_sen_len, add_len, desc_len, k;
0209 const u8 * descp;
0210
0211 if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
0212 return NULL;
0213 if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
0214 return NULL;
0215 add_sen_len = (add_sen_len < (sb_len - 8)) ?
0216 add_sen_len : (sb_len - 8);
0217 descp = &sense_buffer[8];
0218 for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
0219 descp += desc_len;
0220 add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
0221 desc_len = add_len + 2;
0222 if (descp[0] == desc_type)
0223 return descp;
0224 if (add_len < 0)
0225 break;
0226 }
0227 return NULL;
0228 }
0229 EXPORT_SYMBOL(scsi_sense_desc_find);
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq)
0242 {
0243 if (desc) {
0244 buf[0] = 0x72;
0245 buf[1] = key;
0246 buf[2] = asc;
0247 buf[3] = ascq;
0248 buf[7] = 0;
0249 } else {
0250 buf[0] = 0x70;
0251 buf[2] = key;
0252 buf[7] = 0xa;
0253 buf[12] = asc;
0254 buf[13] = ascq;
0255 }
0256 }
0257 EXPORT_SYMBOL(scsi_build_sense_buffer);
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 int scsi_set_sense_information(u8 *buf, int buf_len, u64 info)
0270 {
0271 if ((buf[0] & 0x7f) == 0x72) {
0272 u8 *ucp, len;
0273
0274 len = buf[7];
0275 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0);
0276 if (!ucp) {
0277 buf[7] = len + 0xc;
0278 ucp = buf + 8 + len;
0279 }
0280
0281 if (buf_len < len + 0xc)
0282
0283 return -EINVAL;
0284
0285 ucp[0] = 0;
0286 ucp[1] = 0xa;
0287 ucp[2] = 0x80;
0288 ucp[3] = 0;
0289 put_unaligned_be64(info, &ucp[4]);
0290 } else if ((buf[0] & 0x7f) == 0x70) {
0291
0292
0293
0294
0295
0296 if (info <= 0xffffffffUL)
0297 buf[0] |= 0x80;
0298 else
0299 buf[0] &= 0x7f;
0300 put_unaligned_be32((u32)info, &buf[3]);
0301 }
0302
0303 return 0;
0304 }
0305 EXPORT_SYMBOL(scsi_set_sense_information);
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd)
0320 {
0321 u8 *ucp, len;
0322
0323 if ((buf[0] & 0x7f) == 0x72) {
0324 len = buf[7];
0325 ucp = (char *)scsi_sense_desc_find(buf, len + 8, 2);
0326 if (!ucp) {
0327 buf[7] = len + 8;
0328 ucp = buf + 8 + len;
0329 }
0330
0331 if (buf_len < len + 8)
0332
0333 return -EINVAL;
0334
0335 ucp[0] = 2;
0336 ucp[1] = 6;
0337 ucp[4] = 0x80;
0338 if (cd)
0339 ucp[4] |= 0x40;
0340 if (bp < 0x8)
0341 ucp[4] |= 0x8 | bp;
0342 put_unaligned_be16(fp, &ucp[5]);
0343 } else if ((buf[0] & 0x7f) == 0x70) {
0344 len = buf[7];
0345 if (len < 18)
0346 buf[7] = 18;
0347
0348 buf[15] = 0x80;
0349 if (cd)
0350 buf[15] |= 0x40;
0351 if (bp < 0x8)
0352 buf[15] |= 0x8 | bp;
0353 put_unaligned_be16(fp, &buf[16]);
0354 }
0355
0356 return 0;
0357 }
0358 EXPORT_SYMBOL(scsi_set_sense_field_pointer);