Annotation of tme/scsi/scsi-cdb.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.