Annotation of qemu/block/iscsi.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * QEMU Block driver for iSCSI images
                      3:  *
                      4:  * Copyright (c) 2010-2011 Ronnie Sahlberg <[email protected]>
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: 
                     25: #include "config-host.h"
                     26: 
                     27: #include <poll.h>
1.1.1.2 ! root       28: #include <arpa/inet.h>
1.1       root       29: #include "qemu-common.h"
                     30: #include "qemu-error.h"
                     31: #include "block_int.h"
                     32: #include "trace.h"
1.1.1.2 ! root       33: #include "hw/scsi-defs.h"
1.1       root       34: 
                     35: #include <iscsi/iscsi.h>
                     36: #include <iscsi/scsi-lowlevel.h>
                     37: 
                     38: 
                     39: typedef struct IscsiLun {
                     40:     struct iscsi_context *iscsi;
                     41:     int lun;
1.1.1.2 ! root       42:     enum scsi_inquiry_peripheral_device_type type;
1.1       root       43:     int block_size;
1.1.1.2 ! root       44:     uint64_t num_blocks;
        !            45:     int events;
1.1       root       46: } IscsiLun;
                     47: 
                     48: typedef struct IscsiAIOCB {
                     49:     BlockDriverAIOCB common;
                     50:     QEMUIOVector *qiov;
                     51:     QEMUBH *bh;
                     52:     IscsiLun *iscsilun;
                     53:     struct scsi_task *task;
                     54:     uint8_t *buf;
                     55:     int status;
                     56:     int canceled;
                     57:     size_t read_size;
                     58:     size_t read_offset;
                     59: } IscsiAIOCB;
                     60: 
                     61: struct IscsiTask {
                     62:     IscsiLun *iscsilun;
                     63:     BlockDriverState *bs;
                     64:     int status;
                     65:     int complete;
                     66: };
                     67: 
                     68: static void
                     69: iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
                     70:                     void *private_data)
                     71: {
                     72: }
                     73: 
                     74: static void
                     75: iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
                     76: {
                     77:     IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
                     78:     IscsiLun *iscsilun = acb->iscsilun;
                     79: 
                     80:     acb->common.cb(acb->common.opaque, -ECANCELED);
                     81:     acb->canceled = 1;
                     82: 
                     83:     /* send a task mgmt call to the target to cancel the task on the target */
                     84:     iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
                     85:                                      iscsi_abort_task_cb, NULL);
                     86: 
                     87:     /* then also cancel the task locally in libiscsi */
                     88:     iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
                     89: }
                     90: 
                     91: static AIOPool iscsi_aio_pool = {
                     92:     .aiocb_size         = sizeof(IscsiAIOCB),
                     93:     .cancel             = iscsi_aio_cancel,
                     94: };
                     95: 
                     96: 
                     97: static void iscsi_process_read(void *arg);
                     98: static void iscsi_process_write(void *arg);
                     99: 
                    100: static int iscsi_process_flush(void *arg)
                    101: {
                    102:     IscsiLun *iscsilun = arg;
                    103: 
                    104:     return iscsi_queue_length(iscsilun->iscsi) > 0;
                    105: }
                    106: 
                    107: static void
                    108: iscsi_set_events(IscsiLun *iscsilun)
                    109: {
                    110:     struct iscsi_context *iscsi = iscsilun->iscsi;
1.1.1.2 ! root      111:     int ev;
1.1       root      112: 
1.1.1.2 ! root      113:     /* We always register a read handler.  */
        !           114:     ev = POLLIN;
        !           115:     ev |= iscsi_which_events(iscsi);
        !           116:     if (ev != iscsilun->events) {
        !           117:         qemu_aio_set_fd_handler(iscsi_get_fd(iscsi),
        !           118:                       iscsi_process_read,
        !           119:                       (ev & POLLOUT) ? iscsi_process_write : NULL,
        !           120:                       iscsi_process_flush,
        !           121:                       iscsilun);
        !           122: 
        !           123:     }
        !           124: 
        !           125:     /* If we just added an event, the callback might be delayed
        !           126:      * unless we call qemu_notify_event().
        !           127:      */
        !           128:     if (ev & ~iscsilun->events) {
        !           129:         qemu_notify_event();
        !           130:     }
        !           131:     iscsilun->events = ev;
1.1       root      132: }
                    133: 
                    134: static void
                    135: iscsi_process_read(void *arg)
                    136: {
                    137:     IscsiLun *iscsilun = arg;
                    138:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    139: 
                    140:     iscsi_service(iscsi, POLLIN);
                    141:     iscsi_set_events(iscsilun);
                    142: }
                    143: 
                    144: static void
                    145: iscsi_process_write(void *arg)
                    146: {
                    147:     IscsiLun *iscsilun = arg;
                    148:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    149: 
                    150:     iscsi_service(iscsi, POLLOUT);
                    151:     iscsi_set_events(iscsilun);
                    152: }
                    153: 
                    154: 
                    155: static int
                    156: iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
                    157: {
                    158:     acb->bh = qemu_bh_new(cb, acb);
                    159:     if (!acb->bh) {
                    160:         error_report("oom: could not create iscsi bh");
                    161:         return -EIO;
                    162:     }
                    163: 
                    164:     qemu_bh_schedule(acb->bh);
                    165:     return 0;
                    166: }
                    167: 
                    168: static void
                    169: iscsi_readv_writev_bh_cb(void *p)
                    170: {
                    171:     IscsiAIOCB *acb = p;
                    172: 
                    173:     qemu_bh_delete(acb->bh);
                    174: 
                    175:     if (acb->canceled == 0) {
                    176:         acb->common.cb(acb->common.opaque, acb->status);
                    177:     }
                    178: 
                    179:     qemu_aio_release(acb);
                    180: }
                    181: 
                    182: 
                    183: static void
