|
|
1.1.1.2 ! root 1: /* $Id: scsi-cdb.c,v 1.5 2007/08/25 22:52:18 fredette Exp $ */ 1.1 root 2: 3: /* scsi/scsi-cdb.c - implementation of generic SCSI device CDB support: */ 4: 5: /* 6: * Copyright (c) 2003 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.2 ! root 37: _TME_RCSID("$Id: scsi-cdb.c,v 1.5 2007/08/25 22:52:18 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/scsi/scsi-cdb.h> 41: #include <tme/scsi/scsi-msg.h> 42: 43: /* this handles any illegal request: */ 44: _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_device_cdb_illegal) 45: { 46: struct tme_scsi_device_sense *sense; 47: int lun; 48: 49: /* get the addressed LUN's sense: */ 50: lun = scsi_device->tme_scsi_device_addressed_lun; 51: sense = &scsi_device->tme_scsi_device_sense[lun]; 52: 53: /* if this target does not support extended sense: */ 54: if (scsi_device->tme_scsi_device_sense_no_extended) { 55: 56: /* the error class and error code: */ 57: sense->tme_scsi_device_sense_data[0] 58: = 0x20; 59: sense->tme_scsi_device_sense_data[1] 60: = 0; 61: sense->tme_scsi_device_sense_data[2] 62: = 0; 63: sense->tme_scsi_device_sense_data[3] 64: = 0; 65: sense->tme_scsi_device_sense_valid = 4; 66: } 67: 68: /* otherwise, return an extended sense: */ 69: else { 70: 71: /* the error class and error code: */ 72: sense->tme_scsi_device_sense_data[0] 73: = 0x70; 74: 75: /* the ILLEGAL REQUEST sense key: */ 76: sense->tme_scsi_device_sense_data[2] 77: = 0x05; 78: 79: /* the additional sense length: */ 80: sense->tme_scsi_device_sense_data[7] 81: = 0x00; 82: 83: sense->tme_scsi_device_sense_valid 84: = TRUE; 85: } 86: 87: /* return the CHECK CONDITION status: */ 88: tme_scsi_device_target_do_smf(scsi_device, 89: TME_SCSI_STATUS_CHECK_CONDITION, 90: TME_SCSI_MSG_CMD_COMPLETE); 91: } 92: 93: /* this handles the TEST UNIT READY command: */ 94: _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_device_cdb_tur) 95: { 96: /* finish the command: */ 97: tme_scsi_device_target_do_smf(scsi_device, 98: TME_SCSI_STATUS_GOOD, 99: TME_SCSI_MSG_CMD_COMPLETE); 100: } 101: 102: /* this handles the REQUEST SENSE command: */ 103: _TME_SCSI_DEVICE_CDB_DECL(tme_scsi_device_cdb_request_sense) 104: { 105: int lun; 106: struct tme_scsi_device_sense *sense; 107: unsigned long transfer_length; 108: 109: /* get the addressed LUN's sense: */ 110: lun = scsi_device->tme_scsi_device_addressed_lun; 111: sense = &scsi_device->tme_scsi_device_sense[lun]; 112: 113: /* if the sense is not valid: */ 114: if (!sense->tme_scsi_device_sense_valid) { 115: 116: /* if this device doesn't do extended sense: */ 117: if (scsi_device->tme_scsi_device_sense_no_extended) { 118: 119: /* conjure up a no-error nonextended sense: */ 120: sense->tme_scsi_device_sense_data[0] 121: = 0; 122: sense->tme_scsi_device_sense_data[1] 123: = 0; 124: sense->tme_scsi_device_sense_data[2] 125: = 0; 126: sense->tme_scsi_device_sense_data[3] 127: = 0; 128: sense->tme_scsi_device_sense_valid = 4; 129: } 130: 131: /* otherwise, this device does do extended sense: */ 132: else { 133: 134: /* the error class and error code: */ 135: sense->tme_scsi_device_sense_data[0] 136: = 0x70; 137: 138: /* the NO SENSE sense key: */ 139: sense->tme_scsi_device_sense_data[2] 140: = 0x00; 141: 142: /* the additional sense length: */ 143: sense->tme_scsi_device_sense_data[7] 144: = 0x00; 145: } 146: } 147: 148: /* see how much space for sense bytes the initiator 149: has allocated. zero means four: */ 150: transfer_length 151: = scsi_device->tme_scsi_device_cdb[4]; 152: if (transfer_length == 0) { 153: transfer_length = 4; 154: } 155: 156: /* bound this with the number of sense bytes we have available. an 157: extended sense has a length of 8 plus the additional sense 158: length. any other sense must specify how long it is in the 159: tme_scsi_device_sense_valid field (a standard nonextended sense 160: always has a length of four): */ 161: transfer_length 162: = TME_MIN(transfer_length, 163: (((sense->tme_scsi_device_sense_data[0] 164: & 0x70) 165: == 0x70) 166: ? ((unsigned int) 8 167: + sense->tme_scsi_device_sense_data[7]) 168: : sense->tme_scsi_device_sense_valid)); 169: 170: /* set up to transfer the sense: */ 171: scsi_device->tme_scsi_device_dma.tme_scsi_dma_in 172: = NULL; 173: scsi_device->tme_scsi_device_dma.tme_scsi_dma_out 174: = &sense->tme_scsi_device_sense_data[0]; 175: scsi_device->tme_scsi_device_dma.tme_scsi_dma_resid 176: = transfer_length; 177: 178: /* the sense is no longer valid: */ 179: sense->tme_scsi_device_sense_valid = FALSE; 180: 181: /* finish the command: */ 182: tme_scsi_device_target_do_dsmf(scsi_device, 183: TME_SCSI_STATUS_GOOD, 184: TME_SCSI_MSG_CMD_COMPLETE); 185: } 186: 1.1.1.2 ! root 187: /* this processes the parameter list from a MODE SELECT command: */ ! 188: void ! 189: tme_scsi_device_mode_select_data(struct tme_scsi_device *scsi_device, ! 190: int (*do_mode_select_blocks) _TME_P((struct tme_scsi_device *, ! 191: const struct tme_scsi_device_mode_blocks *)), ! 192: int (*do_mode_select_page) _TME_P((struct tme_scsi_device *, ! 193: const tme_uint8_t *))) ! 194: { ! 195: const tme_uint8_t *data; ! 196: const tme_uint8_t *data_end; ! 197: tme_uint32_t length; ! 198: tme_uint32_t block_descriptor_length; ! 199: struct tme_scsi_device_mode_blocks blocks_buffer; ! 200: int is_group0_cmd; ! 201: ! 202: /* see if this is a Group 0 MODE SELECT: */ ! 203: is_group0_cmd ! 204: = ((scsi_device->tme_scsi_device_cdb[0] ! 205: & TME_SCSI_CDB_GROUP_MASK) ! 206: == TME_SCSI_CDB_GROUP_0); ! 207: ! 208: /* "A parameter list length of zero indicates that no data shall be ! 209: transferred. This condition shall not be considered as an error." */ ! 210: if (scsi_device->tme_scsi_device_cdb[4] == 0) { ! 211: tme_scsi_device_target_do_smf(scsi_device, ! 212: TME_SCSI_STATUS_GOOD, ! 213: TME_SCSI_MSG_CMD_COMPLETE); ! 214: return; ! 215: } ! 216: ! 217: /* get a pointer to the first byte of data, and a pointer past the ! 218: last byte of data: */ ! 219: data = &scsi_device->tme_scsi_device_data[0]; ! 220: length = scsi_device->tme_scsi_device_cdb[4]; ! 221: data_end = (data ! 222: + TME_MIN(sizeof(scsi_device->tme_scsi_device_data), ! 223: length)); ! 224: ! 225: /* "A parameter list length that results in the truncation of any ! 226: descriptor, header or page of parameters shall cause the target ! 227: to terminate the command with CHECK CONDITION status. The sense ! 228: key shall be set to ILLEGAL REQUEST, and the additional sense ! 229: code shall be set to PARAMETER LIST LENGTH ERROR. " */ ! 230: ! 231: /* process the mode data: */ ! 232: do { ! 233: ! 234: /* skip a reserved byte (in a MODE SENSE command, this byte would ! 235: be the Mode Data Length): */ ! 236: data++; ! 237: ! 238: /* skip the Medium Type and the Device Specific Parameter: */ ! 239: if ((data_end - data) < 2) break; ! 240: data += 2; ! 241: ! 242: /* if this is not the Group 0 command, skip two reserved bytes: */ ! 243: if (!is_group0_cmd) { ! 244: if ((data_end - data) < 2) break; ! 245: data += 2; ! 246: } ! 247: ! 248: /* get the Block Descriptor Length: */ ! 249: if (data == data_end) break; ! 250: block_descriptor_length = *(data++); ! 251: if (!is_group0_cmd) { ! 252: if (data == data_end) break; ! 253: block_descriptor_length = (block_descriptor_length << 8) + *(data++); ! 254: } ! 255: ! 256: /* check the Block Descriptors: */ ! 257: if (((unsigned long) (data_end - data)) < block_descriptor_length ! 258: || (block_descriptor_length % 8) != 0) { ! 259: break; ! 260: } ! 261: for (; ! 262: block_descriptor_length >= 8; ! 263: block_descriptor_length -= 8) { ! 264: ! 265: /* get the density code: */ ! 266: blocks_buffer.tme_scsi_device_mode_blocks_density_code = *(data++); ! 267: ! 268: /* get the number of blocks: */ ! 269: blocks_buffer.tme_scsi_device_mode_blocks_number ! 270: = ((((tme_uint32_t) data[0]) << 16) ! 271: | (((tme_uint32_t) data[1]) << 8) ! 272: | ((tme_uint32_t) data[2])); ! 273: data += 3; ! 274: ! 275: /* skip the reserved byte: */ ! 276: data++; ! 277: ! 278: /* get the block length: */ ! 279: blocks_buffer.tme_scsi_device_mode_blocks_length ! 280: = ((((tme_uint32_t) data[0]) << 16) ! 281: | (((tme_uint32_t) data[1]) << 8) ! 282: | ((tme_uint32_t) data[2])); ! 283: data += 3; ! 284: ! 285: /* call back for this blocks descriptor: */ ! 286: if ((*do_mode_select_blocks)(scsi_device, &blocks_buffer)) { ! 287: return; ! 288: } ! 289: } ! 290: ! 291: /* check the Mode Pages: */ ! 292: for (; ! 293: ((data_end - data) >= 2 ! 294: && (data_end - data) >= (2 + data[1])); ! 295: data += (2 + data[1])) { ! 296: ! 297: /* call back for this Mode Page: */ ! 298: if ((*do_mode_select_page)(scsi_device, data)) { ! 299: return; ! 300: } ! 301: } ! 302: ! 303: /* terminate the command with GOOD status: */ ! 304: tme_scsi_device_target_do_smf(scsi_device, ! 305: TME_SCSI_STATUS_GOOD, ! 306: TME_SCSI_MSG_CMD_COMPLETE); ! 307: return; ! 308: ! 309: } while (/* CONSTCOND */ 0); ! 310: ! 311: /* terminate the command with CHECK CONDITION status: */ ! 312: tme_scsi_device_check_condition(scsi_device, ! 313: TME_SCSI_SENSE_EXT_KEY_ILLEGAL_REQUEST, ! 314: TME_SCSI_SENSE_EXT_ASC_ASCQ_PARAMETER_LIST_LENGTH_ERROR); ! 315: } ! 316: 1.1 root 317: /* this adds one of the inquiry strings to the data: */ 318: static tme_uint8_t * 319: _tme_scsi_device_make_inquiry_string(tme_uint8_t *data, 1.1.1.2 ! root 320: const char *string, 1.1 root 321: unsigned int size) 322: { 323: tme_uint8_t c; 324: 325: for (; size-- > 0; ) { 326: c = *(string++); 327: if (c == '\0') { 328: c = ' '; 329: string--; 330: } 331: *(data++) = c; 332: } 333: return (data); 334: } 335: 336: /* this creates INQUIRY data: */ 337: tme_uint8_t * 338: tme_scsi_device_make_inquiry_data(struct tme_scsi_device *scsi_device, 339: const struct tme_scsi_device_inquiry *inquiry) 340: { 341: tme_uint8_t *data; 342: 343: data = &scsi_device->tme_scsi_device_data[0]; 344: scsi_device->tme_scsi_device_dma.tme_scsi_dma_out = data; 345: scsi_device->tme_scsi_device_dma.tme_scsi_dma_in = NULL; 346: 347: /* byte 0 is the peripheral device type: */ 348: *(data++) 349: = (inquiry->tme_scsi_device_inquiry_type 350: | inquiry->tme_scsi_device_inquiry_lun_state); 351: 352: /* byte 1 is the device type qualifier: */ 353: *(data++) 354: = (inquiry->tme_scsi_device_inquiry_type_qualifier 355: | (inquiry->tme_scsi_device_inquiry_lun_removable 356: ? 0x80 357: : 0x00)); 358: 359: /* byte 2 is the standards versions: */ 360: *(data++) 361: = ((inquiry->tme_scsi_device_inquiry_std_iso << 6) 362: | (inquiry->tme_scsi_device_inquiry_std_ecma << 3) 363: | (inquiry->tme_scsi_device_inquiry_std_iso << 0)); 364: 365: /* byte 3 is the response format: */ 366: *(data++) 367: = inquiry->tme_scsi_device_response_format; 368: 369: /* byte 4 is the additional length. we will come back and 370: fill it later: */ 371: data++; 372: 373: /* bytes 5, 6, and 7 are flags, that we initialize to zero: */ 374: *(data++) = 0x00; 375: *(data++) = 0x00; 376: *(data++) = 0x00; 377: 378: /* the next eight bytes are for the vendor: */ 379: data 380: = _tme_scsi_device_make_inquiry_string(data, 381: scsi_device->tme_scsi_device_vendor, 382: 8); 383: 384: /* the next 16 bytes are for the product: */ 385: data 386: = _tme_scsi_device_make_inquiry_string(data, 387: scsi_device->tme_scsi_device_product, 388: 16); 389: 390: /* the next four bytes are for the revision: */ 391: data 392: = _tme_scsi_device_make_inquiry_string(data, 393: scsi_device->tme_scsi_device_revision, 394: 4); 395: 396: /* fill in the additional length byte: */ 397: scsi_device->tme_scsi_device_data[4] 398: = (data 399: - &scsi_device->tme_scsi_device_data[5]); 400: 401: return (data); 402: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.