1c589b249SRonnie Sahlberg /* 2c589b249SRonnie Sahlberg * QEMU Block driver for iSCSI images 3c589b249SRonnie Sahlberg * 4c589b249SRonnie Sahlberg * Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com> 503e40fefSPeter Lieven * Copyright (c) 2012-2015 Peter Lieven <pl@kamp.de> 6c589b249SRonnie Sahlberg * 7c589b249SRonnie Sahlberg * Permission is hereby granted, free of charge, to any person obtaining a copy 8c589b249SRonnie Sahlberg * of this software and associated documentation files (the "Software"), to deal 9c589b249SRonnie Sahlberg * in the Software without restriction, including without limitation the rights 10c589b249SRonnie Sahlberg * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11c589b249SRonnie Sahlberg * copies of the Software, and to permit persons to whom the Software is 12c589b249SRonnie Sahlberg * furnished to do so, subject to the following conditions: 13c589b249SRonnie Sahlberg * 14c589b249SRonnie Sahlberg * The above copyright notice and this permission notice shall be included in 15c589b249SRonnie Sahlberg * all copies or substantial portions of the Software. 16c589b249SRonnie Sahlberg * 17c589b249SRonnie Sahlberg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18c589b249SRonnie Sahlberg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19c589b249SRonnie Sahlberg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20c589b249SRonnie Sahlberg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21c589b249SRonnie Sahlberg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22c589b249SRonnie Sahlberg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23c589b249SRonnie Sahlberg * THE SOFTWARE. 24c589b249SRonnie Sahlberg */ 25c589b249SRonnie Sahlberg 26c589b249SRonnie Sahlberg #include "config-host.h" 27c589b249SRonnie Sahlberg 28c589b249SRonnie Sahlberg #include <poll.h> 29efc6de0dSPeter Lieven #include <math.h> 30f4dfa67fSRonnie Sahlberg #include <arpa/inet.h> 31c589b249SRonnie Sahlberg #include "qemu-common.h" 321de7afc9SPaolo Bonzini #include "qemu/config-file.h" 331de7afc9SPaolo Bonzini #include "qemu/error-report.h" 34b03c3805SPeter Lieven #include "qemu/bitops.h" 35b03c3805SPeter Lieven #include "qemu/bitmap.h" 36737e150eSPaolo Bonzini #include "block/block_int.h" 370d09e41aSPaolo Bonzini #include "block/scsi.h" 380a53f010SRonnie Sahlberg #include "qemu/iov.h" 395accc840SPaolo Bonzini #include "sysemu/sysemu.h" 405accc840SPaolo Bonzini #include "qmp-commands.h" 41c589b249SRonnie Sahlberg 42c589b249SRonnie Sahlberg #include <iscsi/iscsi.h> 43c589b249SRonnie Sahlberg #include <iscsi/scsi-lowlevel.h> 44c589b249SRonnie Sahlberg 4598392453SRonnie Sahlberg #ifdef __linux__ 4698392453SRonnie Sahlberg #include <scsi/sg.h> 470d09e41aSPaolo Bonzini #include <block/scsi.h> 4898392453SRonnie Sahlberg #endif 49c589b249SRonnie Sahlberg 50c589b249SRonnie Sahlberg typedef struct IscsiLun { 51c589b249SRonnie Sahlberg struct iscsi_context *iscsi; 5280cf6257SStefan Hajnoczi AioContext *aio_context; 53c589b249SRonnie Sahlberg int lun; 54dbfff6d7SRonnie Sahlberg enum scsi_inquiry_peripheral_device_type type; 55c589b249SRonnie Sahlberg int block_size; 56c7b4a952SPaolo Bonzini uint64_t num_blocks; 57c9b9f682SRonnie Sahlberg int events; 585b5d34ecSPeter Lieven QEMUTimer *nop_timer; 5905b685fbSPeter Lieven QEMUTimer *event_timer; 60f18a7cbbSPeter Lieven struct scsi_inquiry_logical_block_provisioning lbp; 61f18a7cbbSPeter Lieven struct scsi_inquiry_block_limits bl; 62d4cd9615SPeter Lieven unsigned char *zeroblock; 63b03c3805SPeter Lieven unsigned long *allocationmap; 64b03c3805SPeter Lieven int cluster_sectors; 659281fe9eSPeter Lieven bool use_16_for_rw; 6643ae8fb1SFam Zheng bool write_protected; 670a386e48SPeter Lieven bool lbpme; 680a386e48SPeter Lieven bool lbprz; 69752ce451SPeter Lieven bool dpofua; 700a386e48SPeter Lieven bool has_write_same; 7173b5394eSPeter Lieven bool force_next_flush; 72c589b249SRonnie Sahlberg } IscsiLun; 73c589b249SRonnie Sahlberg 7454a5c1d5SPeter Lieven typedef struct IscsiTask { 7554a5c1d5SPeter Lieven int status; 7654a5c1d5SPeter Lieven int complete; 7754a5c1d5SPeter Lieven int retries; 7854a5c1d5SPeter Lieven int do_retry; 7954a5c1d5SPeter Lieven struct scsi_task *task; 8054a5c1d5SPeter Lieven Coroutine *co; 818b9dfe90SPeter Lieven QEMUBH *bh; 8280cf6257SStefan Hajnoczi IscsiLun *iscsilun; 83efc6de0dSPeter Lieven QEMUTimer retry_timer; 8473b5394eSPeter Lieven bool force_next_flush; 8554a5c1d5SPeter Lieven } IscsiTask; 8654a5c1d5SPeter Lieven 87c589b249SRonnie Sahlberg typedef struct IscsiAIOCB { 887c84b1b8SMarkus Armbruster BlockAIOCB common; 89c589b249SRonnie Sahlberg QEMUIOVector *qiov; 90c589b249SRonnie Sahlberg QEMUBH *bh; 91c589b249SRonnie Sahlberg IscsiLun *iscsilun; 92c589b249SRonnie Sahlberg struct scsi_task *task; 93c589b249SRonnie Sahlberg uint8_t *buf; 94c589b249SRonnie Sahlberg int status; 951dde716eSPeter Lieven int64_t sector_num; 961dde716eSPeter Lieven int nb_sectors; 9798392453SRonnie Sahlberg #ifdef __linux__ 9898392453SRonnie Sahlberg sg_io_hdr_t *ioh; 9998392453SRonnie Sahlberg #endif 100c589b249SRonnie Sahlberg } IscsiAIOCB; 101c589b249SRonnie Sahlberg 10205b685fbSPeter Lieven #define EVENT_INTERVAL 250 1035b5d34ecSPeter Lieven #define NOP_INTERVAL 5000 1045b5d34ecSPeter Lieven #define MAX_NOP_FAILURES 3 105efc6de0dSPeter Lieven #define ISCSI_CMD_RETRIES ARRAY_SIZE(iscsi_retry_times) 10659dd0a22SPeter Lieven static const unsigned iscsi_retry_times[] = {8, 32, 128, 512, 2048, 8192, 32768}; 1075b5d34ecSPeter Lieven 1085d831be2SStefan Weil /* this threshold is a trade-off knob to choose between 1095917af81SPeter Lieven * the potential additional overhead of an extra GET_LBA_STATUS request 1105917af81SPeter Lieven * vs. unnecessarily reading a lot of zero sectors over the wire. 1115917af81SPeter Lieven * If a read request is greater or equal than ISCSI_CHECKALLOC_THRES 1125917af81SPeter Lieven * sectors we check the allocation status of the area covered by the 1135917af81SPeter Lieven * request first if the allocationmap indicates that the area might be 1145917af81SPeter Lieven * unallocated. */ 1155917af81SPeter Lieven #define ISCSI_CHECKALLOC_THRES 64 116c589b249SRonnie Sahlberg 117c589b249SRonnie Sahlberg static void 118cfb3f506SPaolo Bonzini iscsi_bh_cb(void *p) 11927cbd828SPaolo Bonzini { 12027cbd828SPaolo Bonzini IscsiAIOCB *acb = p; 12127cbd828SPaolo Bonzini 12227cbd828SPaolo Bonzini qemu_bh_delete(acb->bh); 12327cbd828SPaolo Bonzini 1244790b03dSPaolo Bonzini g_free(acb->buf); 1254790b03dSPaolo Bonzini acb->buf = NULL; 1264790b03dSPaolo Bonzini 12727cbd828SPaolo Bonzini acb->common.cb(acb->common.opaque, acb->status); 12827cbd828SPaolo Bonzini 1291bd075f2SPaolo Bonzini if (acb->task != NULL) { 1301bd075f2SPaolo Bonzini scsi_free_scsi_task(acb->task); 1311bd075f2SPaolo Bonzini acb->task = NULL; 1321bd075f2SPaolo Bonzini } 1331bd075f2SPaolo Bonzini 1348007429aSFam Zheng qemu_aio_unref(acb); 13527cbd828SPaolo Bonzini } 13627cbd828SPaolo Bonzini 137cfb3f506SPaolo Bonzini static void 138cfb3f506SPaolo Bonzini iscsi_schedule_bh(IscsiAIOCB *acb) 13927cbd828SPaolo Bonzini { 1401bd075f2SPaolo Bonzini if (acb->bh) { 1411bd075f2SPaolo Bonzini return; 1421bd075f2SPaolo Bonzini } 14380cf6257SStefan Hajnoczi acb->bh = aio_bh_new(acb->iscsilun->aio_context, iscsi_bh_cb, acb); 14427cbd828SPaolo Bonzini qemu_bh_schedule(acb->bh); 14527cbd828SPaolo Bonzini } 14627cbd828SPaolo Bonzini 1478b9dfe90SPeter Lieven static void iscsi_co_generic_bh_cb(void *opaque) 1488b9dfe90SPeter Lieven { 1498b9dfe90SPeter Lieven struct IscsiTask *iTask = opaque; 150fcd470d8SPeter Lieven iTask->complete = 1; 1518b9dfe90SPeter Lieven qemu_bh_delete(iTask->bh); 1528b9dfe90SPeter Lieven qemu_coroutine_enter(iTask->co, NULL); 1538b9dfe90SPeter Lieven } 1548b9dfe90SPeter Lieven 155efc6de0dSPeter Lieven static void iscsi_retry_timer_expired(void *opaque) 156efc6de0dSPeter Lieven { 157efc6de0dSPeter Lieven struct IscsiTask *iTask = opaque; 158fcd470d8SPeter Lieven iTask->complete = 1; 159efc6de0dSPeter Lieven if (iTask->co) { 160efc6de0dSPeter Lieven qemu_coroutine_enter(iTask->co, NULL); 161efc6de0dSPeter Lieven } 162efc6de0dSPeter Lieven } 163efc6de0dSPeter Lieven 164efc6de0dSPeter Lieven static inline unsigned exp_random(double mean) 165efc6de0dSPeter Lieven { 166efc6de0dSPeter Lieven return -mean * log((double)rand() / RAND_MAX); 167efc6de0dSPeter Lieven } 168efc6de0dSPeter Lieven 16954a5c1d5SPeter Lieven static void 17054a5c1d5SPeter Lieven iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, 17154a5c1d5SPeter Lieven void *command_data, void *opaque) 17254a5c1d5SPeter Lieven { 17354a5c1d5SPeter Lieven struct IscsiTask *iTask = opaque; 17454a5c1d5SPeter Lieven struct scsi_task *task = command_data; 17554a5c1d5SPeter Lieven 17654a5c1d5SPeter Lieven iTask->status = status; 17754a5c1d5SPeter Lieven iTask->do_retry = 0; 17854a5c1d5SPeter Lieven iTask->task = task; 17954a5c1d5SPeter Lieven 180efc6de0dSPeter Lieven if (status != SCSI_STATUS_GOOD) { 181efc6de0dSPeter Lieven if (iTask->retries++ < ISCSI_CMD_RETRIES) { 182efc6de0dSPeter Lieven if (status == SCSI_STATUS_CHECK_CONDITION 18354a5c1d5SPeter Lieven && task->sense.key == SCSI_SENSE_UNIT_ATTENTION) { 184efc6de0dSPeter Lieven error_report("iSCSI CheckCondition: %s", 185efc6de0dSPeter Lieven iscsi_get_error(iscsi)); 18654a5c1d5SPeter Lieven iTask->do_retry = 1; 18754a5c1d5SPeter Lieven goto out; 18854a5c1d5SPeter Lieven } 189e380aff8SPeter Lieven /* status 0x28 is SCSI_TASK_SET_FULL. It was first introduced 190e380aff8SPeter Lieven * in libiscsi 1.10.0. Hardcode this value here to avoid 191e380aff8SPeter Lieven * the need to bump the libiscsi requirement to 1.10.0 */ 192e380aff8SPeter Lieven if (status == SCSI_STATUS_BUSY || status == 0x28) { 193efc6de0dSPeter Lieven unsigned retry_time = 194efc6de0dSPeter Lieven exp_random(iscsi_retry_times[iTask->retries - 1]); 195e380aff8SPeter Lieven error_report("iSCSI Busy/TaskSetFull (retry #%u in %u ms): %s", 196efc6de0dSPeter Lieven iTask->retries, retry_time, 197efc6de0dSPeter Lieven iscsi_get_error(iscsi)); 198efc6de0dSPeter Lieven aio_timer_init(iTask->iscsilun->aio_context, 199efc6de0dSPeter Lieven &iTask->retry_timer, QEMU_CLOCK_REALTIME, 200efc6de0dSPeter Lieven SCALE_MS, iscsi_retry_timer_expired, iTask); 201efc6de0dSPeter Lieven timer_mod(&iTask->retry_timer, 202efc6de0dSPeter Lieven qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time); 203efc6de0dSPeter Lieven iTask->do_retry = 1; 204efc6de0dSPeter Lieven return; 205efc6de0dSPeter Lieven } 206efc6de0dSPeter Lieven } 207837c3901SPeter Lieven error_report("iSCSI Failure: %s", iscsi_get_error(iscsi)); 20873b5394eSPeter Lieven } else { 20973b5394eSPeter Lieven iTask->iscsilun->force_next_flush |= iTask->force_next_flush; 21054a5c1d5SPeter Lieven } 21154a5c1d5SPeter Lieven 21254a5c1d5SPeter Lieven out: 21354a5c1d5SPeter Lieven if (iTask->co) { 21480cf6257SStefan Hajnoczi iTask->bh = aio_bh_new(iTask->iscsilun->aio_context, 21580cf6257SStefan Hajnoczi iscsi_co_generic_bh_cb, iTask); 2168b9dfe90SPeter Lieven qemu_bh_schedule(iTask->bh); 217fcd470d8SPeter Lieven } else { 218fcd470d8SPeter Lieven iTask->complete = 1; 21954a5c1d5SPeter Lieven } 22054a5c1d5SPeter Lieven } 22154a5c1d5SPeter Lieven 22254a5c1d5SPeter Lieven static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask) 22354a5c1d5SPeter Lieven { 22454a5c1d5SPeter Lieven *iTask = (struct IscsiTask) { 22554a5c1d5SPeter Lieven .co = qemu_coroutine_self(), 22680cf6257SStefan Hajnoczi .iscsilun = iscsilun, 22754a5c1d5SPeter Lieven }; 22854a5c1d5SPeter Lieven } 22927cbd828SPaolo Bonzini 23027cbd828SPaolo Bonzini static void 231c589b249SRonnie Sahlberg iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data, 232c589b249SRonnie Sahlberg void *private_data) 233c589b249SRonnie Sahlberg { 2341bd075f2SPaolo Bonzini IscsiAIOCB *acb = private_data; 2351bd075f2SPaolo Bonzini 2361bd075f2SPaolo Bonzini acb->status = -ECANCELED; 2371bd075f2SPaolo Bonzini iscsi_schedule_bh(acb); 238c589b249SRonnie Sahlberg } 239c589b249SRonnie Sahlberg 240c589b249SRonnie Sahlberg static void 2417c84b1b8SMarkus Armbruster iscsi_aio_cancel(BlockAIOCB *blockacb) 242c589b249SRonnie Sahlberg { 243c589b249SRonnie Sahlberg IscsiAIOCB *acb = (IscsiAIOCB *)blockacb; 244c589b249SRonnie Sahlberg IscsiLun *iscsilun = acb->iscsilun; 245c589b249SRonnie Sahlberg 2461bd075f2SPaolo Bonzini if (acb->status != -EINPROGRESS) { 2471bd075f2SPaolo Bonzini return; 2481bd075f2SPaolo Bonzini } 2491bd075f2SPaolo Bonzini 250b2090919SPaolo Bonzini /* send a task mgmt call to the target to cancel the task on the target */ 25164e69e80SStefan Priebe iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task, 2521bd075f2SPaolo Bonzini iscsi_abort_task_cb, acb); 253b2090919SPaolo Bonzini 254c589b249SRonnie Sahlberg } 255c589b249SRonnie Sahlberg 256d7331bedSStefan Hajnoczi static const AIOCBInfo iscsi_aiocb_info = { 257c589b249SRonnie Sahlberg .aiocb_size = sizeof(IscsiAIOCB), 258722d9333SFam Zheng .cancel_async = iscsi_aio_cancel, 259c589b249SRonnie Sahlberg }; 260c589b249SRonnie Sahlberg 261c589b249SRonnie Sahlberg 262c589b249SRonnie Sahlberg static void iscsi_process_read(void *arg); 263c589b249SRonnie Sahlberg static void iscsi_process_write(void *arg); 264c589b249SRonnie Sahlberg 265c589b249SRonnie Sahlberg static void 266c589b249SRonnie Sahlberg iscsi_set_events(IscsiLun *iscsilun) 267c589b249SRonnie Sahlberg { 268c589b249SRonnie Sahlberg struct iscsi_context *iscsi = iscsilun->iscsi; 26905b685fbSPeter Lieven int ev = iscsi_which_events(iscsi); 270c589b249SRonnie Sahlberg 271c9b9f682SRonnie Sahlberg if (ev != iscsilun->events) { 27280cf6257SStefan Hajnoczi aio_set_fd_handler(iscsilun->aio_context, 27380cf6257SStefan Hajnoczi iscsi_get_fd(iscsi), 27405b685fbSPeter Lieven (ev & POLLIN) ? iscsi_process_read : NULL, 275c9b9f682SRonnie Sahlberg (ev & POLLOUT) ? iscsi_process_write : NULL, 276c9b9f682SRonnie Sahlberg iscsilun); 27705b685fbSPeter Lieven iscsilun->events = ev; 278c9b9f682SRonnie Sahlberg } 279c9b9f682SRonnie Sahlberg 28005b685fbSPeter Lieven /* newer versions of libiscsi may return zero events. In this 28105b685fbSPeter Lieven * case start a timer to ensure we are able to return to service 28205b685fbSPeter Lieven * once this situation changes. */ 28305b685fbSPeter Lieven if (!ev) { 28405b685fbSPeter Lieven timer_mod(iscsilun->event_timer, 28505b685fbSPeter Lieven qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + EVENT_INTERVAL); 28605b685fbSPeter Lieven } 28705b685fbSPeter Lieven } 28805b685fbSPeter Lieven 28905b685fbSPeter Lieven static void iscsi_timed_set_events(void *opaque) 29005b685fbSPeter Lieven { 29105b685fbSPeter Lieven IscsiLun *iscsilun = opaque; 29205b685fbSPeter Lieven iscsi_set_events(iscsilun); 293c589b249SRonnie Sahlberg } 294c589b249SRonnie Sahlberg 295c589b249SRonnie Sahlberg static void 296c589b249SRonnie Sahlberg iscsi_process_read(void *arg) 297c589b249SRonnie Sahlberg { 298c589b249SRonnie Sahlberg IscsiLun *iscsilun = arg; 299c589b249SRonnie Sahlberg struct iscsi_context *iscsi = iscsilun->iscsi; 300c589b249SRonnie Sahlberg 301c589b249SRonnie Sahlberg iscsi_service(iscsi, POLLIN); 302c589b249SRonnie Sahlberg iscsi_set_events(iscsilun); 303c589b249SRonnie Sahlberg } 304c589b249SRonnie Sahlberg 305c589b249SRonnie Sahlberg static void 306c589b249SRonnie Sahlberg iscsi_process_write(void *arg) 307c589b249SRonnie Sahlberg { 308c589b249SRonnie Sahlberg IscsiLun *iscsilun = arg; 309c589b249SRonnie Sahlberg struct iscsi_context *iscsi = iscsilun->iscsi; 310c589b249SRonnie Sahlberg 311c589b249SRonnie Sahlberg iscsi_service(iscsi, POLLOUT); 312c589b249SRonnie Sahlberg iscsi_set_events(iscsilun); 313c589b249SRonnie Sahlberg } 314c589b249SRonnie Sahlberg 3150777b5ddSPeter Lieven static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun) 3160777b5ddSPeter Lieven { 3170777b5ddSPeter Lieven return sector * iscsilun->block_size / BDRV_SECTOR_SIZE; 3180777b5ddSPeter Lieven } 3190777b5ddSPeter Lieven 320c589b249SRonnie Sahlberg static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun) 321c589b249SRonnie Sahlberg { 322c589b249SRonnie Sahlberg return sector * BDRV_SECTOR_SIZE / iscsilun->block_size; 323c589b249SRonnie Sahlberg } 324c589b249SRonnie Sahlberg 32591bea4e2SPeter Lieven static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors, 32691bea4e2SPeter Lieven IscsiLun *iscsilun) 32791bea4e2SPeter Lieven { 32891bea4e2SPeter Lieven if ((sector_num * BDRV_SECTOR_SIZE) % iscsilun->block_size || 32991bea4e2SPeter Lieven (nb_sectors * BDRV_SECTOR_SIZE) % iscsilun->block_size) { 330f5075224SRichard W.M. Jones error_report("iSCSI misaligned request: " 331f5075224SRichard W.M. Jones "iscsilun->block_size %u, sector_num %" PRIi64 332f5075224SRichard W.M. Jones ", nb_sectors %d", 33391bea4e2SPeter Lieven iscsilun->block_size, sector_num, nb_sectors); 33491bea4e2SPeter Lieven return 0; 33591bea4e2SPeter Lieven } 33691bea4e2SPeter Lieven return 1; 33791bea4e2SPeter Lieven } 33891bea4e2SPeter Lieven 339a9fe4c95SPeter Lieven static unsigned long *iscsi_allocationmap_init(IscsiLun *iscsilun) 340a9fe4c95SPeter Lieven { 341a9fe4c95SPeter Lieven return bitmap_try_new(DIV_ROUND_UP(sector_lun2qemu(iscsilun->num_blocks, 342a9fe4c95SPeter Lieven iscsilun), 343a9fe4c95SPeter Lieven iscsilun->cluster_sectors)); 344a9fe4c95SPeter Lieven } 345a9fe4c95SPeter Lieven 346b03c3805SPeter Lieven static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num, 347b03c3805SPeter Lieven int nb_sectors) 348b03c3805SPeter Lieven { 349b03c3805SPeter Lieven if (iscsilun->allocationmap == NULL) { 350b03c3805SPeter Lieven return; 351b03c3805SPeter Lieven } 352b03c3805SPeter Lieven bitmap_set(iscsilun->allocationmap, 353b03c3805SPeter Lieven sector_num / iscsilun->cluster_sectors, 354b03c3805SPeter Lieven DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors)); 355b03c3805SPeter Lieven } 356b03c3805SPeter Lieven 357b03c3805SPeter Lieven static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num, 358b03c3805SPeter Lieven int nb_sectors) 359b03c3805SPeter Lieven { 360b03c3805SPeter Lieven int64_t cluster_num, nb_clusters; 361b03c3805SPeter Lieven if (iscsilun->allocationmap == NULL) { 362b03c3805SPeter Lieven return; 363b03c3805SPeter Lieven } 364b03c3805SPeter Lieven cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors); 365b03c3805SPeter Lieven nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors 366b03c3805SPeter Lieven - cluster_num; 367b03c3805SPeter Lieven if (nb_clusters > 0) { 368b03c3805SPeter Lieven bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters); 369b03c3805SPeter Lieven } 370b03c3805SPeter Lieven } 371b03c3805SPeter Lieven 372063c3378SPeter Lieven static int coroutine_fn iscsi_co_writev(BlockDriverState *bs, 373063c3378SPeter Lieven int64_t sector_num, int nb_sectors, 374063c3378SPeter Lieven QEMUIOVector *iov) 375c589b249SRonnie Sahlberg { 376063c3378SPeter Lieven IscsiLun *iscsilun = bs->opaque; 377063c3378SPeter Lieven struct IscsiTask iTask; 378f4dfa67fSRonnie Sahlberg uint64_t lba; 379063c3378SPeter Lieven uint32_t num_sectors; 38073b5394eSPeter Lieven int fua; 381063c3378SPeter Lieven 382063c3378SPeter Lieven if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { 383063c3378SPeter Lieven return -EINVAL; 384063c3378SPeter Lieven } 385063c3378SPeter Lieven 386dc9e7163SPeter Lieven if (bs->bl.max_transfer_length && nb_sectors > bs->bl.max_transfer_length) { 387dc9e7163SPeter Lieven error_report("iSCSI Error: Write of %d sectors exceeds max_xfer_len " 388dc9e7163SPeter Lieven "of %d sectors", nb_sectors, bs->bl.max_transfer_length); 389dc9e7163SPeter Lieven return -EINVAL; 390dc9e7163SPeter Lieven } 391dc9e7163SPeter Lieven 392063c3378SPeter Lieven lba = sector_qemu2lun(sector_num, iscsilun); 393063c3378SPeter Lieven num_sectors = sector_qemu2lun(nb_sectors, iscsilun); 394063c3378SPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 395063c3378SPeter Lieven retry: 39673b5394eSPeter Lieven fua = iscsilun->dpofua && !bs->enable_write_cache; 39773b5394eSPeter Lieven iTask.force_next_flush = !fua; 3989281fe9eSPeter Lieven if (iscsilun->use_16_for_rw) { 399063c3378SPeter Lieven iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba, 4008c215a9fSPeter Lieven NULL, num_sectors * iscsilun->block_size, 40173b5394eSPeter Lieven iscsilun->block_size, 0, 0, fua, 0, 0, 402063c3378SPeter Lieven iscsi_co_generic_cb, &iTask); 4039281fe9eSPeter Lieven } else { 4049281fe9eSPeter Lieven iTask.task = iscsi_write10_task(iscsilun->iscsi, iscsilun->lun, lba, 4058c215a9fSPeter Lieven NULL, num_sectors * iscsilun->block_size, 40673b5394eSPeter Lieven iscsilun->block_size, 0, 0, fua, 0, 0, 4079281fe9eSPeter Lieven iscsi_co_generic_cb, &iTask); 4089281fe9eSPeter Lieven } 409063c3378SPeter Lieven if (iTask.task == NULL) { 41092397116SPeter Lieven return -ENOMEM; 411f4dfa67fSRonnie Sahlberg } 412063c3378SPeter Lieven scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov, 413063c3378SPeter Lieven iov->niov); 414063c3378SPeter Lieven while (!iTask.complete) { 415063c3378SPeter Lieven iscsi_set_events(iscsilun); 416063c3378SPeter Lieven qemu_coroutine_yield(); 417c589b249SRonnie Sahlberg } 418c589b249SRonnie Sahlberg 419063c3378SPeter Lieven if (iTask.task != NULL) { 420063c3378SPeter Lieven scsi_free_scsi_task(iTask.task); 421063c3378SPeter Lieven iTask.task = NULL; 422063c3378SPeter Lieven } 423063c3378SPeter Lieven 424063c3378SPeter Lieven if (iTask.do_retry) { 425837c3901SPeter Lieven iTask.complete = 0; 426063c3378SPeter Lieven goto retry; 427063c3378SPeter Lieven } 428063c3378SPeter Lieven 429063c3378SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 430063c3378SPeter Lieven return -EIO; 431063c3378SPeter Lieven } 4327371d56fSPeter Lieven 433b03c3805SPeter Lieven iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors); 434b03c3805SPeter Lieven 4351dde716eSPeter Lieven return 0; 4361dde716eSPeter Lieven } 437c589b249SRonnie Sahlberg 438b03c3805SPeter Lieven 439b03c3805SPeter Lieven static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun, 440b03c3805SPeter Lieven int64_t sector_num, int nb_sectors) 441b03c3805SPeter Lieven { 442b03c3805SPeter Lieven unsigned long size; 443b03c3805SPeter Lieven if (iscsilun->allocationmap == NULL) { 444b03c3805SPeter Lieven return true; 445b03c3805SPeter Lieven } 446b03c3805SPeter Lieven size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors); 447b03c3805SPeter Lieven return !(find_next_bit(iscsilun->allocationmap, size, 448b03c3805SPeter Lieven sector_num / iscsilun->cluster_sectors) == size); 449b03c3805SPeter Lieven } 450b03c3805SPeter Lieven 451b03c3805SPeter Lieven static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, 452b03c3805SPeter Lieven int64_t sector_num, 453b03c3805SPeter Lieven int nb_sectors, int *pnum) 454b03c3805SPeter Lieven { 455b03c3805SPeter Lieven IscsiLun *iscsilun = bs->opaque; 456b03c3805SPeter Lieven struct scsi_get_lba_status *lbas = NULL; 457b03c3805SPeter Lieven struct scsi_lba_status_descriptor *lbasd = NULL; 458b03c3805SPeter Lieven struct IscsiTask iTask; 459b03c3805SPeter Lieven int64_t ret; 460b03c3805SPeter Lieven 461b03c3805SPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 462b03c3805SPeter Lieven 463b03c3805SPeter Lieven if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { 464b03c3805SPeter Lieven ret = -EINVAL; 465b03c3805SPeter Lieven goto out; 466b03c3805SPeter Lieven } 467b03c3805SPeter Lieven 468b03c3805SPeter Lieven /* default to all sectors allocated */ 469b03c3805SPeter Lieven ret = BDRV_BLOCK_DATA; 470b03c3805SPeter Lieven ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID; 471b03c3805SPeter Lieven *pnum = nb_sectors; 472b03c3805SPeter Lieven 473b03c3805SPeter Lieven /* LUN does not support logical block provisioning */ 4740a386e48SPeter Lieven if (!iscsilun->lbpme) { 475b03c3805SPeter Lieven goto out; 476b03c3805SPeter Lieven } 477b03c3805SPeter Lieven 478b03c3805SPeter Lieven retry: 479b03c3805SPeter Lieven if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun, 480b03c3805SPeter Lieven sector_qemu2lun(sector_num, iscsilun), 481b03c3805SPeter Lieven 8 + 16, iscsi_co_generic_cb, 482b03c3805SPeter Lieven &iTask) == NULL) { 483b03c3805SPeter Lieven ret = -ENOMEM; 484b03c3805SPeter Lieven goto out; 485b03c3805SPeter Lieven } 486b03c3805SPeter Lieven 487b03c3805SPeter Lieven while (!iTask.complete) { 488b03c3805SPeter Lieven iscsi_set_events(iscsilun); 489b03c3805SPeter Lieven qemu_coroutine_yield(); 490b03c3805SPeter Lieven } 491b03c3805SPeter Lieven 492b03c3805SPeter Lieven if (iTask.do_retry) { 493b03c3805SPeter Lieven if (iTask.task != NULL) { 494b03c3805SPeter Lieven scsi_free_scsi_task(iTask.task); 495b03c3805SPeter Lieven iTask.task = NULL; 496b03c3805SPeter Lieven } 497b03c3805SPeter Lieven iTask.complete = 0; 498b03c3805SPeter Lieven goto retry; 499b03c3805SPeter Lieven } 500b03c3805SPeter Lieven 501b03c3805SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 502b03c3805SPeter Lieven /* in case the get_lba_status_callout fails (i.e. 503b03c3805SPeter Lieven * because the device is busy or the cmd is not 504b03c3805SPeter Lieven * supported) we pretend all blocks are allocated 505b03c3805SPeter Lieven * for backwards compatibility */ 506b03c3805SPeter Lieven goto out; 507b03c3805SPeter Lieven } 508b03c3805SPeter Lieven 509b03c3805SPeter Lieven lbas = scsi_datain_unmarshall(iTask.task); 510b03c3805SPeter Lieven if (lbas == NULL) { 511b03c3805SPeter Lieven ret = -EIO; 512b03c3805SPeter Lieven goto out; 513b03c3805SPeter Lieven } 514b03c3805SPeter Lieven 515b03c3805SPeter Lieven lbasd = &lbas->descriptors[0]; 516b03c3805SPeter Lieven 517b03c3805SPeter Lieven if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) { 518b03c3805SPeter Lieven ret = -EIO; 519b03c3805SPeter Lieven goto out; 520b03c3805SPeter Lieven } 521b03c3805SPeter Lieven 522b03c3805SPeter Lieven *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun); 523b03c3805SPeter Lieven 524b03c3805SPeter Lieven if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED || 525b03c3805SPeter Lieven lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) { 526b03c3805SPeter Lieven ret &= ~BDRV_BLOCK_DATA; 527b03c3805SPeter Lieven if (iscsilun->lbprz) { 528b03c3805SPeter Lieven ret |= BDRV_BLOCK_ZERO; 529b03c3805SPeter Lieven } 530b03c3805SPeter Lieven } 531b03c3805SPeter Lieven 532b03c3805SPeter Lieven if (ret & BDRV_BLOCK_ZERO) { 533b03c3805SPeter Lieven iscsi_allocationmap_clear(iscsilun, sector_num, *pnum); 534b03c3805SPeter Lieven } else { 535b03c3805SPeter Lieven iscsi_allocationmap_set(iscsilun, sector_num, *pnum); 536b03c3805SPeter Lieven } 537b03c3805SPeter Lieven 538b03c3805SPeter Lieven if (*pnum > nb_sectors) { 539b03c3805SPeter Lieven *pnum = nb_sectors; 540b03c3805SPeter Lieven } 541b03c3805SPeter Lieven out: 542b03c3805SPeter Lieven if (iTask.task != NULL) { 543b03c3805SPeter Lieven scsi_free_scsi_task(iTask.task); 544b03c3805SPeter Lieven } 545b03c3805SPeter Lieven return ret; 546b03c3805SPeter Lieven } 547b03c3805SPeter Lieven 548063c3378SPeter Lieven static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, 549063c3378SPeter Lieven int64_t sector_num, int nb_sectors, 550063c3378SPeter Lieven QEMUIOVector *iov) 5511dde716eSPeter Lieven { 5521dde716eSPeter Lieven IscsiLun *iscsilun = bs->opaque; 553063c3378SPeter Lieven struct IscsiTask iTask; 5541dde716eSPeter Lieven uint64_t lba; 5551dde716eSPeter Lieven uint32_t num_sectors; 556c589b249SRonnie Sahlberg 557063c3378SPeter Lieven if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { 558063c3378SPeter Lieven return -EINVAL; 559f4dfa67fSRonnie Sahlberg } 560f4dfa67fSRonnie Sahlberg 561dc9e7163SPeter Lieven if (bs->bl.max_transfer_length && nb_sectors > bs->bl.max_transfer_length) { 562dc9e7163SPeter Lieven error_report("iSCSI Error: Read of %d sectors exceeds max_xfer_len " 563dc9e7163SPeter Lieven "of %d sectors", nb_sectors, bs->bl.max_transfer_length); 564dc9e7163SPeter Lieven return -EINVAL; 565dc9e7163SPeter Lieven } 566dc9e7163SPeter Lieven 5675917af81SPeter Lieven if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES && 568b03c3805SPeter Lieven !iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) { 569b03c3805SPeter Lieven int64_t ret; 570b03c3805SPeter Lieven int pnum; 571b03c3805SPeter Lieven ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum); 572b03c3805SPeter Lieven if (ret < 0) { 573b03c3805SPeter Lieven return ret; 574b03c3805SPeter Lieven } 575b03c3805SPeter Lieven if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) { 576b03c3805SPeter Lieven qemu_iovec_memset(iov, 0, 0x00, iov->size); 577b03c3805SPeter Lieven return 0; 578b03c3805SPeter Lieven } 579b03c3805SPeter Lieven } 580b03c3805SPeter Lieven 581063c3378SPeter Lieven lba = sector_qemu2lun(sector_num, iscsilun); 582063c3378SPeter Lieven num_sectors = sector_qemu2lun(nb_sectors, iscsilun); 583f4dfa67fSRonnie Sahlberg 584063c3378SPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 585063c3378SPeter Lieven retry: 5869281fe9eSPeter Lieven if (iscsilun->use_16_for_rw) { 587063c3378SPeter Lieven iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba, 588063c3378SPeter Lieven num_sectors * iscsilun->block_size, 589063c3378SPeter Lieven iscsilun->block_size, 0, 0, 0, 0, 0, 590063c3378SPeter Lieven iscsi_co_generic_cb, &iTask); 5919281fe9eSPeter Lieven } else { 592063c3378SPeter Lieven iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba, 593063c3378SPeter Lieven num_sectors * iscsilun->block_size, 594219c2521SStefan Weil iscsilun->block_size, 595219c2521SStefan Weil 0, 0, 0, 0, 0, 596063c3378SPeter Lieven iscsi_co_generic_cb, &iTask); 597f4dfa67fSRonnie Sahlberg } 598063c3378SPeter Lieven if (iTask.task == NULL) { 59992397116SPeter Lieven return -ENOMEM; 600c589b249SRonnie Sahlberg } 601063c3378SPeter Lieven scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov); 6021dde716eSPeter Lieven 603063c3378SPeter Lieven while (!iTask.complete) { 604c589b249SRonnie Sahlberg iscsi_set_events(iscsilun); 605063c3378SPeter Lieven qemu_coroutine_yield(); 606c589b249SRonnie Sahlberg } 607c589b249SRonnie Sahlberg 608063c3378SPeter Lieven if (iTask.task != NULL) { 609063c3378SPeter Lieven scsi_free_scsi_task(iTask.task); 610063c3378SPeter Lieven iTask.task = NULL; 611c589b249SRonnie Sahlberg } 612c589b249SRonnie Sahlberg 613063c3378SPeter Lieven if (iTask.do_retry) { 614837c3901SPeter Lieven iTask.complete = 0; 615063c3378SPeter Lieven goto retry; 616c589b249SRonnie Sahlberg } 617c589b249SRonnie Sahlberg 618063c3378SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 619063c3378SPeter Lieven return -EIO; 6201dde716eSPeter Lieven } 6211dde716eSPeter Lieven 6221dde716eSPeter Lieven return 0; 6231dde716eSPeter Lieven } 6241dde716eSPeter Lieven 625063c3378SPeter Lieven static int coroutine_fn iscsi_co_flush(BlockDriverState *bs) 6261dde716eSPeter Lieven { 6271dde716eSPeter Lieven IscsiLun *iscsilun = bs->opaque; 628063c3378SPeter Lieven struct IscsiTask iTask; 6291dde716eSPeter Lieven 630b2f9c08aSPaolo Bonzini if (bs->sg) { 631b2f9c08aSPaolo Bonzini return 0; 632b2f9c08aSPaolo Bonzini } 633b2f9c08aSPaolo Bonzini 63473b5394eSPeter Lieven if (!iscsilun->force_next_flush) { 63573b5394eSPeter Lieven return 0; 63673b5394eSPeter Lieven } 63773b5394eSPeter Lieven iscsilun->force_next_flush = false; 6381dde716eSPeter Lieven 63973b5394eSPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 640063c3378SPeter Lieven retry: 641063c3378SPeter Lieven if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0, 642063c3378SPeter Lieven 0, iscsi_co_generic_cb, &iTask) == NULL) { 64392397116SPeter Lieven return -ENOMEM; 644c589b249SRonnie Sahlberg } 645c589b249SRonnie Sahlberg 646063c3378SPeter Lieven while (!iTask.complete) { 647c589b249SRonnie Sahlberg iscsi_set_events(iscsilun); 648063c3378SPeter Lieven qemu_coroutine_yield(); 649063c3378SPeter Lieven } 650c589b249SRonnie Sahlberg 651063c3378SPeter Lieven if (iTask.task != NULL) { 652063c3378SPeter Lieven scsi_free_scsi_task(iTask.task); 653063c3378SPeter Lieven iTask.task = NULL; 654063c3378SPeter Lieven } 655063c3378SPeter Lieven 656063c3378SPeter Lieven if (iTask.do_retry) { 657837c3901SPeter Lieven iTask.complete = 0; 658063c3378SPeter Lieven goto retry; 659063c3378SPeter Lieven } 660063c3378SPeter Lieven 661063c3378SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 662063c3378SPeter Lieven return -EIO; 663063c3378SPeter Lieven } 664063c3378SPeter Lieven 665063c3378SPeter Lieven return 0; 666c589b249SRonnie Sahlberg } 667c589b249SRonnie Sahlberg 66898392453SRonnie Sahlberg #ifdef __linux__ 66998392453SRonnie Sahlberg static void 67098392453SRonnie Sahlberg iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status, 67198392453SRonnie Sahlberg void *command_data, void *opaque) 67298392453SRonnie Sahlberg { 67398392453SRonnie Sahlberg IscsiAIOCB *acb = opaque; 67498392453SRonnie Sahlberg 6750a53f010SRonnie Sahlberg g_free(acb->buf); 6760a53f010SRonnie Sahlberg acb->buf = NULL; 6770a53f010SRonnie Sahlberg 67898392453SRonnie Sahlberg acb->status = 0; 67998392453SRonnie Sahlberg if (status < 0) { 68098392453SRonnie Sahlberg error_report("Failed to ioctl(SG_IO) to iSCSI lun. %s", 68198392453SRonnie Sahlberg iscsi_get_error(iscsi)); 68298392453SRonnie Sahlberg acb->status = -EIO; 68398392453SRonnie Sahlberg } 68498392453SRonnie Sahlberg 68598392453SRonnie Sahlberg acb->ioh->driver_status = 0; 68698392453SRonnie Sahlberg acb->ioh->host_status = 0; 68798392453SRonnie Sahlberg acb->ioh->resid = 0; 68898392453SRonnie Sahlberg 68998392453SRonnie Sahlberg #define SG_ERR_DRIVER_SENSE 0x08 69098392453SRonnie Sahlberg 69198392453SRonnie Sahlberg if (status == SCSI_STATUS_CHECK_CONDITION && acb->task->datain.size >= 2) { 69298392453SRonnie Sahlberg int ss; 69398392453SRonnie Sahlberg 69498392453SRonnie Sahlberg acb->ioh->driver_status |= SG_ERR_DRIVER_SENSE; 69598392453SRonnie Sahlberg 69698392453SRonnie Sahlberg acb->ioh->sb_len_wr = acb->task->datain.size - 2; 69798392453SRonnie Sahlberg ss = (acb->ioh->mx_sb_len >= acb->ioh->sb_len_wr) ? 69898392453SRonnie Sahlberg acb->ioh->mx_sb_len : acb->ioh->sb_len_wr; 69998392453SRonnie Sahlberg memcpy(acb->ioh->sbp, &acb->task->datain.data[2], ss); 70098392453SRonnie Sahlberg } 70198392453SRonnie Sahlberg 702cfb3f506SPaolo Bonzini iscsi_schedule_bh(acb); 70398392453SRonnie Sahlberg } 70498392453SRonnie Sahlberg 7057c84b1b8SMarkus Armbruster static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, 70698392453SRonnie Sahlberg unsigned long int req, void *buf, 707097310b5SMarkus Armbruster BlockCompletionFunc *cb, void *opaque) 70898392453SRonnie Sahlberg { 70998392453SRonnie Sahlberg IscsiLun *iscsilun = bs->opaque; 71098392453SRonnie Sahlberg struct iscsi_context *iscsi = iscsilun->iscsi; 71198392453SRonnie Sahlberg struct iscsi_data data; 71298392453SRonnie Sahlberg IscsiAIOCB *acb; 71398392453SRonnie Sahlberg 71498392453SRonnie Sahlberg assert(req == SG_IO); 71598392453SRonnie Sahlberg 716d7331bedSStefan Hajnoczi acb = qemu_aio_get(&iscsi_aiocb_info, bs, cb, opaque); 71798392453SRonnie Sahlberg 71898392453SRonnie Sahlberg acb->iscsilun = iscsilun; 7191bd075f2SPaolo Bonzini acb->bh = NULL; 7201bd075f2SPaolo Bonzini acb->status = -EINPROGRESS; 72198392453SRonnie Sahlberg acb->buf = NULL; 72298392453SRonnie Sahlberg acb->ioh = buf; 72398392453SRonnie Sahlberg 72498392453SRonnie Sahlberg acb->task = malloc(sizeof(struct scsi_task)); 72598392453SRonnie Sahlberg if (acb->task == NULL) { 72698392453SRonnie Sahlberg error_report("iSCSI: Failed to allocate task for scsi command. %s", 72798392453SRonnie Sahlberg iscsi_get_error(iscsi)); 7288007429aSFam Zheng qemu_aio_unref(acb); 72998392453SRonnie Sahlberg return NULL; 73098392453SRonnie Sahlberg } 73198392453SRonnie Sahlberg memset(acb->task, 0, sizeof(struct scsi_task)); 73298392453SRonnie Sahlberg 73398392453SRonnie Sahlberg switch (acb->ioh->dxfer_direction) { 73498392453SRonnie Sahlberg case SG_DXFER_TO_DEV: 73598392453SRonnie Sahlberg acb->task->xfer_dir = SCSI_XFER_WRITE; 73698392453SRonnie Sahlberg break; 73798392453SRonnie Sahlberg case SG_DXFER_FROM_DEV: 73898392453SRonnie Sahlberg acb->task->xfer_dir = SCSI_XFER_READ; 73998392453SRonnie Sahlberg break; 74098392453SRonnie Sahlberg default: 74198392453SRonnie Sahlberg acb->task->xfer_dir = SCSI_XFER_NONE; 74298392453SRonnie Sahlberg break; 74398392453SRonnie Sahlberg } 74498392453SRonnie Sahlberg 74598392453SRonnie Sahlberg acb->task->cdb_size = acb->ioh->cmd_len; 74698392453SRonnie Sahlberg memcpy(&acb->task->cdb[0], acb->ioh->cmdp, acb->ioh->cmd_len); 74798392453SRonnie Sahlberg acb->task->expxferlen = acb->ioh->dxfer_len; 74898392453SRonnie Sahlberg 7490a53f010SRonnie Sahlberg data.size = 0; 75098392453SRonnie Sahlberg if (acb->task->xfer_dir == SCSI_XFER_WRITE) { 7510a53f010SRonnie Sahlberg if (acb->ioh->iovec_count == 0) { 75298392453SRonnie Sahlberg data.data = acb->ioh->dxferp; 75398392453SRonnie Sahlberg data.size = acb->ioh->dxfer_len; 7540a53f010SRonnie Sahlberg } else { 7550a53f010SRonnie Sahlberg scsi_task_set_iov_out(acb->task, 7560a53f010SRonnie Sahlberg (struct scsi_iovec *) acb->ioh->dxferp, 7570a53f010SRonnie Sahlberg acb->ioh->iovec_count); 75898392453SRonnie Sahlberg } 7590a53f010SRonnie Sahlberg } 7600a53f010SRonnie Sahlberg 76198392453SRonnie Sahlberg if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task, 76298392453SRonnie Sahlberg iscsi_aio_ioctl_cb, 7630a53f010SRonnie Sahlberg (data.size > 0) ? &data : NULL, 76498392453SRonnie Sahlberg acb) != 0) { 76598392453SRonnie Sahlberg scsi_free_scsi_task(acb->task); 7668007429aSFam Zheng qemu_aio_unref(acb); 76798392453SRonnie Sahlberg return NULL; 76898392453SRonnie Sahlberg } 76998392453SRonnie Sahlberg 77098392453SRonnie Sahlberg /* tell libiscsi to read straight into the buffer we got from ioctl */ 77198392453SRonnie Sahlberg if (acb->task->xfer_dir == SCSI_XFER_READ) { 7720a53f010SRonnie Sahlberg if (acb->ioh->iovec_count == 0) { 77398392453SRonnie Sahlberg scsi_task_add_data_in_buffer(acb->task, 77498392453SRonnie Sahlberg acb->ioh->dxfer_len, 77598392453SRonnie Sahlberg acb->ioh->dxferp); 7760a53f010SRonnie Sahlberg } else { 7770a53f010SRonnie Sahlberg scsi_task_set_iov_in(acb->task, 7780a53f010SRonnie Sahlberg (struct scsi_iovec *) acb->ioh->dxferp, 7790a53f010SRonnie Sahlberg acb->ioh->iovec_count); 7800a53f010SRonnie Sahlberg } 78198392453SRonnie Sahlberg } 78298392453SRonnie Sahlberg 78398392453SRonnie Sahlberg iscsi_set_events(iscsilun); 78498392453SRonnie Sahlberg 78598392453SRonnie Sahlberg return &acb->common; 78698392453SRonnie Sahlberg } 78798392453SRonnie Sahlberg 788f1a12821SRonnie Sahlberg static void ioctl_cb(void *opaque, int status) 789f1a12821SRonnie Sahlberg { 790f1a12821SRonnie Sahlberg int *p_status = opaque; 791f1a12821SRonnie Sahlberg *p_status = status; 792f1a12821SRonnie Sahlberg } 793f1a12821SRonnie Sahlberg 79498392453SRonnie Sahlberg static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) 79598392453SRonnie Sahlberg { 79698392453SRonnie Sahlberg IscsiLun *iscsilun = bs->opaque; 797f1a12821SRonnie Sahlberg int status; 79898392453SRonnie Sahlberg 79998392453SRonnie Sahlberg switch (req) { 80098392453SRonnie Sahlberg case SG_GET_VERSION_NUM: 80198392453SRonnie Sahlberg *(int *)buf = 30000; 80298392453SRonnie Sahlberg break; 80398392453SRonnie Sahlberg case SG_GET_SCSI_ID: 80498392453SRonnie Sahlberg ((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type; 80598392453SRonnie Sahlberg break; 806f1a12821SRonnie Sahlberg case SG_IO: 807f1a12821SRonnie Sahlberg status = -EINPROGRESS; 808f1a12821SRonnie Sahlberg iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status); 809f1a12821SRonnie Sahlberg 810f1a12821SRonnie Sahlberg while (status == -EINPROGRESS) { 81180cf6257SStefan Hajnoczi aio_poll(iscsilun->aio_context, true); 812f1a12821SRonnie Sahlberg } 813f1a12821SRonnie Sahlberg 814f1a12821SRonnie Sahlberg return 0; 81598392453SRonnie Sahlberg default: 81698392453SRonnie Sahlberg return -1; 81798392453SRonnie Sahlberg } 81898392453SRonnie Sahlberg return 0; 81998392453SRonnie Sahlberg } 82098392453SRonnie Sahlberg #endif 82198392453SRonnie Sahlberg 822c589b249SRonnie Sahlberg static int64_t 823c589b249SRonnie Sahlberg iscsi_getlength(BlockDriverState *bs) 824c589b249SRonnie Sahlberg { 825c589b249SRonnie Sahlberg IscsiLun *iscsilun = bs->opaque; 826c589b249SRonnie Sahlberg int64_t len; 827c589b249SRonnie Sahlberg 828c589b249SRonnie Sahlberg len = iscsilun->num_blocks; 829c589b249SRonnie Sahlberg len *= iscsilun->block_size; 830c589b249SRonnie Sahlberg 831c589b249SRonnie Sahlberg return len; 832c589b249SRonnie Sahlberg } 833c589b249SRonnie Sahlberg 83465f3e339SPeter Lieven static int 83565f3e339SPeter Lieven coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num, 83665f3e339SPeter Lieven int nb_sectors) 83765f3e339SPeter Lieven { 83865f3e339SPeter Lieven IscsiLun *iscsilun = bs->opaque; 83965f3e339SPeter Lieven struct IscsiTask iTask; 84065f3e339SPeter Lieven struct unmap_list list; 84165f3e339SPeter Lieven 84265f3e339SPeter Lieven if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { 84365f3e339SPeter Lieven return -EINVAL; 84465f3e339SPeter Lieven } 84565f3e339SPeter Lieven 84665f3e339SPeter Lieven if (!iscsilun->lbp.lbpu) { 84765f3e339SPeter Lieven /* UNMAP is not supported by the target */ 84865f3e339SPeter Lieven return 0; 84965f3e339SPeter Lieven } 85065f3e339SPeter Lieven 85165f3e339SPeter Lieven list.lba = sector_qemu2lun(sector_num, iscsilun); 85201a6a238SPeter Lieven list.num = sector_qemu2lun(nb_sectors, iscsilun); 85365f3e339SPeter Lieven 85465f3e339SPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 85565f3e339SPeter Lieven retry: 85665f3e339SPeter Lieven if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1, 85765f3e339SPeter Lieven iscsi_co_generic_cb, &iTask) == NULL) { 85892397116SPeter Lieven return -ENOMEM; 85965f3e339SPeter Lieven } 86065f3e339SPeter Lieven 86165f3e339SPeter Lieven while (!iTask.complete) { 86265f3e339SPeter Lieven iscsi_set_events(iscsilun); 86365f3e339SPeter Lieven qemu_coroutine_yield(); 86465f3e339SPeter Lieven } 86565f3e339SPeter Lieven 86665f3e339SPeter Lieven if (iTask.task != NULL) { 86765f3e339SPeter Lieven scsi_free_scsi_task(iTask.task); 86865f3e339SPeter Lieven iTask.task = NULL; 86965f3e339SPeter Lieven } 87065f3e339SPeter Lieven 87165f3e339SPeter Lieven if (iTask.do_retry) { 872837c3901SPeter Lieven iTask.complete = 0; 87365f3e339SPeter Lieven goto retry; 87465f3e339SPeter Lieven } 87565f3e339SPeter Lieven 87665f3e339SPeter Lieven if (iTask.status == SCSI_STATUS_CHECK_CONDITION) { 87765f3e339SPeter Lieven /* the target might fail with a check condition if it 87865f3e339SPeter Lieven is not happy with the alignment of the UNMAP request 87965f3e339SPeter Lieven we silently fail in this case */ 88065f3e339SPeter Lieven return 0; 88165f3e339SPeter Lieven } 88265f3e339SPeter Lieven 88365f3e339SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 88465f3e339SPeter Lieven return -EIO; 88565f3e339SPeter Lieven } 88665f3e339SPeter Lieven 887b03c3805SPeter Lieven iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors); 888b03c3805SPeter Lieven 88965f3e339SPeter Lieven return 0; 89065f3e339SPeter Lieven } 89165f3e339SPeter Lieven 892d4cd9615SPeter Lieven static int 893d4cd9615SPeter Lieven coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, 894d4cd9615SPeter Lieven int nb_sectors, BdrvRequestFlags flags) 895d4cd9615SPeter Lieven { 896d4cd9615SPeter Lieven IscsiLun *iscsilun = bs->opaque; 897d4cd9615SPeter Lieven struct IscsiTask iTask; 898d4cd9615SPeter Lieven uint64_t lba; 899d4cd9615SPeter Lieven uint32_t nb_blocks; 9009281fe9eSPeter Lieven bool use_16_for_ws = iscsilun->use_16_for_rw; 901d4cd9615SPeter Lieven 902d4cd9615SPeter Lieven if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { 903d4cd9615SPeter Lieven return -EINVAL; 904d4cd9615SPeter Lieven } 905d4cd9615SPeter Lieven 9069281fe9eSPeter Lieven if (flags & BDRV_REQ_MAY_UNMAP) { 9079281fe9eSPeter Lieven if (!use_16_for_ws && !iscsilun->lbp.lbpws10) { 9089281fe9eSPeter Lieven /* WRITESAME10 with UNMAP is unsupported try WRITESAME16 */ 9099281fe9eSPeter Lieven use_16_for_ws = true; 9109281fe9eSPeter Lieven } 9119281fe9eSPeter Lieven if (use_16_for_ws && !iscsilun->lbp.lbpws) { 9129281fe9eSPeter Lieven /* WRITESAME16 with UNMAP is not supported by the target, 9139281fe9eSPeter Lieven * fall back and try WRITESAME10/16 without UNMAP */ 914dbe5c58fSPeter Lieven flags &= ~BDRV_REQ_MAY_UNMAP; 9159281fe9eSPeter Lieven use_16_for_ws = iscsilun->use_16_for_rw; 9169281fe9eSPeter Lieven } 917fa6252b0SPaolo Bonzini } 918fa6252b0SPaolo Bonzini 919dbe5c58fSPeter Lieven if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { 920dbe5c58fSPeter Lieven /* WRITESAME without UNMAP is not supported by the target */ 921d4cd9615SPeter Lieven return -ENOTSUP; 922d4cd9615SPeter Lieven } 923d4cd9615SPeter Lieven 924d4cd9615SPeter Lieven lba = sector_qemu2lun(sector_num, iscsilun); 925d4cd9615SPeter Lieven nb_blocks = sector_qemu2lun(nb_sectors, iscsilun); 926d4cd9615SPeter Lieven 927d4cd9615SPeter Lieven if (iscsilun->zeroblock == NULL) { 9284d5a3f88SKevin Wolf iscsilun->zeroblock = g_try_malloc0(iscsilun->block_size); 9294d5a3f88SKevin Wolf if (iscsilun->zeroblock == NULL) { 9304d5a3f88SKevin Wolf return -ENOMEM; 9314d5a3f88SKevin Wolf } 932d4cd9615SPeter Lieven } 933d4cd9615SPeter Lieven 934d4cd9615SPeter Lieven iscsi_co_init_iscsitask(iscsilun, &iTask); 93573b5394eSPeter Lieven iTask.force_next_flush = true; 936d4cd9615SPeter Lieven retry: 9379281fe9eSPeter Lieven if (use_16_for_ws) { 9389281fe9eSPeter Lieven iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba, 939d4cd9615SPeter Lieven iscsilun->zeroblock, iscsilun->block_size, 940d4cd9615SPeter Lieven nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP), 9419281fe9eSPeter Lieven 0, 0, iscsi_co_generic_cb, &iTask); 9429281fe9eSPeter Lieven } else { 9439281fe9eSPeter Lieven iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba, 9449281fe9eSPeter Lieven iscsilun->zeroblock, iscsilun->block_size, 9459281fe9eSPeter Lieven nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP), 9469281fe9eSPeter Lieven 0, 0, iscsi_co_generic_cb, &iTask); 9479281fe9eSPeter Lieven } 9489281fe9eSPeter Lieven if (iTask.task == NULL) { 94992397116SPeter Lieven return -ENOMEM; 950d4cd9615SPeter Lieven } 951d4cd9615SPeter Lieven 952d4cd9615SPeter Lieven while (!iTask.complete) { 953d4cd9615SPeter Lieven iscsi_set_events(iscsilun); 954d4cd9615SPeter Lieven qemu_coroutine_yield(); 955d4cd9615SPeter Lieven } 956d4cd9615SPeter Lieven 957d9738fd2SPeter Lieven if (iTask.status == SCSI_STATUS_CHECK_CONDITION && 958d9738fd2SPeter Lieven iTask.task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST && 95927898a5dSPaolo Bonzini (iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE || 96027898a5dSPaolo Bonzini iTask.task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB)) { 961d9738fd2SPeter Lieven /* WRITE SAME is not supported by the target */ 962d9738fd2SPeter Lieven iscsilun->has_write_same = false; 963d9738fd2SPeter Lieven scsi_free_scsi_task(iTask.task); 964d9738fd2SPeter Lieven return -ENOTSUP; 965d9738fd2SPeter Lieven } 966d9738fd2SPeter Lieven 967d4cd9615SPeter Lieven if (iTask.task != NULL) { 968d4cd9615SPeter Lieven scsi_free_scsi_task(iTask.task); 969d4cd9615SPeter Lieven iTask.task = NULL; 970d4cd9615SPeter Lieven } 971d4cd9615SPeter Lieven 972d4cd9615SPeter Lieven if (iTask.do_retry) { 973837c3901SPeter Lieven iTask.complete = 0; 974d4cd9615SPeter Lieven goto retry; 975d4cd9615SPeter Lieven } 976d4cd9615SPeter Lieven 977d4cd9615SPeter Lieven if (iTask.status != SCSI_STATUS_GOOD) { 978d4cd9615SPeter Lieven return -EIO; 979d4cd9615SPeter Lieven } 980d4cd9615SPeter Lieven 981b03c3805SPeter Lieven if (flags & BDRV_REQ_MAY_UNMAP) { 982b03c3805SPeter Lieven iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors); 983b03c3805SPeter Lieven } else { 984b03c3805SPeter Lieven iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors); 985b03c3805SPeter Lieven } 986b03c3805SPeter Lieven 987d4cd9615SPeter Lieven return 0; 988d4cd9615SPeter Lieven } 989d4cd9615SPeter Lieven 990f2917853SPaolo Bonzini static void parse_chap(struct iscsi_context *iscsi, const char *target, 991f2917853SPaolo Bonzini Error **errp) 992f9dadc98SRonnie Sahlberg { 993f9dadc98SRonnie Sahlberg QemuOptsList *list; 994f9dadc98SRonnie Sahlberg QemuOpts *opts; 995f9dadc98SRonnie Sahlberg const char *user = NULL; 996f9dadc98SRonnie Sahlberg const char *password = NULL; 997f9dadc98SRonnie Sahlberg 998f9dadc98SRonnie Sahlberg list = qemu_find_opts("iscsi"); 999f9dadc98SRonnie Sahlberg if (!list) { 1000f2917853SPaolo Bonzini return; 1001f9dadc98SRonnie Sahlberg } 1002f9dadc98SRonnie Sahlberg 1003f9dadc98SRonnie Sahlberg opts = qemu_opts_find(list, target); 1004f9dadc98SRonnie Sahlberg if (opts == NULL) { 1005f9dadc98SRonnie Sahlberg opts = QTAILQ_FIRST(&list->head); 1006f9dadc98SRonnie Sahlberg if (!opts) { 1007f2917853SPaolo Bonzini return; 1008f9dadc98SRonnie Sahlberg } 1009f9dadc98SRonnie Sahlberg } 1010f9dadc98SRonnie Sahlberg 1011f9dadc98SRonnie Sahlberg user = qemu_opt_get(opts, "user"); 1012f9dadc98SRonnie Sahlberg if (!user) { 1013f2917853SPaolo Bonzini return; 1014f9dadc98SRonnie Sahlberg } 1015f9dadc98SRonnie Sahlberg 1016f9dadc98SRonnie Sahlberg password = qemu_opt_get(opts, "password"); 1017f9dadc98SRonnie Sahlberg if (!password) { 1018f2917853SPaolo Bonzini error_setg(errp, "CHAP username specified but no password was given"); 1019f2917853SPaolo Bonzini return; 1020f9dadc98SRonnie Sahlberg } 1021f9dadc98SRonnie Sahlberg 1022f9dadc98SRonnie Sahlberg if (iscsi_set_initiator_username_pwd(iscsi, user, password)) { 1023f2917853SPaolo Bonzini error_setg(errp, "Failed to set initiator username and password"); 1024f2917853SPaolo Bonzini } 1025f9dadc98SRonnie Sahlberg } 1026f9dadc98SRonnie Sahlberg 1027f2917853SPaolo Bonzini static void parse_header_digest(struct iscsi_context *iscsi, const char *target, 1028f2917853SPaolo Bonzini Error **errp) 1029f9dadc98SRonnie Sahlberg { 1030f9dadc98SRonnie Sahlberg QemuOptsList *list; 1031f9dadc98SRonnie Sahlberg QemuOpts *opts; 1032f9dadc98SRonnie Sahlberg const char *digest = NULL; 1033f9dadc98SRonnie Sahlberg 1034f9dadc98SRonnie Sahlberg list = qemu_find_opts("iscsi"); 1035f9dadc98SRonnie Sahlberg if (!list) { 1036f9dadc98SRonnie Sahlberg return; 1037f9dadc98SRonnie Sahlberg } 1038f9dadc98SRonnie Sahlberg 1039f9dadc98SRonnie Sahlberg opts = qemu_opts_find(list, target); 1040f9dadc98SRonnie Sahlberg if (opts == NULL) { 1041f9dadc98SRonnie Sahlberg opts = QTAILQ_FIRST(&list->head); 1042f9dadc98SRonnie Sahlberg if (!opts) { 1043f9dadc98SRonnie Sahlberg return; 1044f9dadc98SRonnie Sahlberg } 1045f9dadc98SRonnie Sahlberg } 1046f9dadc98SRonnie Sahlberg 1047f9dadc98SRonnie Sahlberg digest = qemu_opt_get(opts, "header-digest"); 1048f9dadc98SRonnie Sahlberg if (!digest) { 1049f9dadc98SRonnie Sahlberg return; 1050f9dadc98SRonnie Sahlberg } 1051f9dadc98SRonnie Sahlberg 1052f9dadc98SRonnie Sahlberg if (!strcmp(digest, "CRC32C")) { 1053f9dadc98SRonnie Sahlberg iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C); 1054f9dadc98SRonnie Sahlberg } else if (!strcmp(digest, "NONE")) { 1055f9dadc98SRonnie Sahlberg iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE); 1056f9dadc98SRonnie Sahlberg } else if (!strcmp(digest, "CRC32C-NONE")) { 1057f9dadc98SRonnie Sahlberg iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE); 1058f9dadc98SRonnie Sahlberg } else if (!strcmp(digest, "NONE-CRC32C")) { 1059f9dadc98SRonnie Sahlberg iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); 1060f9dadc98SRonnie Sahlberg } else { 1061f2917853SPaolo Bonzini error_setg(errp, "Invalid header-digest setting : %s", digest); 1062f9dadc98SRonnie Sahlberg } 1063f9dadc98SRonnie Sahlberg } 1064f9dadc98SRonnie Sahlberg 1065f9dadc98SRonnie Sahlberg static char *parse_initiator_name(const char *target) 1066f9dadc98SRonnie Sahlberg { 1067f9dadc98SRonnie Sahlberg QemuOptsList *list; 1068f9dadc98SRonnie Sahlberg QemuOpts *opts; 10695accc840SPaolo Bonzini const char *name; 10705accc840SPaolo Bonzini char *iscsi_name; 10715accc840SPaolo Bonzini UuidInfo *uuid_info; 1072f9dadc98SRonnie Sahlberg 1073f9dadc98SRonnie Sahlberg list = qemu_find_opts("iscsi"); 1074f2ef4a6dSPaolo Bonzini if (list) { 1075f9dadc98SRonnie Sahlberg opts = qemu_opts_find(list, target); 1076f9dadc98SRonnie Sahlberg if (!opts) { 1077f2ef4a6dSPaolo Bonzini opts = QTAILQ_FIRST(&list->head); 1078f9dadc98SRonnie Sahlberg } 1079f2ef4a6dSPaolo Bonzini if (opts) { 1080f9dadc98SRonnie Sahlberg name = qemu_opt_get(opts, "initiator-name"); 10815accc840SPaolo Bonzini if (name) { 10825accc840SPaolo Bonzini return g_strdup(name); 10835accc840SPaolo Bonzini } 1084f2ef4a6dSPaolo Bonzini } 1085f9dadc98SRonnie Sahlberg } 1086f9dadc98SRonnie Sahlberg 10875accc840SPaolo Bonzini uuid_info = qmp_query_uuid(NULL); 10885accc840SPaolo Bonzini if (strcmp(uuid_info->UUID, UUID_NONE) == 0) { 10895accc840SPaolo Bonzini name = qemu_get_vm_name(); 1090f2ef4a6dSPaolo Bonzini } else { 10915accc840SPaolo Bonzini name = uuid_info->UUID; 1092f2ef4a6dSPaolo Bonzini } 10935accc840SPaolo Bonzini iscsi_name = g_strdup_printf("iqn.2008-11.org.linux-kvm%s%s", 10945accc840SPaolo Bonzini name ? ":" : "", name ? name : ""); 10955accc840SPaolo Bonzini qapi_free_UuidInfo(uuid_info); 10965accc840SPaolo Bonzini return iscsi_name; 1097f9dadc98SRonnie Sahlberg } 1098f9dadc98SRonnie Sahlberg 10995b5d34ecSPeter Lieven static void iscsi_nop_timed_event(void *opaque) 11005b5d34ecSPeter Lieven { 11015b5d34ecSPeter Lieven IscsiLun *iscsilun = opaque; 11025b5d34ecSPeter Lieven 11035b5d34ecSPeter Lieven if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) { 11045b5d34ecSPeter Lieven error_report("iSCSI: NOP timeout. Reconnecting..."); 11055b5d34ecSPeter Lieven iscsi_reconnect(iscsilun->iscsi); 11065b5d34ecSPeter Lieven } 11075b5d34ecSPeter Lieven 11085b5d34ecSPeter Lieven if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) { 11095b5d34ecSPeter Lieven error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages."); 11105b5d34ecSPeter Lieven return; 11115b5d34ecSPeter Lieven } 11125b5d34ecSPeter Lieven 1113bc72ad67SAlex Bligh timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); 11145b5d34ecSPeter Lieven iscsi_set_events(iscsilun); 11155b5d34ecSPeter Lieven } 11165b5d34ecSPeter Lieven 1117f2917853SPaolo Bonzini static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp) 1118cb1b83e7SPeter Lieven { 1119cb1b83e7SPeter Lieven struct scsi_task *task = NULL; 1120cb1b83e7SPeter Lieven struct scsi_readcapacity10 *rc10 = NULL; 1121cb1b83e7SPeter Lieven struct scsi_readcapacity16 *rc16 = NULL; 1122cb1b83e7SPeter Lieven int retries = ISCSI_CMD_RETRIES; 1123cb1b83e7SPeter Lieven 11241288844eSPaolo Bonzini do { 11251288844eSPaolo Bonzini if (task != NULL) { 11261288844eSPaolo Bonzini scsi_free_scsi_task(task); 11271288844eSPaolo Bonzini task = NULL; 11281288844eSPaolo Bonzini } 11291288844eSPaolo Bonzini 1130cb1b83e7SPeter Lieven switch (iscsilun->type) { 1131cb1b83e7SPeter Lieven case TYPE_DISK: 1132cb1b83e7SPeter Lieven task = iscsi_readcapacity16_sync(iscsilun->iscsi, iscsilun->lun); 11331288844eSPaolo Bonzini if (task != NULL && task->status == SCSI_STATUS_GOOD) { 1134cb1b83e7SPeter Lieven rc16 = scsi_datain_unmarshall(task); 1135cb1b83e7SPeter Lieven if (rc16 == NULL) { 1136f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to unmarshall readcapacity16 data."); 11371288844eSPaolo Bonzini } else { 1138cb1b83e7SPeter Lieven iscsilun->block_size = rc16->block_length; 1139cb1b83e7SPeter Lieven iscsilun->num_blocks = rc16->returned_lba + 1; 11400a386e48SPeter Lieven iscsilun->lbpme = !!rc16->lbpme; 11410a386e48SPeter Lieven iscsilun->lbprz = !!rc16->lbprz; 11429281fe9eSPeter Lieven iscsilun->use_16_for_rw = (rc16->returned_lba > 0xffffffff); 11431288844eSPaolo Bonzini } 11441288844eSPaolo Bonzini } 1145cb1b83e7SPeter Lieven break; 1146cb1b83e7SPeter Lieven case TYPE_ROM: 1147cb1b83e7SPeter Lieven task = iscsi_readcapacity10_sync(iscsilun->iscsi, iscsilun->lun, 0, 0); 11481288844eSPaolo Bonzini if (task != NULL && task->status == SCSI_STATUS_GOOD) { 1149cb1b83e7SPeter Lieven rc10 = scsi_datain_unmarshall(task); 1150cb1b83e7SPeter Lieven if (rc10 == NULL) { 1151f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to unmarshall readcapacity10 data."); 11521288844eSPaolo Bonzini } else { 1153cb1b83e7SPeter Lieven iscsilun->block_size = rc10->block_size; 1154cb1b83e7SPeter Lieven if (rc10->lba == 0) { 1155cb1b83e7SPeter Lieven /* blank disk loaded */ 1156cb1b83e7SPeter Lieven iscsilun->num_blocks = 0; 1157cb1b83e7SPeter Lieven } else { 1158cb1b83e7SPeter Lieven iscsilun->num_blocks = rc10->lba + 1; 1159cb1b83e7SPeter Lieven } 11601288844eSPaolo Bonzini } 11611288844eSPaolo Bonzini } 1162cb1b83e7SPeter Lieven break; 1163cb1b83e7SPeter Lieven default: 1164f2917853SPaolo Bonzini return; 1165cb1b83e7SPeter Lieven } 11661288844eSPaolo Bonzini } while (task != NULL && task->status == SCSI_STATUS_CHECK_CONDITION 11671288844eSPaolo Bonzini && task->sense.key == SCSI_SENSE_UNIT_ATTENTION 11681288844eSPaolo Bonzini && retries-- > 0); 1169cb1b83e7SPeter Lieven 11701288844eSPaolo Bonzini if (task == NULL || task->status != SCSI_STATUS_GOOD) { 1171f2917853SPaolo Bonzini error_setg(errp, "iSCSI: failed to send readcapacity10 command."); 11721288844eSPaolo Bonzini } 1173cb1b83e7SPeter Lieven if (task) { 1174cb1b83e7SPeter Lieven scsi_free_scsi_task(task); 1175cb1b83e7SPeter Lieven } 1176cb1b83e7SPeter Lieven } 1177cb1b83e7SPeter Lieven 117860beb341SKevin Wolf /* TODO Convert to fine grained options */ 117960beb341SKevin Wolf static QemuOptsList runtime_opts = { 118060beb341SKevin Wolf .name = "iscsi", 118160beb341SKevin Wolf .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), 118260beb341SKevin Wolf .desc = { 118360beb341SKevin Wolf { 118460beb341SKevin Wolf .name = "filename", 118560beb341SKevin Wolf .type = QEMU_OPT_STRING, 118660beb341SKevin Wolf .help = "URL to the iscsi image", 118760beb341SKevin Wolf }, 118860beb341SKevin Wolf { /* end of list */ } 118960beb341SKevin Wolf }, 119060beb341SKevin Wolf }; 119160beb341SKevin Wolf 119235cb1748SPaolo Bonzini static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun, 119324d3bd67SPeter Lieven int evpd, int pc, void **inq, Error **errp) 119435cb1748SPaolo Bonzini { 1195f18a7cbbSPeter Lieven int full_size; 1196f18a7cbbSPeter Lieven struct scsi_task *task = NULL; 1197f18a7cbbSPeter Lieven task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, 64); 1198f18a7cbbSPeter Lieven if (task == NULL || task->status != SCSI_STATUS_GOOD) { 1199f18a7cbbSPeter Lieven goto fail; 1200f18a7cbbSPeter Lieven } 1201f18a7cbbSPeter Lieven full_size = scsi_datain_getfullsize(task); 1202f18a7cbbSPeter Lieven if (full_size > task->datain.size) { 1203f18a7cbbSPeter Lieven scsi_free_scsi_task(task); 1204f18a7cbbSPeter Lieven 1205f18a7cbbSPeter Lieven /* we need more data for the full list */ 1206f18a7cbbSPeter Lieven task = iscsi_inquiry_sync(iscsi, lun, evpd, pc, full_size); 1207f18a7cbbSPeter Lieven if (task == NULL || task->status != SCSI_STATUS_GOOD) { 1208f18a7cbbSPeter Lieven goto fail; 1209f18a7cbbSPeter Lieven } 1210f18a7cbbSPeter Lieven } 1211f18a7cbbSPeter Lieven 121224d3bd67SPeter Lieven *inq = scsi_datain_unmarshall(task); 121324d3bd67SPeter Lieven if (*inq == NULL) { 121424d3bd67SPeter Lieven error_setg(errp, "iSCSI: failed to unmarshall inquiry datain blob"); 1215172fc4ddSMarkus Armbruster goto fail_with_err; 121624d3bd67SPeter Lieven } 121724d3bd67SPeter Lieven 1218f18a7cbbSPeter Lieven return task; 1219f18a7cbbSPeter Lieven 1220f18a7cbbSPeter Lieven fail: 1221f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Inquiry command failed : %s", 1222f18a7cbbSPeter Lieven iscsi_get_error(iscsi)); 1223172fc4ddSMarkus Armbruster fail_with_err: 122424d3bd67SPeter Lieven if (task != NULL) { 1225f18a7cbbSPeter Lieven scsi_free_scsi_task(task); 1226f18a7cbbSPeter Lieven } 1227f18a7cbbSPeter Lieven return NULL; 1228f18a7cbbSPeter Lieven } 1229f18a7cbbSPeter Lieven 123080cf6257SStefan Hajnoczi static void iscsi_detach_aio_context(BlockDriverState *bs) 123180cf6257SStefan Hajnoczi { 123280cf6257SStefan Hajnoczi IscsiLun *iscsilun = bs->opaque; 123380cf6257SStefan Hajnoczi 123480cf6257SStefan Hajnoczi aio_set_fd_handler(iscsilun->aio_context, 123580cf6257SStefan Hajnoczi iscsi_get_fd(iscsilun->iscsi), 123680cf6257SStefan Hajnoczi NULL, NULL, NULL); 123780cf6257SStefan Hajnoczi iscsilun->events = 0; 123880cf6257SStefan Hajnoczi 123980cf6257SStefan Hajnoczi if (iscsilun->nop_timer) { 124080cf6257SStefan Hajnoczi timer_del(iscsilun->nop_timer); 124180cf6257SStefan Hajnoczi timer_free(iscsilun->nop_timer); 124280cf6257SStefan Hajnoczi iscsilun->nop_timer = NULL; 124380cf6257SStefan Hajnoczi } 124405b685fbSPeter Lieven if (iscsilun->event_timer) { 124505b685fbSPeter Lieven timer_del(iscsilun->event_timer); 124605b685fbSPeter Lieven timer_free(iscsilun->event_timer); 124705b685fbSPeter Lieven iscsilun->event_timer = NULL; 124805b685fbSPeter Lieven } 124980cf6257SStefan Hajnoczi } 125080cf6257SStefan Hajnoczi 125180cf6257SStefan Hajnoczi static void iscsi_attach_aio_context(BlockDriverState *bs, 125280cf6257SStefan Hajnoczi AioContext *new_context) 125380cf6257SStefan Hajnoczi { 125480cf6257SStefan Hajnoczi IscsiLun *iscsilun = bs->opaque; 125580cf6257SStefan Hajnoczi 125680cf6257SStefan Hajnoczi iscsilun->aio_context = new_context; 125780cf6257SStefan Hajnoczi iscsi_set_events(iscsilun); 125880cf6257SStefan Hajnoczi 125980cf6257SStefan Hajnoczi /* Set up a timer for sending out iSCSI NOPs */ 126080cf6257SStefan Hajnoczi iscsilun->nop_timer = aio_timer_new(iscsilun->aio_context, 126180cf6257SStefan Hajnoczi QEMU_CLOCK_REALTIME, SCALE_MS, 126280cf6257SStefan Hajnoczi iscsi_nop_timed_event, iscsilun); 126380cf6257SStefan Hajnoczi timer_mod(iscsilun->nop_timer, 126480cf6257SStefan Hajnoczi qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); 126505b685fbSPeter Lieven 126605b685fbSPeter Lieven /* Prepare a timer for a delayed call to iscsi_set_events */ 126705b685fbSPeter Lieven iscsilun->event_timer = aio_timer_new(iscsilun->aio_context, 126805b685fbSPeter Lieven QEMU_CLOCK_REALTIME, SCALE_MS, 126905b685fbSPeter Lieven iscsi_timed_set_events, iscsilun); 127080cf6257SStefan Hajnoczi } 127180cf6257SStefan Hajnoczi 12727191f208SPeter Lieven static void iscsi_modesense_sync(IscsiLun *iscsilun) 1273c1d4096bSFam Zheng { 1274c1d4096bSFam Zheng struct scsi_task *task; 1275c1d4096bSFam Zheng struct scsi_mode_sense *ms = NULL; 12767191f208SPeter Lieven iscsilun->write_protected = false; 1277752ce451SPeter Lieven iscsilun->dpofua = false; 1278c1d4096bSFam Zheng 1279c1d4096bSFam Zheng task = iscsi_modesense6_sync(iscsilun->iscsi, iscsilun->lun, 1280c1d4096bSFam Zheng 1, SCSI_MODESENSE_PC_CURRENT, 1281c1d4096bSFam Zheng 0x3F, 0, 255); 1282c1d4096bSFam Zheng if (task == NULL) { 1283c1d4096bSFam Zheng error_report("iSCSI: Failed to send MODE_SENSE(6) command: %s", 1284c1d4096bSFam Zheng iscsi_get_error(iscsilun->iscsi)); 1285c1d4096bSFam Zheng goto out; 1286c1d4096bSFam Zheng } 1287c1d4096bSFam Zheng 1288c1d4096bSFam Zheng if (task->status != SCSI_STATUS_GOOD) { 1289c1d4096bSFam Zheng error_report("iSCSI: Failed MODE_SENSE(6), LUN assumed writable"); 1290c1d4096bSFam Zheng goto out; 1291c1d4096bSFam Zheng } 1292c1d4096bSFam Zheng ms = scsi_datain_unmarshall(task); 1293c1d4096bSFam Zheng if (!ms) { 1294c1d4096bSFam Zheng error_report("iSCSI: Failed to unmarshall MODE_SENSE(6) data: %s", 1295c1d4096bSFam Zheng iscsi_get_error(iscsilun->iscsi)); 1296c1d4096bSFam Zheng goto out; 1297c1d4096bSFam Zheng } 12987191f208SPeter Lieven iscsilun->write_protected = ms->device_specific_parameter & 0x80; 1299752ce451SPeter Lieven iscsilun->dpofua = ms->device_specific_parameter & 0x10; 1300c1d4096bSFam Zheng 1301c1d4096bSFam Zheng out: 1302c1d4096bSFam Zheng if (task) { 1303c1d4096bSFam Zheng scsi_free_scsi_task(task); 1304c1d4096bSFam Zheng } 1305c1d4096bSFam Zheng } 1306c1d4096bSFam Zheng 1307c589b249SRonnie Sahlberg /* 1308c589b249SRonnie Sahlberg * We support iscsi url's on the form 1309c589b249SRonnie Sahlberg * iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun> 1310c589b249SRonnie Sahlberg */ 1311015a1036SMax Reitz static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, 1312015a1036SMax Reitz Error **errp) 1313c589b249SRonnie Sahlberg { 1314c589b249SRonnie Sahlberg IscsiLun *iscsilun = bs->opaque; 1315c589b249SRonnie Sahlberg struct iscsi_context *iscsi = NULL; 1316c589b249SRonnie Sahlberg struct iscsi_url *iscsi_url = NULL; 1317e829b0bbSPeter Lieven struct scsi_task *task = NULL; 1318e829b0bbSPeter Lieven struct scsi_inquiry_standard *inq = NULL; 131924d3bd67SPeter Lieven struct scsi_inquiry_supported_pages *inq_vpd; 1320f9dadc98SRonnie Sahlberg char *initiator_name = NULL; 132160beb341SKevin Wolf QemuOpts *opts; 132260beb341SKevin Wolf Error *local_err = NULL; 132360beb341SKevin Wolf const char *filename; 1324debfb917SPeter Wu int i, ret = 0; 1325c589b249SRonnie Sahlberg 1326c589b249SRonnie Sahlberg if ((BDRV_SECTOR_SIZE % 512) != 0) { 1327f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Invalid BDRV_SECTOR_SIZE. " 1328c589b249SRonnie Sahlberg "BDRV_SECTOR_SIZE(%lld) is not a multiple " 1329c589b249SRonnie Sahlberg "of 512", BDRV_SECTOR_SIZE); 1330c589b249SRonnie Sahlberg return -EINVAL; 1331c589b249SRonnie Sahlberg } 1332c589b249SRonnie Sahlberg 133387ea75d5SPeter Crosthwaite opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); 133460beb341SKevin Wolf qemu_opts_absorb_qdict(opts, options, &local_err); 133584d18f06SMarkus Armbruster if (local_err) { 1336f2917853SPaolo Bonzini error_propagate(errp, local_err); 133760beb341SKevin Wolf ret = -EINVAL; 133860beb341SKevin Wolf goto out; 133960beb341SKevin Wolf } 134060beb341SKevin Wolf 134160beb341SKevin Wolf filename = qemu_opt_get(opts, "filename"); 134260beb341SKevin Wolf 1343c589b249SRonnie Sahlberg iscsi_url = iscsi_parse_full_url(iscsi, filename); 1344c589b249SRonnie Sahlberg if (iscsi_url == NULL) { 1345f2917853SPaolo Bonzini error_setg(errp, "Failed to parse URL : %s", filename); 1346c589b249SRonnie Sahlberg ret = -EINVAL; 1347b93c94f7SPaolo Bonzini goto out; 1348c589b249SRonnie Sahlberg } 1349c589b249SRonnie Sahlberg 1350f9dadc98SRonnie Sahlberg memset(iscsilun, 0, sizeof(IscsiLun)); 1351f9dadc98SRonnie Sahlberg 1352f9dadc98SRonnie Sahlberg initiator_name = parse_initiator_name(iscsi_url->target); 1353f9dadc98SRonnie Sahlberg 1354f9dadc98SRonnie Sahlberg iscsi = iscsi_create_context(initiator_name); 1355f9dadc98SRonnie Sahlberg if (iscsi == NULL) { 1356f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to create iSCSI context."); 1357f9dadc98SRonnie Sahlberg ret = -ENOMEM; 1358b93c94f7SPaolo Bonzini goto out; 1359f9dadc98SRonnie Sahlberg } 1360f9dadc98SRonnie Sahlberg 1361c589b249SRonnie Sahlberg if (iscsi_set_targetname(iscsi, iscsi_url->target)) { 1362f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to set target name."); 1363c589b249SRonnie Sahlberg ret = -EINVAL; 1364b93c94f7SPaolo Bonzini goto out; 1365c589b249SRonnie Sahlberg } 1366c589b249SRonnie Sahlberg 1367532cee41SStefan Weil if (iscsi_url->user[0] != '\0') { 1368c589b249SRonnie Sahlberg ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, 1369c589b249SRonnie Sahlberg iscsi_url->passwd); 1370c589b249SRonnie Sahlberg if (ret != 0) { 1371f2917853SPaolo Bonzini error_setg(errp, "Failed to set initiator username and password"); 1372c589b249SRonnie Sahlberg ret = -EINVAL; 1373b93c94f7SPaolo Bonzini goto out; 1374c589b249SRonnie Sahlberg } 1375c589b249SRonnie Sahlberg } 1376f9dadc98SRonnie Sahlberg 1377f9dadc98SRonnie Sahlberg /* check if we got CHAP username/password via the options */ 1378f2917853SPaolo Bonzini parse_chap(iscsi, iscsi_url->target, &local_err); 1379f2917853SPaolo Bonzini if (local_err != NULL) { 1380f2917853SPaolo Bonzini error_propagate(errp, local_err); 1381f9dadc98SRonnie Sahlberg ret = -EINVAL; 1382b93c94f7SPaolo Bonzini goto out; 1383f9dadc98SRonnie Sahlberg } 1384f9dadc98SRonnie Sahlberg 1385c589b249SRonnie Sahlberg if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) { 1386f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to set session type to normal."); 1387c589b249SRonnie Sahlberg ret = -EINVAL; 1388b93c94f7SPaolo Bonzini goto out; 1389c589b249SRonnie Sahlberg } 1390c589b249SRonnie Sahlberg 1391c589b249SRonnie Sahlberg iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C); 1392c589b249SRonnie Sahlberg 1393f9dadc98SRonnie Sahlberg /* check if we got HEADER_DIGEST via the options */ 1394f2917853SPaolo Bonzini parse_header_digest(iscsi, iscsi_url->target, &local_err); 1395f2917853SPaolo Bonzini if (local_err != NULL) { 1396f2917853SPaolo Bonzini error_propagate(errp, local_err); 1397f2917853SPaolo Bonzini ret = -EINVAL; 1398f2917853SPaolo Bonzini goto out; 1399f2917853SPaolo Bonzini } 1400f9dadc98SRonnie Sahlberg 1401e829b0bbSPeter Lieven if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { 1402f2917853SPaolo Bonzini error_setg(errp, "iSCSI: Failed to connect to LUN : %s", 1403c589b249SRonnie Sahlberg iscsi_get_error(iscsi)); 1404c589b249SRonnie Sahlberg ret = -EINVAL; 1405b93c94f7SPaolo Bonzini goto out; 1406c589b249SRonnie Sahlberg } 1407622695a4SRonnie Sahlberg 1408e829b0bbSPeter Lieven iscsilun->iscsi = iscsi; 140980cf6257SStefan Hajnoczi iscsilun->aio_context = bdrv_get_aio_context(bs); 1410e829b0bbSPeter Lieven iscsilun->lun = iscsi_url->lun; 1411fa6252b0SPaolo Bonzini iscsilun->has_write_same = true; 1412e829b0bbSPeter Lieven 141324d3bd67SPeter Lieven task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0, 141424d3bd67SPeter Lieven (void **) &inq, errp); 141524d3bd67SPeter Lieven if (task == NULL) { 141624d3bd67SPeter Lieven ret = -EINVAL; 141724d3bd67SPeter Lieven goto out; 141824d3bd67SPeter Lieven } 141924d3bd67SPeter Lieven iscsilun->type = inq->periperal_device_type; 142024d3bd67SPeter Lieven scsi_free_scsi_task(task); 142124d3bd67SPeter Lieven task = NULL; 142224d3bd67SPeter Lieven 14237191f208SPeter Lieven iscsi_modesense_sync(iscsilun); 14247191f208SPeter Lieven 1425c1d4096bSFam Zheng /* Check the write protect flag of the LUN if we want to write */ 1426c1d4096bSFam Zheng if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && 142743ae8fb1SFam Zheng iscsilun->write_protected) { 1428c1d4096bSFam Zheng error_setg(errp, "Cannot open a write protected LUN as read-write"); 1429c1d4096bSFam Zheng ret = -EACCES; 1430c1d4096bSFam Zheng goto out; 1431c1d4096bSFam Zheng } 1432c1d4096bSFam Zheng 1433f2917853SPaolo Bonzini iscsi_readcapacity_sync(iscsilun, &local_err); 1434f2917853SPaolo Bonzini if (local_err != NULL) { 1435f2917853SPaolo Bonzini error_propagate(errp, local_err); 1436cd82b6fbSFam Zheng ret = -EINVAL; 1437e829b0bbSPeter Lieven goto out; 1438e829b0bbSPeter Lieven } 14390777b5ddSPeter Lieven bs->total_sectors = sector_lun2qemu(iscsilun->num_blocks, iscsilun); 14402c9880c4SPaolo Bonzini bs->request_alignment = iscsilun->block_size; 1441e829b0bbSPeter Lieven 1442f47c3f5aSKevin Wolf /* We don't have any emulation for devices other than disks and CD-ROMs, so 1443f47c3f5aSKevin Wolf * this must be sg ioctl compatible. We force it to be sg, otherwise qemu 1444f47c3f5aSKevin Wolf * will try to read from the device to guess the image format. 1445622695a4SRonnie Sahlberg */ 1446f47c3f5aSKevin Wolf if (iscsilun->type != TYPE_DISK && iscsilun->type != TYPE_ROM) { 1447622695a4SRonnie Sahlberg bs->sg = 1; 1448622695a4SRonnie Sahlberg } 1449622695a4SRonnie Sahlberg 1450f18a7cbbSPeter Lieven task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, 145124d3bd67SPeter Lieven SCSI_INQUIRY_PAGECODE_SUPPORTED_VPD_PAGES, 145224d3bd67SPeter Lieven (void **) &inq_vpd, errp); 1453f18a7cbbSPeter Lieven if (task == NULL) { 1454f18a7cbbSPeter Lieven ret = -EINVAL; 1455f18a7cbbSPeter Lieven goto out; 1456f18a7cbbSPeter Lieven } 145724d3bd67SPeter Lieven for (i = 0; i < inq_vpd->num_pages; i++) { 145824d3bd67SPeter Lieven struct scsi_task *inq_task; 145924d3bd67SPeter Lieven struct scsi_inquiry_logical_block_provisioning *inq_lbp; 146024d3bd67SPeter Lieven struct scsi_inquiry_block_limits *inq_bl; 146124d3bd67SPeter Lieven switch (inq_vpd->pages[i]) { 146224d3bd67SPeter Lieven case SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING: 146324d3bd67SPeter Lieven inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, 146424d3bd67SPeter Lieven SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING, 146524d3bd67SPeter Lieven (void **) &inq_lbp, errp); 146624d3bd67SPeter Lieven if (inq_task == NULL) { 1467f18a7cbbSPeter Lieven ret = -EINVAL; 1468f18a7cbbSPeter Lieven goto out; 1469f18a7cbbSPeter Lieven } 1470f18a7cbbSPeter Lieven memcpy(&iscsilun->lbp, inq_lbp, 1471f18a7cbbSPeter Lieven sizeof(struct scsi_inquiry_logical_block_provisioning)); 147224d3bd67SPeter Lieven scsi_free_scsi_task(inq_task); 147324d3bd67SPeter Lieven break; 147424d3bd67SPeter Lieven case SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS: 147524d3bd67SPeter Lieven inq_task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 1, 147624d3bd67SPeter Lieven SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS, 147724d3bd67SPeter Lieven (void **) &inq_bl, errp); 147824d3bd67SPeter Lieven if (inq_task == NULL) { 1479f18a7cbbSPeter Lieven ret = -EINVAL; 1480f18a7cbbSPeter Lieven goto out; 1481f18a7cbbSPeter Lieven } 1482f18a7cbbSPeter Lieven memcpy(&iscsilun->bl, inq_bl, 1483f18a7cbbSPeter Lieven sizeof(struct scsi_inquiry_block_limits)); 148424d3bd67SPeter Lieven scsi_free_scsi_task(inq_task); 148524d3bd67SPeter Lieven break; 148624d3bd67SPeter Lieven default: 148724d3bd67SPeter Lieven break; 148824d3bd67SPeter Lieven } 148924d3bd67SPeter Lieven } 1490f18a7cbbSPeter Lieven scsi_free_scsi_task(task); 1491f18a7cbbSPeter Lieven task = NULL; 1492f18a7cbbSPeter Lieven 149380cf6257SStefan Hajnoczi iscsi_attach_aio_context(bs, iscsilun->aio_context); 14945b5d34ecSPeter Lieven 1495b03c3805SPeter Lieven /* Guess the internal cluster (page) size of the iscsi target by the means 1496b03c3805SPeter Lieven * of opt_unmap_gran. Transfer the unmap granularity only if it has a 1497b03c3805SPeter Lieven * reasonable size */ 14983d2acaa3SPeter Lieven if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 && 1499b03c3805SPeter Lieven iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) { 1500b03c3805SPeter Lieven iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran * 1501b03c3805SPeter Lieven iscsilun->block_size) >> BDRV_SECTOR_BITS; 1502*9eac3622SPeter Lieven if (iscsilun->lbprz) { 1503a9fe4c95SPeter Lieven iscsilun->allocationmap = iscsi_allocationmap_init(iscsilun); 1504a9fe4c95SPeter Lieven if (iscsilun->allocationmap == NULL) { 1505a9fe4c95SPeter Lieven ret = -ENOMEM; 1506a9fe4c95SPeter Lieven } 1507b03c3805SPeter Lieven } 1508b03c3805SPeter Lieven } 1509b03c3805SPeter Lieven 1510b93c94f7SPaolo Bonzini out: 151160beb341SKevin Wolf qemu_opts_del(opts); 1512f9dadc98SRonnie Sahlberg g_free(initiator_name); 1513c589b249SRonnie Sahlberg if (iscsi_url != NULL) { 1514c589b249SRonnie Sahlberg iscsi_destroy_url(iscsi_url); 1515c589b249SRonnie Sahlberg } 1516e829b0bbSPeter Lieven if (task != NULL) { 1517e829b0bbSPeter Lieven scsi_free_scsi_task(task); 1518e829b0bbSPeter Lieven } 1519b93c94f7SPaolo Bonzini 1520b93c94f7SPaolo Bonzini if (ret) { 1521c589b249SRonnie Sahlberg if (iscsi != NULL) { 152220474e9aSPeter Lieven if (iscsi_is_logged_in(iscsi)) { 152320474e9aSPeter Lieven iscsi_logout_sync(iscsi); 152420474e9aSPeter Lieven } 1525c589b249SRonnie Sahlberg iscsi_destroy_context(iscsi); 1526c589b249SRonnie Sahlberg } 1527c589b249SRonnie Sahlberg memset(iscsilun, 0, sizeof(IscsiLun)); 1528b93c94f7SPaolo Bonzini } 1529c589b249SRonnie Sahlberg return ret; 1530c589b249SRonnie Sahlberg } 1531c589b249SRonnie Sahlberg 1532c589b249SRonnie Sahlberg static void iscsi_close(BlockDriverState *bs) 1533c589b249SRonnie Sahlberg { 1534c589b249SRonnie Sahlberg IscsiLun *iscsilun = bs->opaque; 1535c589b249SRonnie Sahlberg struct iscsi_context *iscsi = iscsilun->iscsi; 1536c589b249SRonnie Sahlberg 153780cf6257SStefan Hajnoczi iscsi_detach_aio_context(bs); 153820474e9aSPeter Lieven if (iscsi_is_logged_in(iscsi)) { 153920474e9aSPeter Lieven iscsi_logout_sync(iscsi); 154020474e9aSPeter Lieven } 1541c589b249SRonnie Sahlberg iscsi_destroy_context(iscsi); 1542d4cd9615SPeter Lieven g_free(iscsilun->zeroblock); 1543b03c3805SPeter Lieven g_free(iscsilun->allocationmap); 1544c589b249SRonnie Sahlberg memset(iscsilun, 0, sizeof(IscsiLun)); 1545c589b249SRonnie Sahlberg } 1546c589b249SRonnie Sahlberg 154752f6fa14SPeter Lieven static int sector_limits_lun2qemu(int64_t sector, IscsiLun *iscsilun) 154852f6fa14SPeter Lieven { 154952f6fa14SPeter Lieven return MIN(sector_lun2qemu(sector, iscsilun), INT_MAX / 2 + 1); 155052f6fa14SPeter Lieven } 155152f6fa14SPeter Lieven 15523baca891SKevin Wolf static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp) 1553d34682cdSKevin Wolf { 1554d34682cdSKevin Wolf /* We don't actually refresh here, but just return data queried in 1555d34682cdSKevin Wolf * iscsi_open(): iscsi targets don't change their limits. */ 155652f6fa14SPeter Lieven 155752f6fa14SPeter Lieven IscsiLun *iscsilun = bs->opaque; 155852f6fa14SPeter Lieven uint32_t max_xfer_len = iscsilun->use_16_for_rw ? 0xffffffff : 0xffff; 155952f6fa14SPeter Lieven 156052f6fa14SPeter Lieven if (iscsilun->bl.max_xfer_len) { 156152f6fa14SPeter Lieven max_xfer_len = MIN(max_xfer_len, iscsilun->bl.max_xfer_len); 156252f6fa14SPeter Lieven } 156352f6fa14SPeter Lieven 156452f6fa14SPeter Lieven bs->bl.max_transfer_length = sector_limits_lun2qemu(max_xfer_len, iscsilun); 156552f6fa14SPeter Lieven 1566c97ca29dSPaolo Bonzini if (iscsilun->lbp.lbpu) { 1567d34682cdSKevin Wolf if (iscsilun->bl.max_unmap < 0xffffffff) { 15683dab1551SPeter Lieven bs->bl.max_discard = 15693dab1551SPeter Lieven sector_limits_lun2qemu(iscsilun->bl.max_unmap, iscsilun); 1570d34682cdSKevin Wolf } 15713dab1551SPeter Lieven bs->bl.discard_alignment = 15723dab1551SPeter Lieven sector_limits_lun2qemu(iscsilun->bl.opt_unmap_gran, iscsilun); 1573c97ca29dSPaolo Bonzini } 1574d34682cdSKevin Wolf 1575d34682cdSKevin Wolf if (iscsilun->bl.max_ws_len < 0xffffffff) { 15763dab1551SPeter Lieven bs->bl.max_write_zeroes = 15773dab1551SPeter Lieven sector_limits_lun2qemu(iscsilun->bl.max_ws_len, iscsilun); 1578d34682cdSKevin Wolf } 1579c97ca29dSPaolo Bonzini if (iscsilun->lbp.lbpws) { 15803dab1551SPeter Lieven bs->bl.write_zeroes_alignment = 15813dab1551SPeter Lieven sector_limits_lun2qemu(iscsilun->bl.opt_unmap_gran, iscsilun); 15825d259fc7SPeter Lieven } 15833dab1551SPeter Lieven bs->bl.opt_transfer_length = 15843dab1551SPeter Lieven sector_limits_lun2qemu(iscsilun->bl.opt_xfer_len, iscsilun); 1585e9f526abSAnthony Liguori } 1586d34682cdSKevin Wolf 158743ae8fb1SFam Zheng /* Note that this will not re-establish a connection with an iSCSI target - it 158843ae8fb1SFam Zheng * is effectively a NOP. */ 1589dc6afb99SJeff Cody static int iscsi_reopen_prepare(BDRVReopenState *state, 1590dc6afb99SJeff Cody BlockReopenQueue *queue, Error **errp) 1591dc6afb99SJeff Cody { 159243ae8fb1SFam Zheng IscsiLun *iscsilun = state->bs->opaque; 159343ae8fb1SFam Zheng 159443ae8fb1SFam Zheng if (state->flags & BDRV_O_RDWR && iscsilun->write_protected) { 159543ae8fb1SFam Zheng error_setg(errp, "Cannot open a write protected LUN as read-write"); 159643ae8fb1SFam Zheng return -EACCES; 159743ae8fb1SFam Zheng } 1598d34682cdSKevin Wolf return 0; 1599d34682cdSKevin Wolf } 1600d34682cdSKevin Wolf 1601cb1b83e7SPeter Lieven static int iscsi_truncate(BlockDriverState *bs, int64_t offset) 1602cb1b83e7SPeter Lieven { 1603cb1b83e7SPeter Lieven IscsiLun *iscsilun = bs->opaque; 1604f2917853SPaolo Bonzini Error *local_err = NULL; 1605cb1b83e7SPeter Lieven 1606cb1b83e7SPeter Lieven if (iscsilun->type != TYPE_DISK) { 1607cb1b83e7SPeter Lieven return -ENOTSUP; 1608cb1b83e7SPeter Lieven } 1609cb1b83e7SPeter Lieven 1610f2917853SPaolo Bonzini iscsi_readcapacity_sync(iscsilun, &local_err); 1611f2917853SPaolo Bonzini if (local_err != NULL) { 1612f2917853SPaolo Bonzini error_free(local_err); 1613f2917853SPaolo Bonzini return -EIO; 1614cb1b83e7SPeter Lieven } 1615cb1b83e7SPeter Lieven 1616cb1b83e7SPeter Lieven if (offset > iscsi_getlength(bs)) { 1617cb1b83e7SPeter Lieven return -EINVAL; 1618cb1b83e7SPeter Lieven } 1619cb1b83e7SPeter Lieven 1620b03c3805SPeter Lieven if (iscsilun->allocationmap != NULL) { 1621b03c3805SPeter Lieven g_free(iscsilun->allocationmap); 1622a9fe4c95SPeter Lieven iscsilun->allocationmap = iscsi_allocationmap_init(iscsilun); 1623b03c3805SPeter Lieven } 1624b03c3805SPeter Lieven 1625cb1b83e7SPeter Lieven return 0; 1626cb1b83e7SPeter Lieven } 1627cb1b83e7SPeter Lieven 1628a59479e3SChunyan Liu static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp) 1629de8864e5SPeter Lieven { 1630de8864e5SPeter Lieven int ret = 0; 1631de8864e5SPeter Lieven int64_t total_size = 0; 163213c91cb7SFam Zheng BlockDriverState *bs; 1633de8864e5SPeter Lieven IscsiLun *iscsilun = NULL; 163460beb341SKevin Wolf QDict *bs_options; 1635de8864e5SPeter Lieven 1636e4e9986bSMarkus Armbruster bs = bdrv_new(); 1637de8864e5SPeter Lieven 1638de8864e5SPeter Lieven /* Read out options */ 1639c2eb918eSHu Tao total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 1640c2eb918eSHu Tao BDRV_SECTOR_SIZE); 16415839e53bSMarkus Armbruster bs->opaque = g_new0(struct IscsiLun, 1); 164213c91cb7SFam Zheng iscsilun = bs->opaque; 1643de8864e5SPeter Lieven 164460beb341SKevin Wolf bs_options = qdict_new(); 164560beb341SKevin Wolf qdict_put(bs_options, "filename", qstring_from_str(filename)); 1646015a1036SMax Reitz ret = iscsi_open(bs, bs_options, 0, NULL); 164760beb341SKevin Wolf QDECREF(bs_options); 164860beb341SKevin Wolf 1649de8864e5SPeter Lieven if (ret != 0) { 1650de8864e5SPeter Lieven goto out; 1651de8864e5SPeter Lieven } 165280cf6257SStefan Hajnoczi iscsi_detach_aio_context(bs); 1653de8864e5SPeter Lieven if (iscsilun->type != TYPE_DISK) { 1654de8864e5SPeter Lieven ret = -ENODEV; 1655de8864e5SPeter Lieven goto out; 1656de8864e5SPeter Lieven } 165713c91cb7SFam Zheng if (bs->total_sectors < total_size) { 1658de8864e5SPeter Lieven ret = -ENOSPC; 1659d3bda7bcSPeter Lieven goto out; 1660de8864e5SPeter Lieven } 1661de8864e5SPeter Lieven 1662de8864e5SPeter Lieven ret = 0; 1663de8864e5SPeter Lieven out: 1664de8864e5SPeter Lieven if (iscsilun->iscsi != NULL) { 1665de8864e5SPeter Lieven iscsi_destroy_context(iscsilun->iscsi); 1666de8864e5SPeter Lieven } 166713c91cb7SFam Zheng g_free(bs->opaque); 166813c91cb7SFam Zheng bs->opaque = NULL; 16694f6fd349SFam Zheng bdrv_unref(bs); 1670de8864e5SPeter Lieven return ret; 1671de8864e5SPeter Lieven } 1672de8864e5SPeter Lieven 1673186d4f2bSPeter Lieven static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 1674186d4f2bSPeter Lieven { 1675186d4f2bSPeter Lieven IscsiLun *iscsilun = bs->opaque; 16760a386e48SPeter Lieven bdi->unallocated_blocks_are_zero = iscsilun->lbprz; 1677186d4f2bSPeter Lieven bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws; 1678b03c3805SPeter Lieven bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE; 1679186d4f2bSPeter Lieven return 0; 1680186d4f2bSPeter Lieven } 1681186d4f2bSPeter Lieven 1682a59479e3SChunyan Liu static QemuOptsList iscsi_create_opts = { 1683a59479e3SChunyan Liu .name = "iscsi-create-opts", 1684a59479e3SChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head), 1685a59479e3SChunyan Liu .desc = { 1686de8864e5SPeter Lieven { 1687de8864e5SPeter Lieven .name = BLOCK_OPT_SIZE, 1688a59479e3SChunyan Liu .type = QEMU_OPT_SIZE, 1689de8864e5SPeter Lieven .help = "Virtual disk size" 1690de8864e5SPeter Lieven }, 1691a59479e3SChunyan Liu { /* end of list */ } 1692a59479e3SChunyan Liu } 1693de8864e5SPeter Lieven }; 1694de8864e5SPeter Lieven 1695c589b249SRonnie Sahlberg static BlockDriver bdrv_iscsi = { 1696c589b249SRonnie Sahlberg .format_name = "iscsi", 1697c589b249SRonnie Sahlberg .protocol_name = "iscsi", 1698c589b249SRonnie Sahlberg 1699c589b249SRonnie Sahlberg .instance_size = sizeof(IscsiLun), 1700030be321SBenoît Canet .bdrv_needs_filename = true, 1701c589b249SRonnie Sahlberg .bdrv_file_open = iscsi_open, 1702c589b249SRonnie Sahlberg .bdrv_close = iscsi_close, 1703c282e1fdSChunyan Liu .bdrv_create = iscsi_create, 1704a59479e3SChunyan Liu .create_opts = &iscsi_create_opts, 1705dc6afb99SJeff Cody .bdrv_reopen_prepare = iscsi_reopen_prepare, 1706c589b249SRonnie Sahlberg 1707c589b249SRonnie Sahlberg .bdrv_getlength = iscsi_getlength, 1708186d4f2bSPeter Lieven .bdrv_get_info = iscsi_get_info, 1709cb1b83e7SPeter Lieven .bdrv_truncate = iscsi_truncate, 1710d34682cdSKevin Wolf .bdrv_refresh_limits = iscsi_refresh_limits, 1711c589b249SRonnie Sahlberg 171254a5c1d5SPeter Lieven .bdrv_co_get_block_status = iscsi_co_get_block_status, 171365f3e339SPeter Lieven .bdrv_co_discard = iscsi_co_discard, 1714d4cd9615SPeter Lieven .bdrv_co_write_zeroes = iscsi_co_write_zeroes, 1715063c3378SPeter Lieven .bdrv_co_readv = iscsi_co_readv, 1716063c3378SPeter Lieven .bdrv_co_writev = iscsi_co_writev, 1717063c3378SPeter Lieven .bdrv_co_flush_to_disk = iscsi_co_flush, 1718fa6acb0cSRonnie Sahlberg 171998392453SRonnie Sahlberg #ifdef __linux__ 172098392453SRonnie Sahlberg .bdrv_ioctl = iscsi_ioctl, 172198392453SRonnie Sahlberg .bdrv_aio_ioctl = iscsi_aio_ioctl, 172298392453SRonnie Sahlberg #endif 172380cf6257SStefan Hajnoczi 172480cf6257SStefan Hajnoczi .bdrv_detach_aio_context = iscsi_detach_aio_context, 172580cf6257SStefan Hajnoczi .bdrv_attach_aio_context = iscsi_attach_aio_context, 1726c589b249SRonnie Sahlberg }; 1727c589b249SRonnie Sahlberg 17284d454574SPaolo Bonzini static QemuOptsList qemu_iscsi_opts = { 17294d454574SPaolo Bonzini .name = "iscsi", 17304d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head), 17314d454574SPaolo Bonzini .desc = { 17324d454574SPaolo Bonzini { 17334d454574SPaolo Bonzini .name = "user", 17344d454574SPaolo Bonzini .type = QEMU_OPT_STRING, 17354d454574SPaolo Bonzini .help = "username for CHAP authentication to target", 17364d454574SPaolo Bonzini },{ 17374d454574SPaolo Bonzini .name = "password", 17384d454574SPaolo Bonzini .type = QEMU_OPT_STRING, 17394d454574SPaolo Bonzini .help = "password for CHAP authentication to target", 17404d454574SPaolo Bonzini },{ 17414d454574SPaolo Bonzini .name = "header-digest", 17424d454574SPaolo Bonzini .type = QEMU_OPT_STRING, 17434d454574SPaolo Bonzini .help = "HeaderDigest setting. " 17444d454574SPaolo Bonzini "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}", 17454d454574SPaolo Bonzini },{ 17464d454574SPaolo Bonzini .name = "initiator-name", 17474d454574SPaolo Bonzini .type = QEMU_OPT_STRING, 17484d454574SPaolo Bonzini .help = "Initiator iqn name to use when connecting", 17494d454574SPaolo Bonzini }, 17504d454574SPaolo Bonzini { /* end of list */ } 17514d454574SPaolo Bonzini }, 17524d454574SPaolo Bonzini }; 17534d454574SPaolo Bonzini 1754c589b249SRonnie Sahlberg static void iscsi_block_init(void) 1755c589b249SRonnie Sahlberg { 1756c589b249SRonnie Sahlberg bdrv_register(&bdrv_iscsi); 17574d454574SPaolo Bonzini qemu_add_opts(&qemu_iscsi_opts); 1758c589b249SRonnie Sahlberg } 1759c589b249SRonnie Sahlberg 1760c589b249SRonnie Sahlberg block_init(iscsi_block_init); 1761