1.1.1.2 ! root      184: iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
1.1       root      185:                      void *command_data, void *opaque)
                    186: {
                    187:     IscsiAIOCB *acb = opaque;
                    188: 
1.1.1.2 ! root      189:     trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
1.1       root      190: 
                    191:     g_free(acb->buf);
                    192: 
                    193:     if (acb->canceled != 0) {
                    194:         qemu_aio_release(acb);
                    195:         scsi_free_scsi_task(acb->task);
                    196:         acb->task = NULL;
                    197:         return;
                    198:     }
                    199: 
                    200:     acb->status = 0;
                    201:     if (status < 0) {
1.1.1.2 ! root      202:         error_report("Failed to write16 data to iSCSI lun. %s",
1.1       root      203:                      iscsi_get_error(iscsi));
                    204:         acb->status = -EIO;
                    205:     }
                    206: 
                    207:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    208:     scsi_free_scsi_task(acb->task);
                    209:     acb->task = NULL;
                    210: }
                    211: 
                    212: static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
                    213: {
                    214:     return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
                    215: }
                    216: 
                    217: static BlockDriverAIOCB *
                    218: iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
                    219:                  QEMUIOVector *qiov, int nb_sectors,
                    220:                  BlockDriverCompletionFunc *cb,
                    221:                  void *opaque)
                    222: {
                    223:     IscsiLun *iscsilun = bs->opaque;
                    224:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    225:     IscsiAIOCB *acb;
                    226:     size_t size;
1.1.1.2 ! root      227:     uint32_t num_sectors;
        !           228:     uint64_t lba;
        !           229:     struct iscsi_data data;
1.1       root      230: 
                    231:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    232:     trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
                    233: 
                    234:     acb->iscsilun = iscsilun;
                    235:     acb->qiov     = qiov;
                    236: 
                    237:     acb->canceled   = 0;
                    238: 
1.1.1.2 ! root      239:     /* XXX we should pass the iovec to write16 to avoid the extra copy */
1.1       root      240:     /* this will allow us to get rid of 'buf' completely */
                    241:     size = nb_sectors * BDRV_SECTOR_SIZE;
                    242:     acb->buf = g_malloc(size);
                    243:     qemu_iovec_to_buffer(acb->qiov, acb->buf);
1.1.1.2 ! root      244: 
        !           245: 
        !           246:     acb->task = malloc(sizeof(struct scsi_task));
1.1       root      247:     if (acb->task == NULL) {
1.1.1.2 ! root      248:         error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
        !           249:                      "command. %s", iscsi_get_error(iscsi));
        !           250:         qemu_aio_release(acb);
        !           251:         return NULL;
        !           252:     }
        !           253:     memset(acb->task, 0, sizeof(struct scsi_task));
        !           254: 
        !           255:     acb->task->xfer_dir = SCSI_XFER_WRITE;
        !           256:     acb->task->cdb_size = 16;
        !           257:     acb->task->cdb[0] = 0x8a;
        !           258:     if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
        !           259:         /* set FUA on writes when cache mode is write through */
        !           260:         acb->task->cdb[1] |= 0x04;
        !           261:     }
        !           262:     lba = sector_qemu2lun(sector_num, iscsilun);
        !           263:     *(uint32_t *)&acb->task->cdb[2]  = htonl(lba >> 32);
        !           264:     *(uint32_t *)&acb->task->cdb[6]  = htonl(lba & 0xffffffff);
        !           265:     num_sectors = size / iscsilun->block_size;
        !           266:     *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
        !           267:     acb->task->expxferlen = size;
        !           268: 
        !           269:     data.data = acb->buf;
        !           270:     data.size = size;
        !           271: 
        !           272:     if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
        !           273:                                  iscsi_aio_write16_cb,
        !           274:                                  &data,
        !           275:                                  acb) != 0) {
        !           276:         scsi_free_scsi_task(acb->task);
1.1       root      277:         g_free(acb->buf);
                    278:         qemu_aio_release(acb);
                    279:         return NULL;
                    280:     }
                    281: 
                    282:     iscsi_set_events(iscsilun);
                    283: 
                    284:     return &acb->common;
                    285: }
                    286: 
                    287: static void
