win-pvdrivers

view xenvbd_common/common_miniport.h @ 1106:2d392ecdd366

Fix race is xenvbd causing 30 second freeze under high load
author James Harper <james.harper@bendigoit.com.au>
date Tue Nov 11 23:08:11 2014 +1100 (2014-11-11)
parents 27bd2a5a4704
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #if defined(__x86_64__)
31 #define LongLongToPtr(x) (PVOID)(x)
32 #else
33 #define LongLongToPtr(x) UlongToPtr(x)
34 #endif
36 #if defined(__x86_64__)
37 #define ABI_PROTOCOL "x86_64-abi"
38 #else
39 #define ABI_PROTOCOL "x86_32-abi"
40 #endif
42 ULONGLONG parse_numeric_string(PCHAR string) {
43 ULONGLONG val = 0;
44 while (*string != 0) {
45 val = val * 10 + (*string - '0');
46 string++;
47 }
48 return val;
49 }
51 /* called with StartIoLock held */
52 static blkif_shadow_t *
53 get_shadow_from_freelist(PXENVBD_DEVICE_DATA xvdd) {
54 if (xvdd->shadow_free == 0) {
55 FUNCTION_MSG("No more shadow entries\n");
56 return NULL;
57 }
58 xvdd->shadow_free--;
59 //if (xvdd->shadow_free < xvdd->shadow_min_free)
60 // xvdd->shadow_min_free = xvdd->shadow_free;
61 return &xvdd->shadows[xvdd->shadow_free_list[xvdd->shadow_free]];
62 }
64 /* called with StartIoLock held */
65 static VOID
66 put_shadow_on_freelist(PXENVBD_DEVICE_DATA xvdd, blkif_shadow_t *shadow)
67 {
68 xvdd->shadow_free_list[xvdd->shadow_free] = (USHORT)(shadow->req.id & SHADOW_ID_ID_MASK);
69 shadow->srb = NULL;
70 shadow->reset = FALSE;
71 shadow->aligned_buffer_in_use = FALSE;
72 xvdd->shadow_free++;
73 }
75 static __inline ULONG
76 decode_cdb_length(PSCSI_REQUEST_BLOCK srb) {
77 switch (srb->Cdb[0]) {
78 case SCSIOP_READ:
79 case SCSIOP_WRITE:
80 return ((ULONG)(UCHAR)srb->Cdb[7] << 8) | (ULONG)(UCHAR)srb->Cdb[8];
81 case SCSIOP_READ16:
82 case SCSIOP_WRITE16:
83 return ((ULONG)(UCHAR)srb->Cdb[10] << 24) | ((ULONG)(UCHAR)srb->Cdb[11] << 16) | ((ULONG)(UCHAR)srb->Cdb[12] << 8) | (ULONG)(UCHAR)srb->Cdb[13];
84 default:
85 FUNCTION_MSG("Unknown SCSIOP function %02x\n", srb->Cdb[0]);
86 return 0;
87 }
88 }
90 static blkif_response_t *
91 XenVbd_GetResponse(PXENVBD_DEVICE_DATA xvdd, int i) {
92 return RING_GET_RESPONSE(&xvdd->ring, i);
93 }
95 static VOID
96 XenVbd_PutRequest(PXENVBD_DEVICE_DATA xvdd, blkif_request_t *req) {
97 *RING_GET_REQUEST(&xvdd->ring, xvdd->ring.req_prod_pvt) = *req;
98 xvdd->ring.req_prod_pvt++;
99 }
101 static VOID
102 XenVbd_PutSrbOnList(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
103 srb_list_entry_t *srb_entry = srb->SrbExtension;
104 srb_entry->srb = srb;
105 srb_entry->outstanding_requests = 0;
106 srb_entry->length = srb->DataTransferLength;
107 srb_entry->offset = 0;
108 srb_entry->error = FALSE;
109 InsertTailList(&xvdd->srb_list, (PLIST_ENTRY)srb_entry);
110 }
112 static __inline ULONGLONG
113 decode_cdb_sector(PSCSI_REQUEST_BLOCK srb)
114 {
115 ULONGLONG sector;
117 switch (srb->Cdb[0]) {
118 case SCSIOP_READ:
119 case SCSIOP_WRITE:
120 sector = ((ULONG)(UCHAR)srb->Cdb[2] << 24) | ((ULONG)(UCHAR)srb->Cdb[3] << 16) | ((ULONG)(UCHAR)srb->Cdb[4] << 8) | (ULONG)(UCHAR)srb->Cdb[5];
121 break;
122 case SCSIOP_READ16:
123 case SCSIOP_WRITE16:
124 sector = ((ULONGLONG)(UCHAR)srb->Cdb[2] << 56) | ((ULONGLONG)(UCHAR)srb->Cdb[3] << 48)
125 | ((ULONGLONG)(UCHAR)srb->Cdb[4] << 40) | ((ULONGLONG)(UCHAR)srb->Cdb[5] << 32)
126 | ((ULONGLONG)(UCHAR)srb->Cdb[6] << 24) | ((ULONGLONG)(UCHAR)srb->Cdb[7] << 16)
127 | ((ULONGLONG)(UCHAR)srb->Cdb[8] << 8) | ((ULONGLONG)(UCHAR)srb->Cdb[9]);
128 //FUNCTION_MSG("sector_number = %d (high) %d (low)\n", (ULONG)(sector >> 32), (ULONG)sector);
129 break;
130 default:
131 FUNCTION_MSG("Unknown SCSIOP function %02x\n", srb->Cdb[0]);
132 sector = 0;
133 break;
134 }
135 return sector;
136 }
138 static __inline BOOLEAN
139 decode_cdb_is_read(PSCSI_REQUEST_BLOCK srb)
140 {
141 switch (srb->Cdb[0])
142 {
143 case SCSIOP_READ:
144 case SCSIOP_READ16:
145 return TRUE;
146 case SCSIOP_WRITE:
147 case SCSIOP_WRITE16:
148 return FALSE;
149 default:
150 FUNCTION_MSG("Unknown SCSIOP function %02x\n", srb->Cdb[0]);
151 return FALSE;
152 }
153 }
155 static ULONG
156 XenVbd_MakeSense(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
157 PSENSE_DATA sd = srb->SenseInfoBuffer;
159 UNREFERENCED_PARAMETER(xvdd);
161 if (!srb->SenseInfoBuffer)
162 return 0;
164 sd->ErrorCode = 0x70;
165 sd->Valid = 1;
166 sd->SenseKey = xvdd->last_sense_key;
167 sd->AdditionalSenseLength = sizeof(SENSE_DATA) - FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength);
168 sd->AdditionalSenseCode = xvdd->last_additional_sense_code;
169 sd->AdditionalSenseCodeQualifier = xvdd->last_additional_sense_code_qualifier;
170 xvdd->last_sense_key = SCSI_SENSE_NO_SENSE;
171 xvdd->last_additional_sense_code = SCSI_ADSENSE_NO_SENSE;
172 xvdd->last_additional_sense_code_qualifier = 0;
173 xvdd->cac = FALSE;
174 return sizeof(SENSE_DATA);
175 }
177 static VOID
178 XenVbd_MakeAutoSense(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
179 if (xvdd->last_sense_key == SCSI_SENSE_NO_SENSE) {
180 return;
181 }
182 srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
183 if (srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) {
184 /* because cac is set nothing will progress until sense is requested */
185 xvdd->cac = TRUE;
186 return;
187 }
188 XenVbd_MakeSense(xvdd, srb);
189 srb->SrbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
190 }
192 /* called with StartIo lock held */
193 static VOID
194 XenVbd_HandleEvent(PXENVBD_DEVICE_DATA xvdd) {
195 PSCSI_REQUEST_BLOCK srb;
196 RING_IDX i, rp;
197 ULONG j;
198 blkif_response_t *rep;
199 //int block_count;
200 int more_to_do = TRUE;
201 blkif_shadow_t *shadow;
202 srb_list_entry_t *srb_entry;
204 if (xvdd->device_state != DEVICE_STATE_ACTIVE && xvdd->device_state != DEVICE_STATE_DISCONNECTING) {
205 /* if we aren't active (eg just restored from hibernate) then we still want to process non-scsi srb's */
206 XenVbd_ProcessSrbList(xvdd);
207 return;
208 }
210 while (more_to_do && !xvdd->cac) {
211 rp = xvdd->ring.sring->rsp_prod;
212 KeMemoryBarrier();
213 for (i = xvdd->ring.rsp_cons; i != rp && !xvdd->cac; i++) {
214 rep = XenVbd_GetResponse(xvdd, i);
215 shadow = &xvdd->shadows[rep->id & SHADOW_ID_ID_MASK];
216 if (shadow->reset) {
217 /* the srb's here have already been returned */
218 FUNCTION_MSG("discarding reset shadow\n");
219 for (j = 0; j < shadow->req.nr_segments; j++) {
220 XnEndAccess(xvdd->handle,
221 shadow->req.seg[j].gref, FALSE, xvdd->grant_tag);
222 }
223 } else if (dump_mode && !(rep->id & SHADOW_ID_DUMP_FLAG)) {
224 FUNCTION_MSG("discarding stale (non-dump-mode) shadow\n");
225 } else {
226 srb = shadow->srb;
227 XN_ASSERT(srb);
228 srb_entry = srb->SrbExtension;
229 XN_ASSERT(srb_entry);
230 /* 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 */
231 if (rep->status == BLKIF_RSP_OKAY || (dump_mode && dump_mode_errors++ < DUMP_MODE_ERROR_LIMIT)) {
232 srb->SrbStatus = SRB_STATUS_SUCCESS;
233 } else {
234 FUNCTION_MSG("Xen Operation returned error\n");
235 if (decode_cdb_is_read(srb))
236 FUNCTION_MSG("Operation = Read\n");
237 else
238 FUNCTION_MSG("Operation = Write\n");
239 srb_entry->error = TRUE;
240 }
241 if (shadow->aligned_buffer_in_use) {
242 XN_ASSERT(xvdd->aligned_buffer_in_use);
243 xvdd->aligned_buffer_in_use = FALSE;
244 if (srb->SrbStatus == SRB_STATUS_SUCCESS && decode_cdb_is_read(srb))
245 memcpy((PUCHAR)shadow->system_address, xvdd->aligned_buffer, shadow->length);
246 }
247 for (j = 0; j < shadow->req.nr_segments; j++) {
248 XnEndAccess(xvdd->handle, shadow->req.seg[j].gref, FALSE, xvdd->grant_tag);
249 }
250 srb_entry->outstanding_requests--;
251 if (srb_entry->outstanding_requests == 0 && srb_entry->offset == srb_entry->length) {
252 if (srb_entry->error) {
253 srb->SrbStatus = SRB_STATUS_ERROR;
254 xvdd->last_sense_key = SCSI_SENSE_MEDIUM_ERROR;
255 }
256 XenVbd_MakeAutoSense(xvdd, srb);
257 SxxxPortNotification(RequestComplete, xvdd, srb);
258 }
259 }
260 put_shadow_on_freelist(xvdd, shadow);
261 }
263 /* put queue'd Srbs onto the ring now so we can set the event in the best possible way */
264 if (dump_mode || xvdd->device_state == DEVICE_STATE_ACTIVE) {
265 XenVbd_ProcessSrbList(xvdd);
266 }
268 xvdd->ring.rsp_cons = i;
269 if (i == xvdd->ring.req_prod_pvt) {
270 /* all possible requests complete - can't have more responses than requests */
271 more_to_do = FALSE;
272 xvdd->ring.sring->rsp_event = i + 1;
273 } else {
274 more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xvdd->ring);
275 if (!more_to_do) {
276 xvdd->ring.sring->rsp_event = i + max(1, (SHADOW_ENTRIES - xvdd->shadow_free) / 2);
277 KeMemoryBarrier();
278 more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xvdd->ring);
279 }
280 }
281 }
283 if (xvdd->device_state == DEVICE_STATE_DISCONNECTING && xvdd->shadow_free == SHADOW_ENTRIES) {
284 FUNCTION_MSG("ring now empty - completing disconnect\n");
285 XenVbd_CompleteDisconnect(xvdd);
286 }
287 return;
288 }
290 /* called with StartIoLock held */
291 /* returns TRUE if something was put on the ring and notify might be required */
292 static BOOLEAN
293 XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
294 srb_list_entry_t *srb_entry = srb->SrbExtension;
295 /* sector_number and block_count are the adjusted-to-512-byte-sector values */
296 ULONGLONG sector_number;
297 ULONG block_count;
298 blkif_shadow_t *shadow;
299 ULONG remaining, offset, length;
300 grant_ref_t gref;
301 PUCHAR ptr;
302 int i;
303 PVOID system_address;
305 //if (dump_mode) FUNCTION_ENTER();
307 //FUNCTION_MSG("aligned_buffer_in_use = %d\n", xvdd->aligned_buffer_in_use);
308 //FUNCTION_MSG("shadow_free = %d\n", xvdd->shadow_free);
310 XN_ASSERT(srb);
312 if (xvdd->device_state != DEVICE_STATE_ACTIVE) {
313 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
314 return FALSE;
315 }
317 if (!dump_mode) {
318 if (SxxxPortGetSystemAddress(xvdd, srb, &system_address) != STATUS_SUCCESS) {
319 FUNCTION_MSG("Failed to map DataBuffer\n");
320 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
321 return FALSE;
322 }
323 system_address = (PUCHAR)system_address + srb_entry->offset;
324 } else {
325 system_address = (PUCHAR)srb->DataBuffer + srb_entry->offset;
326 }
327 block_count = decode_cdb_length(srb);
328 sector_number = decode_cdb_sector(srb);
329 block_count *= xvdd->bytes_per_sector / 512;
330 sector_number *= xvdd->bytes_per_sector / 512;
332 XN_ASSERT(block_count * 512 == srb->DataTransferLength);
334 sector_number += srb_entry->offset / 512;
335 block_count -= srb_entry->offset / 512;
337 XN_ASSERT(block_count > 0);
339 /* look for pending writes that overlap this one */
340 /* we get warnings from drbd if we don't */
341 if (srb_entry->offset == 0) {
342 for (i = 0; i < MAX_SHADOW_ENTRIES; i++) {
343 PSCSI_REQUEST_BLOCK srb2;
344 ULONGLONG sector_number2;
345 ULONG block_count2;
347 srb2 = xvdd->shadows[i].srb;
348 if (!srb2)
349 continue;
350 if (decode_cdb_is_read(srb2))
351 continue;
352 block_count2 = decode_cdb_length(srb2);;
353 block_count2 *= xvdd->bytes_per_sector / 512;
354 sector_number2 = decode_cdb_sector(srb2);
355 sector_number2 *= xvdd->bytes_per_sector / 512;
357 if (sector_number < sector_number2 && sector_number + block_count <= sector_number2)
358 continue;
359 if (sector_number2 < sector_number && sector_number2 + block_count2 <= sector_number)
360 continue;
362 FUNCTION_MSG("Concurrent outstanding write detected (%I64d, %d) (%I64d, %d)\n",
363 sector_number, block_count, sector_number2, block_count2);
364 break;
365 }
366 if (i != MAX_SHADOW_ENTRIES) {
367 /* put the srb back at the start of the queue */
368 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
369 return FALSE;
370 }
371 }
373 shadow = get_shadow_from_freelist(xvdd);
374 if (!shadow) {
375 /* put the srb back at the start of the queue */
376 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
377 //if (dump_mode) FUNCTION_EXIT();
378 return FALSE;
379 }
380 XN_ASSERT(!shadow->aligned_buffer_in_use);
381 XN_ASSERT(!shadow->srb);
382 shadow->req.sector_number = sector_number;
383 shadow->req.handle = 0;
384 shadow->req.operation = decode_cdb_is_read(srb)?BLKIF_OP_READ:BLKIF_OP_WRITE;
385 shadow->req.nr_segments = 0;
386 shadow->srb = srb;
387 shadow->length = 0;
388 shadow->system_address = system_address;
389 shadow->reset = FALSE;
391 if (!dump_mode) {
392 if ((ULONG_PTR)shadow->system_address & 511) {
393 xvdd->aligned_buffer_in_use = TRUE;
394 /* limit to aligned_buffer_size */
395 block_count = min(block_count, xvdd->aligned_buffer_size / 512);
396 ptr = (PUCHAR)xvdd->aligned_buffer;
397 if (!decode_cdb_is_read(srb))
398 memcpy(ptr, shadow->system_address, block_count * 512);
399 shadow->aligned_buffer_in_use = TRUE;
400 } else {
401 ptr = (PUCHAR)shadow->system_address;
402 shadow->aligned_buffer_in_use = FALSE;
403 }
404 } else {
405 XN_ASSERT(!((ULONG_PTR)shadow->system_address & 511));
406 ptr = shadow->system_address;
407 shadow->aligned_buffer_in_use = FALSE;
408 }
410 remaining = block_count * 512;
411 while (remaining > 0 && shadow->req.nr_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) {
412 PHYSICAL_ADDRESS physical_address;
414 if (!dump_mode) {
415 physical_address = MmGetPhysicalAddress(ptr);
416 } else {
417 ULONG length;
418 physical_address = SxxxPortGetPhysicalAddress(xvdd, srb, ptr, &length);
419 //FUNCTION_MSG("physical_address = %08I64x\n", physical_address.QuadPart);
421 }
422 gref = XnGrantAccess(xvdd->handle,
423 (ULONG)(physical_address.QuadPart >> PAGE_SHIFT), FALSE, INVALID_GRANT_REF, xvdd->grant_tag);
424 if (gref == INVALID_GRANT_REF) {
425 ULONG i;
426 for (i = 0; i < shadow->req.nr_segments; i++) {
427 XnEndAccess(xvdd->handle,
428 shadow->req.seg[i].gref, FALSE, xvdd->grant_tag);
429 }
430 if (shadow->aligned_buffer_in_use) {
431 shadow->aligned_buffer_in_use = FALSE;
432 xvdd->aligned_buffer_in_use = FALSE;
433 }
434 /* put the srb back at the start of the queue */
435 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb_entry);
436 put_shadow_on_freelist(xvdd, shadow);
437 FUNCTION_MSG("Out of gref's. Deferring\n");
438 /* TODO: what if there are no requests currently in progress to kick the queue again?? timer? */
439 return FALSE;
440 }
441 offset = physical_address.LowPart & (PAGE_SIZE - 1);
442 length = min(PAGE_SIZE - offset, remaining);
443 XN_ASSERT((offset & 511) == 0);
444 XN_ASSERT((length & 511) == 0);
445 XN_ASSERT(offset + length <= PAGE_SIZE);
446 shadow->req.seg[shadow->req.nr_segments].gref = gref;
447 shadow->req.seg[shadow->req.nr_segments].first_sect = (UCHAR)(offset / 512);
448 shadow->req.seg[shadow->req.nr_segments].last_sect = (UCHAR)(((offset + length) / 512) - 1);
449 remaining -= length;
450 ptr += length;
451 shadow->length += length;
452 shadow->req.nr_segments++;
453 }
454 srb_entry->offset += shadow->length;
455 srb_entry->outstanding_requests++;
456 XenVbd_PutRequest(xvdd, &shadow->req);
457 if (srb_entry->offset < srb_entry->length) {
458 /* put the srb back at the start of the queue to continue on the next request */
459 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb_entry);
460 }
461 //if (dump_mode)
462 //FUNCTION_EXIT();
463 return TRUE;
464 }
466 static UCHAR
467 XenVbd_FillModePage(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb, PULONG data_transfer_length) {
468 PMODE_PARAMETER_HEADER parameter_header = NULL;
469 PMODE_PARAMETER_HEADER10 parameter_header10 = NULL;
470 PMODE_PARAMETER_BLOCK param_block;
471 PMODE_FORMAT_PAGE format_page;
472 ULONG offset = 0;
473 UCHAR buffer[1024];
474 BOOLEAN valid_page = FALSE;
475 BOOLEAN cdb_llbaa;
476 BOOLEAN cdb_dbd;
477 UCHAR cdb_page_code;
478 USHORT cdb_allocation_length;
480 UNREFERENCED_PARAMETER(xvdd);
482 RtlZeroMemory(srb->DataBuffer, srb->DataTransferLength);
483 RtlZeroMemory(buffer, ARRAY_SIZE(buffer));
484 offset = 0;
486 switch (srb->Cdb[0]) {
487 case SCSIOP_MODE_SENSE:
488 cdb_llbaa = FALSE;
489 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
490 cdb_page_code = srb->Cdb[2] & 0x3f;
491 cdb_allocation_length = srb->Cdb[4];
492 parameter_header = (PMODE_PARAMETER_HEADER)&buffer[offset];
493 parameter_header->MediumType = 0;
494 parameter_header->DeviceSpecificParameter = 0;
495 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ) {
496 FUNCTION_MSG(" Mode sense to a read only disk.\n");
497 parameter_header->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
498 }
499 offset += sizeof(MODE_PARAMETER_HEADER);
500 break;
501 case SCSIOP_MODE_SENSE10:
502 cdb_llbaa = (BOOLEAN)!!(srb->Cdb[1] & 16);
503 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
504 cdb_page_code = srb->Cdb[2] & 0x3f;
505 cdb_allocation_length = (srb->Cdb[7] << 8) | srb->Cdb[8];
506 parameter_header10 = (PMODE_PARAMETER_HEADER10)&buffer[offset];
507 parameter_header10->MediumType = 0;
508 parameter_header10->DeviceSpecificParameter = 0;
509 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ) {
510 FUNCTION_MSG(" Mode sense to a read only disk.\n");
511 parameter_header10->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
512 }
513 offset += sizeof(MODE_PARAMETER_HEADER10);
514 break;
515 default:
516 FUNCTION_MSG("SCSIOP_MODE_SENSE_WTF (%02x)\n", (ULONG)srb->Cdb[0]);
517 return FALSE;
518 }
520 if (!cdb_dbd) {
521 param_block = (PMODE_PARAMETER_BLOCK)&buffer[offset];
522 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK) {
523 if (xvdd->total_sectors >> 32) {
524 param_block->DensityCode = 0xff;
525 param_block->NumberOfBlocks[0] = 0xff;
526 param_block->NumberOfBlocks[1] = 0xff;
527 param_block->NumberOfBlocks[2] = 0xff;
528 } else {
529 param_block->DensityCode = (UCHAR)((xvdd->total_sectors >> 24) & 0xff);
530 param_block->NumberOfBlocks[0] = (UCHAR)((xvdd->total_sectors >> 16) & 0xff);
531 param_block->NumberOfBlocks[1] = (UCHAR)((xvdd->total_sectors >> 8) & 0xff);
532 param_block->NumberOfBlocks[2] = (UCHAR)((xvdd->total_sectors >> 0) & 0xff);
533 }
534 param_block->BlockLength[0] = (UCHAR)((xvdd->bytes_per_sector >> 16) & 0xff);
535 param_block->BlockLength[1] = (UCHAR)((xvdd->bytes_per_sector >> 8) & 0xff);
536 param_block->BlockLength[2] = (UCHAR)((xvdd->bytes_per_sector >> 0) & 0xff);
537 }
538 offset += sizeof(MODE_PARAMETER_BLOCK);
539 }
540 switch (srb->Cdb[0])
541 {
542 case SCSIOP_MODE_SENSE:
543 parameter_header->BlockDescriptorLength = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER));
544 break;
545 case SCSIOP_MODE_SENSE10:
546 parameter_header10->BlockDescriptorLength[0] = (UCHAR)((offset - sizeof(MODE_PARAMETER_HEADER10)) >> 8);
547 parameter_header10->BlockDescriptorLength[1] = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER10));
548 break;
549 }
550 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_FORMAT_DEVICE || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
551 valid_page = TRUE;
552 format_page = (PMODE_FORMAT_PAGE)&buffer[offset];
553 format_page->PageCode = MODE_PAGE_FORMAT_DEVICE;
554 format_page->PageLength = sizeof(MODE_FORMAT_PAGE) - FIELD_OFFSET(MODE_FORMAT_PAGE, PageLength);
555 /* 256 sectors per track */
556 format_page->SectorsPerTrack[0] = 0x01;
557 format_page->SectorsPerTrack[1] = 0x00;
558 /* xxx bytes per sector */
559 format_page->BytesPerPhysicalSector[0] = (UCHAR)(xvdd->bytes_per_sector >> 8);
560 format_page->BytesPerPhysicalSector[1] = (UCHAR)(xvdd->bytes_per_sector & 0xff);
561 format_page->HardSectorFormating = TRUE;
562 format_page->SoftSectorFormating = TRUE;
563 offset += sizeof(MODE_FORMAT_PAGE);
564 }
565 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_CACHING || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
566 PMODE_CACHING_PAGE caching_page;
567 valid_page = TRUE;
568 caching_page = (PMODE_CACHING_PAGE)&buffer[offset];
569 caching_page->PageCode = MODE_PAGE_CACHING;
570 caching_page->PageLength = sizeof(MODE_CACHING_PAGE) - FIELD_OFFSET(MODE_CACHING_PAGE, PageLength);
571 // caching_page-> // all zeros is just fine... maybe
572 offset += sizeof(MODE_CACHING_PAGE);
573 }
574 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_MEDIUM_TYPES || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
575 PUCHAR medium_types_page;
576 valid_page = TRUE;
577 medium_types_page = &buffer[offset];
578 medium_types_page[0] = MODE_PAGE_MEDIUM_TYPES;
579 medium_types_page[1] = 0x06;
580 medium_types_page[2] = 0;
581 medium_types_page[3] = 0;
582 medium_types_page[4] = 0;
583 medium_types_page[5] = 0;
584 medium_types_page[6] = 0;
585 medium_types_page[7] = 0;
586 offset += 8;
587 }
588 switch (srb->Cdb[0]) {
589 case SCSIOP_MODE_SENSE:
590 parameter_header->ModeDataLength = (UCHAR)(offset - 1);
591 break;
592 case SCSIOP_MODE_SENSE10:
593 parameter_header10->ModeDataLength[0] = (UCHAR)((offset - 2) >> 8);
594 parameter_header10->ModeDataLength[1] = (UCHAR)(offset - 2);
595 break;
596 }
598 if (!valid_page && cdb_page_code != MODE_SENSE_RETURN_ALL) {
599 srb->ScsiStatus = 0; // TODO: make this something meaningful
600 *data_transfer_length = 0;
601 return SRB_STATUS_ERROR;
602 }
603 srb->ScsiStatus = 0;
604 memcpy(srb->DataBuffer, buffer, min(srb->DataTransferLength, offset));
605 *data_transfer_length = offset;
607 return SRB_STATUS_SUCCESS;
608 }
610 static BOOLEAN
611 XenVbd_ResetBus(PXENVBD_DEVICE_DATA xvdd, ULONG PathId) {
612 //srb_list_entry_t *srb_entry;
613 int i;
614 /* need to make sure that each SRB is only reset once */
615 LIST_ENTRY srb_reset_list;
616 PLIST_ENTRY list_entry;
618 UNREFERENCED_PARAMETER(PathId);
620 FUNCTION_ENTER();
622 if (dump_mode) {
623 FUNCTION_MSG("dump mode - doing nothing\n");
624 FUNCTION_EXIT();
625 return TRUE;
626 }
628 /* It appears that the StartIo spinlock is already held at this point */
630 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
632 xvdd->aligned_buffer_in_use = FALSE;
634 InitializeListHead(&srb_reset_list);
636 /* add all queued srbs to the list */
637 while((list_entry = RemoveHeadList(&xvdd->srb_list)) != &xvdd->srb_list) {
638 #if DBG
639 srb_list_entry_t *srb_entry = CONTAINING_RECORD(list_entry, srb_list_entry_t, list_entry);
640 FUNCTION_MSG("adding queued SRB %p to reset list\n", srb_entry->srb);
641 #endif
642 InsertTailList(&srb_reset_list, list_entry);
643 }
645 /* add any in-flight srbs that aren't already on the list (could be multiple shadows per srb if it's been broken up */
646 for (i = 0; i < MAX_SHADOW_ENTRIES; i++) {
647 if (xvdd->shadows[i].srb) {
648 srb_list_entry_t *srb_entry = xvdd->shadows[i].srb->SrbExtension;
649 for (list_entry = srb_reset_list.Flink; list_entry != &srb_reset_list; list_entry = list_entry->Flink) {
650 if (list_entry == &srb_entry->list_entry)
651 break;
652 }
653 if (list_entry == &srb_reset_list) {
654 FUNCTION_MSG("adding in-flight SRB %p to reset list\n", srb_entry->srb);
655 InsertTailList(&srb_reset_list, &srb_entry->list_entry);
656 }
657 /* set reset here so that the interrupt won't do anything with the srb but will dispose of the shadow entry correctly */
658 xvdd->shadows[i].reset = TRUE;
659 xvdd->shadows[i].srb = NULL;
660 xvdd->shadows[i].aligned_buffer_in_use = FALSE;
661 }
662 }
664 while((list_entry = RemoveHeadList(&srb_reset_list)) != &srb_reset_list) {
665 srb_list_entry_t *srb_entry = CONTAINING_RECORD(list_entry, srb_list_entry_t, list_entry);
666 srb_entry->outstanding_requests = 0;
667 srb_entry->srb->SrbStatus = SRB_STATUS_BUS_RESET;
668 FUNCTION_MSG("completing SRB %p with status SRB_STATUS_BUS_RESET\n", srb_entry->srb);
669 SxxxPortNotification(RequestComplete, xvdd, srb_entry->srb);
670 }
672 /* send a notify to Dom0 just in case it was missed for some reason (which should _never_ happen normally but could in dump mode) */
673 XnNotify(xvdd->handle, xvdd->event_channel);
675 SxxxPortNotification(NextRequest, xvdd);
676 FUNCTION_EXIT();
678 return TRUE;
679 }
681 /* called with StartIo lock held */
682 VOID
683 XenVbd_ProcessSrbList(PXENVBD_DEVICE_DATA xvdd) {
684 PUCHAR data_buffer;
685 #ifdef _NTSTORPORT_
686 PSCSI_PNP_REQUEST_BLOCK sprb;
687 PSCSI_POWER_REQUEST_BLOCK spwrb;
688 PMINIPORT_DUMP_POINTERS dump_pointers;
689 #endif
690 PCDB cdb;
691 ULONG data_transfer_length;
692 UCHAR srb_status;
693 ULONG notify = FALSE;
694 PSCSI_REQUEST_BLOCK srb;
695 srb_list_entry_t *srb_entry;
696 PSRB_IO_CONTROL sic;
697 ULONG prev_offset;
699 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) {
700 srb = srb_entry->srb;
701 prev_offset = srb_entry->offset;
702 if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
703 /* need to check again as may have been initialising when this srb was put on the list */
704 FUNCTION_MSG("Inactive Device (in ProcessSrbList)\n");
705 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
706 SxxxPortNotification(RequestComplete, xvdd, srb);
707 continue;
708 }
709 data_transfer_length = srb->DataTransferLength;
710 srb_status = SRB_STATUS_PENDING;
712 switch (srb->Function) {
713 case SRB_FUNCTION_EXECUTE_SCSI:
714 if (xvdd->device_state != DEVICE_STATE_ACTIVE) {
715 FUNCTION_MSG("Not yet active - state = %d\n", xvdd->device_state);
716 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
717 break;
718 }
719 if (xvdd->new_total_sectors != xvdd->total_sectors) {
720 if (xvdd->new_total_sectors == -1L) {
721 xvdd->new_total_sectors = xvdd->total_sectors;
722 } else {
723 FUNCTION_MSG("Resize detected. Setting UNIT_ATTENTION\n");
724 xvdd->total_sectors = xvdd->new_total_sectors;
725 xvdd->last_sense_key = SCSI_SENSE_UNIT_ATTENTION;
726 xvdd->last_additional_sense_code = SCSI_ADSENSE_PARAMETERS_CHANGED;
727 xvdd->last_additional_sense_code_qualifier = 0x09; /* capacity changed */
728 }
729 }
730 cdb = (PCDB)srb->Cdb;
731 if (xvdd->cac && cdb->CDB6GENERIC.OperationCode != SCSIOP_REQUEST_SENSE) {
732 FUNCTION_MSG("Waiting for REQUEST_SENSE\n");
733 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
734 break;
735 }
736 switch(cdb->CDB6GENERIC.OperationCode) {
737 case SCSIOP_TEST_UNIT_READY:
738 if (dump_mode)
739 FUNCTION_MSG("Command = TEST_UNIT_READY\n");
740 srb_status = SRB_STATUS_SUCCESS;
741 srb->ScsiStatus = 0;
742 break;
743 case SCSIOP_INQUIRY:
744 // if (dump_mode)
745 FUNCTION_MSG("Command = INQUIRY\n");
746 // FUNCTION_MSG("(LUN = %d, EVPD = %d, Page Code = %02X)\n", srb->Cdb[1] >> 5, srb->Cdb[1] & 1, srb->Cdb[2]);
747 // FUNCTION_MSG("(Length = %d)\n", srb->DataTransferLength);
749 data_buffer = srb->DataBuffer;
750 RtlZeroMemory(data_buffer, srb->DataTransferLength);
751 srb_status = SRB_STATUS_SUCCESS;
752 srb->ScsiStatus = 0;
753 switch (xvdd->device_type) {
754 case XENVBD_DEVICETYPE_DISK:
755 if ((srb->Cdb[1] & 1) == 0) {
756 if (srb->Cdb[2]) {
757 srb_status = SRB_STATUS_ERROR;
758 } else {
759 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
760 id->DeviceType = DIRECT_ACCESS_DEVICE;
761 id->Versions = 5; /* SPC-3 */
762 id->ResponseDataFormat = 2; /* not sure about this but WHQL complains otherwise */
763 id->HiSupport = 1; /* WHQL test says we should set this */
764 //id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
765 id->AdditionalLength = sizeof(INQUIRYDATA) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength) - 1;
766 id->CommandQueue = 1;
767 memcpy(id->VendorId, SCSI_DEVICE_MANUFACTURER, 8); // vendor id
768 memcpy(id->ProductId, SCSI_DISK_MODEL, 16); // product id
769 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
770 data_transfer_length = FIELD_OFFSET(INQUIRYDATA, VendorSpecific);
771 }
772 } else {
773 switch (srb->Cdb[2]) {
774 case VPD_SUPPORTED_PAGES: /* list of pages we support */
775 FUNCTION_MSG("VPD_SUPPORTED_PAGES - length = %d\n", srb->DataTransferLength);
776 data_buffer[0] = DIRECT_ACCESS_DEVICE;
777 data_buffer[1] = VPD_SUPPORTED_PAGES;
778 data_buffer[2] = 0x00;
779 data_buffer[3] = 4;
780 data_buffer[4] = VPD_SUPPORTED_PAGES;
781 data_buffer[5] = VPD_SERIAL_NUMBER;
782 data_buffer[6] = VPD_DEVICE_IDENTIFIERS;
783 data_buffer[7] = VPD_BLOCK_LIMITS;
784 data_transfer_length = 8;
785 break;
786 case VPD_SERIAL_NUMBER: /* serial number */
787 FUNCTION_MSG("VPD_SERIAL_NUMBER\n");
788 data_buffer[0] = DIRECT_ACCESS_DEVICE;
789 data_buffer[1] = VPD_SERIAL_NUMBER;
790 data_buffer[2] = 0x00;
791 data_buffer[3] = (UCHAR)strlen(xvdd->serial_number);
792 if (data_transfer_length > 4) {
793 memcpy(&data_buffer[4], xvdd->serial_number, min(data_transfer_length - 4, strlen(xvdd->serial_number)));
794 }
795 data_transfer_length = 4 + (UCHAR)strlen(xvdd->serial_number);
796 break;
797 case VPD_DEVICE_IDENTIFIERS: /* identification - we don't support any so just return zero */
798 FUNCTION_MSG("VPD_DEVICE_IDENTIFIERS\n");
799 data_buffer[0] = DIRECT_ACCESS_DEVICE;
800 data_buffer[1] = VPD_DEVICE_IDENTIFIERS;
801 data_buffer[2] = 0x00;
802 data_buffer[3] = 2 * (4 + (UCHAR)strlen(xvdd->serial_number));
803 if (data_transfer_length >= 4 + 2 * (4 + (ULONG)strlen(xvdd->serial_number))) {
804 data_buffer[4] = 2; /* ASCII */
805 data_buffer[5] = 0; /* VendorId */
806 data_buffer[6] = 0; /* reserved */
807 data_buffer[7] = (UCHAR)strlen(xvdd->serial_number);
808 memcpy(&data_buffer[8], xvdd->serial_number, (UCHAR)strlen(xvdd->serial_number));
809 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 0] = 2; /* ASCII */
810 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 1] = 1; /* T10 VendorId */
811 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 2] = 0; /* Reserved */
812 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 3] = (UCHAR)strlen(xvdd->serial_number);
813 memcpy(&data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 4], xvdd->serial_number, (UCHAR)strlen(xvdd->serial_number));
814 }
815 data_transfer_length = 4 + 2 * (4 + (ULONG)strlen(xvdd->serial_number));
816 break;
817 case VPD_BLOCK_LIMITS: /* to indicate support for UNMAP (TRIM/DISCARD) */
818 FUNCTION_MSG("VPD_BLOCK_LIMITS\n");
819 // max descriptors = 1
820 // max sectors = 0xFFFFFFFF
821 // granularity = from xenbus
822 // alignment = from xenbus(?)
823 srb_status = SRB_STATUS_ERROR;
824 break;
825 default:
826 FUNCTION_MSG("Unknown Page %02x requested\n", srb->Cdb[2]);
827 srb_status = SRB_STATUS_ERROR;
828 break;
829 }
830 }
831 break;
832 case XENVBD_DEVICETYPE_CDROM:
833 if ((srb->Cdb[1] & 1) == 0)
834 {
835 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
836 id->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
837 id->RemovableMedia = 1;
838 id->Versions = 3;
839 id->ResponseDataFormat = 0;
840 id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
841 id->CommandQueue = 1;
842 memcpy(id->VendorId, SCSI_DEVICE_MANUFACTURER, 8); // vendor id
843 memcpy(id->ProductId, SCSI_CDROM_MODEL, 16); // product id
844 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
845 data_transfer_length = sizeof(INQUIRYDATA);
846 }
847 else
848 {
849 switch (srb->Cdb[2])
850 {
851 case 0x00:
852 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
853 data_buffer[1] = 0x00;
854 data_buffer[2] = 0x00;
855 data_buffer[3] = 2;
856 data_buffer[4] = 0x00;
857 data_buffer[5] = 0x80;
858 data_transfer_length = 6;
859 break;
860 case 0x80:
861 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
862 data_buffer[1] = 0x80;
863 data_buffer[2] = 0x00;
864 data_buffer[3] = 8;
865 data_buffer[4] = 0x31;
866 data_buffer[5] = 0x32;
867 data_buffer[6] = 0x33;
868 data_buffer[7] = 0x34;
869 data_buffer[8] = 0x35;
870 data_buffer[9] = 0x36;
871 data_buffer[10] = 0x37;
872 data_buffer[11] = 0x38;
873 data_transfer_length = 12;
874 break;
875 default:
876 FUNCTION_MSG("Unknown Page %02x requested\n", srb->Cdb[2]);
877 srb_status = SRB_STATUS_ERROR;
878 break;
879 }
880 }
881 break;
882 default:
883 FUNCTION_MSG("Unknown DeviceType %02x requested\n", xvdd->device_type);
884 srb_status = SRB_STATUS_ERROR;
885 break;
886 }
887 break;
888 case SCSIOP_READ_CAPACITY:
889 //if (dump_mode)
890 FUNCTION_MSG("Command = READ_CAPACITY\n");
891 //FUNCTION_MSG(" LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1);
892 //FUNCTION_MSG(" LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]);
893 //FUNCTION_MSG(" PMI = %d\n", srb->Cdb[8] & 1);
894 data_buffer = srb->DataBuffer;
895 RtlZeroMemory(data_buffer, srb->DataTransferLength);
896 if ((xvdd->total_sectors - 1) >> 32) {
897 data_buffer[0] = 0xff;
898 data_buffer[1] = 0xff;
899 data_buffer[2] = 0xff;
900 data_buffer[3] = 0xff;
901 } else {
902 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
903 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
904 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
905 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
906 }
907 data_buffer[4] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
908 data_buffer[5] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
909 data_buffer[6] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
910 data_buffer[7] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
911 data_transfer_length = 8;
912 srb->ScsiStatus = 0;
913 srb_status = SRB_STATUS_SUCCESS;
914 break;
915 case SCSIOP_READ_CAPACITY16:
916 //if (dump_mode)
917 FUNCTION_MSG("Command = READ_CAPACITY16\n");
918 //FUNCTION_MSG(" LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1);
919 //FUNCTION_MSG(" LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]);
920 //FUNCTION_MSG(" PMI = %d\n", srb->Cdb[8] & 1);
921 data_buffer = srb->DataBuffer;
922 RtlZeroMemory(data_buffer, srb->DataTransferLength);
923 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 56) & 0xff;
924 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 48) & 0xff;
925 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 40) & 0xff;
926 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 32) & 0xff;
927 data_buffer[4] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
928 data_buffer[5] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
929 data_buffer[6] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
930 data_buffer[7] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
931 data_buffer[8] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
932 data_buffer[9] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
933 data_buffer[10] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
934 data_buffer[11] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
935 data_buffer[12] = 0;
936 switch (xvdd->hw_bytes_per_sector / xvdd->bytes_per_sector) {
937 case 1:
938 data_buffer[13] = 0; /* 512 byte hardware sectors */
939 break;
940 case 2:
941 data_buffer[13] = 1; /* 1024 byte hardware sectors */
942 break;
943 case 4:
944 data_buffer[13] = 2; /* 2048 byte hardware sectors */
945 break;
946 case 8:
947 data_buffer[13] = 3; /* 4096 byte hardware sectors */
948 break;
949 default:
950 data_buffer[13] = 0; /* 512 byte hardware sectors */
951 FUNCTION_MSG("Unknown logical blocks per physical block %d (%d / %d)\n", xvdd->hw_bytes_per_sector / xvdd->bytes_per_sector, xvdd->hw_bytes_per_sector, xvdd->bytes_per_sector);
952 break;
953 }
954 data_buffer[14] = 0xC0; //0;
955 data_buffer[15] = 0;
956 data_transfer_length = 16;
957 srb->ScsiStatus = 0;
958 srb_status = SRB_STATUS_SUCCESS;
959 break;
960 case SCSIOP_MODE_SENSE:
961 case SCSIOP_MODE_SENSE10:
962 if (dump_mode)
963 FUNCTION_MSG("Command = MODE_SENSE (DBD = %d, PC = %d, Page Code = %02x)\n", srb->Cdb[1] & 0x08, srb->Cdb[2] & 0xC0, srb->Cdb[2] & 0x3F);
964 srb_status = XenVbd_FillModePage(xvdd, srb, &data_transfer_length);
965 break;
966 case SCSIOP_READ:
967 case SCSIOP_READ16:
968 case SCSIOP_WRITE:
969 case SCSIOP_WRITE16:
970 if (XenVbd_PutSrbOnRing(xvdd, srb)) {
971 notify = TRUE;
972 }
973 break;
974 case SCSIOP_WRITE_SAME:
975 case SCSIOP_WRITE_SAME16:
976 /* not yet supported */
977 FUNCTION_MSG("WRITE_SAME\n");
978 srb_status = SRB_STATUS_ERROR;
979 break;
980 case SCSIOP_UNMAP:
981 /* not yet supported */
982 FUNCTION_MSG("UNMAP\n");
983 srb_status = SRB_STATUS_ERROR;
984 break;
985 case SCSIOP_VERIFY:
986 case SCSIOP_VERIFY16:
987 // Should we do more here?
988 if (dump_mode)
989 FUNCTION_MSG("Command = VERIFY\n");
990 srb_status = SRB_STATUS_SUCCESS;
991 break;
992 case SCSIOP_REPORT_LUNS:
993 //if (dump_mode)
994 FUNCTION_MSG("Command = REPORT_LUNS\n");
995 switch (srb->Cdb[2]) {
996 case 1:
997 FUNCTION_MSG(" SELECT REPORT = %d\n", srb->Cdb[2] & 255);
998 break;
999 default:
1000 FUNCTION_MSG(" SELECT REPORT = %d\n", srb->Cdb[2] & 255);
1001 break;
1003 FUNCTION_MSG(" ALLOCATION LENGTH = %d\n", (srb->Cdb[6] << 24)|(srb->Cdb[7] << 16)|(srb->Cdb[8] << 8)|(srb->Cdb[9]));
1004 data_buffer = srb->DataBuffer;
1005 RtlZeroMemory(data_buffer, srb->DataTransferLength);
1006 data_buffer[3] = 8; /* 1 lun */
1007 /* rest of the data is blank */
1008 data_transfer_length = 16;
1009 srb->ScsiStatus = 0;
1010 srb_status = SRB_STATUS_SUCCESS;
1011 break;
1012 case SCSIOP_REQUEST_SENSE:
1013 if (dump_mode)
1014 FUNCTION_MSG("Command = REQUEST_SENSE\n");
1015 data_transfer_length = XenVbd_MakeSense(xvdd, srb);
1016 srb_status = SRB_STATUS_SUCCESS;
1017 break;
1018 case SCSIOP_READ_TOC:
1019 //if (dump_mode)
1020 FUNCTION_MSG("Command = READ_TOC\n");
1021 data_buffer = srb->DataBuffer;
1022 /*
1023 #define READ_TOC_FORMAT_TOC 0x00
1024 #define READ_TOC_FORMAT_SESSION 0x01
1025 #define READ_TOC_FORMAT_FULL_TOC 0x02
1026 #define READ_TOC_FORMAT_PMA 0x03
1027 #define READ_TOC_FORMAT_ATIP 0x04
1028 */
1029 switch (cdb->READ_TOC.Format2) {
1030 case READ_TOC_FORMAT_TOC:
1031 data_buffer[0] = 0; // length MSB
1032 data_buffer[1] = 10; // length LSB
1033 data_buffer[2] = 1; // First Track
1034 data_buffer[3] = 1; // Last Track
1035 data_buffer[4] = 0; // Reserved
1036 data_buffer[5] = 0x14; // current position data + uninterrupted data
1037 data_buffer[6] = 1; // last complete track
1038 data_buffer[7] = 0; // reserved
1039 data_buffer[8] = 0; // MSB Block
1040 data_buffer[9] = 0;
1041 data_buffer[10] = 0;
1042 data_buffer[11] = 0; // LSB Block
1043 data_transfer_length = 12;
1044 srb_status = SRB_STATUS_SUCCESS;
1045 break;
1046 case READ_TOC_FORMAT_SESSION:
1047 case READ_TOC_FORMAT_FULL_TOC:
1048 case READ_TOC_FORMAT_PMA:
1049 case READ_TOC_FORMAT_ATIP:
1050 srb_status = SRB_STATUS_ERROR;
1051 break;
1052 default:
1053 srb_status = SRB_STATUS_ERROR;
1054 break;
1056 break;
1057 case SCSIOP_START_STOP_UNIT:
1058 FUNCTION_MSG("Command = SCSIOP_START_STOP_UNIT\n");
1059 srb_status = SRB_STATUS_SUCCESS;
1060 break;
1061 case SCSIOP_RESERVE_UNIT:
1062 FUNCTION_MSG("Command = SCSIOP_RESERVE_UNIT\n");
1063 srb_status = SRB_STATUS_SUCCESS;
1064 break;
1065 case SCSIOP_RELEASE_UNIT:
1066 FUNCTION_MSG("Command = SCSIOP_RELEASE_UNIT\n");
1067 srb_status = SRB_STATUS_SUCCESS;
1068 break;
1069 case SCSIOP_SYNCHRONIZE_CACHE:
1070 FUNCTION_MSG("Command = SCSIOP_SYNCHRONIZE_CACHE\n");
1071 srb_status = SRB_STATUS_SUCCESS;
1072 break;
1073 default:
1074 FUNCTION_MSG("Unhandled EXECUTE_SCSI Command = %02X\n", srb->Cdb[0]);
1075 xvdd->last_sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
1076 xvdd->last_additional_sense_code = SCSI_ADSENSE_NO_SENSE;
1077 xvdd->last_additional_sense_code_qualifier = 0;
1078 srb_status = SRB_STATUS_ERROR;
1079 break;
1081 if (srb_status == SRB_STATUS_ERROR) {
1082 FUNCTION_MSG("EXECUTE_SCSI Command = %02X returned error %02x\n", srb->Cdb[0], xvdd->last_sense_key);
1083 if (xvdd->last_sense_key == SCSI_SENSE_NO_SENSE) {
1084 xvdd->last_sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
1085 xvdd->last_additional_sense_code = SCSI_ADSENSE_INVALID_CDB;
1086 xvdd->last_additional_sense_code_qualifier = 0;
1088 srb->SrbStatus = srb_status;
1089 XenVbd_MakeAutoSense(xvdd, srb);
1090 SxxxPortNotification(RequestComplete, xvdd, srb);
1091 } else if (srb_status != SRB_STATUS_PENDING) {
1092 if (srb->ScsiStatus != 0) {
1093 FUNCTION_MSG("ScsiStatus = 0x%02x\n", srb->ScsiStatus);
1095 if (data_transfer_length > srb->DataTransferLength)
1096 FUNCTION_MSG("data_transfer_length too big - %d > %d\n", data_transfer_length, srb->DataTransferLength);
1097 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
1098 srb->DataTransferLength = data_transfer_length;
1099 if (srb_status == SRB_STATUS_SUCCESS && data_transfer_length < srb->DataTransferLength) {
1100 FUNCTION_MSG("data_transfer_length too small - %d < %d\n", data_transfer_length, srb->DataTransferLength);
1101 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
1102 srb->DataTransferLength = data_transfer_length;
1103 } else {
1104 srb->SrbStatus = srb_status;
1106 XenVbd_MakeAutoSense(xvdd, srb);
1107 SxxxPortNotification(RequestComplete, xvdd, srb);
1109 break;
1110 case SRB_FUNCTION_FLUSH:
1111 FUNCTION_MSG("SRB_FUNCTION_FLUSH %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free);
1112 srb->SrbStatus = SRB_STATUS_SUCCESS;
1113 SxxxPortNotification(RequestComplete, xvdd, srb);
1114 break;
1115 #ifdef _NTSTORPORT_
1116 case SRB_FUNCTION_PNP:
1117 FUNCTION_MSG("SRB_FUNCTION_PNP\n");
1118 sprb = (PSCSI_PNP_REQUEST_BLOCK)srb;
1119 switch (sprb->PnPAction)
1121 case StorStartDevice:
1122 FUNCTION_MSG(" StorStartDevice\n");
1123 break;
1124 case StorRemoveDevice:
1125 FUNCTION_MSG(" StorRemoveDevice\n");
1126 break;
1127 case StorStopDevice:
1128 FUNCTION_MSG(" StorStopDevice\n");
1129 break;
1130 case StorQueryCapabilities:
1131 FUNCTION_MSG(" StorQueryCapabilities\n");
1132 break;
1133 case StorFilterResourceRequirements:
1134 FUNCTION_MSG(" StorFilterResourceRequirements\n");
1135 break;
1136 default:
1137 FUNCTION_MSG(" Stor%d\n", sprb->PnPAction);
1138 break;
1140 FUNCTION_MSG(" SrbPnPFlags = %08x\n", sprb->SrbPnPFlags);
1141 srb->SrbStatus = SRB_STATUS_SUCCESS;
1142 SxxxPortNotification(RequestComplete, xvdd, srb);
1143 break;
1145 case SRB_FUNCTION_POWER:
1146 FUNCTION_MSG("SRB_FUNCTION_POWER\n");
1147 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
1148 spwrb = (PSCSI_POWER_REQUEST_BLOCK)srb;
1149 if (spwrb->DevicePowerState == StorPowerDeviceD0) {
1150 FUNCTION_MSG("Entering D0\n");
1151 } else {
1152 FUNCTION_MSG("Entering D%d (%d)\n", spwrb->DevicePowerState - StorPowerDeviceD0, spwrb->DevicePowerState);
1153 switch (spwrb->PowerAction) {
1154 case StorPowerActionNone:
1155 FUNCTION_MSG(" StorPowerActionNone\n");
1156 break;
1157 case StorPowerActionReserved:
1158 FUNCTION_MSG(" StorPowerActionReserved\n");
1159 break;
1160 case StorPowerActionSleep:
1161 FUNCTION_MSG(" StorPowerActionSleep\n");
1162 break;
1163 case StorPowerActionHibernate:
1164 FUNCTION_MSG(" StorPowerActionHibernate\n");
1165 break;
1166 case StorPowerActionShutdown:
1167 FUNCTION_MSG(" StorPowerActionShutdown\n");
1168 break;
1169 case StorPowerActionShutdownReset:
1170 FUNCTION_MSG(" StorPowerActionShutdownReset\n");
1171 break;
1172 case StorPowerActionShutdownOff:
1173 FUNCTION_MSG(" StorPowerActionShutdownOff\n");
1174 break;
1175 case StorPowerActionWarmEject:
1176 FUNCTION_MSG(" StorPowerActionWarmEject\n");
1177 break;
1178 default:
1179 FUNCTION_MSG(" Stor%d\n", spwrb->PowerAction);
1180 break;
1183 xvdd->power_state = spwrb->DevicePowerState;
1184 xvdd->power_action = spwrb->PowerAction;
1185 srb->SrbStatus = SRB_STATUS_SUCCESS;
1186 SxxxPortNotification(RequestComplete, xvdd, srb);
1187 break;
1188 case SRB_FUNCTION_DUMP_POINTERS:
1189 FUNCTION_MSG("SRB_FUNCTION_DUMP_POINTERS\n");
1190 FUNCTION_MSG("DataTransferLength = %d\n", srb->DataTransferLength);
1191 dump_pointers = srb->DataBuffer;
1192 FUNCTION_MSG(" Version = %d\n", dump_pointers->Version);
1193 FUNCTION_MSG(" Size = %d\n", dump_pointers->Size);
1194 FUNCTION_MSG(" DriverName = %S\n", dump_pointers->DriverName);
1195 FUNCTION_MSG(" AdapterObject = %p\n", dump_pointers->AdapterObject);
1196 FUNCTION_MSG(" MappedRegisterBase = %d\n", dump_pointers->MappedRegisterBase);
1197 FUNCTION_MSG(" CommonBufferSize = %d\n", dump_pointers->CommonBufferSize);
1198 FUNCTION_MSG(" MiniportPrivateDumpData = %p\n", dump_pointers->MiniportPrivateDumpData);
1199 FUNCTION_MSG(" SystemIoBusNumber = %d\n", dump_pointers->SystemIoBusNumber);
1200 FUNCTION_MSG(" AdapterInterfaceType = %d\n", dump_pointers->AdapterInterfaceType);
1201 FUNCTION_MSG(" MaximumTransferLength = %d\n", dump_pointers->MaximumTransferLength);
1202 FUNCTION_MSG(" NumberOfPhysicalBreaks = %d\n", dump_pointers->NumberOfPhysicalBreaks);
1203 FUNCTION_MSG(" AlignmentMask = %d\n", dump_pointers->AlignmentMask);
1204 FUNCTION_MSG(" NumberOfAccessRanges = %d\n", dump_pointers->NumberOfAccessRanges);
1205 FUNCTION_MSG(" NumberOfBuses = %d\n", dump_pointers->NumberOfBuses);
1206 FUNCTION_MSG(" Master = %d\n", dump_pointers->Master);
1207 FUNCTION_MSG(" MapBuffers = %d\n", dump_pointers->MapBuffers);
1208 FUNCTION_MSG(" MaximumNumberOfTargets = %d\n", dump_pointers->MaximumNumberOfTargets);
1210 dump_pointers->Version = DUMP_MINIPORT_VERSION_1;
1211 dump_pointers->Size = sizeof(MINIPORT_DUMP_POINTERS);
1212 RtlStringCchCopyW(dump_pointers->DriverName, DUMP_MINIPORT_NAME_LENGTH, L"xenvbd.sys");
1213 dump_pointers->AdapterObject = NULL;
1214 dump_pointers->MappedRegisterBase = 0;
1215 dump_pointers->CommonBufferSize = 0;
1216 dump_pointers->MiniportPrivateDumpData = xvdd;
1217 dump_pointers->MaximumTransferLength = 4 * 1024 * 1024;
1218 dump_pointers->NumberOfPhysicalBreaks = dump_pointers->MaximumTransferLength >> PAGE_SHIFT;
1219 dump_pointers->AlignmentMask = 0;
1220 dump_pointers->NumberOfAccessRanges = 0;
1221 dump_pointers->NumberOfBuses = 1;
1222 dump_pointers->Master = TRUE;
1223 dump_pointers->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
1224 dump_pointers->MaximumNumberOfTargets = 2;
1226 FUNCTION_MSG(" Version = %d\n", dump_pointers->Version);
1227 FUNCTION_MSG(" Size = %d\n", dump_pointers->Size);
1228 //FUNCTION_MSG(" DriverName = %S\n", dump_pointers->DriverName);
1229 FUNCTION_MSG(" AdapterObject = %p\n", dump_pointers->AdapterObject);
1230 FUNCTION_MSG(" MappedRegisterBase = %d\n", dump_pointers->MappedRegisterBase);
1231 FUNCTION_MSG(" CommonBufferSize = %d\n", dump_pointers->CommonBufferSize);
1232 FUNCTION_MSG(" MiniportPrivateDumpData = %p\n", dump_pointers->MiniportPrivateDumpData);
1233 FUNCTION_MSG(" SystemIoBusNumber = %d\n", dump_pointers->SystemIoBusNumber);
1234 FUNCTION_MSG(" AdapterInterfaceType = %d\n", dump_pointers->AdapterInterfaceType);
1235 FUNCTION_MSG(" MaximumTransferLength = %d\n", dump_pointers->MaximumTransferLength);
1236 FUNCTION_MSG(" NumberOfPhysicalBreaks = %d\n", dump_pointers->NumberOfPhysicalBreaks);
1237 FUNCTION_MSG(" AlignmentMask = %d\n", dump_pointers->AlignmentMask);
1238 FUNCTION_MSG(" NumberOfAccessRanges = %d\n", dump_pointers->NumberOfAccessRanges);
1239 FUNCTION_MSG(" NumberOfBuses = %d\n", dump_pointers->NumberOfBuses);
1240 FUNCTION_MSG(" Master = %d\n", dump_pointers->Master);
1241 FUNCTION_MSG(" MapBuffers = %d\n", dump_pointers->MapBuffers);
1242 FUNCTION_MSG(" MaximumNumberOfTargets = %d\n", dump_pointers->MaximumNumberOfTargets);
1244 srb->SrbStatus = SRB_STATUS_SUCCESS;
1245 SxxxPortNotification(RequestComplete, xvdd, srb);
1246 break;
1247 #endif
1248 case SRB_FUNCTION_SHUTDOWN:
1249 FUNCTION_MSG("SRB_FUNCTION_SHUTDOWN %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free);
1250 srb->SrbStatus = SRB_STATUS_SUCCESS;
1251 SxxxPortNotification(RequestComplete, xvdd, srb);
1252 break;
1253 case SRB_FUNCTION_RESET_BUS:
1254 case SRB_FUNCTION_RESET_DEVICE:
1255 case SRB_FUNCTION_RESET_LOGICAL_UNIT:
1256 /* the path doesn't matter here - only ever one device*/
1257 FUNCTION_MSG("SRB_FUNCTION_RESET_XXX\n");
1258 XenVbd_ResetBus(xvdd, 0);
1259 srb->SrbStatus = SRB_STATUS_SUCCESS;
1260 SxxxPortNotification(RequestComplete, xvdd, srb);
1261 break;
1262 case SRB_FUNCTION_WMI:
1263 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1264 SxxxPortNotification(RequestComplete, xvdd, srb);
1265 break;
1266 case SRB_FUNCTION_IO_CONTROL:
1267 FUNCTION_MSG("SRB_FUNCTION_IO_CONTROL\n");
1268 sic = srb->DataBuffer;
1269 FUNCTION_MSG("ControlCode = %d\n", sic->ControlCode);
1270 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1271 SxxxPortNotification(RequestComplete, xvdd, srb);
1272 break;
1273 case 0x27:
1274 FUNCTION_MSG("SRB_FUNCTION_FREE_DUMP_POINTERS\n");
1275 srb->SrbStatus = SRB_STATUS_SUCCESS;
1276 SxxxPortNotification(RequestComplete, xvdd, srb);
1277 break;
1278 default:
1279 FUNCTION_MSG("Unhandled srb->Function = %08X\n", srb->Function);
1280 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1281 SxxxPortNotification(RequestComplete, xvdd, srb);
1282 break;
1284 if ((PLIST_ENTRY)srb_entry == xvdd->srb_list.Flink && srb_entry->offset == prev_offset) {
1285 FUNCTION_MSG("Same entry\n");
1286 /* same entry was put back onto the head of the list unchanged, so we can't progress */
1287 break;
1290 if (notify) {
1291 notify = FALSE;
1292 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xvdd->ring, notify);
1293 if (notify) {
1294 XnNotify(xvdd->handle, xvdd->event_channel);
1297 return;