|
|
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);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.