1.1.1.2 ! root      288: iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
1.1       root      289:                     void *command_data, void *opaque)
                    290: {
                    291:     IscsiAIOCB *acb = opaque;
                    292: 
1.1.1.2 ! root      293:     trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
1.1       root      294: 
                    295:     if (acb->canceled != 0) {
                    296:         qemu_aio_release(acb);
                    297:         scsi_free_scsi_task(acb->task);
                    298:         acb->task = NULL;
                    299:         return;
                    300:     }
                    301: 
                    302:     acb->status = 0;
                    303:     if (status != 0) {
1.1.1.2 ! root      304:         error_report("Failed to read16 data from iSCSI lun. %s",
1.1       root      305:                      iscsi_get_error(iscsi));
                    306:         acb->status = -EIO;
                    307:     }
                    308: 
                    309:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    310:     scsi_free_scsi_task(acb->task);
                    311:     acb->task = NULL;
                    312: }
                    313: 
                    314: static BlockDriverAIOCB *
                    315: iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
                    316:                 QEMUIOVector *qiov, int nb_sectors,
                    317:                 BlockDriverCompletionFunc *cb,
                    318:                 void *opaque)
                    319: {
                    320:     IscsiLun *iscsilun = bs->opaque;
                    321:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    322:     IscsiAIOCB *acb;
1.1.1.2 ! root      323:     size_t qemu_read_size;
1.1       root      324:     int i;
1.1.1.2 ! root      325:     uint64_t lba;
        !           326:     uint32_t num_sectors;
1.1       root      327: 
                    328:     qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
                    329: 
                    330:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    331:     trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
                    332: 
                    333:     acb->iscsilun = iscsilun;
                    334:     acb->qiov     = qiov;
                    335: 
                    336:     acb->canceled    = 0;
                    337:     acb->read_size   = qemu_read_size;
                    338:     acb->buf         = NULL;
                    339: 
                    340:     /* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
                    341:      * may be misaligned to the LUN, so we may need to read some extra
                    342:      * data.
                    343:      */
                    344:     acb->read_offset = 0;
                    345:     if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
                    346:         uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
                    347: 
                    348:         acb->read_offset  = bdrv_offset % iscsilun->block_size;
                    349:     }
                    350: 
1.1.1.2 ! root      351:     num_sectors  = (qemu_read_size + iscsilun->block_size
        !           352:                     + acb->read_offset - 1)
        !           353:                     / iscsilun->block_size;
        !           354: 
        !           355:     acb->task = malloc(sizeof(struct scsi_task));
