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

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

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