Annotation of embedaddon/istgt/src/istgt_lu_pass.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  *
                     14:  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     17:  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
                     18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     24:  * SUCH DAMAGE.
                     25:  *
                     26:  */
                     27: 
                     28: #ifdef HAVE_CONFIG_H
                     29: #include "config.h"
                     30: #endif
                     31: 
                     32: #include <inttypes.h>
                     33: #include <stdint.h>
                     34: 
                     35: #include <stdio.h>
                     36: #include <string.h>
                     37: #include <pthread.h>
                     38: 
                     39: #include <fcntl.h>
                     40: #include <unistd.h>
                     41: 
                     42: #ifdef HAVE_LIBCAM
                     43: #include <camlib.h>
                     44: #include <cam/cam.h>
                     45: #include <cam/cam_ccb.h>
                     46: #include <cam/scsi/scsi_message.h>
                     47: 
                     48: #include "istgt.h"
                     49: #include "istgt_ver.h"
                     50: #include "istgt_log.h"
                     51: #include "istgt_misc.h"
                     52: #include "istgt_lu.h"
                     53: #include "istgt_proto.h"
                     54: #include "istgt_scsi.h"
                     55: 
                     56: //#define ISTGT_TRACE_PASS
                     57: 
                     58: #define ISTGT_LU_CAM_TIMEOUT 60000 /* 60sec. */
                     59: 
                     60: typedef struct istgt_lu_pass_t {
                     61:        ISTGT_LU_Ptr lu;
                     62:        int num;
                     63:        int lun;
                     64: 
                     65:        const char *file;
                     66:        uint64_t size;
                     67:        uint64_t blocklen;
                     68:        uint64_t blockcnt;
                     69: 
                     70:        char *device;
                     71:        int unit;
                     72:        struct cam_device *cam_dev;
                     73:        union ccb *ccb;
                     74: 
                     75:        int timeout;
                     76: 
                     77:        uint8_t *inq_standard;
                     78:        int inq_standard_len;
                     79:        int inq_pd;
                     80:        int inq_rmb;
                     81:        int inq_ver;
                     82:        int inq_fmt;
                     83:        uint64_t ms_blocklen;
                     84:        uint64_t ms_blockcnt;
                     85: } ISTGT_LU_PASS;
                     86: 
                     87: #define BUILD_SENSE(SK,ASC,ASCQ)                                                                               \
                     88:        do {                                                                                                                            \
                     89:                *sense_len =                                                                                                    \
                     90:                        istgt_lu_pass_build_sense_data(spec, sense_data,                        \
                     91:                                                                                   ISTGT_SCSI_SENSE_ ## SK,             \
                     92:                                                                                   (ASC), (ASCQ));                              \
                     93:        } while (0)
                     94: 
                     95: static int istgt_lu_pass_build_sense_data(ISTGT_LU_PASS *spec, uint8_t *data, int sk, int asc, int ascq);
                     96: 
                     97: static void
                     98: istgt_lu_pass_parse_sense_key(uint8_t *sense_data, int *skp, int *ascp, int *ascqp)
                     99: {
                    100:        int rsp;
                    101:        int sk, asc, ascq;
                    102: 
                    103:        if (sense_data == NULL) {
                    104:                if (skp != NULL)
                    105:                        *skp = -1;
                    106:                if (ascp != NULL)
                    107:                        *ascp = -1;
                    108:                if (ascqp != NULL)
                    109:                        *ascqp = -1;
                    110:                return;
                    111:        }
                    112: 
                    113:        rsp = BGET8W(&sense_data[0], 6, 7);
                    114:        switch (rsp) {
                    115:        case 0x70: /* Current Fixed */
                    116:                sk = BGET8W(&sense_data[2], 3, 4);
                    117:                asc = sense_data[12];
                    118:                ascq = sense_data[13];
                    119:                break;
                    120:        case 0x71: /* Deferred Fixed */
                    121:                sk = BGET8W(&sense_data[2], 3, 4);
                    122:                asc = sense_data[12];
                    123:                ascq = sense_data[13];
                    124:                break;
                    125:        case 0x72: /* Current Descriptor */
                    126:                sk = BGET8W(&sense_data[2], 3, 4);
                    127:                asc = sense_data[2];
                    128:                ascq = sense_data[3];
                    129:                break;
                    130:        case 0x73: /* Deferred Descriptor */
                    131:                sk = BGET8W(&sense_data[2], 3, 4);
                    132:                asc = sense_data[2];
                    133:                ascq = sense_data[3];
                    134:                break;
                    135:        default:
                    136:                sk = asc = ascq = -1;
                    137:                break;
                    138:        }
                    139: 
                    140:        if (skp != NULL)
                    141:                *skp = sk;
                    142:        if (ascp != NULL)
                    143:                *ascp = asc;
                    144:        if (ascqp != NULL)
                    145:                *ascqp = ascq;
                    146: }
                    147: 
                    148: static void
                    149: istgt_lu_pass_print_sense_key(uint8_t *sense_data)
                    150: {
                    151:        int sk, asc, ascq;
                    152: 
                    153:        istgt_lu_pass_parse_sense_key(sense_data, &sk, &asc, &ascq);
                    154:        if (sk >= 0) {
                    155:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    156:                                           "SK=0x%x, ASC=0x%x, ASCQ=0x%x\n",
                    157:                                           sk, asc, ascq);
                    158:        }
                    159: }
                    160: 
                    161: static int
                    162: istgt_lu_pass_set_inquiry(ISTGT_LU_PASS *spec)
                    163: {
                    164:        uint8_t buf[MAX_TMPBUF];
                    165:        uint8_t cdb[16];
                    166:        uint32_t flags;
                    167:        uint8_t *data;
                    168:        int cdb_len;
                    169:        int data_len;
                    170:        int data_alloc_len;
                    171:        int retry = 1;
                    172:        int rc;
                    173: 
                    174:        memset(buf, 0, sizeof buf);
                    175:        memset(cdb, 0, sizeof cdb);
                    176:        data = buf;
                    177:        if (sizeof buf > 0xff) {
                    178:                data_alloc_len = 0xff;
                    179:        } else {
                    180:                data_alloc_len = sizeof buf;
                    181:        }
                    182: 
                    183:        /* issue standard INQUIRY */
                    184:        cdb[0] = SPC_INQUIRY;
                    185:        cdb[1] = 0;
                    186:        cdb[2] = 0;
                    187:        DSET16(&cdb[3], data_alloc_len); /* ALLOCATION LENGTH */
                    188:        cdb[5] = 0;
                    189:        cdb_len = 6;
                    190:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                    191: 
                    192:        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                    193:        flags = CAM_DIR_IN;
                    194:        flags |= CAM_DEV_QFRZDIS;
                    195:        cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                    196:                                  data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
                    197:                                  spec->timeout);
                    198:        rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                    199:        if (rc < 0) {
                    200:                ISTGT_ERRLOG("cam_send_ccb() failed\n");
                    201:                return -1;
                    202:        }
                    203: 
                    204:        if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                    205:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    206:                                           "request error CAM=0x%x, SCSI=0x%x\n",
                    207:                                           spec->ccb->ccb_h.status,
                    208:                                           spec->ccb->csio.scsi_status);
                    209:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                    210:                                                (uint8_t *) &spec->ccb->csio.sense_data,
                    211:                                                SSD_FULL_SIZE);
                    212:                istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
                    213:                return -1;
                    214:        }
                    215:        data_len = spec->ccb->csio.dxfer_len;
                    216:        data_len -= spec->ccb->csio.resid;
                    217: 
                    218:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
                    219:        spec->inq_standard = xmalloc(data_len);
                    220:        spec->inq_standard_len = data_len;
                    221:        memcpy(spec->inq_standard, data, data_len);
                    222: 
                    223:        return 0;
                    224: }
                    225: 
                    226: static int
                    227: istgt_lu_pass_set_modesense(ISTGT_LU_PASS *spec)
                    228: {
                    229:        uint8_t buf[MAX_TMPBUF];
                    230:        uint8_t cdb[16];
                    231:        uint32_t flags;
                    232:        uint8_t *data;
                    233:        int cdb_len;
                    234:        int data_len;
                    235:        int data_alloc_len;
                    236:        int req_len;
                    237:        int retry = 1;
                    238:        int sk, asc, ascq;
                    239:        int rc;
                    240: 
                    241:        memset(buf, 0, sizeof buf);
                    242:        memset(cdb, 0, sizeof cdb);
                    243:        data = buf;
                    244:        if (sizeof buf > 0xff) {
                    245:                data_alloc_len = 0xff;
                    246:        } else {
                    247:                data_alloc_len = sizeof buf;
                    248:        }
                    249: 
                    250:        if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
                    251:                /* MMC have only 10 */
                    252:                goto retry_sense10;
                    253:        }
                    254:  retry_sense6:
                    255:        spec->ms_blockcnt = 0;
                    256:        spec->ms_blocklen = 0;
                    257:        memset(cdb, 0, sizeof cdb);
                    258:        /* issue MODE SENSE(6) */
                    259:        data_alloc_len = 4 + 8;         /* only block descriptor */
                    260:        req_len = 4 + 8;
                    261:        cdb[0] = SPC_MODE_SENSE_6;
                    262:        BDADD8(&cdb[1], 0, 3);          /* DBD */
                    263:        BDSET8W(&cdb[2], 0x00, 7, 2);   /* PC */
                    264:        //BDADD8W(&cdb[2], 0x00, 5, 6);   /* PAGE CODE */
                    265:        BDADD8W(&cdb[2], 0x3f, 5, 6);   /* PAGE CODE */
                    266:        cdb[3] = 0x00;                  /* SUBPAGE CODE */
                    267:        cdb[4] = data_alloc_len;        /* ALLOCATION LENGTH */
                    268:        cdb_len = 6;
                    269:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                    270: 
                    271:        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                    272:        flags = CAM_DIR_IN;
                    273:        flags |= CAM_DEV_QFRZDIS;
                    274:        cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                    275:                                  data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
                    276:                                  spec->timeout);
                    277:        rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                    278:        if (rc < 0) {
                    279:                ISTGT_ERRLOG("cam_send_ccb() failed\n");
                    280:                return -1;
                    281:        }
                    282: 
                    283:        if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                    284:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    285:                                           "request error CAM=0x%x, SCSI=0x%x\n",
                    286:                                           spec->ccb->ccb_h.status,
                    287:                                           spec->ccb->csio.scsi_status);
                    288:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                    289:                                                (uint8_t *) &spec->ccb->csio.sense_data,
                    290:                                                SSD_FULL_SIZE);
                    291:                istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
                    292:                istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
                    293:                                                                          &sk, &asc, &ascq);
                    294:                if (sk == ISTGT_SCSI_SENSE_ILLEGAL_REQUEST) {
                    295:                        if (asc == 0x20 && ascq == 0x00) {
                    296:                                /* INVALID COMMAND OPERATION CODE */
                    297:                                goto retry_sense10;
                    298:                        } else if (asc == 0x24 && ascq == 0x00) {
                    299:                                /* INVALID FIELD IN CDB */
                    300:                                goto retry_sense10;
                    301:                        }
                    302:                }
                    303:                if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
                    304:                        if (asc == 0x28 && ascq == 0x00) {
                    305:                                /* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
                    306:                                goto retry_sense6;
                    307:                        }
                    308:                        if (asc == 0x29 && ascq == 0x00) {
                    309:                                /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
                    310:                                goto retry_sense6;
                    311:                        } else if (asc == 0x29 && ascq == 0x01) {
                    312:                                /* POWER ON OCCURRED */
                    313:                                goto retry_sense6;
                    314:                        } else if (asc == 0x29 && ascq == 0x02) {
                    315:                                /* SCSI BUS RESET OCCURRED */
                    316:                                goto retry_sense6;
                    317:                        } else if (asc == 0x29 && ascq == 0x03) {
                    318:                                /* BUS DEVICE RESET FUNCTION OCCURRED */
                    319:                                goto retry_sense6;
                    320:                        } else if (asc == 0x29 && ascq == 0x04) {
                    321:                                /* DEVICE INTERNAL RESET */
                    322:                                goto retry_sense6;
                    323:                        } else if (asc == 0x29 && ascq == 0x05) {
                    324:                                /* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
                    325:                                goto retry_sense6;
                    326:                        } else if (asc == 0x29 && ascq == 0x06) {
                    327:                                /* TRANSCEIVER MODE CHANGED TO LVD */
                    328:                                goto retry_sense6;
                    329:                        } else if (asc == 0x29 && ascq == 0x07) {
                    330:                                /* I_T NEXUS LOSS OCCURRED */
                    331:                                goto retry_sense6;
                    332:                        }
                    333:                }
                    334:                return -1;
                    335:        }
                    336:        data_len = spec->ccb->csio.dxfer_len;
                    337:        data_len -= spec->ccb->csio.resid;
                    338:        if (data_len < req_len) {
                    339:                ISTGT_ERRLOG("result is short\n");
                    340:                return -1;              
                    341:        }
                    342: 
                    343:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "MODE SENSE(6)", data, data_len);
                    344:        if (DGET8(&data[3]) != 0) { /* BLOCK DESCRIPTOR LENGTH */
                    345:                if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
                    346:                        spec->ms_blockcnt = DGET32(&data[4+0]);
                    347:                        spec->ms_blocklen = DGET24(&data[4+5]);
                    348:                } else {
                    349:                        spec->ms_blockcnt = DGET24(&data[4+1]);
                    350:                        spec->ms_blocklen = DGET24(&data[4+5]);
                    351:                }
                    352:        } else {
                    353:                goto retry_sense10;
                    354:        }
                    355: 
                    356:        if ((spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK
                    357:                 && spec->ms_blockcnt == 0xffffffffU)
                    358:                || (spec->inq_pd != SPC_PERIPHERAL_DEVICE_TYPE_DISK
                    359:                        && spec->ms_blockcnt == 0x00ffffffU)) {
                    360:        retry_sense10:
                    361:                spec->ms_blockcnt = 0;
                    362:                spec->ms_blocklen = 0;
                    363:                memset(cdb, 0, sizeof cdb);
                    364:                /* issue MODE SENSE(10) */
                    365:                data_alloc_len = 8 + 16;        /* only block descriptor */
                    366:                req_len = 8 + 16;
                    367:                cdb[0] = SPC_MODE_SENSE_10;
                    368:                BDSET8(&cdb[1], 1, 4);          /* LLBAA */
                    369:                BDADD8(&cdb[1], 0, 3);          /* DBD */
                    370:                BDSET8W(&cdb[2], 0x00, 7, 2);   /* PC */
                    371:                //BDADD8W(&cdb[2], 0x00, 5, 6);   /* PAGE CODE */
                    372:                BDADD8W(&cdb[2], 0x3f, 5, 6);   /* PAGE CODE */
                    373:                cdb[3] = 0x00;                  /* SUBPAGE CODE */
                    374:                DSET16(&cdb[7], data_alloc_len); /* ALLOCATION LENGTH */
                    375:                cdb_len = 10;
                    376:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                    377: 
                    378:                memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                    379:                flags = CAM_DIR_IN;
                    380:                flags |= CAM_DEV_QFRZDIS;
                    381:                cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                    382:                                          data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
                    383:                                          spec->timeout);
                    384:                rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                    385:                if (rc < 0) {
                    386:                        ISTGT_ERRLOG("cam_send_ccb() failed\n");
                    387:                        return -1;
                    388:                }
                    389: 
                    390:                if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                    391:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    392:                                                   "request error CAM=0x%x, SCSI=0x%x\n",
                    393:                                                   spec->ccb->ccb_h.status,
                    394:                                                   spec->ccb->csio.scsi_status);
                    395:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                    396:                                                        (uint8_t *) &spec->ccb->csio.sense_data,
                    397:                                                        SSD_FULL_SIZE);
                    398:                        istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
                    399:                        istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
                    400:                                                                                  &sk, &asc, &ascq);
                    401:                        if (sk == ISTGT_SCSI_SENSE_ILLEGAL_REQUEST) {
                    402:                                if (spec->inq_ver < SPC_VERSION_SPC3) {
                    403:                                        //ISTGT_WARNLOG("MODE SENSE was not supported\n");
                    404:                                        return 0;
                    405:                                }
                    406:                                if (asc == 0x20 && ascq == 0x00) {
                    407:                                        /* INVALID COMMAND OPERATION CODE */
                    408:                                        return 0;
                    409:                                } else if (asc == 0x24 && ascq == 0x00) {
                    410:                                        /* INVALID FIELD IN CDB */
                    411:                                        return 0;
                    412:                                }
                    413:                        }
                    414:                        if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
                    415:                                if (asc == 0x28 && ascq == 0x00) {
                    416:                                        /* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
                    417:                                        goto retry_sense10;
                    418:                                }
                    419:                                if (asc == 0x29 && ascq == 0x00) {
                    420:                                        /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
                    421:                                        goto retry_sense10;
                    422:                                } else if (asc == 0x29 && ascq == 0x01) {
                    423:                                        /* POWER ON OCCURRED */
                    424:                                        goto retry_sense10;
                    425:                                } else if (asc == 0x29 && ascq == 0x02) {
                    426:                                        /* SCSI BUS RESET OCCURRED */
                    427:                                        goto retry_sense10;
                    428:                                } else if (asc == 0x29 && ascq == 0x03) {
                    429:                                        /* BUS DEVICE RESET FUNCTION OCCURRED */
                    430:                                        goto retry_sense10;
                    431:                                } else if (asc == 0x29 && ascq == 0x04) {
                    432:                                        /* DEVICE INTERNAL RESET */
                    433:                                        goto retry_sense10;
                    434:                                } else if (asc == 0x29 && ascq == 0x05) {
                    435:                                        /* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
                    436:                                        goto retry_sense10;
                    437:                                } else if (asc == 0x29 && ascq == 0x06) {
                    438:                                        /* TRANSCEIVER MODE CHANGED TO LVD */
                    439:                                        goto retry_sense10;
                    440:                                } else if (asc == 0x29 && ascq == 0x07) {
                    441:                                        /* I_T NEXUS LOSS OCCURRED */
                    442:                                        goto retry_sense10;
                    443:                                }
                    444:                        }
                    445:                        return -1;
                    446:                }
                    447:                data_len = spec->ccb->csio.dxfer_len;
                    448:                data_len -= spec->ccb->csio.resid;
                    449:                if (data_len < req_len) {
                    450:                        ISTGT_ERRLOG("result is short\n");
                    451:                        return -1;              
                    452:                }
                    453: 
                    454:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "MODE SENSE(10)", data, data_len);
                    455:                if (DGET16(&data[6]) != 0) { /* BLOCK DESCRIPTOR LENGTH */
                    456:                        spec->ms_blockcnt = DGET64(&data[8+0]);
                    457:                        spec->ms_blocklen = DGET32(&data[8+12]);
                    458:                }
                    459:        }
                    460: 
                    461:        return 0;
                    462: }
                    463: 
                    464: static int
                    465: istgt_lu_pass_set_capacity(ISTGT_LU_PASS *spec)
                    466: {
                    467:        uint8_t buf[MAX_TMPBUF];
                    468:        uint8_t cdb[16];
                    469:        uint32_t flags;
                    470:        uint8_t *data;
                    471:        int cdb_len;
                    472:        int data_len;
                    473:        int data_alloc_len;
                    474:        int req_len;
                    475:        int retry = 1;
                    476:        int sk, asc, ascq;
                    477:        int rc;
                    478: 
                    479:        memset(buf, 0, sizeof buf);
                    480:        memset(cdb, 0, sizeof cdb);
                    481:        data = buf;
                    482:        if (sizeof buf > 0xff) {
                    483:                data_alloc_len = 0xff;
                    484:        } else {
                    485:                data_alloc_len = sizeof buf;
                    486:        }
                    487: 
                    488:        /* issue READ CAPACITY (10) */
                    489:  retry_capacity10:
                    490:        memset(cdb, 0, sizeof cdb);
                    491:        data_alloc_len = 8;
                    492:        req_len = 8;
                    493:        if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
                    494:                cdb[0] = SBC_READ_CAPACITY_10;
                    495:                cdb_len = 10;
                    496:        } else if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
                    497:                cdb[0] = MMC_READ_CAPACITY;
                    498:                cdb_len = 10;
                    499:        } else {
                    500:                ISTGT_ERRLOG("unsupported device\n");
                    501:                return -1;
                    502:        }
                    503:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                    504: 
                    505:        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                    506:        flags = CAM_DIR_IN;
                    507:        flags |= CAM_DEV_QFRZDIS;
                    508:        cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                    509:                                  data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
                    510:                                  spec->timeout);
                    511:        rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                    512:        if (rc < 0) {
                    513:                ISTGT_ERRLOG("cam_send_ccb() failed\n");
                    514:                return -1;
                    515:        }
                    516: 
                    517:        if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                    518:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    519:                                           "request error CAM=0x%x, SCSI=0x%x\n",
                    520:                                           spec->ccb->ccb_h.status,
                    521:                                           spec->ccb->csio.scsi_status);
                    522:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                    523:                                                (uint8_t *) &spec->ccb->csio.sense_data,
                    524:                                                SSD_FULL_SIZE);
                    525:                istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
                    526:                istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
                    527:                                                                          &sk, &asc, &ascq);
                    528:                if (sk == ISTGT_SCSI_SENSE_NOT_READY) {
                    529:                        if (asc == 0x04 && ascq == 0x01) {
                    530:                                /* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
                    531:                                sleep(2);
                    532:                                goto retry_capacity10;
                    533:                        }
                    534:                        if (asc == 0x3a && ascq == 0x00) {
                    535:                                /* MEDIUM NOT PRESENT */
                    536:                                goto medium_not_present;
                    537:                        } else if (asc == 0x3a && ascq == 0x01) {
                    538:                                /* MEDIUM NOT PRESENT - TRAY CLOSED */
                    539:                                goto medium_not_present;
                    540:                        } else if (asc == 0x3a && ascq == 0x02) {
                    541:                                /* MEDIUM NOT PRESENT - TRAY OPEN */
                    542:                                goto medium_not_present;
                    543:                        } else if (asc == 0x3a && ascq == 0x03) {
                    544:                                /* MEDIUM NOT PRESENT - LOADABLE */
                    545:                                goto medium_not_present;
                    546:                        } else if (asc == 0x3a && ascq == 0x04) {
                    547:                                /* MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE */
                    548:                                goto medium_not_present;
                    549:                        }
                    550:                        ISTGT_ERRLOG("device not ready\n");
                    551:                        return -1;
                    552:                }
                    553:                if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
                    554:                        if (asc == 0x28 && ascq == 0x00) {
                    555:                                /* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
                    556:                                goto retry_capacity10;
                    557:                        }
                    558:                        if (asc == 0x29 && ascq == 0x00) {
                    559:                                /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
                    560:                                goto retry_capacity10;
                    561:                        } else if (asc == 0x29 && ascq == 0x01) {
                    562:                                /* POWER ON OCCURRED */
                    563:                                goto retry_capacity10;
                    564:                        } else if (asc == 0x29 && ascq == 0x02) {
                    565:                                /* SCSI BUS RESET OCCURRED */
                    566:                                goto retry_capacity10;
                    567:                        } else if (asc == 0x29 && ascq == 0x03) {
                    568:                                /* BUS DEVICE RESET FUNCTION OCCURRED */
                    569:                                goto retry_capacity10;
                    570:                        } else if (asc == 0x29 && ascq == 0x04) {
                    571:                                /* DEVICE INTERNAL RESET */
                    572:                                goto retry_capacity10;
                    573:                        } else if (asc == 0x29 && ascq == 0x05) {
                    574:                                /* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
                    575:                                goto retry_capacity10;
                    576:                        } else if (asc == 0x29 && ascq == 0x06) {
                    577:                                /* TRANSCEIVER MODE CHANGED TO LVD */
                    578:                                goto retry_capacity10;
                    579:                        } else if (asc == 0x29 && ascq == 0x07) {
                    580:                                /* I_T NEXUS LOSS OCCURRED */
                    581:                                goto retry_capacity10;
                    582:                        }
                    583:                }
                    584:                return -1;
                    585:        }
                    586:        data_len = spec->ccb->csio.dxfer_len;
                    587:        data_len -= spec->ccb->csio.resid;
                    588:        if (data_len < req_len) {
                    589:                ISTGT_ERRLOG("result is short\n");
                    590:                return -1;              
                    591:        }
                    592: 
                    593:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "READ CAPACITY(10)", data, data_len);
                    594:        spec->blockcnt = (uint64_t) DGET32(&data[0]); // last LBA
                    595:        spec->blocklen = (uint64_t) DGET32(&data[4]);
                    596: 
                    597:        if (spec->blockcnt == 0xffffffffU) {
                    598:        retry_capacity16:
                    599:                memset(cdb, 0, sizeof cdb);
                    600:                /* issue READ CAPACITY(16) */
                    601:                data_alloc_len = 32;
                    602:                req_len = 32;
                    603:                if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK) {
                    604:                        cdb[0] = SPC_SERVICE_ACTION_IN_16;
                    605:                        /* SERVICE ACTION */
                    606:                        BDSET8W(&cdb[1], SBC_SAI_READ_CAPACITY_16, 4, 5);
                    607:                        /* ALLOCATION LENGTH */
                    608:                        DSET16(&cdb[10], data_alloc_len);
                    609:                        cdb_len = 16;
                    610:                } else if (spec->inq_pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
                    611:                        ISTGT_ERRLOG("unsupported device\n");
                    612:                        return -1;
                    613:                } else {
                    614:                        ISTGT_ERRLOG("unsupported device\n");
                    615:                        return -1;
                    616:                }
                    617:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                    618: 
                    619:                memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                    620:                flags = CAM_DIR_IN;
                    621:                flags |= CAM_DEV_QFRZDIS;
                    622:                cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                    623:                                          data, data_alloc_len, SSD_FULL_SIZE, cdb_len,
                    624:                                          spec->timeout);
                    625:                rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                    626:                if (rc < 0) {
                    627:                        ISTGT_ERRLOG("cam_send_ccb() failed\n");
                    628:                        return -1;
                    629:                }
                    630: 
                    631:                if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                    632:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                    633:                                                   "request error CAM=0x%x, SCSI=0x%x\n",
                    634:                                                   spec->ccb->ccb_h.status,
                    635:                                                   spec->ccb->csio.scsi_status);
                    636:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                    637:                                                        (uint8_t *) &spec->ccb->csio.sense_data,
                    638:                                                        SSD_FULL_SIZE);
                    639:                        istgt_lu_pass_print_sense_key((uint8_t *) &spec->ccb->csio.sense_data);
                    640:                        istgt_lu_pass_parse_sense_key((uint8_t *) &spec->ccb->csio.sense_data,
                    641:                                                                                  &sk, &asc, &ascq);
                    642:                        if (sk == ISTGT_SCSI_SENSE_NOT_READY) {
                    643:                                if (asc == 0x04 && ascq == 0x01) {
                    644:                                        /* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
                    645:                                        sleep(2);
                    646:                                        goto retry_capacity16;
                    647:                                }
                    648:                                if (asc == 0x3a && ascq == 0x00) {
                    649:                                        /* MEDIUM NOT PRESENT */
                    650:                                        goto medium_not_present;
                    651:                                } else if (asc == 0x3a && ascq == 0x01) {
                    652:                                        /* MEDIUM NOT PRESENT - TRAY CLOSED */
                    653:                                        goto medium_not_present;
                    654:                                } else if (asc == 0x3a && ascq == 0x02) {
                    655:                                        /* MEDIUM NOT PRESENT - TRAY OPEN */
                    656:                                        goto medium_not_present;
                    657:                                } else if (asc == 0x3a && ascq == 0x03) {
                    658:                                        /* MEDIUM NOT PRESENT - LOADABLE */
                    659:                                        goto medium_not_present;
                    660:                                } else if (asc == 0x3a && ascq == 0x04) {
                    661:                                        /* MEDIUM NOT PRESENT - MEDIUM AUXILIARY MEMORY ACCESSIBLE */
                    662:                                        goto medium_not_present;
                    663:                                }
                    664:                                ISTGT_ERRLOG("device not ready\n");
                    665:                                return -1;
                    666:                        }
                    667:                        if (sk == ISTGT_SCSI_SENSE_UNIT_ATTENTION) {
                    668:                                if (asc == 0x28 && ascq == 0x00) {
                    669:                                        /* NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED */
                    670:                                        goto retry_capacity16;
                    671:                                }
                    672:                                if (asc == 0x29 && ascq == 0x00) {
                    673:                                        /* POWER ON, RESET, OR BUS DEVICE RESET OCCURRED */
                    674:                                        goto retry_capacity16;
                    675:                                } else if (asc == 0x29 && ascq == 0x01) {
                    676:                                        /* POWER ON OCCURRED */
                    677:                                        goto retry_capacity16;
                    678:                                } else if (asc == 0x29 && ascq == 0x02) {
                    679:                                        /* SCSI BUS RESET OCCURRED */
                    680:                                        goto retry_capacity16;
                    681:                                } else if (asc == 0x29 && ascq == 0x03) {
                    682:                                        /* BUS DEVICE RESET FUNCTION OCCURRED */
                    683:                                        goto retry_capacity16;
                    684:                                } else if (asc == 0x29 && ascq == 0x04) {
                    685:                                        /* DEVICE INTERNAL RESET */
                    686:                                        goto retry_capacity16;
                    687:                                } else if (asc == 0x29 && ascq == 0x05) {
                    688:                                        /* TRANSCEIVER MODE CHANGED TO SINGLE-ENDED */
                    689:                                        goto retry_capacity16;
                    690:                                } else if (asc == 0x29 && ascq == 0x06) {
                    691:                                        /* TRANSCEIVER MODE CHANGED TO LVD */
                    692:                                        goto retry_capacity16;
                    693:                                } else if (asc == 0x29 && ascq == 0x07) {
                    694:                                        /* I_T NEXUS LOSS OCCURRED */
                    695:                                        goto retry_capacity16;
                    696:                                }
                    697:                        }
                    698:                        return -1;
                    699:                }
                    700:                data_len = spec->ccb->csio.dxfer_len;
                    701:                data_len -= spec->ccb->csio.resid;
                    702:                if (data_len < req_len) {
                    703:                        ISTGT_ERRLOG("result is short\n");
                    704:                        return -1;              
                    705:                }
                    706: 
                    707:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "READ CAPACITY(16)",
                    708:                                                data, data_len);
                    709:                spec->blockcnt = DGET64(&data[0]); // last LBA
                    710:                spec->blocklen = (uint64_t) DGET32(&data[8]);
                    711:        }
                    712: 
                    713:        spec->blockcnt++;
                    714:        spec->size = spec->blockcnt * spec->blocklen;
                    715:        return 0;
                    716: 
                    717:  medium_not_present:
                    718:        spec->blockcnt = 0;
                    719:        spec->blocklen = 0;
                    720:        spec->size = 0;
                    721:        return 0;
                    722: }
                    723: 
                    724: int
                    725: istgt_lu_pass_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
                    726: {
                    727:        char buf[MAX_TMPBUF];
                    728:        ISTGT_LU_PASS *spec;
                    729:        uint64_t gb_size;
                    730:        uint64_t mb_size;
                    731:        int mb_digit;
                    732:        int flags;
                    733:        int rc;
                    734:        int pq, pd, rmb;
                    735:        int ver, fmt;
                    736:        int i;
                    737: 
                    738:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_pass_init\n");
                    739: 
                    740:        printf("LU%d PASS-THROUGH UNIT\n", lu->num);
                    741:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
                    742:                                   lu->num, lu->name);
                    743:        for (i = 0; i < lu->maxlun; i++) {
                    744:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
                    745:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
                    746:                                                   lu->num, i);
                    747:                        lu->lun[i].spec = NULL;
                    748:                        continue;
                    749:                }
                    750:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_DEVICE) {
                    751:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
                    752:                        return -1;
                    753:                }
                    754:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d device\n",
                    755:                                           lu->num, i);
                    756: 
                    757:                spec = xmalloc(sizeof *spec);
                    758:                memset(spec, 0, sizeof *spec);
                    759:                spec->lu = lu;
                    760:                spec->num = lu->num;
                    761:                spec->lun = i;
                    762: 
                    763:                spec->timeout = ISTGT_LU_CAM_TIMEOUT;
                    764:                spec->inq_standard = NULL;
                    765:                spec->inq_standard_len = 0;
                    766:                spec->inq_pd = 0;
                    767:                spec->inq_rmb = 0;
                    768:                spec->inq_ver = 0;
                    769: 
                    770:                spec->file = lu->lun[i].u.device.file;
                    771:                spec->size = 0;
                    772:                spec->blocklen = 0;
                    773:                spec->blockcnt = 0;
                    774: 
                    775:                printf("LU%d: LUN%d file=%s\n",
                    776:                           lu->num, i, spec->file);
                    777: 
                    778:                flags = lu->readonly ? O_RDONLY : O_RDWR;
                    779:                rc = cam_get_device(spec->file, buf, sizeof buf,
                    780:                                                        &spec->unit);
                    781:                if (rc < 0) {
                    782:                        ISTGT_ERRLOG("LU%d: LUN%d: cam_get_device() failed\n", lu->num, i);
                    783:                        xfree(spec);
                    784:                        return -1;
                    785:                }
                    786:                spec->device = xstrdup(buf);
                    787:                spec->cam_dev = cam_open_spec_device(spec->device, spec->unit,
                    788:                                                                                         flags, NULL);
                    789:                if (spec->cam_dev == NULL) {
                    790:                        ISTGT_ERRLOG("LU%d: LUN%d: cam_open() failed\n", lu->num, i);
                    791:                        xfree(spec->device);
                    792:                        xfree(spec);
                    793:                        return -1;
                    794:                }
                    795:                spec->ccb = cam_getccb(spec->cam_dev);
                    796:                if (spec->ccb == NULL) {
                    797:                        ISTGT_ERRLOG("LU%d: LUN%d: cam_getccb() failed\n", lu->num, i);
                    798:                        cam_close_spec_device(spec->cam_dev);
                    799:                        xfree(spec->device);
                    800:                        xfree(spec);
                    801:                        return -1;
                    802:                }
                    803:                memset((uint8_t *) spec->ccb + sizeof(struct ccb_hdr), 0,
                    804:                           sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
                    805: 
                    806:                rc = istgt_lu_pass_set_inquiry(spec);
                    807:                if (rc < 0) {
                    808:                        ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_inquiry() failed\n",
                    809:                                                 lu->num, i);
                    810:                error_return:
                    811:                        cam_freeccb(spec->ccb);
                    812:                        cam_close_spec_device(spec->cam_dev);
                    813:                        xfree(spec->device);
                    814:                        xfree(spec);
                    815:                        return -1;
                    816:                }
                    817: 
                    818:                /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                    819:                pq = BGET8W(&spec->inq_standard[0], 7, 3);
                    820:                pd = BGET8W(&spec->inq_standard[0], 4, 5);
                    821:                /* RMB(7) */
                    822:                rmb = BGET8W(&spec->inq_standard[1], 7, 1);
                    823:                /* VERSION ANSI(2-0) */
                    824:                ver = BGET8W(&spec->inq_standard[2], 2, 3);
                    825:                /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
                    826:                fmt = BGET8W(&spec->inq_standard[3], 3, 4);
                    827: 
                    828:                printf("LU%d: LUN%d pq=0x%x, pd=0x%x, rmb=%d, ver=%d, fmt=%d\n",
                    829:                           lu->num, i,
                    830:                           pq, pd, rmb, ver, fmt);
                    831: 
                    832:                if (pq != 0x00) {
                    833:                        ISTGT_ERRLOG("unsupported peripheral qualifier (%x)\n", pq);
                    834:                        goto error_return;
                    835:                }
                    836: 
                    837:                switch (pd) {
                    838:                case SPC_PERIPHERAL_DEVICE_TYPE_DISK:
                    839:                        printf("LU%d: LUN%d Direct access block device\n", lu->num, i);
                    840:                        break;
                    841:                case SPC_PERIPHERAL_DEVICE_TYPE_TAPE:
                    842:                        printf("LU%d: LUN%d Sequential-access device\n", lu->num, i);
                    843:                        break;
                    844:                case SPC_PERIPHERAL_DEVICE_TYPE_DVD:
                    845:                        printf("LU%d: LUN%d CD/DVD device\n", lu->num, i);
                    846:                        break;
                    847:                case SPC_PERIPHERAL_DEVICE_TYPE_CHANGER:
                    848:                        printf("LU%d: LUN%d Medium changer device\n", lu->num, i);
                    849:                        break;
                    850:                default:
                    851:                        ISTGT_ERRLOG("unsupported peripheral device type (%x)\n", pd);
                    852:                        goto error_return;
                    853:                }
                    854: 
                    855:                switch (ver) {
                    856:                case SPC_VERSION_NONE:
                    857:                        printf("LU%d: LUN%d version NONE\n", lu->num, i);
                    858:                        break;
                    859:                case SPC_VERSION_SPC:
                    860:                        printf("LU%d: LUN%d version SPC\n", lu->num, i);
                    861:                        break;
                    862:                case SPC_VERSION_SPC2:
                    863:                        printf("LU%d: LUN%d version SPC2\n", lu->num, i);
                    864:                        break;
                    865:                case SPC_VERSION_SPC3:
                    866:                        printf("LU%d: LUN%d version SPC3\n", lu->num, i);
                    867:                        break;
                    868:                case SPC_VERSION_SPC4:
                    869:                        printf("LU%d: LUN%d version SPC4\n", lu->num, i);
                    870:                        break;
                    871:                case 0x01:
                    872:                        printf("LU%d: LUN%d version SCSI1\n", lu->num, i);
                    873:                        break;
                    874:                case 0x02:
                    875:                        printf("LU%d: LUN%d version SCSI2\n", lu->num, i);
                    876:                        break;
                    877:                default:
                    878:                        ISTGT_ERRLOG("LU%d: LUN%d: unsupported version(%d)\n",
                    879:                                                 lu->num, i, ver);
                    880:                        goto error_return;
                    881:                }
                    882:                switch (fmt) {
                    883:                case 0x00:
                    884:                        printf("LU%d: LUN%d format SCSI1\n", lu->num, i);
                    885:                        break;
                    886:                case 0x01:
                    887:                        printf("LU%d: LUN%d format CCS\n", lu->num, i);
                    888:                        break;
                    889:                case 0x02:
                    890:                        printf("LU%d: LUN%d format SCSI2/SPC\n", lu->num, i);
                    891:                        break;
                    892:                default:
                    893:                        ISTGT_ERRLOG("LU%d: LUN%d: unsupported format(%d)\n",
                    894:                                                 lu->num, i, fmt);
                    895:                        goto error_return;
                    896:                }
                    897: 
                    898:                spec->inq_pd = pd;
                    899:                spec->inq_rmb = rmb;
                    900:                spec->inq_ver = ver;
                    901:                spec->inq_fmt = fmt;
                    902: 
                    903:                if (pd != SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
                    904:                        rc = istgt_lu_pass_set_modesense(spec);
                    905:                        if (rc < 0) {
                    906: #if 0
                    907:                                ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_modesense() failed\n",
                    908:                                                         lu->num, i);
                    909:                                goto error_return;
                    910: #else
                    911:                                spec->ms_blockcnt = 0;
                    912:                                spec->ms_blocklen = 0;
                    913: #endif
                    914:                        }
                    915:                } else {
                    916:                        spec->ms_blockcnt = 0;
                    917:                        spec->ms_blocklen = 0;
                    918:                }
                    919: 
                    920:                if (pd == SPC_PERIPHERAL_DEVICE_TYPE_TAPE
                    921:                        || pd == SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
                    922:                        spec->timeout *= 10;
                    923:                }
                    924:                if (pd == SPC_PERIPHERAL_DEVICE_TYPE_DISK
                    925:                        || pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
                    926:                        rc = istgt_lu_pass_set_capacity(spec);
                    927:                        if (rc < 0) {
                    928:                                ISTGT_ERRLOG("LU%d: LUN%d: lu_pass_set_capacity() failed\n",
                    929:                                                         lu->num, i);
                    930:                                goto error_return;
                    931:                        }
                    932:                } else {
                    933:                        spec->blockcnt = 0;
                    934:                        spec->blocklen = 0;
                    935:                        spec->size = 0;
                    936:                }
                    937:                if (spec->ms_blocklen == 0) {
                    938:                        if (spec->blocklen == 0) {
                    939:                                if (pd == SPC_PERIPHERAL_DEVICE_TYPE_DVD) {
                    940:                                        spec->ms_blocklen = 2048;
                    941:                                } else {
                    942:                                        spec->ms_blocklen = 512;
                    943:                                }
                    944:                        } else {
                    945:                                spec->ms_blocklen = spec->blocklen;
                    946:                        }
                    947:                }
                    948: 
                    949:                if (pd != SPC_PERIPHERAL_DEVICE_TYPE_CHANGER) {
                    950:                        printf("LU%d: LUN%d block descriptor\n", lu->num, i);
                    951:                        printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
                    952:                                   lu->num, i, spec->ms_blockcnt, spec->ms_blocklen);
                    953: 
                    954:                        if (spec->inq_rmb && spec->blockcnt == 0) {
                    955:                                printf("LU%d: LUN%d medium not present\n", lu->num, i);
                    956:                        } else {
                    957:                                printf("LU%d: LUN%d medium capacity\n", lu->num, i);
                    958:                                printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
                    959:                                           lu->num, i, spec->blockcnt, spec->blocklen);
                    960: 
                    961:                                gb_size = spec->size / ISTGT_LU_1GB;
                    962:                                mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
                    963:                                if (gb_size > 0) {
                    964:                                        mb_digit = (int) (((mb_size * 100) / 1024) / 10);
                    965:                                        printf("LU%d: LUN%d %"PRIu64".%dGB\n",
                    966:                                                   lu->num, i, gb_size, mb_digit);
                    967:                                } else {
                    968:                                        printf("LU%d: LUN%d %"PRIu64"MB\n",
                    969:                                                   lu->num, i, mb_size);
                    970:                                }
                    971:                        }
                    972:                }
                    973: 
                    974:                printf("LU%d: LUN%d %spass through for %s\n",
                    975:                           lu->num, i,
                    976:                           lu->readonly ? "readonly " : "", lu->name);
                    977: 
                    978:                lu->lun[i].spec = spec;
                    979:        }
                    980: 
                    981:        return 0;
                    982: }
                    983: 
                    984: int
                    985: istgt_lu_pass_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
                    986: {
                    987:        ISTGT_LU_PASS *spec;
                    988:        int i;
                    989: 
                    990:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_pass_shutdown\n");
                    991: 
                    992:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
                    993:                                   lu->num, lu->name);
                    994:        for (i = 0; i < lu->maxlun; i++) {
                    995:                if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
                    996:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
                    997:                                                   lu->num, i);
                    998:                        continue;
                    999:                }
                   1000:                if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_DEVICE) {
                   1001:                        ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
                   1002:                        return -1;
                   1003:                }
                   1004:                spec = (ISTGT_LU_PASS *) lu->lun[i].spec;
                   1005: 
                   1006:                if (spec->ccb != NULL) {
                   1007:                        cam_freeccb(spec->ccb);
                   1008:                        spec->ccb = NULL;
                   1009:                }
                   1010:                if (spec->cam_dev != NULL) {
                   1011:                        cam_close_spec_device(spec->cam_dev);
                   1012:                        spec->cam_dev = NULL;
                   1013:                }
                   1014:                if (spec->device != NULL) {
                   1015:                        xfree(spec->device);
                   1016:                        spec->device = NULL;
                   1017:                }
                   1018:                xfree(spec);
                   1019:                lu->lun[i].spec = NULL;
                   1020:        }
                   1021: 
                   1022:        return 0;
                   1023: }
                   1024: 
                   1025: static int
                   1026: istgt_scsi_get_cdb_len(uint8_t *cdb)
                   1027: {
                   1028:        int group;
                   1029:        int cdblen = 0;
                   1030: 
                   1031:        if (cdb == NULL)
                   1032:                return 0;
                   1033: 
                   1034:        group = (cdb[0] >> 5) & 0x07;
                   1035:        switch (group) {
                   1036:        case 0x00:
                   1037:                /* 6byte commands */
                   1038:                cdblen = 6;
                   1039:                break;
                   1040:        case 0x01:
                   1041:                /* 10byte commands */
                   1042:                cdblen = 10;
                   1043:                break;
                   1044:        case 0x02:
                   1045:                /* 10byte commands */
                   1046:                cdblen = 10;
                   1047:                break;
                   1048:        case 0x03:
                   1049:                /* reserved */
                   1050:                if (cdb[0] == 0x7f) {
                   1051:                        /* variable length */
                   1052:                        cdblen = 8 + (cdb[7] & 0xff);
                   1053:                } else {
                   1054:                        /* XXX */
                   1055:                        cdblen = 6;
                   1056:                }
                   1057:                break;
                   1058:        case 0x04:
                   1059:                /* 16byte commands */
                   1060:                cdblen = 16;
                   1061:                break;
                   1062:        case 0x05:
                   1063:                /* 12byte commands */
                   1064:                cdblen = 12;
                   1065:                break;
                   1066:        case 0x06:
                   1067:        case 0x07:
                   1068:                /* vendor specific */
                   1069:                cdblen = 6;
                   1070:                break;
                   1071:        }
                   1072:        return cdblen;
                   1073: }
                   1074: 
                   1075: static int
                   1076: istgt_lu_pass_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
                   1077: {
                   1078:        int rc;
                   1079: 
                   1080:        if (len > bufsize) {
                   1081:                ISTGT_ERRLOG("bufsize(%d) too small\n", bufsize);
                   1082:                return -1;
                   1083:        }
                   1084:        rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
                   1085:        if (rc < 0) {
                   1086:                ISTGT_ERRLOG("iscsi_transfer_out()\n");
                   1087:                return -1;
                   1088:        }
                   1089:        return 0;
                   1090: }
                   1091: 
                   1092: static int
                   1093: istgt_lu_pass_do_cam(ISTGT_LU_PASS *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
                   1094: {
                   1095:        uint32_t flags;
                   1096:        uint8_t *cdb;
                   1097:        uint8_t *data;
                   1098:        int cdb_len;
                   1099:        int data_len;
                   1100:        int data_alloc_len;
                   1101:        uint8_t *sense_data;
                   1102:        int *sense_len;
                   1103:        int R_bit, W_bit;
                   1104:        int transfer_len;
                   1105:        int retry = 1;
                   1106:        int sk, asc, ascq;
                   1107:        int len;
                   1108:        int rc;
                   1109: 
                   1110:        cdb = lu_cmd->cdb;
                   1111:        data = lu_cmd->data;
                   1112:        data_alloc_len = lu_cmd->alloc_len;
                   1113:        sense_data = lu_cmd->sense_data;
                   1114:        sense_len = &lu_cmd->sense_data_len;
                   1115:        *sense_len = 0;
                   1116:        R_bit = lu_cmd->R_bit;
                   1117:        W_bit = lu_cmd->W_bit;
                   1118:        transfer_len = lu_cmd->transfer_len;
                   1119: 
                   1120:        cdb_len = istgt_scsi_get_cdb_len(cdb);
                   1121:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                   1122: 
                   1123:        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                   1124:        flags = CAM_DIR_NONE;
                   1125:        if (R_bit != 0) {
                   1126:                flags = CAM_DIR_IN;
                   1127:        } else if (W_bit != 0) {
                   1128:                flags = CAM_DIR_OUT;
                   1129:        }
                   1130:        flags |= CAM_DEV_QFRZDIS;
                   1131:        cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                   1132:                                  data, transfer_len, SSD_FULL_SIZE, cdb_len,
                   1133:                                  spec->timeout);
                   1134:        rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                   1135:        if (rc < 0) {
                   1136:                ISTGT_ERRLOG("cam_send_ccb() failed\n");
                   1137:                /* INTERNAL TARGET FAILURE */
                   1138:                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1139:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1140:                return -1;
                   1141:        }
                   1142: 
                   1143:        if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                   1144:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                   1145:                                           "request error CAM=0x%x, SCSI=0x%x\n",
                   1146:                                           spec->ccb->ccb_h.status,
                   1147:                                           spec->ccb->csio.scsi_status);
                   1148:                ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                   1149:                                                (uint8_t *) &spec->ccb->csio.sense_data,
                   1150:                                                SSD_FULL_SIZE);
                   1151:                if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK)
                   1152:                        == CAM_SCSI_STATUS_ERROR) {
                   1153:                        memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
                   1154:                        DSET16(&sense_data[0], SSD_FULL_SIZE);
                   1155:                        *sense_len = SSD_FULL_SIZE + 2;
                   1156:                        lu_cmd->status = spec->ccb->csio.scsi_status;
                   1157: #if 0
                   1158:                        if (lu_cmd->status == 0) {
                   1159:                                /* INTERNAL TARGET FAILURE */
                   1160:                                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1161:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1162:                        }
                   1163: #endif
                   1164:                        /* adjust fixed format length */
                   1165:                        if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
                   1166:                                || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
                   1167:                                len = DGET8(&sense_data[2+7]);
                   1168:                                len += 8;
                   1169:                                if (len < SSD_FULL_SIZE) {
                   1170:                                        *sense_len = len + 2;
                   1171:                                        DSET16(&sense_data[0], len);
                   1172:                                }
                   1173:                        }
                   1174:                        istgt_lu_pass_print_sense_key(sense_data + 2);
                   1175:                        istgt_lu_pass_parse_sense_key(sense_data + 2,
                   1176:                                                                                  &sk, &asc, &ascq);
                   1177:                } else {
                   1178: #if 0
                   1179:                        /* INTERNAL TARGET FAILURE */
                   1180:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1181:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1182: #endif
                   1183:                        memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
                   1184:                        DSET16(&sense_data[0], SSD_FULL_SIZE);
                   1185:                        *sense_len = SSD_FULL_SIZE + 2;
                   1186:                        lu_cmd->status = spec->ccb->csio.scsi_status;
                   1187:                        /* adjust fixed format length */
                   1188:                        if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
                   1189:                                || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
                   1190:                                len = DGET8(&sense_data[2+7]);
                   1191:                                len += 8;
                   1192:                                if (len < SSD_FULL_SIZE) {
                   1193:                                        *sense_len = len + 2;
                   1194:                                        DSET16(&sense_data[0], len);
                   1195:                                }
                   1196:                        }
                   1197:                        istgt_lu_pass_print_sense_key(sense_data + 2);
                   1198:                        istgt_lu_pass_parse_sense_key(sense_data + 2,
                   1199:                                                                                  &sk, &asc, &ascq);
                   1200:                }
                   1201:                return -1;
                   1202:        }
                   1203:        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "dxfer=%d, resid=%d, sense=%d\n",
                   1204:                                   spec->ccb->csio.dxfer_len,
                   1205:                                   spec->ccb->csio.resid,
                   1206:                                   spec->ccb->csio.sense_resid);
                   1207:        data_len = spec->ccb->csio.dxfer_len;
                   1208:        data_len -= spec->ccb->csio.resid;
                   1209: 
                   1210:        if (R_bit != 0 || W_bit != 0) {
                   1211: #if 0
                   1212:                if (data_len > 256) {
                   1213:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, 256);
                   1214:                } else {
                   1215:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, data_len);
                   1216:                }
                   1217: #endif
                   1218:                lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
                   1219:        } else {
                   1220:                lu_cmd->data_len = 0;
                   1221:        }
                   1222: 
                   1223:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1224:        return 0;
                   1225: }
                   1226: 
                   1227: static int
                   1228: istgt_lu_pass_do_cam_seg(ISTGT_LU_PASS *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
                   1229: {
                   1230:        uint64_t llba;
                   1231:        uint32_t lcnt;
                   1232:        uint32_t flags;
                   1233:        uint8_t fixcdb[16];
                   1234:        uint8_t *cdb;
                   1235:        uint8_t *data;
                   1236:        int pad_len;
                   1237:        int cdb_len;
                   1238:        int data_len;
                   1239:        int data_alloc_len;
                   1240:        uint8_t *sense_data;
                   1241:        int *sense_len;
                   1242:        int R_bit, W_bit;
                   1243:        int transfer_len;
                   1244:        int retry = 1;
                   1245:        int offset;
                   1246:        int seglen;
                   1247:        int len, cnt;
                   1248:        int sk, asc, ascq;
                   1249:        int rc;
                   1250: 
                   1251:        cdb = lu_cmd->cdb;
                   1252:        data = lu_cmd->data;
                   1253:        data_alloc_len = lu_cmd->alloc_len;
                   1254:        sense_data = lu_cmd->sense_data;
                   1255:        sense_len = &lu_cmd->sense_data_len;
                   1256:        *sense_len = 0;
                   1257:        R_bit = lu_cmd->R_bit;
                   1258:        W_bit = lu_cmd->W_bit;
                   1259:        transfer_len = lu_cmd->transfer_len;
                   1260: 
                   1261:        cdb_len = istgt_scsi_get_cdb_len(cdb);
                   1262:        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "CDB", cdb, cdb_len);
                   1263: 
                   1264:        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, cdb, cdb_len);
                   1265:        flags = CAM_DIR_NONE;
                   1266:        if (R_bit != 0) {
                   1267:                flags = CAM_DIR_IN;
                   1268:        } else if (W_bit != 0) {
                   1269:                flags = CAM_DIR_OUT;
                   1270:        }
                   1271:        flags |= CAM_DEV_QFRZDIS;
                   1272: 
                   1273: //#define MAX_SEGLEN (65536-4096)
                   1274: #define MAX_SEGLEN (65536)
                   1275:        pad_len = (int) ((uintptr_t) data & (4096 - 1));
                   1276:        if (pad_len != 0) {
                   1277:                pad_len = 4096 - pad_len;
                   1278:                data += pad_len;
                   1279:                data_alloc_len -= pad_len;
                   1280:        }
                   1281:        data_len = 0;
                   1282:        seglen = MAX_SEGLEN;
                   1283:        seglen -= MAX_SEGLEN % (int) spec->ms_blocklen;
                   1284:        len = 0;
                   1285:        for (offset = 0; offset < transfer_len; offset += seglen) {
                   1286:                len = DMIN32(seglen, (transfer_len - offset));
                   1287:                cnt = len / (int) spec->ms_blocklen;
                   1288:                switch(cdb[0]) {
                   1289:                case SBC_READ_6:
                   1290:                        memcpy(fixcdb, cdb, cdb_len);
                   1291:                        llba = (uint64_t) DGET16(&cdb[2]);
                   1292:                        lcnt = (uint32_t) DGET8(&cdb[4]);
                   1293:                        llba += offset / spec->ms_blocklen;
                   1294:                        lcnt = (uint64_t) cnt;
                   1295:                        DSET16(&fixcdb[2], (uint16_t) llba);
                   1296:                        DSET8(&fixcdb[4], (uint8_t) lcnt);
                   1297:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1298:                        break;
                   1299: 
                   1300:                case SBC_READ_10:
                   1301:                        memcpy(fixcdb, cdb, cdb_len);
                   1302:                        llba = (uint64_t) DGET32(&cdb[2]);
                   1303:                        lcnt = (uint32_t) DGET16(&cdb[7]);
                   1304:                        llba += offset / spec->ms_blocklen;
                   1305:                        lcnt = (uint64_t) cnt;
                   1306:                        DSET32(&fixcdb[2], (uint32_t) llba);
                   1307:                        DSET16(&fixcdb[7], (uint16_t) lcnt);
                   1308:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1309:                        break;
                   1310: 
                   1311:                case SBC_READ_12:
                   1312:                        memcpy(fixcdb, cdb, cdb_len);
                   1313:                        llba = (uint64_t) DGET32(&cdb[2]);
                   1314:                        lcnt = (uint32_t) DGET32(&cdb[6]);
                   1315:                        llba += offset / spec->ms_blocklen;
                   1316:                        lcnt = (uint64_t) cnt;
                   1317:                        DSET32(&fixcdb[2], (uint32_t) llba);
                   1318:                        DSET32(&fixcdb[6], (uint32_t) lcnt);
                   1319:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1320:                        break;
                   1321: 
                   1322:                case SBC_READ_16:
                   1323:                        memcpy(fixcdb, cdb, cdb_len);
                   1324:                        llba = (uint64_t) DGET64(&cdb[2]);
                   1325:                        lcnt = (uint32_t) DGET32(&cdb[10]);
                   1326:                        llba += offset / spec->ms_blocklen;
                   1327:                        lcnt = (uint64_t) cnt;
                   1328:                        DSET64(&fixcdb[2], (uint64_t) llba);
                   1329:                        DSET32(&fixcdb[10], (uint32_t) lcnt);
                   1330:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1331:                        break;
                   1332: 
                   1333:                case SBC_WRITE_6:
                   1334:                        memcpy(fixcdb, cdb, cdb_len);
                   1335:                        llba = (uint64_t) DGET16(&cdb[2]);
                   1336:                        lcnt = (uint32_t) DGET8(&cdb[4]);
                   1337:                        llba += offset / spec->ms_blocklen;
                   1338:                        lcnt = (uint64_t) cnt;
                   1339:                        DSET16(&fixcdb[2], (uint16_t) llba);
                   1340:                        DSET8(&fixcdb[4], (uint8_t) lcnt);
                   1341:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1342:                        break;
                   1343: 
                   1344:                case SBC_WRITE_10:
                   1345:                case SBC_WRITE_AND_VERIFY_10:
                   1346:                        memcpy(fixcdb, cdb, cdb_len);
                   1347:                        llba = (uint64_t) DGET32(&cdb[2]);
                   1348:                        lcnt = (uint32_t) DGET16(&cdb[7]);
                   1349:                        llba += offset / spec->ms_blocklen;
                   1350:                        lcnt = (uint64_t) cnt;
                   1351:                        DSET32(&fixcdb[2], (uint32_t) llba);
                   1352:                        DSET16(&fixcdb[7], (uint16_t) lcnt);
                   1353:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1354:                        break;
                   1355: 
                   1356:                case SBC_WRITE_12:
                   1357:                case SBC_WRITE_AND_VERIFY_12:
                   1358:                        memcpy(fixcdb, cdb, cdb_len);
                   1359:                        llba = (uint64_t) DGET32(&cdb[2]);
                   1360:                        lcnt = (uint32_t) DGET32(&cdb[6]);
                   1361:                        llba += offset / spec->ms_blocklen;
                   1362:                        lcnt = (uint64_t) cnt;
                   1363:                        DSET32(&fixcdb[2], (uint32_t) llba);
                   1364:                        DSET32(&fixcdb[6], (uint32_t) lcnt);
                   1365:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1366:                        break;
                   1367: 
                   1368:                case SBC_WRITE_16:
                   1369:                case SBC_WRITE_AND_VERIFY_16:
                   1370:                        memcpy(fixcdb, cdb, cdb_len);
                   1371:                        llba = (uint64_t) DGET64(&cdb[2]);
                   1372:                        lcnt = (uint32_t) DGET32(&cdb[10]);
                   1373:                        llba += offset / spec->ms_blocklen;
                   1374:                        lcnt = (uint64_t) cnt;
                   1375:                        DSET64(&fixcdb[2], (uint64_t) llba);
                   1376:                        DSET32(&fixcdb[10], (uint32_t) lcnt);
                   1377:                        memcpy(spec->ccb->csio.cdb_io.cdb_bytes, fixcdb, cdb_len);
                   1378:                        break;
                   1379: 
                   1380:                default:
                   1381:                        ISTGT_ERRLOG("unsupported OP=0x%x\n", cdb[0]);
                   1382:                        /* INTERNAL TARGET FAILURE */
                   1383:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1384:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1385:                        return -1;
                   1386:                }
                   1387: 
                   1388:                cam_fill_csio(&spec->ccb->csio, retry, NULL, flags, MSG_SIMPLE_Q_TAG,
                   1389:                                          data + offset, len, SSD_FULL_SIZE, cdb_len,
                   1390:                                          spec->timeout);
                   1391:                rc = cam_send_ccb(spec->cam_dev, spec->ccb);
                   1392:                if (rc < 0) {
                   1393:                        ISTGT_ERRLOG("cam_send_ccb() failed\n");
                   1394:                        /* INTERNAL TARGET FAILURE */
                   1395:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1396:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1397:                        return -1;
                   1398:                }
                   1399: 
                   1400:                if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                   1401:                        ISTGT_TRACELOG(ISTGT_TRACE_DEBUG,
                   1402:                                                   "request error CAM=0x%x, SCSI=0x%x\n",
                   1403:                                                   spec->ccb->ccb_h.status,
                   1404:                                                   spec->ccb->csio.scsi_status);
                   1405:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "SENSE",
                   1406:                                                        (uint8_t *) &spec->ccb->csio.sense_data,
                   1407:                                                        SSD_FULL_SIZE);
                   1408:                        if ((spec->ccb->ccb_h.status & CAM_STATUS_MASK)
                   1409:                                == CAM_SCSI_STATUS_ERROR) {
                   1410:                                memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
                   1411:                                DSET16(&sense_data[0], SSD_FULL_SIZE);
                   1412:                                *sense_len = SSD_FULL_SIZE + 2;
                   1413:                                lu_cmd->status = spec->ccb->csio.scsi_status;
                   1414: #if 0
                   1415:                                if (lu_cmd->status == 0) {
                   1416:                                        /* INTERNAL TARGET FAILURE */
                   1417:                                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1418:                                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1419:                                }
                   1420: #endif
                   1421:                                /* adjust fixed format length */
                   1422:                                if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
                   1423:                                        || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
                   1424:                                        len = DGET8(&sense_data[2+7]);
                   1425:                                        len += 8;
                   1426:                                        if (len < SSD_FULL_SIZE) {
                   1427:                                                *sense_len = len + 2;
                   1428:                                                DSET16(&sense_data[0], len);
                   1429:                                        }
                   1430:                                }
                   1431:                                istgt_lu_pass_print_sense_key(sense_data + 2);
                   1432:                                istgt_lu_pass_parse_sense_key(sense_data + 2,
                   1433:                                                                                          &sk, &asc, &ascq);
                   1434:                        } else {
                   1435: #if 0
                   1436:                                /* INTERNAL TARGET FAILURE */
                   1437:                                BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1438:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1439: #endif
                   1440:                                memcpy(sense_data + 2, &spec->ccb->csio.sense_data, SSD_FULL_SIZE);
                   1441:                                DSET16(&sense_data[0], SSD_FULL_SIZE);
                   1442:                                *sense_len = SSD_FULL_SIZE + 2;
                   1443:                                lu_cmd->status = spec->ccb->csio.scsi_status;
                   1444:                                /* adjust fixed format length */
                   1445:                                if (BGET8W(&sense_data[2+0], 6, 7) == 0x70
                   1446:                                        || BGET8W(&sense_data[2+0], 6, 7) == 0x71) {
                   1447:                                        len = DGET8(&sense_data[2+7]);
                   1448:                                        len += 8;
                   1449:                                        if (len < SSD_FULL_SIZE) {
                   1450:                                                *sense_len = len + 2;
                   1451:                                                DSET16(&sense_data[0], len);
                   1452:                                        }
                   1453:                                }
                   1454:                                istgt_lu_pass_print_sense_key(sense_data + 2);
                   1455:                                istgt_lu_pass_parse_sense_key(sense_data + 2,
                   1456:                                                                                          &sk, &asc, &ascq);
                   1457:                        }
                   1458:                        return -1;
                   1459:                }
                   1460:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "dxfer=%d, resid=%d, sense=%d\n",
                   1461:                                           spec->ccb->csio.dxfer_len,
                   1462:                                           spec->ccb->csio.resid,
                   1463:                                           spec->ccb->csio.sense_resid);
                   1464:                if (spec->ccb->csio.resid != 0) {
                   1465:                        /* INTERNAL TARGET FAILURE */
                   1466:                        BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
                   1467:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1468:                        return -1;
                   1469:                }
                   1470:                data_len += spec->ccb->csio.dxfer_len;
                   1471:                data_len -= spec->ccb->csio.resid;
                   1472:        }
                   1473: 
                   1474:        if (pad_len != 0) {
                   1475:                memcpy(lu_cmd->data, lu_cmd->data + pad_len, data_len);
                   1476:        }
                   1477:        if (R_bit !=0 || W_bit != 0) {
                   1478: #if 0
                   1479:                if (data_len > 256) {
                   1480:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, 256);
                   1481:                } else {
                   1482:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "DOCAM", data, data_len);
                   1483:                }
                   1484: #endif
                   1485:                lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
                   1486:        } else {
                   1487:                lu_cmd->data_len = 0;
                   1488:        }
                   1489: 
                   1490:        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1491:        return 0;
                   1492: }
                   1493: 
                   1494: static int
                   1495: istgt_lu_pass_build_sense_data(ISTGT_LU_PASS *spec, uint8_t *data, int sk, int asc, int ascq)
                   1496: {
                   1497:        int rc;
                   1498: 
                   1499:        rc = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
                   1500:        if (rc < 0) {
                   1501:                return -1;
                   1502:        }
                   1503:        return rc;
                   1504: }
                   1505: 
                   1506: int
                   1507: istgt_lu_pass_reset(ISTGT_LU_Ptr lu, int lun)
                   1508: {
                   1509:        ISTGT_LU_PASS *spec;
                   1510: 
                   1511:        if (lun >= lu->maxlun) {
                   1512:                return -1;
                   1513:        }
                   1514:        if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
                   1515:                return -1;
                   1516:        }
                   1517:        spec = (ISTGT_LU_PASS *) lu->lun[lun].spec;
                   1518: 
                   1519: #if 0
                   1520:        if (spec->lock) {
                   1521:                ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
                   1522:                spec->lock = 0;
                   1523:        }
                   1524: #endif
                   1525: 
                   1526:        return 0;
                   1527: }
                   1528: 
                   1529: int
                   1530: istgt_lu_pass_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
                   1531: {
                   1532:        ISTGT_LU_Ptr lu;
                   1533:        ISTGT_LU_PASS *spec;
                   1534:        uint8_t *data;
                   1535:        uint8_t *cdb;
                   1536:        uint64_t fmt_lun;
                   1537:        uint64_t lun;
                   1538:        uint64_t method;
                   1539:        uint32_t allocation_len;
                   1540:        int data_len;
                   1541:        int data_alloc_len;
                   1542:        uint32_t transfer_len;
                   1543:        uint8_t *sense_data;
                   1544:        int *sense_len;
                   1545:        int rc;
                   1546: 
                   1547:        if (lu_cmd == NULL)
                   1548:                return -1;
                   1549:        lu = lu_cmd->lu;
                   1550:        if (lu == NULL) {
                   1551:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1552:                return -1;
                   1553:        }
                   1554:        spec = NULL;
                   1555:        cdb = lu_cmd->cdb;
                   1556:        data = lu_cmd->data;
                   1557:        data_alloc_len = lu_cmd->alloc_len;
                   1558:        sense_data = lu_cmd->sense_data;
                   1559:        sense_len = &lu_cmd->sense_data_len;
                   1560:        *sense_len = 0;
                   1561: 
                   1562:        fmt_lun = lu_cmd->lun;
                   1563:        method = (fmt_lun >> 62) & 0x03U;
                   1564:        fmt_lun = fmt_lun >> 48;
                   1565:        if (method == 0x00U) {
                   1566:                lun = fmt_lun & 0x00ffU;
                   1567:        } else if (method == 0x01U) {
                   1568:                lun = fmt_lun & 0x3fffU;
                   1569:        } else {
                   1570:                lun = 0xffffU;
                   1571:        }
                   1572:        if (lun >= lu->maxlun) {
                   1573: #ifdef ISTGT_TRACE_PASS
                   1574:                ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
                   1575:                                         lu->num, lun);
                   1576: #endif /* ISTGT_TRACE_PASS */
                   1577:                if (cdb[0] == SPC_INQUIRY) {
                   1578:                        allocation_len = DGET16(&cdb[3]);
                   1579:                        if (allocation_len > data_alloc_len) {
                   1580:                                ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
                   1581:                                                         data_alloc_len);
                   1582:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1583:                                return -1;
                   1584:                        }
                   1585:                        memset(data, 0, allocation_len);
                   1586:                        /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
                   1587:                        BDSET8W(&data[0], 0x03, 7, 3);
                   1588:                        BDADD8W(&data[0], 0x1f, 4, 5);
                   1589:                        data_len = 96;
                   1590:                        memset(&data[1], 0, data_len - 1);
                   1591:                        /* ADDITIONAL LENGTH */
                   1592:                        data[4] = data_len - 5;
                   1593:                        lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
                   1594:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1595:                        return 0;
                   1596:                } else {
                   1597:                        /* LOGICAL UNIT NOT SUPPORTED */
                   1598:                        BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
                   1599:                        lu_cmd->data_len = 0;
                   1600:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1601:                        return 0;
                   1602:                }
                   1603:        }
                   1604:        spec = (ISTGT_LU_PASS *) lu->lun[lun].spec;
                   1605:        if (spec == NULL) {
                   1606:                /* LOGICAL UNIT NOT SUPPORTED */
                   1607:                BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
                   1608:                lu_cmd->data_len = 0;
                   1609:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1610:                return 0;
                   1611:        }
                   1612: 
                   1613:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
                   1614:                                   cdb[0], lu_cmd->lun);
                   1615: #ifdef ISTGT_TRACE_PASS
                   1616:        if (cdb[0] != SPC_TEST_UNIT_READY) {
                   1617:                istgt_scsi_dump_cdb(cdb);
                   1618:        }
                   1619: #endif /* ISTGT_TRACE_DISK */
                   1620: 
                   1621:        if (lu_cmd->W_bit != 0) {
                   1622:                transfer_len = lu_cmd->transfer_len;
                   1623:                rc = istgt_lu_pass_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
                   1624:                                                                                 lu_cmd->iobufsize, transfer_len);
                   1625:                if (rc < 0) {
                   1626:                        ISTGT_ERRLOG("lu_pass_transfer_data() failed\n");
                   1627:                        lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1628:                        return -1;
                   1629:                }
                   1630:                lu_cmd->data = lu_cmd->iobuf;
                   1631:                lu_cmd->alloc_len = lu_cmd->iobufsize;
                   1632:        }
                   1633: 
                   1634:        switch (spec->inq_pd) {
                   1635:        case SPC_PERIPHERAL_DEVICE_TYPE_DISK:
                   1636:                switch (cdb[0]) {
                   1637:                case SBC_READ_6:
                   1638:                case SBC_READ_10:
                   1639:                case SBC_READ_12:
                   1640:                case SBC_READ_16:
                   1641:                case SBC_WRITE_6:
                   1642:                case SBC_WRITE_12:
                   1643:                case SBC_WRITE_AND_VERIFY_12:
                   1644:                case SBC_WRITE_10:
                   1645:                case SBC_WRITE_AND_VERIFY_10:
                   1646:                case SBC_WRITE_16:
                   1647:                case SBC_WRITE_AND_VERIFY_16:
                   1648:                        lu_cmd->data = lu_cmd->iobuf;
                   1649:                        lu_cmd->alloc_len = lu_cmd->iobufsize;
                   1650:                        if (lu_cmd->transfer_len > lu_cmd->alloc_len) {
                   1651:                                ISTGT_ERRLOG("alloc_len(%d) too small\n", lu_cmd->alloc_len);
                   1652:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1653:                                return -1;
                   1654:                        }
                   1655:                        rc = istgt_lu_pass_do_cam_seg(spec, conn, lu_cmd);
                   1656:                        if (rc < 0) {
                   1657:                                /* build by function */
                   1658:                                break;
                   1659:                        }
                   1660:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1661:                        break;
                   1662:                default:
                   1663:                        rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
                   1664:                        if (rc < 0) {
                   1665:                                /* build by function */
                   1666:                                break;
                   1667:                        }
                   1668:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1669:                        break;
                   1670:                }
                   1671:                break;
                   1672:        case SPC_PERIPHERAL_DEVICE_TYPE_TAPE:
                   1673:                switch (cdb[0]) {
                   1674:                default:
                   1675:                        rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
                   1676:                        if (rc < 0) {
                   1677:                                /* build by function */
                   1678:                                break;
                   1679:                        }
                   1680:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1681:                        break;
                   1682:                }
                   1683:                break;
                   1684:        case SPC_PERIPHERAL_DEVICE_TYPE_DVD:
                   1685:                switch (cdb[0]) {
                   1686:                case MMC_READ_10:
                   1687:                case MMC_READ_12:
                   1688:                case MMC_WRITE_10:
                   1689:                case MMC_WRITE_AND_VERIFY_10:
                   1690:                case MMC_WRITE_12:
                   1691:                        lu_cmd->data = lu_cmd->iobuf;
                   1692:                        lu_cmd->alloc_len = lu_cmd->iobufsize;
                   1693:                        if (lu_cmd->transfer_len > lu_cmd->alloc_len) {
                   1694:                                ISTGT_ERRLOG("alloc_len(%d) too small\n", lu_cmd->alloc_len);
                   1695:                                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1696:                                return -1;
                   1697:                        }
                   1698:                        rc = istgt_lu_pass_do_cam_seg(spec, conn, lu_cmd);
                   1699:                        if (rc < 0) {
                   1700:                                /* build by function */
                   1701:                                break;
                   1702:                        }
                   1703:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1704:                        break;
                   1705: #ifdef ISTGT_TRACE_PASS
                   1706:                case MMC_GET_EVENT_STATUS_NOTIFICATION:
                   1707:                        rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
                   1708:                        if (rc < 0) {
                   1709:                                /* build by function */
                   1710:                                break;
                   1711:                        }
                   1712:                        ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "EVENT",
                   1713:                                                        lu_cmd->data, lu_cmd->data_len);
                   1714:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1715:                        break;
                   1716: #endif /* ISTGT_TRACE_PASS */
                   1717:                default:
                   1718:                        rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
                   1719:                        if (rc < 0) {
                   1720:                                /* build by function */
                   1721:                                break;
                   1722:                        }
                   1723:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1724:                        break;
                   1725:                }
                   1726:                break;
                   1727:        case SPC_PERIPHERAL_DEVICE_TYPE_CHANGER:
                   1728:                switch (cdb[0]) {
                   1729:                default:
                   1730:                        rc = istgt_lu_pass_do_cam(spec, conn, lu_cmd);
                   1731:                        if (rc < 0) {
                   1732:                                /* build by function */
                   1733:                                break;
                   1734:                        }
                   1735:                        lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
                   1736:                        break;
                   1737:                }
                   1738:                break;
                   1739:        default:
                   1740:                ISTGT_ERRLOG("unsupported peripheral device type (%x)\n",
                   1741:                                         spec->inq_pd);
                   1742:                /* LOGICAL UNIT NOT SUPPORTED */
                   1743:                BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
                   1744:                lu_cmd->data_len = 0;
                   1745:                lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
                   1746:                break;
                   1747:        }
                   1748: 
                   1749:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
                   1750:                                   "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
                   1751:                                   " complete\n",
                   1752:                                   cdb[0], lu_cmd->lun, lu_cmd->status);
                   1753:        return 0;
                   1754: }
                   1755: #else /* HAVE_LIBCAM */
                   1756: #include "istgt.h"
                   1757: #include "istgt_ver.h"
                   1758: #include "istgt_log.h"
                   1759: #include "istgt_misc.h"
                   1760: #include "istgt_lu.h"
                   1761: #include "istgt_proto.h"
                   1762: #include "istgt_scsi.h"
                   1763: 
                   1764: int
                   1765: istgt_lu_pass_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
                   1766: {
                   1767:        return 0;
                   1768: }
                   1769: 
                   1770: int
                   1771: istgt_lu_pass_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
                   1772: {
                   1773:        return 0;
                   1774: }
                   1775: 
                   1776: int
                   1777: istgt_lu_pass_reset(ISTGT_LU_Ptr lu, int lun)
                   1778: {
                   1779:        return 0;
                   1780: }
                   1781: 
                   1782: int
                   1783: istgt_lu_pass_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
                   1784: {
                   1785:        ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "unsupported unit\n");
                   1786:        return -1;
                   1787: }
                   1788: #endif /* HAVE_LIBCAM */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>