1.1       root      356:     if (acb->task == NULL) {
1.1.1.2 ! root      357:         error_report("iSCSI: Failed to allocate task for scsi READ16 "
        !           358:                      "command. %s", iscsi_get_error(iscsi));
        !           359:         qemu_aio_release(acb);
        !           360:         return NULL;
        !           361:     }
        !           362:     memset(acb->task, 0, sizeof(struct scsi_task));
        !           363: 
        !           364:     acb->task->xfer_dir = SCSI_XFER_READ;
        !           365:     lba = sector_qemu2lun(sector_num, iscsilun);
        !           366:     acb->task->expxferlen = qemu_read_size;
        !           367: 
        !           368:     switch (iscsilun->type) {
        !           369:     case TYPE_DISK:
        !           370:         acb->task->cdb_size = 16;
        !           371:         acb->task->cdb[0]  = 0x88;
        !           372:         *(uint32_t *)&acb->task->cdb[2]  = htonl(lba >> 32);
        !           373:         *(uint32_t *)&acb->task->cdb[6]  = htonl(lba & 0xffffffff);
        !           374:         *(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
        !           375:         break;
        !           376:     default:
        !           377:         acb->task->cdb_size = 10;
        !           378:         acb->task->cdb[0]  = 0x28;
        !           379:         *(uint32_t *)&acb->task->cdb[2] = htonl(lba);
        !           380:         *(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
        !           381:         break;
        !           382:     }
        !           383:     
        !           384:     if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
        !           385:                                  iscsi_aio_read16_cb,
        !           386:                                  NULL,
        !           387:                                  acb) != 0) {
        !           388:         scsi_free_scsi_task(acb->task);
1.1       root      389:         qemu_aio_release(acb);
                    390:         return NULL;
                    391:     }
                    392: 
                    393:     for (i = 0; i < acb->qiov->niov; i++) {
                    394:         scsi_task_add_data_in_buffer(acb->task,
                    395:                 acb->qiov->iov[i].iov_len,
                    396:                 acb->qiov->iov[i].iov_base);
                    397:     }
                    398: 
                    399:     iscsi_set_events(iscsilun);
                    400: 
                    401:     return &acb->common;
                    402: }
                    403: 
                    404: 
                    405: static void
                    406: iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
                    407:                      void *command_data, void *opaque)
                    408: {
                    409:     IscsiAIOCB *acb = opaque;
                    410: 
                    411:     if (acb->canceled != 0) {
                    412:         qemu_aio_release(acb);
                    413:         scsi_free_scsi_task(acb->task);
                    414:         acb->task = NULL;
                    415:         return;
                    416:     }
                    417: 
                    418:     acb->status = 0;
                    419:     if (status < 0) {
                    420:         error_report("Failed to sync10 data on iSCSI lun. %s",
                    421:                      iscsi_get_error(iscsi));
                    422:         acb->status = -EIO;
                    423:     }
                    424: 
                    425:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
                    426:     scsi_free_scsi_task(acb->task);
                    427:     acb->task = NULL;
                    428: }
                    429: 
                    430: static BlockDriverAIOCB *
                    431: iscsi_aio_flush(BlockDriverState *bs,
                    432:                 BlockDriverCompletionFunc *cb, void *opaque)
                    433: {
                    434:     IscsiLun *iscsilun = bs->opaque;
                    435:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    436:     IscsiAIOCB *acb;
                    437: 
                    438:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
                    439: 
                    440:     acb->iscsilun = iscsilun;
                    441:     acb->canceled   = 0;
                    442: 
                    443:     acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
                    444:                                          0, 0, 0, 0,
                    445:                                          iscsi_synccache10_cb,
                    446:                                          acb);
                    447:     if (acb->task == NULL) {
                    448:         error_report("iSCSI: Failed to send synchronizecache10 command. %s",
                    449:                      iscsi_get_error(iscsi));
                    450:         qemu_aio_release(acb);
                    451:         return NULL;
                    452:     }
                    453: 
                    454:     iscsi_set_events(iscsilun);
                    455: 
                    456:     return &acb->common;
                    457: }
                    458: 
