win-pvdrivers

annotate xenvbd/xenvbd.c @ 812:551d17b09bc1

Force a crash if we get a buffer overrun in hibernate
author James Harper <james.harper@bendigoit.com.au>
date Sat Aug 28 13:53:10 2010 +1000 (2010-08-28)
parents 1293cb31aa0b
children 4d1539643494
rev   line source
james@267 1 /*
james@267 2 PV Drivers for Windows Xen HVM Domains
james@267 3 Copyright (C) 2007 James Harper
james@267 4
james@267 5 This program is free software; you can redistribute it and/or
james@267 6 modify it under the terms of the GNU General Public License
james@267 7 as published by the Free Software Foundation; either version 2
james@267 8 of the License, or (at your option) any later version.
james@267 9
james@267 10 This program is distributed in the hope that it will be useful,
james@267 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@267 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@267 13 GNU General Public License for more details.
james@267 14
james@267 15 You should have received a copy of the GNU General Public License
james@267 16 along with this program; if not, write to the Free Software
james@267 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@267 18 */
steve@479 19
andy@378 20 #define INITGUID
james@0 21 #include "xenvbd.h"
james@0 22 #include <io/blkif.h>
james@0 23 #include <scsi.h>
james@0 24 #include <ntddscsi.h>
james@0 25 #include <ntdddisk.h>
james@0 26 #include <stdlib.h>
james@0 27 #include <xen_public.h>
james@0 28 #include <io/xenbus.h>
james@160 29 #include <io/protocols.h>
james@0 30
andy@119 31 #pragma warning(disable: 4127)
andy@119 32
james@420 33 #if defined(__x86_64__)
james@537 34 #define LongLongToPtr(x) (PVOID)(x)
james@420 35 #else
james@537 36 #define LongLongToPtr(x) UlongToPtr(x)
james@420 37 #endif
james@420 38
james@716 39 /* Not really necessary but keeps PREfast happy */
james@716 40 DRIVER_INITIALIZE DriverEntry;
james@716 41
james@420 42 static BOOLEAN dump_mode = FALSE;
james@766 43 #define DUMP_MODE_ERROR_LIMIT 64
james@766 44 static ULONG dump_mode_errors = 0;
james@420 45
james@563 46 CHAR scsi_device_manufacturer[8];
james@563 47 CHAR scsi_disk_model[16];
james@563 48 CHAR scsi_cdrom_model[16];
james@563 49
james@496 50 ULONGLONG parse_numeric_string(PCHAR string)
james@496 51 {
james@496 52 ULONGLONG val = 0;
james@496 53 while (*string != 0)
james@496 54 {
james@496 55 val = val * 10 + (*string - '0');
james@496 56 string++;
james@496 57 }
james@496 58 return val;
james@496 59 }
james@496 60
james@420 61 static blkif_shadow_t *
james@420 62 get_shadow_from_freelist(PXENVBD_DEVICE_DATA xvdd)
james@420 63 {
james@420 64 if (xvdd->shadow_free == 0)
james@420 65 {
james@790 66 KdPrint((__DRIVER_NAME " No more shadow entries\n"));
james@420 67 return NULL;
james@420 68 }
james@420 69 xvdd->shadow_free--;
james@420 70 if (xvdd->shadow_free < xvdd->shadow_min_free)
james@420 71 xvdd->shadow_min_free = xvdd->shadow_free;
james@420 72 return &xvdd->shadows[xvdd->shadow_free_list[xvdd->shadow_free]];
james@420 73 }
james@420 74
james@420 75 static VOID
james@420 76 put_shadow_on_freelist(PXENVBD_DEVICE_DATA xvdd, blkif_shadow_t *shadow)
james@420 77 {
james@420 78 xvdd->shadow_free_list[xvdd->shadow_free] = (USHORT)shadow->req.id;
james@420 79 shadow->srb = NULL;
james@420 80 xvdd->shadow_free++;
james@420 81 }
james@420 82
james@420 83 static blkif_response_t *
james@420 84 XenVbd_GetResponse(PXENVBD_DEVICE_DATA xvdd, int i)
james@420 85 {
james@420 86 blkif_other_response_t *rep;
james@420 87 if (!xvdd->use_other)
james@420 88 return RING_GET_RESPONSE(&xvdd->ring, i);
james@420 89 rep = RING_GET_RESPONSE(&xvdd->other_ring, i);
james@420 90 xvdd->tmp_rep.id = rep->id;
james@420 91 xvdd->tmp_rep.operation = rep->operation;
james@420 92 xvdd->tmp_rep.status = rep->status;
james@420 93 return &xvdd->tmp_rep;
james@420 94 }
james@420 95
james@420 96 static VOID
james@420 97 XenVbd_PutRequest(PXENVBD_DEVICE_DATA xvdd, blkif_request_t *req)
james@420 98 {
james@420 99 blkif_other_request_t *other_req;
james@420 100
james@420 101 if (!xvdd->use_other)
james@420 102 {
james@420 103 *RING_GET_REQUEST(&xvdd->ring, xvdd->ring.req_prod_pvt) = *req;
james@420 104 }
james@420 105 else
james@420 106 {
james@420 107 other_req = RING_GET_REQUEST(&xvdd->other_ring, xvdd->ring.req_prod_pvt);
james@420 108 other_req->operation = req->operation;
james@420 109 other_req->nr_segments = req->nr_segments;
james@420 110 other_req->handle = req->handle;
james@420 111 other_req->id = req->id;
james@420 112 other_req->sector_number = req->sector_number;
james@420 113 memcpy(other_req->seg, req->seg, sizeof(struct blkif_request_segment) * req->nr_segments);
james@420 114 }
james@420 115 xvdd->ring.req_prod_pvt++;
james@420 116 }
james@420 117
james@420 118 static ULONG
james@420 119 XenVbd_InitFromConfig(PXENVBD_DEVICE_DATA xvdd)
james@420 120 {
james@420 121 ULONG i;
james@420 122 PUCHAR ptr;
james@420 123 USHORT type;
james@536 124 PCHAR setting, value, value2;
james@497 125 ULONG qemu_protocol_version = 0;
james@748 126 BOOLEAN qemu_hide_filter = FALSE;
james@748 127 ULONG qemu_hide_flags_value = 0;
james@420 128
james@420 129 xvdd->device_type = XENVBD_DEVICETYPE_UNKNOWN;
james@420 130 xvdd->sring = NULL;
james@420 131 xvdd->event_channel = 0;
james@748 132
james@495 133 xvdd->inactive = TRUE;
james@420 134 ptr = xvdd->device_base;
james@536 135 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
james@420 136 {
james@420 137 switch(type)
james@420 138 {
james@420 139 case XEN_INIT_TYPE_RING: /* frontend ring */
james@452 140 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
james@420 141 if (strcmp(setting, "ring-ref") == 0)
james@420 142 {
james@420 143 xvdd->sring = (blkif_sring_t *)value;
james@420 144 FRONT_RING_INIT(&xvdd->ring, xvdd->sring, PAGE_SIZE);
james@440 145 /* this bit is for when we have to take over an existing ring on a crash dump */
james@420 146 xvdd->ring.req_prod_pvt = xvdd->sring->req_prod;
james@435 147 xvdd->ring.rsp_cons = xvdd->ring.req_prod_pvt;
james@420 148 }
james@420 149 break;
james@420 150 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
james@420 151 case XEN_INIT_TYPE_EVENT_CHANNEL_IRQ: /* frontend event channel */
james@536 152 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value) & 0x3FFFFFFF));
james@420 153 if (strcmp(setting, "event-channel") == 0)
james@420 154 {
james@435 155 /* cheat here - save the state of the ring in the topmost bits of the event-channel */
james@435 156 xvdd->event_channel_ptr = (ULONG *)(((PCHAR)ptr) - sizeof(ULONG));
james@435 157 xvdd->event_channel = PtrToUlong(value) & 0x3FFFFFFF;
james@435 158 if (PtrToUlong(value) & 0x80000000)
james@435 159 {
james@435 160 xvdd->cached_use_other = (BOOLEAN)!!(PtrToUlong(value) & 0x40000000);
james@435 161 KdPrint((__DRIVER_NAME " cached_use_other = %d\n", xvdd->cached_use_other));
james@435 162 }
james@420 163 }
james@420 164 break;
james@420 165 case XEN_INIT_TYPE_READ_STRING_BACK:
james@420 166 case XEN_INIT_TYPE_READ_STRING_FRONT:
james@452 167 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
james@420 168 if (strcmp(setting, "sectors") == 0)
james@496 169 xvdd->total_sectors = parse_numeric_string(value);
james@420 170 else if (strcmp(setting, "sector-size") == 0)
james@496 171 xvdd->bytes_per_sector = (ULONG)parse_numeric_string(value);
james@420 172 else if (strcmp(setting, "device-type") == 0)
james@420 173 {
james@420 174 if (strcmp(value, "disk") == 0)
james@420 175 {
james@420 176 KdPrint((__DRIVER_NAME " device-type = Disk\n"));
james@420 177 xvdd->device_type = XENVBD_DEVICETYPE_DISK;
james@420 178 }
james@420 179 else if (strcmp(value, "cdrom") == 0)
james@420 180 {
james@420 181 KdPrint((__DRIVER_NAME " device-type = CDROM\n"));
james@420 182 xvdd->device_type = XENVBD_DEVICETYPE_CDROM;
james@420 183 }
james@420 184 else
james@420 185 {
james@420 186 KdPrint((__DRIVER_NAME " device-type = %s (This probably won't work!)\n", value));
james@420 187 xvdd->device_type = XENVBD_DEVICETYPE_UNKNOWN;
james@420 188 }
james@420 189 }
james@420 190 else if (strcmp(setting, "mode") == 0)
james@420 191 {
james@420 192 if (strncmp(value, "r", 1) == 0)
james@420 193 {
james@420 194 KdPrint((__DRIVER_NAME " mode = r\n"));
james@420 195 xvdd->device_mode = XENVBD_DEVICEMODE_READ;
james@420 196 }
james@420 197 else if (strncmp(value, "w", 1) == 0)
james@420 198 {
james@420 199 KdPrint((__DRIVER_NAME " mode = w\n"));
james@420 200 xvdd->device_mode = XENVBD_DEVICEMODE_WRITE;
james@420 201 }
james@420 202 else
james@420 203 {
james@420 204 KdPrint((__DRIVER_NAME " mode = unknown\n"));
james@420 205 xvdd->device_mode = XENVBD_DEVICEMODE_UNKNOWN;
james@420 206 }
james@420 207 }
james@420 208 break;
james@420 209 case XEN_INIT_TYPE_VECTORS:
james@452 210 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
james@420 211 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
james@420 212 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
james@420 213 {
james@420 214 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
james@420 215 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
james@420 216 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@420 217 return SP_RETURN_BAD_CONFIG;
james@420 218 }
james@420 219 else
james@420 220 memcpy(&xvdd->vectors, value, sizeof(XENPCI_VECTORS));
james@420 221 break;
james@420 222 case XEN_INIT_TYPE_STATE_PTR:
james@452 223 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
james@420 224 xvdd->device_state = (PXENPCI_DEVICE_STATE)value;
james@420 225 break;
james@497 226 case XEN_INIT_TYPE_QEMU_PROTOCOL_VERSION:
james@497 227 qemu_protocol_version = PtrToUlong(value);
james@536 228 break;
james@536 229 case XEN_INIT_TYPE_GRANT_ENTRIES:
james@538 230 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_GRANT_ENTRIES - entries = %d\n", PtrToUlong(setting)));
james@790 231 memcpy(xvdd->dump_grant_refs, value, PtrToUlong(setting) * sizeof(grant_ref_t));
james@536 232 break;
james@748 233 case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
james@748 234 qemu_hide_flags_value = PtrToUlong(value);
james@748 235 KdPrint((__DRIVER_NAME " qemu_hide_flags_value = %d\n", qemu_hide_flags_value));
james@748 236 break;
james@748 237 case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
james@748 238 qemu_hide_filter = TRUE;
james@748 239 KdPrint((__DRIVER_NAME " qemu_hide_filter = TRUE\n"));
james@748 240 break;
james@420 241 default:
james@452 242 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
james@420 243 break;
james@420 244 }
james@420 245 }
james@748 246
james@748 247 if (((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) && xvdd->device_type != XENVBD_DEVICETYPE_CDROM) || qemu_hide_filter)
james@748 248 xvdd->inactive = FALSE;
james@748 249
james@553 250 if (!xvdd->inactive && (xvdd->device_type == XENVBD_DEVICETYPE_UNKNOWN
james@553 251 || xvdd->sring == NULL
james@553 252 || xvdd->event_channel == 0
james@553 253 || xvdd->total_sectors == 0
james@553 254 || xvdd->bytes_per_sector == 0))
james@420 255 {
james@420 256 KdPrint((__DRIVER_NAME " Missing settings\n"));
james@420 257 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@420 258 return SP_RETURN_BAD_CONFIG;
james@420 259 }
james@748 260
james@495 261 if (xvdd->inactive)
james@495 262 KdPrint((__DRIVER_NAME " Device is inactive\n"));
james@553 263 else
james@444 264 {
james@553 265 if (xvdd->device_type == XENVBD_DEVICETYPE_CDROM)
james@553 266 {
james@553 267 /* CD/DVD drives must have bytes_per_sector = 2048. */
james@553 268 xvdd->bytes_per_sector = 2048;
james@553 269 }
james@420 270
james@553 271 /* for some reason total_sectors is measured in 512 byte sectors always, so correct this to be in bytes_per_sectors */
james@553 272 xvdd->total_sectors /= xvdd->bytes_per_sector / 512;
james@420 273
james@553 274 xvdd->shadow_free = 0;
james@553 275 memset(xvdd->shadows, 0, sizeof(blkif_shadow_t) * SHADOW_ENTRIES);
james@553 276 for (i = 0; i < SHADOW_ENTRIES; i++)
james@553 277 {
james@553 278 xvdd->shadows[i].req.id = i;
james@553 279 put_shadow_on_freelist(xvdd, &xvdd->shadows[i]);
james@553 280 }
james@420 281 }
james@420 282
james@420 283 return SP_RETURN_FOUND;
james@420 284 }
james@420 285
james@496 286 static __inline ULONG
james@496 287 decode_cdb_length(PSCSI_REQUEST_BLOCK srb)
james@496 288 {
james@496 289 switch (srb->Cdb[0])
james@496 290 {
james@496 291 case SCSIOP_READ:
james@496 292 case SCSIOP_WRITE:
james@708 293 return ((ULONG)(UCHAR)srb->Cdb[7] << 8) | (ULONG)(UCHAR)srb->Cdb[8];
james@496 294 case SCSIOP_READ16:
james@496 295 case SCSIOP_WRITE16:
james@708 296 return ((ULONG)(UCHAR)srb->Cdb[10] << 24) | ((ULONG)(UCHAR)srb->Cdb[11] << 16) | ((ULONG)(UCHAR)srb->Cdb[12] << 8) | (ULONG)(UCHAR)srb->Cdb[13];
james@496 297 default:
james@496 298 return 0;
james@496 299 }
james@496 300 }
james@496 301
james@496 302 static __inline ULONGLONG
james@496 303 decode_cdb_sector(PSCSI_REQUEST_BLOCK srb)
james@496 304 {
james@496 305 ULONGLONG sector;
james@496 306
james@496 307 switch (srb->Cdb[0])
james@496 308 {
james@496 309 case SCSIOP_READ:
james@496 310 case SCSIOP_WRITE:
james@708 311 sector = ((ULONG)(UCHAR)srb->Cdb[2] << 24) | ((ULONG)(UCHAR)srb->Cdb[3] << 16) | ((ULONG)(UCHAR)srb->Cdb[4] << 8) | (ULONG)(UCHAR)srb->Cdb[5];
james@496 312 break;
james@496 313 case SCSIOP_READ16:
james@496 314 case SCSIOP_WRITE16:
james@708 315 sector = ((ULONGLONG)(UCHAR)srb->Cdb[2] << 56) | ((ULONGLONG)(UCHAR)srb->Cdb[3] << 48)
james@708 316 | ((ULONGLONG)(UCHAR)srb->Cdb[4] << 40) | ((ULONGLONG)(UCHAR)srb->Cdb[5] << 32)
james@708 317 | ((ULONGLONG)(UCHAR)srb->Cdb[6] << 24) | ((ULONGLONG)(UCHAR)srb->Cdb[7] << 16)
james@708 318 | ((ULONGLONG)(UCHAR)srb->Cdb[8] << 8) | ((ULONGLONG)(UCHAR)srb->Cdb[9]);
james@496 319 //KdPrint((__DRIVER_NAME " sector_number = %d (high) %d (low)\n", (ULONG)(sector >> 32), (ULONG)sector));
james@496 320 break;
james@496 321 default:
james@496 322 sector = 0;
james@496 323 break;
james@496 324 }
james@496 325 return sector;
james@496 326 }
james@496 327
james@496 328 static __inline BOOLEAN
james@496 329 decode_cdb_is_read(PSCSI_REQUEST_BLOCK srb)
james@496 330 {
james@496 331 switch (srb->Cdb[0])
james@496 332 {
james@496 333 case SCSIOP_READ:
james@496 334 case SCSIOP_READ16:
james@496 335 return TRUE;
james@496 336 case SCSIOP_WRITE:
james@496 337 case SCSIOP_WRITE16:
james@496 338 return FALSE;
james@496 339 default:
james@496 340 return FALSE;
james@496 341 }
james@496 342 }
james@496 343
james@766 344 ULONG max_dump_mode_size = 0;
james@536 345
james@420 346 static VOID
james@781 347 XenVbd_PutSrbOnList(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb)
james@420 348 {
james@781 349 srb_list_entry_t *list_entry = srb->SrbExtension;
james@781 350 list_entry->srb = srb;
james@781 351 InsertTailList(&xvdd->srb_list, (PLIST_ENTRY)list_entry);
james@781 352 }
james@781 353
james@781 354 static VOID
james@781 355 XenVbd_PutQueuedSrbsOnRing(PXENVBD_DEVICE_DATA xvdd)
james@781 356 {
james@781 357 PSCSI_REQUEST_BLOCK srb;
james@781 358 srb_list_entry_t *srb_entry;
james@799 359 ULONGLONG sector_number;
james@534 360 ULONG block_count;
james@420 361 blkif_shadow_t *shadow;
james@420 362 ULONG remaining, offset, length;
james@538 363 grant_ref_t gref;
james@420 364 PUCHAR ptr;
james@420 365 int notify;
james@799 366 int i;
james@420 367
james@534 368 //FUNCTION_ENTER();
james@420 369
james@781 370 if (xvdd->aligned_buffer_in_use)
james@781 371 return;
james@420 372
james@781 373 while(xvdd->shadow_free && (srb_entry = (srb_list_entry_t *)RemoveHeadList(&xvdd->srb_list)) != (srb_list_entry_t *)&xvdd->srb_list)
james@420 374 {
james@781 375 srb = srb_entry->srb;
james@781 376 block_count = decode_cdb_length(srb);;
james@781 377 block_count *= xvdd->bytes_per_sector / 512;
james@799 378 sector_number = decode_cdb_sector(srb);
james@799 379 sector_number *= xvdd->bytes_per_sector / 512;
james@799 380
james@799 381 /* look for pending writes that overlap this one */
james@799 382 /* we get warnings from drbd if we don't */
james@799 383 for (i = 0; i < MAX_SHADOW_ENTRIES; i++)
james@799 384 {
james@799 385 PSCSI_REQUEST_BLOCK srb2;
james@799 386 ULONGLONG sector_number2;
james@799 387 ULONG block_count2;
james@799 388
james@799 389 srb2 = xvdd->shadows[i].srb;
james@799 390 if (!srb2)
james@799 391 continue;
james@799 392 if (decode_cdb_is_read(srb2))
james@799 393 continue;
james@799 394 block_count2 = decode_cdb_length(srb2);;
james@799 395 block_count2 *= xvdd->bytes_per_sector / 512;
james@799 396 sector_number2 = decode_cdb_sector(srb2);
james@799 397 sector_number2 *= xvdd->bytes_per_sector / 512;
james@799 398
james@799 399 if (sector_number < sector_number2 && sector_number + block_count <= sector_number2)
james@799 400 continue;
james@799 401 if (sector_number2 < sector_number && sector_number2 + block_count2 <= sector_number)
james@799 402 continue;
james@799 403
james@799 404 #if 0
james@799 405 /* check if the data being written is identical to the data in the pipe */
james@799 406 {
james@799 407 PUCHAR buf, buf2;
james@799 408 ULONG byte_count;
james@799 409 int j;
james@799 410
james@799 411 buf = (PUCHAR)srb->DataBuffer + (max(sector_number, sector_number2) - sector_number) * xvdd->bytes_per_sector;
james@799 412 buf2 = (PUCHAR)srb2->DataBuffer + (max(sector_number, sector_number2) - sector_number2) * xvdd->bytes_per_sector;
james@799 413 byte_count = (ULONG)(min(sector_number + block_count, sector_number2 + block_count2) - max(sector_number, sector_number2)) * xvdd->bytes_per_sector;
james@799 414 for (j = 0; j < (int)byte_count; j++)
james@799 415 {
james@799 416 if (buf[j] != buf2[j])
james@799 417 break;
james@799 418 }
james@799 419 }
james@799 420 #endif
james@799 421
james@799 422 KdPrint((__DRIVER_NAME " Concurrent outstanding write detected (%I64d, %d) (%I64d, %d)\n",
james@799 423 sector_number, block_count, sector_number2, block_count2));
james@799 424 /* put the srb back at the start of the queue */
james@799 425 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
james@799 426 return; /* stall the queue */
james@799 427 }
james@799 428
james@781 429 remaining = block_count * 512;
james@781 430 shadow = get_shadow_from_freelist(xvdd);
james@781 431 ASSERT(shadow);
james@781 432 ASSERT(!shadow->aligned_buffer_in_use);
james@781 433 ASSERT(!shadow->srb);
james@799 434 shadow->req.sector_number = sector_number;
james@781 435 shadow->req.handle = 0;
james@781 436 shadow->req.operation = decode_cdb_is_read(srb)?BLKIF_OP_READ:BLKIF_OP_WRITE;
james@781 437 shadow->req.nr_segments = 0;
james@781 438 shadow->srb = srb;
james@781 439
james@781 440 if ((ULONG_PTR)srb->DataBuffer & 511)
james@781 441 {
james@812 442 ASSERT(!dump_mode || block_count * 512 < BLKIF_MAX_SEGMENTS_PER_REQUEST_DUMP_MODE * PAGE_SIZE);
james@781 443 xvdd->aligned_buffer_in_use = TRUE;
james@781 444 ptr = xvdd->aligned_buffer;
james@781 445 if (!decode_cdb_is_read(srb))
james@781 446 memcpy(ptr, srb->DataBuffer, block_count * 512);
james@781 447 shadow->aligned_buffer_in_use = TRUE;
james@781 448 }
james@781 449 else
james@781 450 {
james@781 451 ptr = srb->DataBuffer;
james@781 452 shadow->aligned_buffer_in_use = FALSE;
james@781 453 }
james@781 454
james@781 455 if (dump_mode && block_count > max_dump_mode_size)
james@781 456 {
james@781 457 max_dump_mode_size = block_count;
james@781 458 KdPrint((__DRIVER_NAME " max_dump_mode_size = %d\n", max_dump_mode_size));
james@781 459 }
james@781 460
james@781 461 //KdPrint((__DRIVER_NAME " sector_number = %d, block_count = %d\n", (ULONG)shadow->req.sector_number, block_count));
james@781 462 //KdPrint((__DRIVER_NAME " SrbExtension = %p\n", srb->SrbExtension));
james@781 463 //KdPrint((__DRIVER_NAME " DataBuffer = %p\n", srb->DataBuffer));
james@781 464
james@781 465 //KdPrint((__DRIVER_NAME " sector_number = %d\n", (ULONG)shadow->req.sector_number));
james@781 466 //KdPrint((__DRIVER_NAME " handle = %d\n", shadow->req.handle));
james@781 467 //KdPrint((__DRIVER_NAME " operation = %d\n", shadow->req.operation));
james@766 468
james@781 469 while (remaining > 0)
james@779 470 {
james@781 471 PHYSICAL_ADDRESS physical_address = MmGetPhysicalAddress(ptr);
james@781 472
james@790 473 if (dump_mode)
james@790 474 {
james@790 475 gref = xvdd->vectors.GntTbl_GrantAccess(xvdd->vectors.context, 0,
james@790 476 (ULONG)(physical_address.QuadPart >> PAGE_SHIFT), FALSE,
james@790 477 xvdd->dump_grant_refs[shadow->req.nr_segments], (ULONG)'XPDO');
james@790 478 }
james@790 479 else
james@790 480 {
james@790 481 gref = xvdd->vectors.GntTbl_GrantAccess(xvdd->vectors.context, 0,
james@790 482 (ULONG)(physical_address.QuadPart >> PAGE_SHIFT), FALSE, INVALID_GRANT_REF, (ULONG)'XVBD');
james@790 483 }
james@781 484 if (gref == INVALID_GRANT_REF)
james@779 485 {
james@781 486 ULONG i;
james@781 487 for (i = 0; i < shadow->req.nr_segments; i++)
james@781 488 {
james@781 489 xvdd->vectors.GntTbl_EndAccess(xvdd->vectors.context,
james@790 490 shadow->req.seg[i].gref, FALSE, (ULONG)'XVBD');
james@781 491 }
james@781 492 if (shadow->aligned_buffer_in_use)
james@781 493 {
james@781 494 shadow->aligned_buffer_in_use = FALSE;
james@781 495 xvdd->aligned_buffer_in_use = FALSE;
james@781 496 }
james@781 497 /* put the srb back at the start of the queue */
james@781 498 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
james@781 499 put_shadow_on_freelist(xvdd, shadow);
james@781 500 KdPrint((__DRIVER_NAME " Out of gref's. Deferring\n"));
james@781 501 return;
james@779 502 }
james@781 503 offset = physical_address.LowPart & (PAGE_SIZE - 1);
james@781 504 length = min(PAGE_SIZE - offset, remaining);
james@781 505 ASSERT((offset & 511) == 0);
james@781 506 ASSERT((length & 511) == 0);
james@781 507 ASSERT(offset + length <= PAGE_SIZE);
james@781 508 shadow->req.seg[shadow->req.nr_segments].gref = gref;
james@781 509 shadow->req.seg[shadow->req.nr_segments].first_sect = (UCHAR)(offset >> 9);
james@781 510 shadow->req.seg[shadow->req.nr_segments].last_sect = (UCHAR)(((offset + length) >> 9) - 1);
james@781 511 remaining -= length;
james@781 512 ptr += length;
james@781 513 shadow->req.nr_segments++;
james@779 514 }
james@781 515
james@781 516 //KdPrint((__DRIVER_NAME " nr_segments = %d\n", shadow->req.nr_segments));
james@781 517
james@781 518 XenVbd_PutRequest(xvdd, &shadow->req);
james@781 519
james@781 520 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xvdd->ring, notify);
james@781 521 if (notify)
james@781 522 {
james@781 523 //KdPrint((__DRIVER_NAME " Notifying\n"));
james@781 524 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->event_channel);
james@781 525 }
james@781 526
james@420 527 }
james@766 528 if (xvdd->shadow_free && !xvdd->aligned_buffer_in_use)
james@766 529 {
james@420 530 ScsiPortNotification(NextLuRequest, xvdd, 0, 0, 0);
james@766 531 }
james@534 532 //FUNCTION_EXIT();
james@420 533 }
james@420 534
james@420 535 static ULONG DDKAPI
james@420 536 XenVbd_HwScsiFindAdapter(PVOID DeviceExtension, PVOID HwContext, PVOID BusInformation, PCHAR ArgumentString, PPORT_CONFIGURATION_INFORMATION ConfigInfo, PBOOLEAN Again)
james@420 537 {
james@420 538 // PACCESS_RANGE AccessRange;
james@420 539 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)DeviceExtension;
james@420 540 ULONG status;
james@420 541 // PXENPCI_XEN_DEVICE_DATA XenDeviceData;
james@420 542 PACCESS_RANGE access_range;
james@420 543
james@420 544 UNREFERENCED_PARAMETER(HwContext);
james@420 545 UNREFERENCED_PARAMETER(BusInformation);
james@420 546 UNREFERENCED_PARAMETER(ArgumentString);
james@420 547
james@536 548 FUNCTION_ENTER();
james@420 549 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@553 550 KdPrint((__DRIVER_NAME " xvdd = %p\n", xvdd));
james@420 551
james@553 552 RtlZeroMemory(xvdd, sizeof(XENVBD_DEVICE_DATA));
james@420 553 *Again = FALSE;
james@420 554
james@420 555 KdPrint((__DRIVER_NAME " BusInterruptLevel = %d\n", ConfigInfo->BusInterruptLevel));
james@420 556 KdPrint((__DRIVER_NAME " BusInterruptVector = %03x\n", ConfigInfo->BusInterruptVector));
james@420 557
james@495 558 KdPrint((__DRIVER_NAME " NumberOfAccessRanges = %d\n", ConfigInfo->NumberOfAccessRanges));
james@425 559 if (ConfigInfo->NumberOfAccessRanges != 1 && ConfigInfo->NumberOfAccessRanges != 2)
james@420 560 {
james@420 561 return SP_RETURN_BAD_CONFIG;
james@420 562 }
james@420 563
james@495 564 access_range = &((*(ConfigInfo->AccessRanges))[0]);
james@495 565 KdPrint((__DRIVER_NAME " RangeStart = %08x, RangeLength = %08x\n",
james@495 566 access_range->RangeStart.LowPart, access_range->RangeLength));
james@495 567 xvdd->device_base = ScsiPortGetDeviceBase(
james@495 568 DeviceExtension,
james@495 569 ConfigInfo->AdapterInterfaceType,
james@495 570 ConfigInfo->SystemIoBusNumber,
james@495 571 access_range->RangeStart,
james@495 572 access_range->RangeLength,
james@495 573 !access_range->RangeInMemory);
james@425 574 if (!xvdd->device_base)
james@420 575 {
james@425 576 KdPrint((__DRIVER_NAME " Invalid config\n"));
james@536 577 FUNCTION_EXIT();
james@420 578 return SP_RETURN_BAD_CONFIG;
james@420 579 }
james@425 580
james@420 581 status = XenVbd_InitFromConfig(xvdd);
james@420 582 if (status != SP_RETURN_FOUND)
james@536 583 {
james@536 584 FUNCTION_EXIT();
james@420 585 return status;
james@536 586 }
james@536 587
james@766 588 xvdd->aligned_buffer_in_use = FALSE;
james@781 589 /* align the buffer to PAGE_SIZE */
james@766 590 xvdd->aligned_buffer = (PVOID)((ULONG_PTR)((PUCHAR)xvdd->aligned_buffer_data + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
james@766 591 KdPrint((__DRIVER_NAME " aligned_buffer_data = %p\n", xvdd->aligned_buffer_data));
james@766 592 KdPrint((__DRIVER_NAME " aligned_buffer = %p\n", xvdd->aligned_buffer));
james@766 593
james@538 594 if (!dump_mode)
james@536 595 {
james@536 596 ConfigInfo->MaximumTransferLength = BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE;
james@536 597 ConfigInfo->NumberOfPhysicalBreaks = BLKIF_MAX_SEGMENTS_PER_REQUEST - 1;
james@810 598 //ConfigInfo->ScatterGather = TRUE;
james@536 599 }
james@536 600 else
james@536 601 {
james@810 602 ConfigInfo->MaximumTransferLength = BLKIF_MAX_SEGMENTS_PER_REQUEST_DUMP_MODE * PAGE_SIZE;
james@810 603 ConfigInfo->NumberOfPhysicalBreaks = BLKIF_MAX_SEGMENTS_PER_REQUEST_DUMP_MODE - 1;
james@810 604 //ConfigInfo->ScatterGather = FALSE;
james@536 605 }
james@810 606 ConfigInfo->ScatterGather = FALSE;
james@420 607 ConfigInfo->AlignmentMask = 0;
james@420 608 ConfigInfo->NumberOfBuses = 1;
james@420 609 ConfigInfo->InitiatorBusId[0] = 1;
james@420 610 ConfigInfo->MaximumNumberOfLogicalUnits = 1;
james@420 611 ConfigInfo->MaximumNumberOfTargets = 2;
james@810 612 ConfigInfo->BufferAccessScsiPortControlled = FALSE;
james@420 613 if (ConfigInfo->Dma64BitAddresses == SCSI_DMA64_SYSTEM_SUPPORTED)
james@420 614 {
james@420 615 ConfigInfo->Master = TRUE;
james@420 616 ConfigInfo->Dma64BitAddresses = SCSI_DMA64_MINIPORT_SUPPORTED;
james@534 617 ConfigInfo->Dma32BitAddresses = FALSE;
james@420 618 KdPrint((__DRIVER_NAME " Dma64BitAddresses supported\n"));
james@420 619 }
james@420 620 else
james@420 621 {
james@587 622 ConfigInfo->Master = TRUE;
james@534 623 ConfigInfo->Dma32BitAddresses = TRUE;
james@420 624 KdPrint((__DRIVER_NAME " Dma64BitAddresses not supported\n"));
james@420 625 }
james@420 626
james@536 627 FUNCTION_EXIT();
james@420 628
james@420 629 return SP_RETURN_FOUND;
james@420 630 }
james@420 631
james@553 632 static VOID
james@553 633 XenVbd_StartRingDetection(PXENVBD_DEVICE_DATA xvdd)
james@553 634 {
james@553 635 blkif_request_t *req;
james@553 636 int notify;
james@553 637
james@577 638 xvdd->ring_detect_state = RING_DETECT_STATE_DETECT1;
james@590 639 RtlZeroMemory(xvdd->sring->ring, PAGE_SIZE - FIELD_OFFSET(blkif_sring_t, ring));
james@553 640 req = RING_GET_REQUEST(&xvdd->ring, xvdd->ring.req_prod_pvt);
james@553 641 req->operation = 0xff;
james@553 642 xvdd->ring.req_prod_pvt++;
james@553 643 req = RING_GET_REQUEST(&xvdd->ring, xvdd->ring.req_prod_pvt);
james@553 644 req->operation = 0xff;
james@553 645 xvdd->ring.req_prod_pvt++;
james@553 646
james@553 647 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xvdd->ring, notify);
james@553 648 if (notify)
james@553 649 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->event_channel);
james@553 650 }
james@553 651
james@553 652 static BOOLEAN
james@420 653 XenVbd_HwScsiInitialize(PVOID DeviceExtension)
james@420 654 {
james@420 655 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)DeviceExtension;
james@420 656
james@538 657 FUNCTION_ENTER();
james@420 658 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@553 659 KdPrint((__DRIVER_NAME " dump_mode = %d\n", dump_mode));
james@420 660
james@553 661 if (!xvdd->inactive)
james@420 662 {
james@553 663 if (!dump_mode)
james@435 664 {
james@553 665 XenVbd_StartRingDetection(xvdd);
james@435 666 }
james@553 667 else
james@553 668 {
james@553 669 if (xvdd->cached_use_other)
james@553 670 {
james@553 671 xvdd->ring.nr_ents = BLK_OTHER_RING_SIZE;
james@553 672 xvdd->use_other = TRUE;
james@553 673 }
james@577 674 xvdd->ring_detect_state = RING_DETECT_STATE_COMPLETE;
james@553 675 }
james@781 676 InitializeListHead(&xvdd->srb_list);
james@435 677 }
james@538 678 FUNCTION_EXIT();
james@420 679
james@420 680 return TRUE;
james@420 681 }
james@420 682
james@420 683 static ULONG
james@420 684 XenVbd_FillModePage(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb)
james@420 685 {
james@784 686 PMODE_PARAMETER_HEADER parameter_header = NULL;
james@784 687 PMODE_PARAMETER_HEADER10 parameter_header10 = NULL;
james@420 688 PMODE_PARAMETER_BLOCK param_block;
james@420 689 PMODE_FORMAT_PAGE format_page;
james@784 690 ULONG offset = 0;
james@784 691 UCHAR buffer[1024];
james@420 692 BOOLEAN valid_page = FALSE;
james@496 693 BOOLEAN cdb_llbaa;
james@496 694 BOOLEAN cdb_dbd;
james@496 695 UCHAR cdb_page_code;
james@496 696 USHORT cdb_allocation_length;
james@420 697
james@420 698 UNREFERENCED_PARAMETER(xvdd);
james@420 699
james@784 700 RtlZeroMemory(srb->DataBuffer, srb->DataTransferLength);
james@784 701 RtlZeroMemory(buffer, ARRAY_SIZE(buffer));
james@784 702 offset = 0;
james@784 703
james@420 704 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@420 705
james@496 706 switch (srb->Cdb[0])
james@496 707 {
james@496 708 case SCSIOP_MODE_SENSE:
james@496 709 cdb_llbaa = FALSE;
james@496 710 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
james@496 711 cdb_page_code = srb->Cdb[2] & 0x3f;
james@496 712 cdb_allocation_length = srb->Cdb[4];
james@496 713 KdPrint((__DRIVER_NAME " SCSIOP_MODE_SENSE llbaa = %d, dbd = %d, page_code = %d, allocation_length = %d\n",
james@496 714 cdb_llbaa, cdb_dbd, cdb_page_code, cdb_allocation_length));
james@784 715 parameter_header = (PMODE_PARAMETER_HEADER)&buffer[offset];
james@784 716 parameter_header->MediumType = 0;
james@784 717 parameter_header->DeviceSpecificParameter = 0;
james@784 718 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ)
james@784 719 {
james@784 720 KdPrint((__DRIVER_NAME " Mode sense to a read only disk.\n"));
james@784 721 parameter_header->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
james@784 722 }
james@784 723 offset += sizeof(MODE_PARAMETER_HEADER);
james@496 724 break;
james@496 725 case SCSIOP_MODE_SENSE10:
james@496 726 cdb_llbaa = (BOOLEAN)!!(srb->Cdb[1] & 16);
james@496 727 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
james@496 728 cdb_page_code = srb->Cdb[2] & 0x3f;
james@496 729 cdb_allocation_length = (srb->Cdb[7] << 8) | srb->Cdb[8];
james@496 730 KdPrint((__DRIVER_NAME " SCSIOP_MODE_SENSE10 llbaa = %d, dbd = %d, page_code = %d, allocation_length = %d\n",
james@496 731 cdb_llbaa, cdb_dbd, cdb_page_code, cdb_allocation_length));
james@784 732 parameter_header10 = (PMODE_PARAMETER_HEADER10)&buffer[offset];
james@784 733 parameter_header10->MediumType = 0;
james@784 734 parameter_header10->DeviceSpecificParameter = 0;
james@784 735 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ)
james@784 736 {
james@784 737 KdPrint((__DRIVER_NAME " Mode sense to a read only disk.\n"));
james@784 738 parameter_header10->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
james@784 739 }
james@784 740 offset += sizeof(MODE_PARAMETER_HEADER10);
james@496 741 break;
james@496 742 default:
james@496 743 KdPrint((__DRIVER_NAME " SCSIOP_MODE_SENSE_WTF (%02x)\n", (ULONG)srb->Cdb[0]));
james@496 744 return FALSE;
james@784 745 }
james@420 746
james@496 747 if (!cdb_dbd)
james@420 748 {
james@420 749 param_block = (PMODE_PARAMETER_BLOCK)&buffer[offset];
james@420 750 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK)
james@420 751 {
james@420 752 if (xvdd->total_sectors >> 32)
james@420 753 {
james@420 754 param_block->DensityCode = 0xff;
james@420 755 param_block->NumberOfBlocks[0] = 0xff;
james@420 756 param_block->NumberOfBlocks[1] = 0xff;
james@420 757 param_block->NumberOfBlocks[2] = 0xff;
james@420 758 }
james@420 759 else
james@420 760 {
james@420 761 param_block->DensityCode = (UCHAR)((xvdd->total_sectors >> 24) & 0xff);
james@420 762 param_block->NumberOfBlocks[0] = (UCHAR)((xvdd->total_sectors >> 16) & 0xff);
james@420 763 param_block->NumberOfBlocks[1] = (UCHAR)((xvdd->total_sectors >> 8) & 0xff);
james@420 764 param_block->NumberOfBlocks[2] = (UCHAR)((xvdd->total_sectors >> 0) & 0xff);
james@420 765 }
james@420 766 param_block->BlockLength[0] = (UCHAR)((xvdd->bytes_per_sector >> 16) & 0xff);
james@420 767 param_block->BlockLength[1] = (UCHAR)((xvdd->bytes_per_sector >> 8) & 0xff);
james@420 768 param_block->BlockLength[2] = (UCHAR)((xvdd->bytes_per_sector >> 0) & 0xff);
james@420 769 }
james@420 770 offset += sizeof(MODE_PARAMETER_BLOCK);
james@420 771 }
james@784 772 switch (srb->Cdb[0])
james@784 773 {
james@784 774 case SCSIOP_MODE_SENSE:
james@784 775 parameter_header->BlockDescriptorLength = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER));
james@784 776 break;
james@784 777 case SCSIOP_MODE_SENSE10:
james@784 778 parameter_header10->BlockDescriptorLength[0] = (UCHAR)((offset - sizeof(MODE_PARAMETER_HEADER10)) >> 8);
james@784 779 parameter_header10->BlockDescriptorLength[1] = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER10));
james@784 780 break;
james@784 781 }
james@496 782 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_FORMAT_DEVICE || cdb_page_code == MODE_SENSE_RETURN_ALL))
james@420 783 {
james@420 784 valid_page = TRUE;
james@420 785 format_page = (PMODE_FORMAT_PAGE)&buffer[offset];
james@420 786 format_page->PageCode = MODE_PAGE_FORMAT_DEVICE;
james@420 787 format_page->PageLength = sizeof(MODE_FORMAT_PAGE) - FIELD_OFFSET(MODE_FORMAT_PAGE, PageLength);
james@420 788 /* 256 sectors per track */
james@420 789 format_page->SectorsPerTrack[0] = 0x01;
james@420 790 format_page->SectorsPerTrack[1] = 0x00;
james@420 791 /* xxx bytes per sector */
james@420 792 format_page->BytesPerPhysicalSector[0] = (UCHAR)(xvdd->bytes_per_sector >> 8);
james@420 793 format_page->BytesPerPhysicalSector[1] = (UCHAR)(xvdd->bytes_per_sector & 0xff);
james@420 794 format_page->HardSectorFormating = TRUE;
james@420 795 format_page->SoftSectorFormating = TRUE;
james@420 796 offset += sizeof(MODE_FORMAT_PAGE);
james@420 797 }
james@784 798 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_CACHING || cdb_page_code == MODE_SENSE_RETURN_ALL))
james@784 799 {
james@784 800 PMODE_CACHING_PAGE caching_page;
james@784 801 valid_page = TRUE;
james@784 802 caching_page = (PMODE_CACHING_PAGE)&buffer[offset];
james@784 803 caching_page->PageCode = MODE_PAGE_CACHING;
james@784 804 caching_page->PageLength = sizeof(MODE_CACHING_PAGE) - FIELD_OFFSET(MODE_CACHING_PAGE, PageLength);
james@784 805 // caching_page-> // all zeros is just fine... maybe
james@784 806 offset += sizeof(MODE_CACHING_PAGE);
james@784 807 }
james@784 808 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_MEDIUM_TYPES || cdb_page_code == MODE_SENSE_RETURN_ALL))
james@784 809 {
james@784 810 PUCHAR medium_types_page;
james@784 811 valid_page = TRUE;
james@784 812 medium_types_page = &buffer[offset];
james@784 813 medium_types_page[0] = MODE_PAGE_MEDIUM_TYPES;
james@784 814 medium_types_page[1] = 0x06;
james@784 815 medium_types_page[2] = 0;
james@784 816 medium_types_page[3] = 0;
james@784 817 medium_types_page[4] = 0;
james@784 818 medium_types_page[5] = 0;
james@784 819 medium_types_page[6] = 0;
james@784 820 medium_types_page[7] = 0;
james@784 821 offset += 8;
james@784 822 }
james@784 823 switch (srb->Cdb[0])
james@784 824 {
james@784 825 case SCSIOP_MODE_SENSE:
james@784 826 parameter_header->ModeDataLength = (UCHAR)(offset - 1);
james@784 827 break;
james@784 828 case SCSIOP_MODE_SENSE10:
james@784 829 parameter_header10->ModeDataLength[0] = (UCHAR)((offset - 2) >> 8);
james@784 830 parameter_header10->ModeDataLength[1] = (UCHAR)(offset - 2);
james@784 831 break;
james@784 832 }
james@784 833
james@496 834 if (!valid_page && cdb_page_code != MODE_SENSE_RETURN_ALL)
james@420 835 {
james@420 836 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 837 }
james@420 838 else if(offset < srb->DataTransferLength)
james@420 839 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
james@420 840 else
james@420 841 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 842 srb->DataTransferLength = min(srb->DataTransferLength, offset);
james@420 843 srb->ScsiStatus = 0;
james@784 844 memcpy(srb->DataBuffer, buffer, srb->DataTransferLength);
james@420 845
james@420 846 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@420 847
james@420 848 return TRUE;
james@420 849 }
james@420 850
james@420 851 static VOID
james@420 852 XenVbd_MakeSense(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb, UCHAR sense_key, UCHAR additional_sense_code)
james@420 853 {
james@420 854 PSENSE_DATA sd = srb->SenseInfoBuffer;
james@420 855
james@420 856 UNREFERENCED_PARAMETER(xvdd);
james@420 857
james@420 858 if (!srb->SenseInfoBuffer)
james@420 859 return;
james@420 860
james@420 861 sd->ErrorCode = 0x70;
james@420 862 sd->Valid = 1;
james@420 863 sd->SenseKey = sense_key;
james@420 864 sd->AdditionalSenseLength = sizeof(SENSE_DATA) - FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
james@420 865 sd->AdditionalSenseCode = additional_sense_code;
james@420 866 return;
james@420 867 }
james@420 868
james@420 869 static VOID
james@420 870 XenVbd_MakeAutoSense(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb)
james@420 871 {
james@420 872 if (srb->SrbStatus == SRB_STATUS_SUCCESS || srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)
james@420 873 return;
james@420 874 XenVbd_MakeSense(xvdd, srb, xvdd->last_sense_key, xvdd->last_additional_sense_code);
james@420 875 srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
james@420 876 }
james@420 877
james@420 878 static BOOLEAN DDKAPI
james@420 879 XenVbd_HwScsiInterrupt(PVOID DeviceExtension)
james@420 880 {
james@420 881 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)DeviceExtension;
james@420 882 PSCSI_REQUEST_BLOCK srb;
james@420 883 RING_IDX i, rp;
james@538 884 ULONG j;
james@420 885 blkif_response_t *rep;
james@420 886 int block_count;
james@420 887 int more_to_do = TRUE;
james@420 888 blkif_shadow_t *shadow;
james@536 889 ULONG suspend_resume_state_pdo;
james@563 890 BOOLEAN last_interrupt = FALSE;
james@420 891
james@420 892 /* in dump mode I think we get called on a timer, not by an actual IRQ */
james@563 893 if (!dump_mode && !xvdd->vectors.EvtChn_AckEvent(xvdd->vectors.context, xvdd->event_channel, &last_interrupt))
james@420 894 return FALSE; /* interrupt was not for us */
james@536 895
james@536 896 suspend_resume_state_pdo = xvdd->device_state->suspend_resume_state_pdo;
james@536 897 KeMemoryBarrier();
james@534 898
james@536 899 if (suspend_resume_state_pdo != xvdd->device_state->suspend_resume_state_fdo)
james@422 900 {
james@422 901 FUNCTION_ENTER();
james@536 902 switch (suspend_resume_state_pdo)
james@422 903 {
james@536 904 case SR_STATE_SUSPENDING:
james@536 905 KdPrint((__DRIVER_NAME " New pdo state SR_STATE_SUSPENDING\n"));
james@422 906 break;
james@536 907 case SR_STATE_RESUMING:
james@536 908 KdPrint((__DRIVER_NAME " New pdo state SR_STATE_RESUMING\n"));
james@536 909 XenVbd_InitFromConfig(xvdd);
james@536 910 xvdd->device_state->suspend_resume_state_fdo = suspend_resume_state_pdo;
james@536 911 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->device_state->pdo_event_channel);
james@422 912 break;
james@536 913 case SR_STATE_RUNNING:
james@536 914 KdPrint((__DRIVER_NAME " New pdo state %d\n", suspend_resume_state_pdo));
james@536 915 xvdd->device_state->suspend_resume_state_fdo = suspend_resume_state_pdo;
james@536 916 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->device_state->pdo_event_channel);
james@781 917 ScsiPortNotification(NextRequest, DeviceExtension);
james@422 918 default:
james@536 919 KdPrint((__DRIVER_NAME " New pdo state %d\n", suspend_resume_state_pdo));
james@536 920 xvdd->device_state->suspend_resume_state_fdo = suspend_resume_state_pdo;
james@536 921 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->device_state->pdo_event_channel);
james@422 922 break;
james@422 923 }
james@422 924 KeMemoryBarrier();
james@422 925 }
james@422 926
james@536 927 if (xvdd->device_state->suspend_resume_state_fdo != SR_STATE_RUNNING)
james@420 928 {
james@575 929 return last_interrupt;
james@420 930 }
james@420 931
james@420 932 while (more_to_do)
james@420 933 {
james@420 934 rp = xvdd->ring.sring->rsp_prod;
james@420 935 KeMemoryBarrier();
james@435 936 for (i = xvdd->ring.rsp_cons; i < rp; i++)
james@420 937 {
james@420 938 rep = XenVbd_GetResponse(xvdd, i);
james@420 939 /*
james@420 940 * This code is to automatically detect if the backend is using the same
james@420 941 * bit width or a different bit width to us. Later versions of Xen do this
james@420 942 * via a xenstore value, but not all. That 0x0fffffff (notice
james@420 943 * that the msb is not actually set, so we don't have any problems with
james@420 944 * sign extending) is to signify the last entry on the right, which is
james@420 945 * different under 32 and 64 bits, and that is why we set it up there.
james@420 946
james@420 947 * To do the detection, we put two initial entries on the ring, with an op
james@420 948 * of 0xff (which is invalid). The first entry is mostly okay, but the
james@420 949 * second will be grossly misaligned if the backend bit width is different,
james@420 950 * and we detect this and switch frontend structures.
james@420 951 */
james@420 952 switch (xvdd->ring_detect_state)
james@420 953 {
james@577 954 case RING_DETECT_STATE_NOT_STARTED:
james@577 955 KdPrint((__DRIVER_NAME " premature IRQ\n"));
james@577 956 break;
james@577 957 case RING_DETECT_STATE_DETECT1:
james@790 958 KdPrint((__DRIVER_NAME " ring_detect_state = %d, index = %d, operation = %x, id = %lx, status = %d\n", xvdd->ring_detect_state, i, rep->operation, rep->id, rep->status));
james@790 959 KdPrint((__DRIVER_NAME " req_prod = %d, rsp_prod = %d, rsp_cons = %d\n", xvdd->sring->req_prod, xvdd->sring->rsp_prod, xvdd->ring.rsp_cons));
james@577 960 xvdd->ring_detect_state = RING_DETECT_STATE_DETECT2;
james@420 961 break;
james@577 962 case RING_DETECT_STATE_DETECT2:
james@790 963 KdPrint((__DRIVER_NAME " ring_detect_state = %d, index = %d, operation = %x, id = %lx, status = %d\n", xvdd->ring_detect_state, i, rep->operation, rep->id, rep->status));
james@790 964 KdPrint((__DRIVER_NAME " req_prod = %d, rsp_prod = %d, rsp_cons = %d\n", xvdd->sring->req_prod, xvdd->sring->rsp_prod, xvdd->ring.rsp_cons));
james@435 965 *xvdd->event_channel_ptr |= 0x80000000;
james@420 966 if (rep->operation != 0xff)
james@420 967 {
james@790 968 KdPrint((__DRIVER_NAME " switching to 'other' ring size\n"));
james@420 969 xvdd->ring.nr_ents = BLK_OTHER_RING_SIZE;
james@420 970 xvdd->use_other = TRUE;
james@435 971 *xvdd->event_channel_ptr |= 0x40000000;
james@420 972 }
james@577 973 xvdd->ring_detect_state = RING_DETECT_STATE_COMPLETE;
james@420 974 ScsiPortNotification(NextRequest, DeviceExtension);
james@420 975 break;
james@577 976 case RING_DETECT_STATE_COMPLETE:
james@420 977 shadow = &xvdd->shadows[rep->id];
james@420 978 srb = shadow->srb;
james@420 979 ASSERT(srb != NULL);
james@496 980 block_count = decode_cdb_length(srb);
james@420 981 block_count *= xvdd->bytes_per_sector / 512;
james@766 982 /* a few errors occur in dump mode because Xen refuses to allow us to map pages we are using for other stuff. Just ignore them */
james@766 983 if (rep->status == BLKIF_RSP_OKAY || (dump_mode && dump_mode_errors++ < DUMP_MODE_ERROR_LIMIT))
james@420 984 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 985 else
james@420 986 {
james@420 987 KdPrint((__DRIVER_NAME " Xen Operation returned error\n"));
james@496 988 if (decode_cdb_is_read(srb))
james@420 989 KdPrint((__DRIVER_NAME " Operation = Read\n"));
james@420 990 else
james@495 991 KdPrint((__DRIVER_NAME " Operation = Write\n"));
james@766 992 if (dump_mode)
james@766 993 {
james@766 994 KdPrint((__DRIVER_NAME " Sector = %08X, Count = %d\n", (ULONG)shadow->req.sector_number, block_count));
james@766 995 KdPrint((__DRIVER_NAME " DataBuffer = %p, aligned_buffer = %p\n", srb->DataBuffer, xvdd->aligned_buffer));
james@766 996 KdPrint((__DRIVER_NAME " Physical = %08x%08x\n", MmGetPhysicalAddress(srb->DataBuffer).HighPart, MmGetPhysicalAddress(srb->DataBuffer).LowPart));
james@766 997 KdPrint((__DRIVER_NAME " PFN = %08x\n", (ULONG)(MmGetPhysicalAddress(srb->DataBuffer).QuadPart >> PAGE_SHIFT)));
james@766 998
james@766 999 for (j = 0; j < shadow->req.nr_segments; j++)
james@766 1000 {
james@766 1001 KdPrint((__DRIVER_NAME " gref = %d\n", shadow->req.seg[j].gref));
james@766 1002 KdPrint((__DRIVER_NAME " first_sect = %d\n", shadow->req.seg[j].first_sect));
james@766 1003 KdPrint((__DRIVER_NAME " last_sect = %d\n", shadow->req.seg[j].last_sect));
james@766 1004 }
james@766 1005 }
james@420 1006 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1007 srb->ScsiStatus = 0x02;
james@420 1008 xvdd->last_sense_key = SCSI_SENSE_MEDIUM_ERROR;
james@420 1009 xvdd->last_additional_sense_code = SCSI_ADSENSE_NO_SENSE;
james@420 1010 XenVbd_MakeAutoSense(xvdd, srb);
james@420 1011 }
james@766 1012 if (shadow->aligned_buffer_in_use)
james@536 1013 {
james@766 1014 ASSERT(xvdd->aligned_buffer_in_use);
james@766 1015 xvdd->aligned_buffer_in_use = FALSE;
james@766 1016 if (decode_cdb_is_read(srb))
james@766 1017 memcpy(srb->DataBuffer, xvdd->aligned_buffer, block_count * 512);
james@781 1018 //KdPrint((__DRIVER_NAME " Completed use of buffer\n"));
james@536 1019 }
james@781 1020
james@781 1021 #if 0
james@781 1022 if (xvdd->aligned_buffer_in_use)
james@781 1023 {
james@781 1024 KdPrint((__DRIVER_NAME " Completed request while aligned buffer in use\n"));
james@781 1025 }
james@781 1026 #endif
james@766 1027 for (j = 0; j < shadow->req.nr_segments; j++)
james@766 1028 {
james@790 1029 if (dump_mode)
james@790 1030 {
james@790 1031 xvdd->vectors.GntTbl_EndAccess(xvdd->vectors.context,
james@790 1032 shadow->req.seg[j].gref, TRUE, (ULONG)'XPDO');
james@790 1033 }
james@790 1034 else
james@790 1035 {
james@790 1036 xvdd->vectors.GntTbl_EndAccess(xvdd->vectors.context,
james@790 1037 shadow->req.seg[j].gref, FALSE, (ULONG)'XVBD');
james@790 1038 }
james@766 1039 }
james@781 1040 shadow->aligned_buffer_in_use = FALSE;
james@781 1041 shadow->srb = NULL;
james@766 1042 put_shadow_on_freelist(xvdd, shadow);
james@766 1043 //KdPrint((__DRIVER_NAME " B RequestComplete srb = %p\n", srb));
james@534 1044 ScsiPortNotification(RequestComplete, xvdd, srb);
james@420 1045 break;
james@420 1046 }
james@420 1047 }
james@420 1048
james@420 1049 xvdd->ring.rsp_cons = i;
james@420 1050 if (i != xvdd->ring.req_prod_pvt)
james@420 1051 {
james@420 1052 RING_FINAL_CHECK_FOR_RESPONSES(&xvdd->ring, more_to_do);
james@420 1053 }
james@420 1054 else
james@420 1055 {
james@420 1056 xvdd->ring.sring->rsp_event = i + 1;
james@420 1057 more_to_do = FALSE;
james@420 1058 }
james@420 1059 }
james@420 1060
james@781 1061 XenVbd_PutQueuedSrbsOnRing(xvdd);
james@781 1062
james@536 1063 if (suspend_resume_state_pdo == SR_STATE_SUSPENDING)
james@536 1064 {
james@758 1065 if (xvdd->inactive || xvdd->shadow_free == SHADOW_ENTRIES)
james@536 1066 {
james@758 1067 /* all entries are purged from the list (or we are inactive). ready to suspend */
james@536 1068 xvdd->device_state->suspend_resume_state_fdo = suspend_resume_state_pdo;
james@536 1069 KeMemoryBarrier();
james@536 1070 KdPrint((__DRIVER_NAME " Set fdo state SR_STATE_SUSPENDING\n"));
james@536 1071 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xvdd->device_state->pdo_event_channel));
james@536 1072 xvdd->vectors.EvtChn_Notify(xvdd->vectors.context, xvdd->device_state->pdo_event_channel);
james@536 1073 }
james@536 1074 FUNCTION_EXIT();
james@536 1075 }
james@420 1076
james@575 1077 return last_interrupt;
james@420 1078 }
james@420 1079
james@420 1080 static BOOLEAN DDKAPI
james@766 1081 XenVbd_HwScsiStartIo(PVOID DeviceExtension, PSCSI_REQUEST_BLOCK srb)
james@420 1082 {
james@534 1083 PUCHAR data_buffer;
james@536 1084 //ULONG data_buffer_length;
james@420 1085 PCDB cdb;
james@420 1086 PXENVBD_DEVICE_DATA xvdd = DeviceExtension;
james@783 1087 ULONG data_transfer_length = srb->DataTransferLength;
james@420 1088
james@425 1089 if (xvdd->inactive)
james@425 1090 {
james@766 1091 KdPrint((__DRIVER_NAME " Inactive srb->Function = %08X\n", srb->Function));
james@766 1092 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
james@766 1093 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@495 1094 ScsiPortNotification(NextRequest, DeviceExtension);
james@425 1095 return TRUE;
james@425 1096 }
james@425 1097
james@420 1098 // If we haven't enumerated all the devices yet then just defer the request
james@577 1099 if (xvdd->ring_detect_state < RING_DETECT_STATE_COMPLETE)
james@420 1100 {
james@766 1101 srb->SrbStatus = SRB_STATUS_BUSY;
james@766 1102 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@420 1103 KdPrint((__DRIVER_NAME " --- HwScsiStartIo (Still figuring out ring)\n"));
james@420 1104 return TRUE;
james@420 1105 }
james@420 1106
james@536 1107 if (xvdd->device_state->suspend_resume_state_pdo != SR_STATE_RUNNING)
james@420 1108 {
james@758 1109 KdPrint((__DRIVER_NAME " --> HwScsiStartIo (Suspending/Resuming)\n"));
james@766 1110 srb->SrbStatus = SRB_STATUS_BUSY;
james@766 1111 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@758 1112 KdPrint((__DRIVER_NAME " <-- HwScsiStartIo (Suspending/Resuming)\n"));
james@420 1113 return TRUE;
james@420 1114 }
james@420 1115
james@766 1116 if (srb->PathId != 0 || srb->TargetId != 0)
james@420 1117 {
james@766 1118 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
james@766 1119 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@420 1120 ScsiPortNotification(NextRequest, DeviceExtension);
james@420 1121 KdPrint((__DRIVER_NAME " --- HwScsiStartIo (Out of bounds)\n"));
james@420 1122 return TRUE;
james@420 1123 }
james@420 1124
james@766 1125 switch (srb->Function)
james@420 1126 {
james@420 1127 case SRB_FUNCTION_EXECUTE_SCSI:
james@766 1128 cdb = (PCDB)srb->Cdb;
james@420 1129
james@420 1130 switch(cdb->CDB6GENERIC.OperationCode)
james@420 1131 {
james@420 1132 case SCSIOP_TEST_UNIT_READY:
james@536 1133 if (dump_mode)
james@536 1134 KdPrint((__DRIVER_NAME " Command = TEST_UNIT_READY\n"));
james@766 1135 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@766 1136 srb->ScsiStatus = 0;
james@420 1137 break;
james@420 1138 case SCSIOP_INQUIRY:
james@536 1139 if (dump_mode)
james@536 1140 {
james@536 1141 //PHYSICAL_ADDRESS physical;
james@536 1142 KdPrint((__DRIVER_NAME " Command = INQUIRY\n"));
james@766 1143 //KdPrint((__DRIVER_NAME " srb->Databuffer = %p\n", srb->DataBuffer));
james@766 1144 //physical = ScsiPortGetPhysicalAddress(xvdd, srb, srb->DataBuffer, &data_buffer_length);
james@536 1145 //KdPrint((__DRIVER_NAME " ScsiPortGetPhysicalAddress = %08x:%08x\n", physical.LowPart, physical.HighPart));
james@536 1146 }
james@766 1147 // KdPrint((__DRIVER_NAME " (LUN = %d, EVPD = %d, Page Code = %02X)\n", srb->Cdb[1] >> 5, srb->Cdb[1] & 1, srb->Cdb[2]));
james@766 1148 // KdPrint((__DRIVER_NAME " (Length = %d)\n", srb->DataTransferLength));
james@536 1149
james@766 1150 //data_buffer = LongLongToPtr(ScsiPortGetPhysicalAddress(xvdd, srb, srb->DataBuffer, &data_buffer_length).QuadPart);
james@766 1151 data_buffer = srb->DataBuffer;
james@766 1152 RtlZeroMemory(data_buffer, srb->DataTransferLength);
james@766 1153 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1154 switch (xvdd->device_type)
james@420 1155 {
james@420 1156 case XENVBD_DEVICETYPE_DISK:
james@766 1157 if ((srb->Cdb[1] & 1) == 0)
james@420 1158 {
james@783 1159 if (srb->Cdb[2])
james@783 1160 {
james@783 1161 srb->SrbStatus = SRB_STATUS_ERROR;
james@783 1162 }
james@783 1163 else
james@783 1164 {
james@783 1165 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
james@783 1166 id->DeviceType = DIRECT_ACCESS_DEVICE;
james@784 1167 id->Versions = 4; /* minimum that WHQL says we must support */
james@783 1168 id->ResponseDataFormat = 2; /* not sure about this but WHQL complains otherwise */
james@784 1169 id->HiSupport = 1; /* WHQL test says we should set this */
james@784 1170 //id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
james@784 1171 id->AdditionalLength = sizeof(INQUIRYDATA) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength) - 1;
james@783 1172 id->CommandQueue = 1;
james@783 1173 memcpy(id->VendorId, scsi_device_manufacturer, 8); // vendor id
james@783 1174 memcpy(id->ProductId, scsi_disk_model, 16); // product id
james@783 1175 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
james@783 1176 data_transfer_length = sizeof(INQUIRYDATA);
james@783 1177 }
james@420 1178 }
james@420 1179 else
james@420 1180 {
james@766 1181 switch (srb->Cdb[2])
james@420 1182 {
james@784 1183 case VPD_SUPPORTED_PAGES: /* list of pages we support */
james@534 1184 data_buffer[0] = DIRECT_ACCESS_DEVICE;
james@784 1185 data_buffer[1] = VPD_SUPPORTED_PAGES;
james@534 1186 data_buffer[2] = 0x00;
james@534 1187 data_buffer[3] = 2;
james@534 1188 data_buffer[4] = 0x00;
james@534 1189 data_buffer[5] = 0x80;
james@783 1190 data_transfer_length = 6;
james@420 1191 break;
james@784 1192 case VPD_SERIAL_NUMBER: /* serial number */
james@534 1193 data_buffer[0] = DIRECT_ACCESS_DEVICE;
james@784 1194 data_buffer[1] = VPD_SERIAL_NUMBER;
james@534 1195 data_buffer[2] = 0x00;
james@534 1196 data_buffer[3] = 8;
james@534 1197 memset(&data_buffer[4], ' ', 8);
james@783 1198 data_transfer_length = 12;
james@420 1199 break;
james@784 1200 case VPD_DEVICE_IDENTIFIERS: /* identification - we don't support any so just return zero */
james@784 1201 data_buffer[0] = DIRECT_ACCESS_DEVICE;
james@784 1202 data_buffer[1] = VPD_DEVICE_IDENTIFIERS;
james@784 1203 data_buffer[2] = 0x00;
james@784 1204 data_buffer[3] = 4 + (UCHAR)strlen(xvdd->vectors.path); /* length */
james@784 1205 data_buffer[4] = 2; /* ASCII */
james@784 1206 data_buffer[5] = 1; /* VendorId */
james@784 1207 data_buffer[6] = 0;
james@784 1208 data_buffer[7] = (UCHAR)strlen(xvdd->vectors.path);
james@784 1209 memcpy(&data_buffer[8], xvdd->vectors.path, strlen(xvdd->vectors.path));
james@785 1210 data_transfer_length = (ULONG)(8 + strlen(xvdd->vectors.path));
james@784 1211 break;
james@420 1212 default:
james@766 1213 //KdPrint((__DRIVER_NAME " Unknown Page %02x requested\n", srb->Cdb[2]));
james@766 1214 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1215 break;
james@420 1216 }
james@420 1217 }
james@420 1218 break;
james@420 1219 case XENVBD_DEVICETYPE_CDROM:
james@766 1220 if ((srb->Cdb[1] & 1) == 0)
james@420 1221 {
james@534 1222 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
james@420 1223 id->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
james@420 1224 id->RemovableMedia = 1;
james@420 1225 id->Versions = 3;
james@420 1226 id->ResponseDataFormat = 0;
james@420 1227 id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
james@420 1228 id->CommandQueue = 1;
james@563 1229 memcpy(id->VendorId, scsi_device_manufacturer, 8); // vendor id
james@563 1230 memcpy(id->ProductId, scsi_cdrom_model, 16); // product id
james@420 1231 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
james@420 1232 }
james@420 1233 else
james@420 1234 {
james@766 1235 switch (srb->Cdb[2])
james@420 1236 {
james@420 1237 case 0x00:
james@534 1238 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
james@534 1239 data_buffer[1] = 0x00;
james@534 1240 data_buffer[2] = 0x00;
james@534 1241 data_buffer[3] = 2;
james@534 1242 data_buffer[4] = 0x00;
james@534 1243 data_buffer[5] = 0x80;
james@420 1244 break;
james@420 1245 case 0x80:
james@534 1246 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
james@534 1247 data_buffer[1] = 0x80;
james@534 1248 data_buffer[2] = 0x00;
james@534 1249 data_buffer[3] = 8;
james@534 1250 data_buffer[4] = 0x31;
james@534 1251 data_buffer[5] = 0x32;
james@534 1252 data_buffer[6] = 0x33;
james@534 1253 data_buffer[7] = 0x34;
james@534 1254 data_buffer[8] = 0x35;
james@534 1255 data_buffer[9] = 0x36;
james@534 1256 data_buffer[10] = 0x37;
james@534 1257 data_buffer[11] = 0x38;
james@420 1258 break;
james@420 1259 default:
james@766 1260 //KdPrint((__DRIVER_NAME " Unknown Page %02x requested\n", srb->Cdb[2]));
james@766 1261 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1262 break;
james@420 1263 }
james@420 1264 }
james@420 1265 break;
james@420 1266 default:
james@420 1267 //KdPrint((__DRIVER_NAME " Unknown DeviceType %02x requested\n", xvdd->device_type));
james@766 1268 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1269 break;
james@420 1270 }
james@420 1271 break;
james@420 1272 case SCSIOP_READ_CAPACITY:
james@536 1273 if (dump_mode)
james@536 1274 KdPrint((__DRIVER_NAME " Command = READ_CAPACITY\n"));
james@766 1275 //KdPrint((__DRIVER_NAME " LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1));
james@766 1276 //KdPrint((__DRIVER_NAME " LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]));
james@766 1277 //KdPrint((__DRIVER_NAME " PMI = %d\n", srb->Cdb[8] & 1));
james@766 1278 //data_buffer = LongLongToPtr(ScsiPortGetPhysicalAddress(xvdd, srb, srb->DataBuffer, &data_buffer_length).QuadPart);
james@766 1279 data_buffer = srb->DataBuffer;
james@766 1280 RtlZeroMemory(data_buffer, srb->DataTransferLength);
james@420 1281 if ((xvdd->total_sectors - 1) >> 32)
james@420 1282 {
james@534 1283 data_buffer[0] = 0xff;
james@534 1284 data_buffer[1] = 0xff;
james@534 1285 data_buffer[2] = 0xff;
james@534 1286 data_buffer[3] = 0xff;
james@420 1287 }
james@420 1288 else
james@420 1289 {
james@534 1290 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
james@534 1291 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
james@534 1292 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
james@534 1293 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
james@420 1294 }
james@534 1295 data_buffer[4] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
james@534 1296 data_buffer[5] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
james@534 1297 data_buffer[6] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
james@534 1298 data_buffer[7] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
james@766 1299 srb->ScsiStatus = 0;
james@766 1300 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1301 break;
james@496 1302 case SCSIOP_READ_CAPACITY16:
james@536 1303 if (dump_mode)
james@536 1304 KdPrint((__DRIVER_NAME " Command = READ_CAPACITY\n"));
james@766 1305 //KdPrint((__DRIVER_NAME " LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1));
james@766 1306 //KdPrint((__DRIVER_NAME " LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]));
james@766 1307 //KdPrint((__DRIVER_NAME " PMI = %d\n", srb->Cdb[8] & 1));
james@766 1308 //data_buffer = LongLongToPtr(ScsiPortGetPhysicalAddress(xvdd, srb, srb->DataBuffer, &data_buffer_length).QuadPart);
james@766 1309 data_buffer = srb->DataBuffer;
james@766 1310 RtlZeroMemory(data_buffer, srb->DataTransferLength);
james@534 1311 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 56) & 0xff;
james@534 1312 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 48) & 0xff;
james@534 1313 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 40) & 0xff;
james@534 1314 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 32) & 0xff;
james@534 1315 data_buffer[4] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
james@534 1316 data_buffer[5] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
james@534 1317 data_buffer[6] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
james@534 1318 data_buffer[7] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
james@534 1319 data_buffer[8] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
james@534 1320 data_buffer[9] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
james@534 1321 data_buffer[10] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
james@534 1322 data_buffer[11] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
james@766 1323 srb->ScsiStatus = 0;
james@766 1324 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@496 1325 break;
james@420 1326 case SCSIOP_MODE_SENSE:
james@496 1327 case SCSIOP_MODE_SENSE10:
james@536 1328 if (dump_mode)
james@766 1329 KdPrint((__DRIVER_NAME " Command = MODE_SENSE (DBD = %d, PC = %d, Page Code = %02x)\n", srb->Cdb[1] & 0x08, srb->Cdb[2] & 0xC0, srb->Cdb[2] & 0x3F));
james@766 1330 XenVbd_FillModePage(xvdd, srb);
james@420 1331 break;
james@496 1332 case SCSIOP_READ:
james@496 1333 case SCSIOP_READ16:
james@420 1334 case SCSIOP_WRITE:
james@496 1335 case SCSIOP_WRITE16:
james@781 1336 XenVbd_PutSrbOnList(xvdd, srb);
james@781 1337 XenVbd_PutQueuedSrbsOnRing(xvdd);
james@420 1338 break;
james@420 1339 case SCSIOP_VERIFY:
james@708 1340 case SCSIOP_VERIFY16:
james@420 1341 // Should we do more here?
james@536 1342 if (dump_mode)
james@536 1343 KdPrint((__DRIVER_NAME " Command = VERIFY\n"));
james@766 1344 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1345 break;
james@420 1346 case SCSIOP_REPORT_LUNS:
james@536 1347 if (dump_mode)
james@536 1348 KdPrint((__DRIVER_NAME " Command = REPORT_LUNS\n"));
james@766 1349 srb->SrbStatus = SRB_STATUS_SUCCESS;;
james@420 1350 break;
james@420 1351 case SCSIOP_REQUEST_SENSE:
james@536 1352 if (dump_mode)
james@536 1353 KdPrint((__DRIVER_NAME " Command = REQUEST_SENSE\n"));
james@766 1354 XenVbd_MakeSense(xvdd, srb, xvdd->last_sense_key, xvdd->last_additional_sense_code);
james@766 1355 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1356 break;
james@420 1357 case SCSIOP_READ_TOC:
james@536 1358 if (dump_mode)
james@536 1359 KdPrint((__DRIVER_NAME " Command = READ_TOC\n"));
james@766 1360 //data_buffer = LongLongToPtr(ScsiPortGetPhysicalAddress(xvdd, srb, srb->DataBuffer, &data_buffer_length).QuadPart);
james@766 1361 data_buffer = srb->DataBuffer;
james@420 1362 // DataBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
james@420 1363 /*
james@420 1364 #define READ_TOC_FORMAT_TOC 0x00
james@420 1365 #define READ_TOC_FORMAT_SESSION 0x01
james@420 1366 #define READ_TOC_FORMAT_FULL_TOC 0x02
james@420 1367 #define READ_TOC_FORMAT_PMA 0x03
james@420 1368 #define READ_TOC_FORMAT_ATIP 0x04
james@420 1369 */
james@420 1370 // KdPrint((__DRIVER_NAME " Msf = %d\n", cdb->READ_TOC.Msf));
james@420 1371 // KdPrint((__DRIVER_NAME " LogicalUnitNumber = %d\n", cdb->READ_TOC.LogicalUnitNumber));
james@420 1372 // KdPrint((__DRIVER_NAME " Format2 = %d\n", cdb->READ_TOC.Format2));
james@420 1373 // KdPrint((__DRIVER_NAME " StartingTrack = %d\n", cdb->READ_TOC.StartingTrack));
james@420 1374 // KdPrint((__DRIVER_NAME " AllocationLength = %d\n", (cdb->READ_TOC.AllocationLength[0] << 8) | cdb->READ_TOC.AllocationLength[1]));
james@420 1375 // KdPrint((__DRIVER_NAME " Control = %d\n", cdb->READ_TOC.Control));
james@420 1376 // KdPrint((__DRIVER_NAME " Format = %d\n", cdb->READ_TOC.Format));
james@420 1377 switch (cdb->READ_TOC.Format2)
james@420 1378 {
james@420 1379 case READ_TOC_FORMAT_TOC:
james@534 1380 data_buffer[0] = 0; // length MSB
james@534 1381 data_buffer[1] = 10; // length LSB
james@534 1382 data_buffer[2] = 1; // First Track
james@534 1383 data_buffer[3] = 1; // Last Track
james@534 1384 data_buffer[4] = 0; // Reserved
james@534 1385 data_buffer[5] = 0x14; // current position data + uninterrupted data
james@534 1386 data_buffer[6] = 1; // last complete track
james@534 1387 data_buffer[7] = 0; // reserved
james@534 1388 data_buffer[8] = 0; // MSB Block
james@534 1389 data_buffer[9] = 0;
james@534 1390 data_buffer[10] = 0;
james@534 1391 data_buffer[11] = 0; // LSB Block
james@766 1392 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1393 break;
james@420 1394 case READ_TOC_FORMAT_SESSION:
james@420 1395 case READ_TOC_FORMAT_FULL_TOC:
james@420 1396 case READ_TOC_FORMAT_PMA:
james@420 1397 case READ_TOC_FORMAT_ATIP:
james@766 1398 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1399 break;
james@420 1400 }
james@420 1401 break;
james@420 1402 case SCSIOP_START_STOP_UNIT:
james@538 1403 KdPrint((__DRIVER_NAME " Command = SCSIOP_START_STOP_UNIT\n"));
james@766 1404 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1405 break;
james@420 1406 case SCSIOP_RESERVE_UNIT:
james@538 1407 KdPrint((__DRIVER_NAME " Command = SCSIOP_RESERVE_UNIT\n"));
james@766 1408 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1409 break;
james@420 1410 case SCSIOP_RELEASE_UNIT:
james@538 1411 KdPrint((__DRIVER_NAME " Command = SCSIOP_RELEASE_UNIT\n"));
james@766 1412 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@420 1413 break;
james@420 1414 default:
james@766 1415 KdPrint((__DRIVER_NAME " Unhandled EXECUTE_SCSI Command = %02X\n", srb->Cdb[0]));
james@766 1416 srb->SrbStatus = SRB_STATUS_ERROR;
james@420 1417 break;
james@420 1418 }
james@766 1419 if (srb->SrbStatus == SRB_STATUS_ERROR)
james@420 1420 {
james@766 1421 KdPrint((__DRIVER_NAME " EXECUTE_SCSI Command = %02X returned error %02x\n", srb->Cdb[0], xvdd->last_sense_key));
james@420 1422 if (xvdd->last_sense_key == SCSI_SENSE_NO_SENSE)
james@420 1423 {
james@420 1424 xvdd->last_sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
james@420 1425 xvdd->last_additional_sense_code = SCSI_ADSENSE_INVALID_CDB;
james@420 1426 }
james@766 1427 srb->ScsiStatus = 0x02;
james@766 1428 XenVbd_MakeAutoSense(xvdd, srb);
james@766 1429 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1430 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1431 {
james@781 1432 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1433 }
james@420 1434 }
james@766 1435 else if (srb->SrbStatus != SRB_STATUS_PENDING)
james@420 1436 {
james@783 1437 if (srb->SrbStatus == SRB_STATUS_SUCCESS && data_transfer_length < srb->DataTransferLength)
james@783 1438 {
james@783 1439 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
james@783 1440 srb->DataTransferLength = data_transfer_length;
james@783 1441 }
james@420 1442 xvdd->last_sense_key = SCSI_SENSE_NO_SENSE;
james@420 1443 xvdd->last_additional_sense_code = SCSI_ADSENSE_NO_SENSE;
james@766 1444 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1445 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1446 {
james@781 1447 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1448 }
james@420 1449 }
james@420 1450 break;
james@420 1451 case SRB_FUNCTION_IO_CONTROL:
james@538 1452 KdPrint((__DRIVER_NAME " SRB_FUNCTION_IO_CONTROL\n"));
james@766 1453 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
james@766 1454 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1455 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1456 {
james@781 1457 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1458 }
james@420 1459 break;
james@420 1460 case SRB_FUNCTION_FLUSH:
james@766 1461 KdPrint((__DRIVER_NAME " SRB_FUNCTION_FLUSH %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free));
james@766 1462 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@766 1463 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1464 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1465 {
james@781 1466 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1467 }
james@536 1468 break;
james@536 1469 case SRB_FUNCTION_SHUTDOWN:
james@766 1470 KdPrint((__DRIVER_NAME " SRB_FUNCTION_SHUTDOWN %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free));
james@766 1471 srb->SrbStatus = SRB_STATUS_SUCCESS;
james@766 1472 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1473 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1474 {
james@781 1475 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1476 }
james@420 1477 break;
james@420 1478 default:
james@766 1479 KdPrint((__DRIVER_NAME " Unhandled srb->Function = %08X\n", srb->Function));
james@766 1480 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
james@766 1481 ScsiPortNotification(RequestComplete, DeviceExtension, srb);
james@536 1482 if (xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@781 1483 {
james@781 1484 ScsiPortNotification(NextRequest, DeviceExtension);
james@781 1485 }
james@420 1486 break;
james@420 1487 }
james@420 1488
james@537 1489 //FUNCTION_EXIT();
james@420 1490 return TRUE;
james@420 1491 }
james@420 1492
james@538 1493 static BOOLEAN
james@420 1494 XenVbd_HwScsiResetBus(PVOID DeviceExtension, ULONG PathId)
james@420 1495 {
james@452 1496 PXENVBD_DEVICE_DATA xvdd = DeviceExtension;
james@452 1497
james@420 1498 UNREFERENCED_PARAMETER(DeviceExtension);
james@420 1499 UNREFERENCED_PARAMETER(PathId);
james@420 1500
james@538 1501 FUNCTION_ENTER();
james@420 1502
james@420 1503 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@577 1504 if (xvdd->ring_detect_state == RING_DETECT_STATE_COMPLETE && xvdd->device_state->suspend_resume_state_pdo == SR_STATE_RUNNING)
james@452 1505 {
james@452 1506 ScsiPortNotification(NextRequest, DeviceExtension);
james@452 1507 }
james@420 1508
james@538 1509 FUNCTION_EXIT();
james@420 1510
james@420 1511
james@420 1512 return TRUE;
james@420 1513 }
james@420 1514
james@538 1515 static BOOLEAN
james@420 1516 XenVbd_HwScsiAdapterState(PVOID DeviceExtension, PVOID Context, BOOLEAN SaveState)
james@420 1517 {
james@420 1518 UNREFERENCED_PARAMETER(DeviceExtension);
james@420 1519 UNREFERENCED_PARAMETER(Context);
james@420 1520 UNREFERENCED_PARAMETER(SaveState);
james@420 1521
james@538 1522 FUNCTION_ENTER();
james@420 1523 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@420 1524
james@538 1525 FUNCTION_EXIT();
james@420 1526
james@420 1527 return TRUE;
james@420 1528 }
james@420 1529
james@420 1530 static SCSI_ADAPTER_CONTROL_STATUS DDKAPI
james@420 1531 XenVbd_HwScsiAdapterControl(PVOID DeviceExtension, SCSI_ADAPTER_CONTROL_TYPE ControlType, PVOID Parameters)
james@420 1532 {
james@553 1533 PXENVBD_DEVICE_DATA xvdd = DeviceExtension;
james@420 1534 SCSI_ADAPTER_CONTROL_STATUS Status = ScsiAdapterControlSuccess;
james@420 1535 PSCSI_SUPPORTED_CONTROL_TYPE_LIST SupportedControlTypeList;
james@420 1536 //KIRQL OldIrql;
james@420 1537
james@536 1538 FUNCTION_ENTER();
james@420 1539 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@636 1540 KdPrint((__DRIVER_NAME " xvdd = %p\n", xvdd));
james@420 1541
james@420 1542 switch (ControlType)
james@420 1543 {
james@420 1544 case ScsiQuerySupportedControlTypes:
james@420 1545 SupportedControlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters;
james@420 1546 KdPrint((__DRIVER_NAME " ScsiQuerySupportedControlTypes (Max = %d)\n", SupportedControlTypeList->MaxControlType));
james@420 1547 SupportedControlTypeList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE;
james@420 1548 SupportedControlTypeList->SupportedTypeList[ScsiStopAdapter] = TRUE;
james@420 1549 SupportedControlTypeList->SupportedTypeList[ScsiRestartAdapter] = TRUE;
james@420 1550 break;
james@420 1551 case ScsiStopAdapter:
james@420 1552 KdPrint((__DRIVER_NAME " ScsiStopAdapter\n"));
james@420 1553 /* I don't think we actually have to do anything here... xenpci cleans up all the xenbus stuff for us */
james@420 1554 break;
james@420 1555 case ScsiRestartAdapter:
james@420 1556 KdPrint((__DRIVER_NAME " ScsiRestartAdapter\n"));
james@553 1557 if (!xvdd->inactive)
james@636 1558 {
james@636 1559 if (XenVbd_InitFromConfig(xvdd) != SP_RETURN_FOUND)
james@636 1560 KeBugCheckEx(DATA_COHERENCY_EXCEPTION, 0, (ULONG_PTR) xvdd, 0, 0);
james@553 1561 XenVbd_StartRingDetection(xvdd);
james@636 1562 }
james@636 1563 break;
james@420 1564 case ScsiSetBootConfig:
james@420 1565 KdPrint((__DRIVER_NAME " ScsiSetBootConfig\n"));
james@420 1566 break;
james@420 1567 case ScsiSetRunningConfig:
james@420 1568 KdPrint((__DRIVER_NAME " ScsiSetRunningConfig\n"));
james@420 1569 break;
james@420 1570 default:
james@420 1571 KdPrint((__DRIVER_NAME " UNKNOWN\n"));
james@420 1572 break;
james@420 1573 }
james@420 1574
james@536 1575 FUNCTION_EXIT();
james@536 1576
james@420 1577 return Status;
james@420 1578 }
james@420 1579
james@0 1580 NTSTATUS
james@0 1581 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
james@0 1582 {
james@274 1583 ULONG status;
james@48 1584 HW_INITIALIZATION_DATA HwInitializationData;
james@487 1585 PVOID driver_extension;
james@487 1586 PUCHAR ptr;
james@563 1587 OBJECT_ATTRIBUTES oa;
james@563 1588 HANDLE service_handle;
james@563 1589 UNICODE_STRING param_name;
james@563 1590 HANDLE param_handle;
james@563 1591 UNICODE_STRING value_name;
james@563 1592 CHAR buf[256];
james@563 1593 ULONG buf_len;
james@563 1594 PKEY_VALUE_PARTIAL_INFORMATION kpv;
james@563 1595
james@487 1596 FUNCTION_ENTER();
james@116 1597 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
james@538 1598 KdPrint((__DRIVER_NAME " DriverObject = %p, RegistryPath = %p\n", DriverObject, RegistryPath));
james@0 1599
james@440 1600 /* RegistryPath == NULL when we are invoked as a crash dump driver */
james@440 1601 if (!RegistryPath)
james@435 1602 {
james@440 1603 dump_mode = TRUE;
james@435 1604 }
james@509 1605
james@509 1606 if (!dump_mode)
james@509 1607 {
james@509 1608 IoAllocateDriverObjectExtension(DriverObject, UlongToPtr(XEN_INIT_DRIVER_EXTENSION_MAGIC), PAGE_SIZE, &driver_extension);
james@509 1609 ptr = driver_extension;
james@803 1610 //ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RUN, NULL, NULL, NULL);
james@536 1611 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "ring-ref", NULL, NULL);
james@536 1612 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL_IRQ, "event-channel", NULL, NULL);
james@536 1613 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_FRONT, "device-type", NULL, NULL);
james@536 1614 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mode", NULL, NULL);
james@536 1615 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "sectors", NULL, NULL);
james@536 1616 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "sector-size", NULL, NULL);
james@790 1617 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_GRANT_ENTRIES, NULL, ULongToPtr(BLKIF_MAX_SEGMENTS_PER_REQUEST), NULL); /* for use in crash dump */
james@803 1618 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
james@803 1619 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
james@803 1620 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
james@803 1621 __ADD_XEN_INIT_UCHAR(&ptr, 20);
james@803 1622 __ADD_XEN_INIT_UCHAR(&ptr, 0);
james@803 1623 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
james@803 1624 //__ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
james@803 1625 //__ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
james@803 1626 //__ADD_XEN_INIT_UCHAR(&ptr, 20);
james@803 1627 __ADD_XEN_INIT_UCHAR(&ptr, 0);
james@803 1628 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
james@803 1629 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
james@803 1630 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
james@803 1631 __ADD_XEN_INIT_UCHAR(&ptr, 50);
james@803 1632 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
james@803 1633 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
james@803 1634 __ADD_XEN_INIT_UCHAR(&ptr, 50);
james@803 1635 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
james@803 1636 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
james@803 1637 __ADD_XEN_INIT_UCHAR(&ptr, 50);
james@803 1638 __ADD_XEN_INIT_UCHAR(&ptr, 0);
james@803 1639
james@536 1640 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
james@534 1641
james@563 1642 InitializeObjectAttributes(&oa, RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
james@563 1643 status = ZwOpenKey(&service_handle, KEY_READ, &oa);
james@563 1644 if(!NT_SUCCESS(status))
james@563 1645 {
james@563 1646 KdPrint((__DRIVER_NAME " ZwOpenKey(Service) returned %08x\n", status));
james@563 1647 }
james@563 1648 else
james@563 1649 {
james@563 1650 RtlInitUnicodeString(&param_name, L"Parameters");
james@563 1651 InitializeObjectAttributes(&oa, &param_name, OBJ_CASE_INSENSITIVE, service_handle, NULL);
james@563 1652 status = ZwOpenKey(&param_handle, KEY_READ, &oa);
james@563 1653 if(!NT_SUCCESS(status))
james@563 1654 {
james@563 1655 KdPrint((__DRIVER_NAME " ZwOpenKey(Parameters) returned %08x\n", status));
james@563 1656 }
james@563 1657 else
james@563 1658 {
james@563 1659 kpv = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
james@563 1660 RtlFillMemory(scsi_device_manufacturer, 8, ' ');
james@563 1661 RtlFillMemory(scsi_disk_model, 16, ' ');
james@563 1662 RtlFillMemory(scsi_cdrom_model, 16, ' ');
james@563 1663
james@563 1664 RtlInitUnicodeString(&value_name, L"Manufacturer");
james@563 1665 buf_len = 256;
james@563 1666 status = ZwQueryValueKey(param_handle, &value_name, KeyValuePartialInformation, buf, buf_len, &buf_len);
james@563 1667 if(NT_SUCCESS(status))
james@563 1668 wcstombs(scsi_device_manufacturer, (PWCHAR)kpv->Data, min(kpv->DataLength, 8));
james@563 1669 else
james@716 1670 RtlStringCbCopyA(scsi_device_manufacturer, 8, "XEN ");
james@563 1671
james@563 1672 RtlInitUnicodeString(&value_name, L"Disk_Model");
james@563 1673 buf_len = 256;
james@563 1674 status = ZwQueryValueKey(param_handle, &value_name, KeyValuePartialInformation, buf, buf_len, &buf_len);
james@563 1675 if(NT_SUCCESS(status))
james@563 1676 wcstombs(scsi_disk_model, (PWCHAR)kpv->Data, min(kpv->DataLength, 16));
james@563 1677 else
james@716 1678 RtlStringCbCopyA(scsi_disk_model, 16, "PV DISK ");
james@563 1679
james@563 1680 RtlInitUnicodeString(&value_name, L"CDROM_Model");
james@563 1681 buf_len = 256;
james@563 1682 status = ZwQueryValueKey(param_handle, &value_name, KeyValuePartialInformation, buf, buf_len, &buf_len);
james@563 1683 if(NT_SUCCESS(status))
james@563 1684 wcstombs(scsi_cdrom_model, (PWCHAR)kpv->Data, min(kpv->DataLength, 16));
james@563 1685 else
james@716 1686 RtlStringCbCopyA(scsi_cdrom_model, 16, "PV CDROM ");
james@563 1687 }
james@563 1688 ZwClose(service_handle);
james@563 1689 }
james@509 1690 }
james@563 1691
james@48 1692 RtlZeroMemory(&HwInitializationData, sizeof(HW_INITIALIZATION_DATA));
james@0 1693
james@48 1694 HwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
james@527 1695 HwInitializationData.AdapterInterfaceType = PNPBus;
james@810 1696 if (!dump_mode)
james@810 1697 HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_DEVICE_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE;
james@810 1698 else
james@810 1699 HwInitializationData.DeviceExtensionSize = FIELD_OFFSET(XENVBD_DEVICE_DATA, aligned_buffer_data) + UNALIGNED_BUFFER_DATA_SIZE_DUMP_MODE;
james@48 1700 HwInitializationData.SpecificLuExtensionSize = 0;
james@781 1701 HwInitializationData.SrbExtensionSize = sizeof(srb_list_entry_t);
james@48 1702 HwInitializationData.NumberOfAccessRanges = 1;
james@766 1703 HwInitializationData.MapBuffers = TRUE;
james@766 1704 HwInitializationData.NeedPhysicalAddresses = FALSE;
james@538 1705 HwInitializationData.TaggedQueuing = TRUE;
james@284 1706 HwInitializationData.AutoRequestSense = TRUE;
james@157 1707 HwInitializationData.MultipleRequestPerLu = TRUE;
james@124 1708 HwInitializationData.ReceiveEvent = FALSE;
james@48 1709 HwInitializationData.VendorIdLength = 0;
james@48 1710 HwInitializationData.VendorId = NULL;
james@48 1711 HwInitializationData.DeviceIdLength = 0;
james@48 1712 HwInitializationData.DeviceId = NULL;
james@0 1713
james@420 1714 HwInitializationData.HwInitialize = XenVbd_HwScsiInitialize;
james@420 1715 HwInitializationData.HwStartIo = XenVbd_HwScsiStartIo;
james@420 1716 HwInitializationData.HwInterrupt = XenVbd_HwScsiInterrupt;
james@420 1717 HwInitializationData.HwFindAdapter = XenVbd_HwScsiFindAdapter;
james@420 1718 HwInitializationData.HwResetBus = XenVbd_HwScsiResetBus;
james@420 1719 HwInitializationData.HwDmaStarted = NULL;
james@538 1720 HwInitializationData.HwAdapterState = NULL; //XenVbd_HwScsiAdapterState;
james@420 1721 HwInitializationData.HwAdapterControl = XenVbd_HwScsiAdapterControl;
james@195 1722
james@274 1723 status = ScsiPortInitialize(DriverObject, RegistryPath, &HwInitializationData, NULL);
james@267 1724
james@274 1725 if(!NT_SUCCESS(status))
james@0 1726 {
james@274 1727 KdPrint((__DRIVER_NAME " ScsiPortInitialize failed with status 0x%08x\n", status));
james@0 1728 }
james@0 1729
james@487 1730 FUNCTION_EXIT();
james@0 1731
james@274 1732 return status;
amir@625 1733 }