win-pvdrivers

annotate xenvbd/xenvbd_storport.c @ 833:66e79b88f301

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