1.1.1.2 ! root      459: static void
        !           460: iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
        !           461:                      void *command_data, void *opaque)
        !           462: {
        !           463:     IscsiAIOCB *acb = opaque;
        !           464: 
        !           465:     if (acb->canceled != 0) {
        !           466:         qemu_aio_release(acb);
        !           467:         scsi_free_scsi_task(acb->task);
        !           468:         acb->task = NULL;
        !           469:         return;
        !           470:     }
        !           471: 
        !           472:     acb->status = 0;
        !           473:     if (status < 0) {
        !           474:         error_report("Failed to unmap data on iSCSI lun. %s",
        !           475:                      iscsi_get_error(iscsi));
        !           476:         acb->status = -EIO;
        !           477:     }
        !           478: 
        !           479:     iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
        !           480:     scsi_free_scsi_task(acb->task);
        !           481:     acb->task = NULL;
        !           482: }
        !           483: 
        !           484: static BlockDriverAIOCB *
        !           485: iscsi_aio_discard(BlockDriverState *bs,
        !           486:                   int64_t sector_num, int nb_sectors,
        !           487:                   BlockDriverCompletionFunc *cb, void *opaque)
        !           488: {
        !           489:     IscsiLun *iscsilun = bs->opaque;
        !           490:     struct iscsi_context *iscsi = iscsilun->iscsi;
        !           491:     IscsiAIOCB *acb;
        !           492:     struct unmap_list list[1];
        !           493: 
        !           494:     acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
        !           495: 
        !           496:     acb->iscsilun = iscsilun;
        !           497:     acb->canceled   = 0;
        !           498: 
        !           499:     list[0].lba = sector_qemu2lun(sector_num, iscsilun);
        !           500:     list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
        !           501: 
        !           502:     acb->task = iscsi_unmap_task(iscsi, iscsilun->lun,
        !           503:                                  0, 0, &list[0], 1,
        !           504:                                  iscsi_unmap_cb,
        !           505:                                  acb);
        !           506:     if (acb->task == NULL) {
        !           507:         error_report("iSCSI: Failed to send unmap command. %s",
        !           508:                      iscsi_get_error(iscsi));
        !           509:         qemu_aio_release(acb);
        !           510:         return NULL;
        !           511:     }
        !           512: 
        !           513:     iscsi_set_events(iscsilun);
        !           514: 
        !           515:     return &acb->common;
        !           516: }
        !           517: 
1.1       root      518: static int64_t
                    519: iscsi_getlength(BlockDriverState *bs)
                    520: {
                    521:     IscsiLun *iscsilun = bs->opaque;
                    522:     int64_t len;
                    523: 
                    524:     len  = iscsilun->num_blocks;
                    525:     len *= iscsilun->block_size;
                    526: 
                    527:     return len;
                    528: }
                    529: 
                    530: static void
1.1.1.2 ! root      531: iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
        !           532:                         void *command_data, void *opaque)
        !           533: {
        !           534:     struct IscsiTask *itask = opaque;
        !           535:     struct scsi_readcapacity16 *rc16;
        !           536:     struct scsi_task *task = command_data;
        !           537: 
        !           538:     if (status != 0) {
        !           539:         error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
        !           540:                      iscsi_get_error(iscsi));
        !           541:         itask->status   = 1;
        !           542:         itask->complete = 1;
        !           543:         scsi_free_scsi_task(task);
        !           544:         return;
        !           545:     }
        !           546: 
        !           547:     rc16 = scsi_datain_unmarshall(task);
        !           548:     if (rc16 == NULL) {
        !           549:         error_report("iSCSI: Failed to unmarshall readcapacity16 data.");
        !           550:         itask->status   = 1;
        !           551:         itask->complete = 1;
        !           552:         scsi_free_scsi_task(task);
        !           553:         return;
        !           554:     }
        !           555: 
        !           556:     itask->iscsilun->block_size = rc16->block_length;
        !           557:     itask->iscsilun->num_blocks = rc16->returned_lba + 1;
        !           558:     itask->bs->total_sectors    = itask->iscsilun->num_blocks *
        !           559:                                itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
        !           560: 
        !           561:     itask->status   = 0;
        !           562:     itask->complete = 1;
        !           563:     scsi_free_scsi_task(task);
        !           564: }
        !           565: 
        !           566: static void
1.1       root      567: iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
                    568:                         void *command_data, void *opaque)
                    569: {
                    570:     struct IscsiTask *itask = opaque;
                    571:     struct scsi_readcapacity10 *rc10;
                    572:     struct scsi_task *task = command_data;
                    573: 
                    574:     if (status != 0) {
                    575:         error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
                    576:                      iscsi_get_error(iscsi));
                    577:         itask->status   = 1;
                    578:         itask->complete = 1;
                    579:         scsi_free_scsi_task(task);
                    580:         return;
                    581:     }
                    582: 
                    583:     rc10 = scsi_datain_unmarshall(task);
                    584:     if (rc10 == NULL) {
                    585:         error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
                    586:         itask->status   = 1;
                    587:         itask->complete = 1;
                    588:         scsi_free_scsi_task(task);
                    589:         return;
                    590:     }
                    591: 
                    592:     itask->iscsilun->block_size = rc10->block_size;
1.1.1.2 ! root      593:     itask->iscsilun->num_blocks = rc10->lba + 1;
        !           594:     itask->bs->total_sectors    = itask->iscsilun->num_blocks *
        !           595:                                itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
1.1       root      596: 
                    597:     itask->status   = 0;
                    598:     itask->complete = 1;
                    599:     scsi_free_scsi_task(task);
                    600: }
                    601: 
1.1.1.2 ! root      602: static void
        !           603: iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
        !           604:                  void *opaque)
        !           605: {
        !           606:     struct IscsiTask *itask = opaque;
        !           607:     struct scsi_task *task = command_data;
        !           608:     struct scsi_inquiry_standard *inq;
        !           609: 
        !           610:     if (status != 0) {
        !           611:         itask->status   = 1;
        !           612:         itask->complete = 1;
        !           613:         scsi_free_scsi_task(task);
        !           614:         return;
        !           615:     }
        !           616: 
        !           617:     inq = scsi_datain_unmarshall(task);
        !           618:     if (inq == NULL) {
        !           619:         error_report("iSCSI: Failed to unmarshall inquiry data.");
        !           620:         itask->status   = 1;
        !           621:         itask->complete = 1;
        !           622:         scsi_free_scsi_task(task);
        !           623:         return;
        !           624:     }
        !           625: 
        !           626:     itask->iscsilun->type = inq->periperal_device_type;
        !           627: 
        !           628:     scsi_free_scsi_task(task);
        !           629: 
        !           630:     switch (itask->iscsilun->type) {
        !           631:     case TYPE_DISK:
        !           632:         task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
        !           633:                                    iscsi_readcapacity16_cb, opaque);
        !           634:         if (task == NULL) {
        !           635:             error_report("iSCSI: failed to send readcapacity16 command.");
        !           636:             itask->status   = 1;
        !           637:             itask->complete = 1;
        !           638:             return;
        !           639:         }
        !           640:         break;
        !           641:     case TYPE_ROM:
        !           642:         task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
        !           643:                                    0, 0,
        !           644:                                    iscsi_readcapacity10_cb, opaque);
        !           645:         if (task == NULL) {
        !           646:             error_report("iSCSI: failed to send readcapacity16 command.");
        !           647:             itask->status   = 1;
        !           648:             itask->complete = 1;
        !           649:             return;
        !           650:         }
        !           651:         break;
        !           652:     default:
        !           653:         itask->status   = 0;
        !           654:         itask->complete = 1;
        !           655:     }
        !           656: }
1.1       root      657: 
                    658: static void
                    659: iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
                    660:                  void *opaque)
                    661: {
                    662:     struct IscsiTask *itask = opaque;
                    663:     struct scsi_task *task;
                    664: 
                    665:     if (status != 0) {
                    666:         itask->status   = 1;
                    667:         itask->complete = 1;
                    668:         return;
                    669:     }
                    670: 
1.1.1.2 ! root      671:     task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
        !           672:                               0, 0, 36,
        !           673:                               iscsi_inquiry_cb, opaque);
1.1       root      674:     if (task == NULL) {
1.1.1.2 ! root      675:         error_report("iSCSI: failed to send inquiry command.");
1.1       root      676:         itask->status   = 1;
                    677:         itask->complete = 1;
                    678:         return;
                    679:     }
                    680: }
                    681: 
1.1.1.2 ! root      682: static int parse_chap(struct iscsi_context *iscsi, const char *target)
        !           683: {
        !           684:     QemuOptsList *list;
        !           685:     QemuOpts *opts;
        !           686:     const char *user = NULL;
        !           687:     const char *password = NULL;
        !           688: 
        !           689:     list = qemu_find_opts("iscsi");
        !           690:     if (!list) {
        !           691:         return 0;
        !           692:     }
        !           693: 
        !           694:     opts = qemu_opts_find(list, target);
        !           695:     if (opts == NULL) {
        !           696:         opts = QTAILQ_FIRST(&list->head);
        !           697:         if (!opts) {
        !           698:             return 0;
        !           699:         }
        !           700:     }
        !           701: 
        !           702:     user = qemu_opt_get(opts, "user");
        !           703:     if (!user) {
        !           704:         return 0;
        !           705:     }
        !           706: 
        !           707:     password = qemu_opt_get(opts, "password");
        !           708:     if (!password) {
        !           709:         error_report("CHAP username specified but no password was given");
        !           710:         return -1;
        !           711:     }
        !           712: 
        !           713:     if (iscsi_set_initiator_username_pwd(iscsi, user, password)) {
        !           714:         error_report("Failed to set initiator username and password");
        !           715:         return -1;
        !           716:     }
        !           717: 
        !           718:     return 0;
        !           719: }
        !           720: 
        !           721: static void parse_header_digest(struct iscsi_context *iscsi, const char *target)
        !           722: {
        !           723:     QemuOptsList *list;
        !           724:     QemuOpts *opts;
        !           725:     const char *digest = NULL;
        !           726: 
        !           727:     list = qemu_find_opts("iscsi");
        !           728:     if (!list) {
        !           729:         return;
        !           730:     }
        !           731: 
        !           732:     opts = qemu_opts_find(list, target);
        !           733:     if (opts == NULL) {
        !           734:         opts = QTAILQ_FIRST(&list->head);
        !           735:         if (!opts) {
        !           736:             return;
        !           737:         }
        !           738:     }
        !           739: 
        !           740:     digest = qemu_opt_get(opts, "header-digest");
        !           741:     if (!digest) {
        !           742:         return;
        !           743:     }
        !           744: 
        !           745:     if (!strcmp(digest, "CRC32C")) {
        !           746:         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
        !           747:     } else if (!strcmp(digest, "NONE")) {
        !           748:         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
        !           749:     } else if (!strcmp(digest, "CRC32C-NONE")) {
        !           750:         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
        !           751:     } else if (!strcmp(digest, "NONE-CRC32C")) {
        !           752:         iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
        !           753:     } else {
        !           754:         error_report("Invalid header-digest setting : %s", digest);
        !           755:     }
        !           756: }
        !           757: 
        !           758: static char *parse_initiator_name(const char *target)
        !           759: {
        !           760:     QemuOptsList *list;
        !           761:     QemuOpts *opts;
        !           762:     const char *name = NULL;
        !           763: 
        !           764:     list = qemu_find_opts("iscsi");
        !           765:     if (!list) {
        !           766:         return g_strdup("iqn.2008-11.org.linux-kvm");
        !           767:     }
        !           768: 
        !           769:     opts = qemu_opts_find(list, target);
        !           770:     if (opts == NULL) {
        !           771:         opts = QTAILQ_FIRST(&list->head);
        !           772:         if (!opts) {
        !           773:             return g_strdup("iqn.2008-11.org.linux-kvm");
        !           774:         }
        !           775:     }
        !           776: 
        !           777:     name = qemu_opt_get(opts, "initiator-name");
        !           778:     if (!name) {
        !           779:         return g_strdup("iqn.2008-11.org.linux-kvm");
        !           780:     }
        !           781: 
        !           782:     return g_strdup(name);
        !           783: }
        !           784: 
1.1       root      785: /*
                    786:  * We support iscsi url's on the form
                    787:  * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
                    788:  */
                    789: static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
                    790: {
                    791:     IscsiLun *iscsilun = bs->opaque;
                    792:     struct iscsi_context *iscsi = NULL;
                    793:     struct iscsi_url *iscsi_url = NULL;
                    794:     struct IscsiTask task;
1.1.1.2 ! root      795:     char *initiator_name = NULL;
1.1       root      796:     int ret;
                    797: 
                    798:     if ((BDRV_SECTOR_SIZE % 512) != 0) {
                    799:         error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
                    800:                      "BDRV_SECTOR_SIZE(%lld) is not a multiple "
                    801:                      "of 512", BDRV_SECTOR_SIZE);
                    802:         return -EINVAL;
                    803:     }
                    804: 
                    805:     iscsi_url = iscsi_parse_full_url(iscsi, filename);
                    806:     if (iscsi_url == NULL) {
                    807:         error_report("Failed to parse URL : %s %s", filename,
                    808:                      iscsi_get_error(iscsi));
                    809:         ret = -EINVAL;
                    810:         goto failed;
                    811:     }
                    812: 
1.1.1.2 ! root      813:     memset(iscsilun, 0, sizeof(IscsiLun));
        !           814: 
        !           815:     initiator_name = parse_initiator_name(iscsi_url->target);
        !           816: 
        !           817:     iscsi = iscsi_create_context(initiator_name);
        !           818:     if (iscsi == NULL) {
        !           819:         error_report("iSCSI: Failed to create iSCSI context.");
        !           820:         ret = -ENOMEM;
        !           821:         goto failed;
        !           822:     }
        !           823: 
1.1       root      824:     if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
                    825:         error_report("iSCSI: Failed to set target name.");
                    826:         ret = -EINVAL;
                    827:         goto failed;
                    828:     }
                    829: 
                    830:     if (iscsi_url->user != NULL) {
                    831:         ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
                    832:                                               iscsi_url->passwd);
                    833:         if (ret != 0) {
                    834:             error_report("Failed to set initiator username and password");
                    835:             ret = -EINVAL;
                    836:             goto failed;
                    837:         }
                    838:     }
1.1.1.2 ! root      839: 
        !           840:     /* check if we got CHAP username/password via the options */
        !           841:     if (parse_chap(iscsi, iscsi_url->target) != 0) {
        !           842:         error_report("iSCSI: Failed to set CHAP user/password");
        !           843:         ret = -EINVAL;
        !           844:         goto failed;
        !           845:     }
        !           846: 
1.1       root      847:     if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
                    848:         error_report("iSCSI: Failed to set session type to normal.");
                    849:         ret = -EINVAL;
                    850:         goto failed;
                    851:     }
                    852: 
                    853:     iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
                    854: 
1.1.1.2 ! root      855:     /* check if we got HEADER_DIGEST via the options */
        !           856:     parse_header_digest(iscsi, iscsi_url->target);
        !           857: 
1.1       root      858:     task.iscsilun = iscsilun;
                    859:     task.status = 0;
                    860:     task.complete = 0;
                    861:     task.bs = bs;
                    862: 
                    863:     iscsilun->iscsi = iscsi;
                    864:     iscsilun->lun   = iscsi_url->lun;
                    865: 
                    866:     if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
                    867:                                  iscsi_connect_cb, &task)
                    868:         != 0) {
                    869:         error_report("iSCSI: Failed to start async connect.");
                    870:         ret = -EINVAL;
                    871:         goto failed;
                    872:     }
                    873: 
                    874:     while (!task.complete) {
                    875:         iscsi_set_events(iscsilun);
                    876:         qemu_aio_wait();
                    877:     }
                    878:     if (task.status != 0) {
                    879:         error_report("iSCSI: Failed to connect to LUN : %s",
                    880:                      iscsi_get_error(iscsi));
                    881:         ret = -EINVAL;
                    882:         goto failed;
                    883:     }
                    884: 
                    885:     if (iscsi_url != NULL) {
                    886:         iscsi_destroy_url(iscsi_url);
                    887:     }
                    888:     return 0;
                    889: 
                    890: failed:
1.1.1.2 ! root      891:     if (initiator_name != NULL) {
        !           892:         g_free(initiator_name);
        !           893:     }
1.1       root      894:     if (iscsi_url != NULL) {
                    895:         iscsi_destroy_url(iscsi_url);
                    896:     }
                    897:     if (iscsi != NULL) {
                    898:         iscsi_destroy_context(iscsi);
                    899:     }
                    900:     memset(iscsilun, 0, sizeof(IscsiLun));
                    901:     return ret;
                    902: }
                    903: 
                    904: static void iscsi_close(BlockDriverState *bs)
                    905: {
                    906:     IscsiLun *iscsilun = bs->opaque;
                    907:     struct iscsi_context *iscsi = iscsilun->iscsi;
                    908: 
1.1.1.2 ! root      909:     qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
1.1       root      910:     iscsi_destroy_context(iscsi);
                    911:     memset(iscsilun, 0, sizeof(IscsiLun));
                    912: }
                    913: 
                    914: static BlockDriver bdrv_iscsi = {
                    915:     .format_name     = "iscsi",
                    916:     .protocol_name   = "iscsi",
                    917: 
                    918:     .instance_size   = sizeof(IscsiLun),
                    919:     .bdrv_file_open  = iscsi_open,
                    920:     .bdrv_close      = iscsi_close,
                    921: 
                    922:     .bdrv_getlength  = iscsi_getlength,
                    923: 
                    924:     .bdrv_aio_readv  = iscsi_aio_readv,
                    925:     .bdrv_aio_writev = iscsi_aio_writev,
                    926:     .bdrv_aio_flush  = iscsi_aio_flush,
1.1.1.2 ! root      927: 
        !           928:     .bdrv_aio_discard = iscsi_aio_discard,
1.1       root      929: };
                    930: 
                    931: static void iscsi_block_init(void)
                    932: {
                    933:     bdrv_register(&bdrv_iscsi);
                    934: }
                    935: 
                    936: block_init(iscsi_block_init);

unix.superglobalmegacorp.com

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