win-pvdrivers

view xenvbd_common/common_miniport.h @ 1099:27bd2a5a4704

License change from GPL to BSD
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 13 13:38:31 2014 +1100 (2014-03-13)
parents 53eb8a11ea2f
children 2d392ecdd366
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 more_to_do = RING_HAS_UNCONSUMED_RESPONSES(&xvdd->ring);
278 }
279 }
280 }
282 if (xvdd->device_state == DEVICE_STATE_DISCONNECTING && xvdd->shadow_free == SHADOW_ENTRIES) {
283 FUNCTION_MSG("ring now empty - completing disconnect\n");
284 XenVbd_CompleteDisconnect(xvdd);
285 }
286 return;
287 }
289 /* called with StartIoLock held */
290 /* returns TRUE if something was put on the ring and notify might be required */
291 static BOOLEAN
292 XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb) {
293 srb_list_entry_t *srb_entry = srb->SrbExtension;
294 /* sector_number and block_count are the adjusted-to-512-byte-sector values */
295 ULONGLONG sector_number;
296 ULONG block_count;
297 blkif_shadow_t *shadow;
298 ULONG remaining, offset, length;
299 grant_ref_t gref;
300 PUCHAR ptr;
301 int i;
302 PVOID system_address;
304 //if (dump_mode) FUNCTION_ENTER();
306 //FUNCTION_MSG("aligned_buffer_in_use = %d\n", xvdd->aligned_buffer_in_use);
307 //FUNCTION_MSG("shadow_free = %d\n", xvdd->shadow_free);
309 XN_ASSERT(srb);
311 if (xvdd->device_state != DEVICE_STATE_ACTIVE) {
312 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
313 return FALSE;
314 }
316 if (!dump_mode) {
317 if (SxxxPortGetSystemAddress(xvdd, srb, &system_address) != STATUS_SUCCESS) {
318 FUNCTION_MSG("Failed to map DataBuffer\n");
319 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
320 return FALSE;
321 }
322 system_address = (PUCHAR)system_address + srb_entry->offset;
323 } else {
324 system_address = (PUCHAR)srb->DataBuffer + srb_entry->offset;
325 }
326 block_count = decode_cdb_length(srb);
327 sector_number = decode_cdb_sector(srb);
328 block_count *= xvdd->bytes_per_sector / 512;
329 sector_number *= xvdd->bytes_per_sector / 512;
331 XN_ASSERT(block_count * 512 == srb->DataTransferLength);
333 sector_number += srb_entry->offset / 512;
334 block_count -= srb_entry->offset / 512;
336 XN_ASSERT(block_count > 0);
338 /* look for pending writes that overlap this one */
339 /* we get warnings from drbd if we don't */
340 if (srb_entry->offset == 0) {
341 for (i = 0; i < MAX_SHADOW_ENTRIES; i++) {
342 PSCSI_REQUEST_BLOCK srb2;
343 ULONGLONG sector_number2;
344 ULONG block_count2;
346 srb2 = xvdd->shadows[i].srb;
347 if (!srb2)
348 continue;
349 if (decode_cdb_is_read(srb2))
350 continue;
351 block_count2 = decode_cdb_length(srb2);;
352 block_count2 *= xvdd->bytes_per_sector / 512;
353 sector_number2 = decode_cdb_sector(srb2);
354 sector_number2 *= xvdd->bytes_per_sector / 512;
356 if (sector_number < sector_number2 && sector_number + block_count <= sector_number2)
357 continue;
358 if (sector_number2 < sector_number && sector_number2 + block_count2 <= sector_number)
359 continue;
361 FUNCTION_MSG("Concurrent outstanding write detected (%I64d, %d) (%I64d, %d)\n",
362 sector_number, block_count, sector_number2, block_count2);
363 break;
364 }
365 if (i != MAX_SHADOW_ENTRIES) {
366 /* put the srb back at the start of the queue */
367 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
368 return FALSE;
369 }
370 }
372 shadow = get_shadow_from_freelist(xvdd);
373 if (!shadow) {
374 /* put the srb back at the start of the queue */
375 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
376 //if (dump_mode) FUNCTION_EXIT();
377 return FALSE;
378 }
379 XN_ASSERT(!shadow->aligned_buffer_in_use);
380 XN_ASSERT(!shadow->srb);
381 shadow->req.sector_number = sector_number;
382 shadow->req.handle = 0;
383 shadow->req.operation = decode_cdb_is_read(srb)?BLKIF_OP_READ:BLKIF_OP_WRITE;
384 shadow->req.nr_segments = 0;
385 shadow->srb = srb;
386 shadow->length = 0;
387 shadow->system_address = system_address;
388 shadow->reset = FALSE;
390 if (!dump_mode) {
391 if ((ULONG_PTR)shadow->system_address & 511) {
392 xvdd->aligned_buffer_in_use = TRUE;
393 /* limit to aligned_buffer_size */
394 block_count = min(block_count, xvdd->aligned_buffer_size / 512);
395 ptr = (PUCHAR)xvdd->aligned_buffer;
396 if (!decode_cdb_is_read(srb))
397 memcpy(ptr, shadow->system_address, block_count * 512);
398 shadow->aligned_buffer_in_use = TRUE;
399 } else {
400 ptr = (PUCHAR)shadow->system_address;
401 shadow->aligned_buffer_in_use = FALSE;
402 }
403 } else {
404 XN_ASSERT(!((ULONG_PTR)shadow->system_address & 511));
405 ptr = shadow->system_address;
406 shadow->aligned_buffer_in_use = FALSE;
407 }
409 remaining = block_count * 512;
410 while (remaining > 0 && shadow->req.nr_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) {
411 PHYSICAL_ADDRESS physical_address;
413 if (!dump_mode) {
414 physical_address = MmGetPhysicalAddress(ptr);
415 } else {
416 ULONG length;
417 physical_address = SxxxPortGetPhysicalAddress(xvdd, srb, ptr, &length);
418 //FUNCTION_MSG("physical_address = %08I64x\n", physical_address.QuadPart);
420 }
421 gref = XnGrantAccess(xvdd->handle,
422 (ULONG)(physical_address.QuadPart >> PAGE_SHIFT), FALSE, INVALID_GRANT_REF, xvdd->grant_tag);
423 if (gref == INVALID_GRANT_REF) {
424 ULONG i;
425 for (i = 0; i < shadow->req.nr_segments; i++) {
426 XnEndAccess(xvdd->handle,
427 shadow->req.seg[i].gref, FALSE, xvdd->grant_tag);
428 }
429 if (shadow->aligned_buffer_in_use) {
430 shadow->aligned_buffer_in_use = FALSE;
431 xvdd->aligned_buffer_in_use = FALSE;
432 }
433 /* put the srb back at the start of the queue */
434 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb_entry);
435 put_shadow_on_freelist(xvdd, shadow);
436 FUNCTION_MSG("Out of gref's. Deferring\n");
437 /* TODO: what if there are no requests currently in progress to kick the queue again?? timer? */
438 return FALSE;
439 }
440 offset = physical_address.LowPart & (PAGE_SIZE - 1);
441 length = min(PAGE_SIZE - offset, remaining);
442 XN_ASSERT((offset & 511) == 0);
443 XN_ASSERT((length & 511) == 0);
444 XN_ASSERT(offset + length <= PAGE_SIZE);
445 shadow->req.seg[shadow->req.nr_segments].gref = gref;
446 shadow->req.seg[shadow->req.nr_segments].first_sect = (UCHAR)(offset / 512);
447 shadow->req.seg[shadow->req.nr_segments].last_sect = (UCHAR)(((offset + length) / 512) - 1);
448 remaining -= length;
449 ptr += length;
450 shadow->length += length;
451 shadow->req.nr_segments++;
452 }
453 srb_entry->offset += shadow->length;
454 srb_entry->outstanding_requests++;
455 XenVbd_PutRequest(xvdd, &shadow->req);
456 if (srb_entry->offset < srb_entry->length) {
457 /* put the srb back at the start of the queue to continue on the next request */
458 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb_entry);
459 }
460 //if (dump_mode)
461 //FUNCTION_EXIT();
462 return TRUE;
463 }
465 static UCHAR
466 XenVbd_FillModePage(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb, PULONG data_transfer_length) {
467 PMODE_PARAMETER_HEADER parameter_header = NULL;
468 PMODE_PARAMETER_HEADER10 parameter_header10 = NULL;
469 PMODE_PARAMETER_BLOCK param_block;
470 PMODE_FORMAT_PAGE format_page;
471 ULONG offset = 0;
472 UCHAR buffer[1024];
473 BOOLEAN valid_page = FALSE;
474 BOOLEAN cdb_llbaa;
475 BOOLEAN cdb_dbd;
476 UCHAR cdb_page_code;
477 USHORT cdb_allocation_length;
479 UNREFERENCED_PARAMETER(xvdd);
481 RtlZeroMemory(srb->DataBuffer, srb->DataTransferLength);
482 RtlZeroMemory(buffer, ARRAY_SIZE(buffer));
483 offset = 0;
485 switch (srb->Cdb[0]) {
486 case SCSIOP_MODE_SENSE:
487 cdb_llbaa = FALSE;
488 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
489 cdb_page_code = srb->Cdb[2] & 0x3f;
490 cdb_allocation_length = srb->Cdb[4];
491 parameter_header = (PMODE_PARAMETER_HEADER)&buffer[offset];
492 parameter_header->MediumType = 0;
493 parameter_header->DeviceSpecificParameter = 0;
494 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ) {
495 FUNCTION_MSG(" Mode sense to a read only disk.\n");
496 parameter_header->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
497 }
498 offset += sizeof(MODE_PARAMETER_HEADER);
499 break;
500 case SCSIOP_MODE_SENSE10:
501 cdb_llbaa = (BOOLEAN)!!(srb->Cdb[1] & 16);
502 cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
503 cdb_page_code = srb->Cdb[2] & 0x3f;
504 cdb_allocation_length = (srb->Cdb[7] << 8) | srb->Cdb[8];
505 parameter_header10 = (PMODE_PARAMETER_HEADER10)&buffer[offset];
506 parameter_header10->MediumType = 0;
507 parameter_header10->DeviceSpecificParameter = 0;
508 if (xvdd->device_mode == XENVBD_DEVICEMODE_READ) {
509 FUNCTION_MSG(" Mode sense to a read only disk.\n");
510 parameter_header10->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
511 }
512 offset += sizeof(MODE_PARAMETER_HEADER10);
513 break;
514 default:
515 FUNCTION_MSG("SCSIOP_MODE_SENSE_WTF (%02x)\n", (ULONG)srb->Cdb[0]);
516 return FALSE;
517 }
519 if (!cdb_dbd) {
520 param_block = (PMODE_PARAMETER_BLOCK)&buffer[offset];
521 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK) {
522 if (xvdd->total_sectors >> 32) {
523 param_block->DensityCode = 0xff;
524 param_block->NumberOfBlocks[0] = 0xff;
525 param_block->NumberOfBlocks[1] = 0xff;
526 param_block->NumberOfBlocks[2] = 0xff;
527 } else {
528 param_block->DensityCode = (UCHAR)((xvdd->total_sectors >> 24) & 0xff);
529 param_block->NumberOfBlocks[0] = (UCHAR)((xvdd->total_sectors >> 16) & 0xff);
530 param_block->NumberOfBlocks[1] = (UCHAR)((xvdd->total_sectors >> 8) & 0xff);
531 param_block->NumberOfBlocks[2] = (UCHAR)((xvdd->total_sectors >> 0) & 0xff);
532 }
533 param_block->BlockLength[0] = (UCHAR)((xvdd->bytes_per_sector >> 16) & 0xff);
534 param_block->BlockLength[1] = (UCHAR)((xvdd->bytes_per_sector >> 8) & 0xff);
535 param_block->BlockLength[2] = (UCHAR)((xvdd->bytes_per_sector >> 0) & 0xff);
536 }
537 offset += sizeof(MODE_PARAMETER_BLOCK);
538 }
539 switch (srb->Cdb[0])
540 {
541 case SCSIOP_MODE_SENSE:
542 parameter_header->BlockDescriptorLength = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER));
543 break;
544 case SCSIOP_MODE_SENSE10:
545 parameter_header10->BlockDescriptorLength[0] = (UCHAR)((offset - sizeof(MODE_PARAMETER_HEADER10)) >> 8);
546 parameter_header10->BlockDescriptorLength[1] = (UCHAR)(offset - sizeof(MODE_PARAMETER_HEADER10));
547 break;
548 }
549 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_FORMAT_DEVICE || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
550 valid_page = TRUE;
551 format_page = (PMODE_FORMAT_PAGE)&buffer[offset];
552 format_page->PageCode = MODE_PAGE_FORMAT_DEVICE;
553 format_page->PageLength = sizeof(MODE_FORMAT_PAGE) - FIELD_OFFSET(MODE_FORMAT_PAGE, PageLength);
554 /* 256 sectors per track */
555 format_page->SectorsPerTrack[0] = 0x01;
556 format_page->SectorsPerTrack[1] = 0x00;
557 /* xxx bytes per sector */
558 format_page->BytesPerPhysicalSector[0] = (UCHAR)(xvdd->bytes_per_sector >> 8);
559 format_page->BytesPerPhysicalSector[1] = (UCHAR)(xvdd->bytes_per_sector & 0xff);
560 format_page->HardSectorFormating = TRUE;
561 format_page->SoftSectorFormating = TRUE;
562 offset += sizeof(MODE_FORMAT_PAGE);
563 }
564 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_CACHING || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
565 PMODE_CACHING_PAGE caching_page;
566 valid_page = TRUE;
567 caching_page = (PMODE_CACHING_PAGE)&buffer[offset];
568 caching_page->PageCode = MODE_PAGE_CACHING;
569 caching_page->PageLength = sizeof(MODE_CACHING_PAGE) - FIELD_OFFSET(MODE_CACHING_PAGE, PageLength);
570 // caching_page-> // all zeros is just fine... maybe
571 offset += sizeof(MODE_CACHING_PAGE);
572 }
573 if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_MEDIUM_TYPES || cdb_page_code == MODE_SENSE_RETURN_ALL)) {
574 PUCHAR medium_types_page;
575 valid_page = TRUE;
576 medium_types_page = &buffer[offset];
577 medium_types_page[0] = MODE_PAGE_MEDIUM_TYPES;
578 medium_types_page[1] = 0x06;
579 medium_types_page[2] = 0;
580 medium_types_page[3] = 0;
581 medium_types_page[4] = 0;
582 medium_types_page[5] = 0;
583 medium_types_page[6] = 0;
584 medium_types_page[7] = 0;
585 offset += 8;
586 }
587 switch (srb->Cdb[0]) {
588 case SCSIOP_MODE_SENSE:
589 parameter_header->ModeDataLength = (UCHAR)(offset - 1);
590 break;
591 case SCSIOP_MODE_SENSE10:
592 parameter_header10->ModeDataLength[0] = (UCHAR)((offset - 2) >> 8);
593 parameter_header10->ModeDataLength[1] = (UCHAR)(offset - 2);
594 break;
595 }
597 if (!valid_page && cdb_page_code != MODE_SENSE_RETURN_ALL) {
598 srb->ScsiStatus = 0; // TODO: make this something meaningful
599 *data_transfer_length = 0;
600 return SRB_STATUS_ERROR;
601 }
602 srb->ScsiStatus = 0;
603 memcpy(srb->DataBuffer, buffer, min(srb->DataTransferLength, offset));
604 *data_transfer_length = offset;
606 return SRB_STATUS_SUCCESS;
607 }
609 static BOOLEAN
610 XenVbd_ResetBus(PXENVBD_DEVICE_DATA xvdd, ULONG PathId) {
611 //srb_list_entry_t *srb_entry;
612 int i;
613 /* need to make sure that each SRB is only reset once */
614 LIST_ENTRY srb_reset_list;
615 PLIST_ENTRY list_entry;
617 UNREFERENCED_PARAMETER(PathId);
619 FUNCTION_ENTER();
621 if (dump_mode) {
622 FUNCTION_MSG("dump mode - doing nothing\n");
623 FUNCTION_EXIT();
624 return TRUE;
625 }
627 /* It appears that the StartIo spinlock is already held at this point */
629 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
631 xvdd->aligned_buffer_in_use = FALSE;
633 InitializeListHead(&srb_reset_list);
635 /* add all queued srbs to the list */
636 while((list_entry = RemoveHeadList(&xvdd->srb_list)) != &xvdd->srb_list) {
637 #if DBG
638 srb_list_entry_t *srb_entry = CONTAINING_RECORD(list_entry, srb_list_entry_t, list_entry);
639 FUNCTION_MSG("adding queued SRB %p to reset list\n", srb_entry->srb);
640 #endif
641 InsertTailList(&srb_reset_list, list_entry);
642 }
644 /* add any in-flight srbs that aren't already on the list (could be multiple shadows per srb if it's been broken up */
645 for (i = 0; i < MAX_SHADOW_ENTRIES; i++) {
646 if (xvdd->shadows[i].srb) {
647 srb_list_entry_t *srb_entry = xvdd->shadows[i].srb->SrbExtension;
648 for (list_entry = srb_reset_list.Flink; list_entry != &srb_reset_list; list_entry = list_entry->Flink) {
649 if (list_entry == &srb_entry->list_entry)
650 break;
651 }
652 if (list_entry == &srb_reset_list) {
653 FUNCTION_MSG("adding in-flight SRB %p to reset list\n", srb_entry->srb);
654 InsertTailList(&srb_reset_list, &srb_entry->list_entry);
655 }
656 /* set reset here so that the interrupt won't do anything with the srb but will dispose of the shadow entry correctly */
657 xvdd->shadows[i].reset = TRUE;
658 xvdd->shadows[i].srb = NULL;
659 xvdd->shadows[i].aligned_buffer_in_use = FALSE;
660 }
661 }
663 while((list_entry = RemoveHeadList(&srb_reset_list)) != &srb_reset_list) {
664 srb_list_entry_t *srb_entry = CONTAINING_RECORD(list_entry, srb_list_entry_t, list_entry);
665 srb_entry->outstanding_requests = 0;
666 srb_entry->srb->SrbStatus = SRB_STATUS_BUS_RESET;
667 FUNCTION_MSG("completing SRB %p with status SRB_STATUS_BUS_RESET\n", srb_entry->srb);
668 SxxxPortNotification(RequestComplete, xvdd, srb_entry->srb);
669 }
671 /* send a notify to Dom0 just in case it was missed for some reason (which should _never_ happen normally but could in dump mode) */
672 XnNotify(xvdd->handle, xvdd->event_channel);
674 SxxxPortNotification(NextRequest, xvdd);
675 FUNCTION_EXIT();
677 return TRUE;
678 }
680 /* called with StartIo lock held */
681 VOID
682 XenVbd_ProcessSrbList(PXENVBD_DEVICE_DATA xvdd) {
683 PUCHAR data_buffer;
684 #ifdef _NTSTORPORT_
685 PSCSI_PNP_REQUEST_BLOCK sprb;
686 PSCSI_POWER_REQUEST_BLOCK spwrb;
687 PMINIPORT_DUMP_POINTERS dump_pointers;
688 #endif
689 PCDB cdb;
690 ULONG data_transfer_length;
691 UCHAR srb_status;
692 ULONG notify = FALSE;
693 PSCSI_REQUEST_BLOCK srb;
694 srb_list_entry_t *srb_entry;
695 PSRB_IO_CONTROL sic;
696 ULONG prev_offset;
698 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) {
699 srb = srb_entry->srb;
700 prev_offset = srb_entry->offset;
701 if (xvdd->device_state == DEVICE_STATE_INACTIVE) {
702 /* need to check again as may have been initialising when this srb was put on the list */
703 FUNCTION_MSG("Inactive Device (in ProcessSrbList)\n");
704 srb->SrbStatus = SRB_STATUS_NO_DEVICE;
705 SxxxPortNotification(RequestComplete, xvdd, srb);
706 continue;
707 }
708 data_transfer_length = srb->DataTransferLength;
709 srb_status = SRB_STATUS_PENDING;
711 switch (srb->Function) {
712 case SRB_FUNCTION_EXECUTE_SCSI:
713 if (xvdd->device_state != DEVICE_STATE_ACTIVE) {
714 FUNCTION_MSG("Not yet active - state = %d\n", xvdd->device_state);
715 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
716 break;
717 }
718 if (xvdd->new_total_sectors != xvdd->total_sectors) {
719 if (xvdd->new_total_sectors == -1L) {
720 xvdd->new_total_sectors = xvdd->total_sectors;
721 } else {
722 FUNCTION_MSG("Resize detected. Setting UNIT_ATTENTION\n");
723 xvdd->total_sectors = xvdd->new_total_sectors;
724 xvdd->last_sense_key = SCSI_SENSE_UNIT_ATTENTION;
725 xvdd->last_additional_sense_code = SCSI_ADSENSE_PARAMETERS_CHANGED;
726 xvdd->last_additional_sense_code_qualifier = 0x09; /* capacity changed */
727 }
728 }
729 cdb = (PCDB)srb->Cdb;
730 if (xvdd->cac && cdb->CDB6GENERIC.OperationCode != SCSIOP_REQUEST_SENSE) {
731 FUNCTION_MSG("Waiting for REQUEST_SENSE\n");
732 InsertHeadList(&xvdd->srb_list, (PLIST_ENTRY)srb->SrbExtension);
733 break;
734 }
735 switch(cdb->CDB6GENERIC.OperationCode) {
736 case SCSIOP_TEST_UNIT_READY:
737 if (dump_mode)
738 FUNCTION_MSG("Command = TEST_UNIT_READY\n");
739 srb_status = SRB_STATUS_SUCCESS;
740 srb->ScsiStatus = 0;
741 break;
742 case SCSIOP_INQUIRY:
743 // if (dump_mode)
744 FUNCTION_MSG("Command = INQUIRY\n");
745 // FUNCTION_MSG("(LUN = %d, EVPD = %d, Page Code = %02X)\n", srb->Cdb[1] >> 5, srb->Cdb[1] & 1, srb->Cdb[2]);
746 // FUNCTION_MSG("(Length = %d)\n", srb->DataTransferLength);
748 data_buffer = srb->DataBuffer;
749 RtlZeroMemory(data_buffer, srb->DataTransferLength);
750 srb_status = SRB_STATUS_SUCCESS;
751 srb->ScsiStatus = 0;
752 switch (xvdd->device_type) {
753 case XENVBD_DEVICETYPE_DISK:
754 if ((srb->Cdb[1] & 1) == 0) {
755 if (srb->Cdb[2]) {
756 srb_status = SRB_STATUS_ERROR;
757 } else {
758 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
759 id->DeviceType = DIRECT_ACCESS_DEVICE;
760 id->Versions = 5; /* SPC-3 */
761 id->ResponseDataFormat = 2; /* not sure about this but WHQL complains otherwise */
762 id->HiSupport = 1; /* WHQL test says we should set this */
763 //id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
764 id->AdditionalLength = sizeof(INQUIRYDATA) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength) - 1;
765 id->CommandQueue = 1;
766 memcpy(id->VendorId, SCSI_DEVICE_MANUFACTURER, 8); // vendor id
767 memcpy(id->ProductId, SCSI_DISK_MODEL, 16); // product id
768 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
769 data_transfer_length = FIELD_OFFSET(INQUIRYDATA, VendorSpecific);
770 }
771 } else {
772 switch (srb->Cdb[2]) {
773 case VPD_SUPPORTED_PAGES: /* list of pages we support */
774 FUNCTION_MSG("VPD_SUPPORTED_PAGES - length = %d\n", srb->DataTransferLength);
775 data_buffer[0] = DIRECT_ACCESS_DEVICE;
776 data_buffer[1] = VPD_SUPPORTED_PAGES;
777 data_buffer[2] = 0x00;
778 data_buffer[3] = 4;
779 data_buffer[4] = VPD_SUPPORTED_PAGES;
780 data_buffer[5] = VPD_SERIAL_NUMBER;
781 data_buffer[6] = VPD_DEVICE_IDENTIFIERS;
782 data_buffer[7] = VPD_BLOCK_LIMITS;
783 data_transfer_length = 8;
784 break;
785 case VPD_SERIAL_NUMBER: /* serial number */
786 FUNCTION_MSG("VPD_SERIAL_NUMBER\n");
787 data_buffer[0] = DIRECT_ACCESS_DEVICE;
788 data_buffer[1] = VPD_SERIAL_NUMBER;
789 data_buffer[2] = 0x00;
790 data_buffer[3] = (UCHAR)strlen(xvdd->serial_number);
791 if (data_transfer_length > 4) {
792 memcpy(&data_buffer[4], xvdd->serial_number, min(data_transfer_length - 4, strlen(xvdd->serial_number)));
793 }
794 data_transfer_length = 4 + (UCHAR)strlen(xvdd->serial_number);
795 break;
796 case VPD_DEVICE_IDENTIFIERS: /* identification - we don't support any so just return zero */
797 FUNCTION_MSG("VPD_DEVICE_IDENTIFIERS\n");
798 data_buffer[0] = DIRECT_ACCESS_DEVICE;
799 data_buffer[1] = VPD_DEVICE_IDENTIFIERS;
800 data_buffer[2] = 0x00;
801 data_buffer[3] = 2 * (4 + (UCHAR)strlen(xvdd->serial_number));
802 if (data_transfer_length >= 4 + 2 * (4 + (ULONG)strlen(xvdd->serial_number))) {
803 data_buffer[4] = 2; /* ASCII */
804 data_buffer[5] = 0; /* VendorId */
805 data_buffer[6] = 0; /* reserved */
806 data_buffer[7] = (UCHAR)strlen(xvdd->serial_number);
807 memcpy(&data_buffer[8], xvdd->serial_number, (UCHAR)strlen(xvdd->serial_number));
808 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 0] = 2; /* ASCII */
809 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 1] = 1; /* T10 VendorId */
810 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 2] = 0; /* Reserved */
811 data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 3] = (UCHAR)strlen(xvdd->serial_number);
812 memcpy(&data_buffer[8 + (UCHAR)strlen(xvdd->serial_number) + 4], xvdd->serial_number, (UCHAR)strlen(xvdd->serial_number));
813 }
814 data_transfer_length = 4 + 2 * (4 + (ULONG)strlen(xvdd->serial_number));
815 break;
816 case VPD_BLOCK_LIMITS: /* to indicate support for UNMAP (TRIM/DISCARD) */
817 FUNCTION_MSG("VPD_BLOCK_LIMITS\n");
818 // max descriptors = 1
819 // max sectors = 0xFFFFFFFF
820 // granularity = from xenbus
821 // alignment = from xenbus(?)
822 srb_status = SRB_STATUS_ERROR;
823 break;
824 default:
825 FUNCTION_MSG("Unknown Page %02x requested\n", srb->Cdb[2]);
826 srb_status = SRB_STATUS_ERROR;
827 break;
828 }
829 }
830 break;
831 case XENVBD_DEVICETYPE_CDROM:
832 if ((srb->Cdb[1] & 1) == 0)
833 {
834 PINQUIRYDATA id = (PINQUIRYDATA)data_buffer;
835 id->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
836 id->RemovableMedia = 1;
837 id->Versions = 3;
838 id->ResponseDataFormat = 0;
839 id->AdditionalLength = FIELD_OFFSET(INQUIRYDATA, VendorSpecific) - FIELD_OFFSET(INQUIRYDATA, AdditionalLength);
840 id->CommandQueue = 1;
841 memcpy(id->VendorId, SCSI_DEVICE_MANUFACTURER, 8); // vendor id
842 memcpy(id->ProductId, SCSI_CDROM_MODEL, 16); // product id
843 memcpy(id->ProductRevisionLevel, "0000", 4); // product revision level
844 data_transfer_length = sizeof(INQUIRYDATA);
845 }
846 else
847 {
848 switch (srb->Cdb[2])
849 {
850 case 0x00:
851 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
852 data_buffer[1] = 0x00;
853 data_buffer[2] = 0x00;
854 data_buffer[3] = 2;
855 data_buffer[4] = 0x00;
856 data_buffer[5] = 0x80;
857 data_transfer_length = 6;
858 break;
859 case 0x80:
860 data_buffer[0] = READ_ONLY_DIRECT_ACCESS_DEVICE;
861 data_buffer[1] = 0x80;
862 data_buffer[2] = 0x00;
863 data_buffer[3] = 8;
864 data_buffer[4] = 0x31;
865 data_buffer[5] = 0x32;
866 data_buffer[6] = 0x33;
867 data_buffer[7] = 0x34;
868 data_buffer[8] = 0x35;
869 data_buffer[9] = 0x36;
870 data_buffer[10] = 0x37;
871 data_buffer[11] = 0x38;
872 data_transfer_length = 12;
873 break;
874 default:
875 FUNCTION_MSG("Unknown Page %02x requested\n", srb->Cdb[2]);
876 srb_status = SRB_STATUS_ERROR;
877 break;
878 }
879 }
880 break;
881 default:
882 FUNCTION_MSG("Unknown DeviceType %02x requested\n", xvdd->device_type);
883 srb_status = SRB_STATUS_ERROR;
884 break;
885 }
886 break;
887 case SCSIOP_READ_CAPACITY:
888 //if (dump_mode)
889 FUNCTION_MSG("Command = READ_CAPACITY\n");
890 //FUNCTION_MSG(" LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1);
891 //FUNCTION_MSG(" LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]);
892 //FUNCTION_MSG(" PMI = %d\n", srb->Cdb[8] & 1);
893 data_buffer = srb->DataBuffer;
894 RtlZeroMemory(data_buffer, srb->DataTransferLength);
895 if ((xvdd->total_sectors - 1) >> 32) {
896 data_buffer[0] = 0xff;
897 data_buffer[1] = 0xff;
898 data_buffer[2] = 0xff;
899 data_buffer[3] = 0xff;
900 } else {
901 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
902 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
903 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
904 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
905 }
906 data_buffer[4] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
907 data_buffer[5] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
908 data_buffer[6] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
909 data_buffer[7] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
910 data_transfer_length = 8;
911 srb->ScsiStatus = 0;
912 srb_status = SRB_STATUS_SUCCESS;
913 break;
914 case SCSIOP_READ_CAPACITY16:
915 //if (dump_mode)
916 FUNCTION_MSG("Command = READ_CAPACITY16\n");
917 //FUNCTION_MSG(" LUN = %d, RelAdr = %d\n", srb->Cdb[1] >> 4, srb->Cdb[1] & 1);
918 //FUNCTION_MSG(" LBA = %02x%02x%02x%02x\n", srb->Cdb[2], srb->Cdb[3], srb->Cdb[4], srb->Cdb[5]);
919 //FUNCTION_MSG(" PMI = %d\n", srb->Cdb[8] & 1);
920 data_buffer = srb->DataBuffer;
921 RtlZeroMemory(data_buffer, srb->DataTransferLength);
922 data_buffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 56) & 0xff;
923 data_buffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 48) & 0xff;
924 data_buffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 40) & 0xff;
925 data_buffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 32) & 0xff;
926 data_buffer[4] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
927 data_buffer[5] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
928 data_buffer[6] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
929 data_buffer[7] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
930 data_buffer[8] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
931 data_buffer[9] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
932 data_buffer[10] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
933 data_buffer[11] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
934 data_buffer[12] = 0;
935 switch (xvdd->hw_bytes_per_sector / xvdd->bytes_per_sector) {
936 case 1:
937 data_buffer[13] = 0; /* 512 byte hardware sectors */
938 break;
939 case 2:
940 data_buffer[13] = 1; /* 1024 byte hardware sectors */
941 break;
942 case 4:
943 data_buffer[13] = 2; /* 2048 byte hardware sectors */
944 break;
945 case 8:
946 data_buffer[13] = 3; /* 4096 byte hardware sectors */
947 break;
948 default:
949 data_buffer[13] = 0; /* 512 byte hardware sectors */
950 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);
951 break;
952 }
953 data_buffer[14] = 0xC0; //0;
954 data_buffer[15] = 0;
955 data_transfer_length = 16;
956 srb->ScsiStatus = 0;
957 srb_status = SRB_STATUS_SUCCESS;
958 break;
959 case SCSIOP_MODE_SENSE:
960 case SCSIOP_MODE_SENSE10:
961 if (dump_mode)
962 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);
963 srb_status = XenVbd_FillModePage(xvdd, srb, &data_transfer_length);
964 break;
965 case SCSIOP_READ:
966 case SCSIOP_READ16:
967 case SCSIOP_WRITE:
968 case SCSIOP_WRITE16:
969 if (XenVbd_PutSrbOnRing(xvdd, srb)) {
970 notify = TRUE;
971 }
972 break;
973 case SCSIOP_WRITE_SAME:
974 case SCSIOP_WRITE_SAME16:
975 /* not yet supported */
976 FUNCTION_MSG("WRITE_SAME\n");
977 srb_status = SRB_STATUS_ERROR;
978 break;
979 case SCSIOP_UNMAP:
980 /* not yet supported */
981 FUNCTION_MSG("UNMAP\n");
982 srb_status = SRB_STATUS_ERROR;
983 break;
984 case SCSIOP_VERIFY:
985 case SCSIOP_VERIFY16:
986 // Should we do more here?
987 if (dump_mode)
988 FUNCTION_MSG("Command = VERIFY\n");
989 srb_status = SRB_STATUS_SUCCESS;
990 break;
991 case SCSIOP_REPORT_LUNS:
992 //if (dump_mode)
993 FUNCTION_MSG("Command = REPORT_LUNS\n");
994 switch (srb->Cdb[2]) {
995 case 1:
996 FUNCTION_MSG(" SELECT REPORT = %d\n", srb->Cdb[2] & 255);
997 break;
998 default:
999 FUNCTION_MSG(" SELECT REPORT = %d\n", srb->Cdb[2] & 255);
1000 break;
1002 FUNCTION_MSG(" ALLOCATION LENGTH = %d\n", (srb->Cdb[6] << 24)|(srb->Cdb[7] << 16)|(srb->Cdb[8] << 8)|(srb->Cdb[9]));
1003 data_buffer = srb->DataBuffer;
1004 RtlZeroMemory(data_buffer, srb->DataTransferLength);
1005 data_buffer[3] = 8; /* 1 lun */
1006 /* rest of the data is blank */
1007 data_transfer_length = 16;
1008 srb->ScsiStatus = 0;
1009 srb_status = SRB_STATUS_SUCCESS;
1010 break;
1011 case SCSIOP_REQUEST_SENSE:
1012 if (dump_mode)
1013 FUNCTION_MSG("Command = REQUEST_SENSE\n");
1014 data_transfer_length = XenVbd_MakeSense(xvdd, srb);
1015 srb_status = SRB_STATUS_SUCCESS;
1016 break;
1017 case SCSIOP_READ_TOC:
1018 //if (dump_mode)
1019 FUNCTION_MSG("Command = READ_TOC\n");
1020 data_buffer = srb->DataBuffer;
1021 /*
1022 #define READ_TOC_FORMAT_TOC 0x00
1023 #define READ_TOC_FORMAT_SESSION 0x01
1024 #define READ_TOC_FORMAT_FULL_TOC 0x02
1025 #define READ_TOC_FORMAT_PMA 0x03
1026 #define READ_TOC_FORMAT_ATIP 0x04
1027 */
1028 switch (cdb->READ_TOC.Format2) {
1029 case READ_TOC_FORMAT_TOC:
1030 data_buffer[0] = 0; // length MSB
1031 data_buffer[1] = 10; // length LSB
1032 data_buffer[2] = 1; // First Track
1033 data_buffer[3] = 1; // Last Track
1034 data_buffer[4] = 0; // Reserved
1035 data_buffer[5] = 0x14; // current position data + uninterrupted data
1036 data_buffer[6] = 1; // last complete track
1037 data_buffer[7] = 0; // reserved
1038 data_buffer[8] = 0; // MSB Block
1039 data_buffer[9] = 0;
1040 data_buffer[10] = 0;
1041 data_buffer[11] = 0; // LSB Block
1042 data_transfer_length = 12;
1043 srb_status = SRB_STATUS_SUCCESS;
1044 break;
1045 case READ_TOC_FORMAT_SESSION:
1046 case READ_TOC_FORMAT_FULL_TOC:
1047 case READ_TOC_FORMAT_PMA:
1048 case READ_TOC_FORMAT_ATIP:
1049 srb_status = SRB_STATUS_ERROR;
1050 break;
1051 default:
1052 srb_status = SRB_STATUS_ERROR;
1053 break;
1055 break;
1056 case SCSIOP_START_STOP_UNIT:
1057 FUNCTION_MSG("Command = SCSIOP_START_STOP_UNIT\n");
1058 srb_status = SRB_STATUS_SUCCESS;
1059 break;
1060 case SCSIOP_RESERVE_UNIT:
1061 FUNCTION_MSG("Command = SCSIOP_RESERVE_UNIT\n");
1062 srb_status = SRB_STATUS_SUCCESS;
1063 break;
1064 case SCSIOP_RELEASE_UNIT:
1065 FUNCTION_MSG("Command = SCSIOP_RELEASE_UNIT\n");
1066 srb_status = SRB_STATUS_SUCCESS;
1067 break;
1068 case SCSIOP_SYNCHRONIZE_CACHE:
1069 FUNCTION_MSG("Command = SCSIOP_SYNCHRONIZE_CACHE\n");
1070 srb_status = SRB_STATUS_SUCCESS;
1071 break;
1072 default:
1073 FUNCTION_MSG("Unhandled EXECUTE_SCSI Command = %02X\n", srb->Cdb[0]);
1074 xvdd->last_sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
1075 xvdd->last_additional_sense_code = SCSI_ADSENSE_NO_SENSE;
1076 xvdd->last_additional_sense_code_qualifier = 0;
1077 srb_status = SRB_STATUS_ERROR;
1078 break;
1080 if (srb_status == SRB_STATUS_ERROR) {
1081 FUNCTION_MSG("EXECUTE_SCSI Command = %02X returned error %02x\n", srb->Cdb[0], xvdd->last_sense_key);
1082 if (xvdd->last_sense_key == SCSI_SENSE_NO_SENSE) {
1083 xvdd->last_sense_key = SCSI_SENSE_ILLEGAL_REQUEST;
1084 xvdd->last_additional_sense_code = SCSI_ADSENSE_INVALID_CDB;
1085 xvdd->last_additional_sense_code_qualifier = 0;
1087 srb->SrbStatus = srb_status;
1088 XenVbd_MakeAutoSense(xvdd, srb);
1089 SxxxPortNotification(RequestComplete, xvdd, srb);
1090 } else if (srb_status != SRB_STATUS_PENDING) {
1091 if (srb->ScsiStatus != 0) {
1092 FUNCTION_MSG("ScsiStatus = 0x%02x\n", srb->ScsiStatus);
1094 if (data_transfer_length > srb->DataTransferLength)
1095 FUNCTION_MSG("data_transfer_length too big - %d > %d\n", data_transfer_length, srb->DataTransferLength);
1096 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
1097 srb->DataTransferLength = data_transfer_length;
1098 if (srb_status == SRB_STATUS_SUCCESS && data_transfer_length < srb->DataTransferLength) {
1099 FUNCTION_MSG("data_transfer_length too small - %d < %d\n", data_transfer_length, srb->DataTransferLength);
1100 srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
1101 srb->DataTransferLength = data_transfer_length;
1102 } else {
1103 srb->SrbStatus = srb_status;
1105 XenVbd_MakeAutoSense(xvdd, srb);
1106 SxxxPortNotification(RequestComplete, xvdd, srb);
1108 break;
1109 case SRB_FUNCTION_FLUSH:
1110 FUNCTION_MSG("SRB_FUNCTION_FLUSH %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free);
1111 srb->SrbStatus = SRB_STATUS_SUCCESS;
1112 SxxxPortNotification(RequestComplete, xvdd, srb);
1113 break;
1114 #ifdef _NTSTORPORT_
1115 case SRB_FUNCTION_PNP:
1116 FUNCTION_MSG("SRB_FUNCTION_PNP\n");
1117 sprb = (PSCSI_PNP_REQUEST_BLOCK)srb;
1118 switch (sprb->PnPAction)
1120 case StorStartDevice:
1121 FUNCTION_MSG(" StorStartDevice\n");
1122 break;
1123 case StorRemoveDevice:
1124 FUNCTION_MSG(" StorRemoveDevice\n");
1125 break;
1126 case StorStopDevice:
1127 FUNCTION_MSG(" StorStopDevice\n");
1128 break;
1129 case StorQueryCapabilities:
1130 FUNCTION_MSG(" StorQueryCapabilities\n");
1131 break;
1132 case StorFilterResourceRequirements:
1133 FUNCTION_MSG(" StorFilterResourceRequirements\n");
1134 break;
1135 default:
1136 FUNCTION_MSG(" Stor%d\n", sprb->PnPAction);
1137 break;
1139 FUNCTION_MSG(" SrbPnPFlags = %08x\n", sprb->SrbPnPFlags);
1140 srb->SrbStatus = SRB_STATUS_SUCCESS;
1141 SxxxPortNotification(RequestComplete, xvdd, srb);
1142 break;
1144 case SRB_FUNCTION_POWER:
1145 FUNCTION_MSG("SRB_FUNCTION_POWER\n");
1146 FUNCTION_MSG("IRQL = %d\n", KeGetCurrentIrql());
1147 spwrb = (PSCSI_POWER_REQUEST_BLOCK)srb;
1148 if (spwrb->DevicePowerState == StorPowerDeviceD0) {
1149 FUNCTION_MSG("Entering D0\n");
1150 } else {
1151 FUNCTION_MSG("Entering D%d (%d)\n", spwrb->DevicePowerState - StorPowerDeviceD0, spwrb->DevicePowerState);
1152 switch (spwrb->PowerAction) {
1153 case StorPowerActionNone:
1154 FUNCTION_MSG(" StorPowerActionNone\n");
1155 break;
1156 case StorPowerActionReserved:
1157 FUNCTION_MSG(" StorPowerActionReserved\n");
1158 break;
1159 case StorPowerActionSleep:
1160 FUNCTION_MSG(" StorPowerActionSleep\n");
1161 break;
1162 case StorPowerActionHibernate:
1163 FUNCTION_MSG(" StorPowerActionHibernate\n");
1164 break;
1165 case StorPowerActionShutdown:
1166 FUNCTION_MSG(" StorPowerActionShutdown\n");
1167 break;
1168 case StorPowerActionShutdownReset:
1169 FUNCTION_MSG(" StorPowerActionShutdownReset\n");
1170 break;
1171 case StorPowerActionShutdownOff:
1172 FUNCTION_MSG(" StorPowerActionShutdownOff\n");
1173 break;
1174 case StorPowerActionWarmEject:
1175 FUNCTION_MSG(" StorPowerActionWarmEject\n");
1176 break;
1177 default:
1178 FUNCTION_MSG(" Stor%d\n", spwrb->PowerAction);
1179 break;
1182 xvdd->power_state = spwrb->DevicePowerState;
1183 xvdd->power_action = spwrb->PowerAction;
1184 srb->SrbStatus = SRB_STATUS_SUCCESS;
1185 SxxxPortNotification(RequestComplete, xvdd, srb);
1186 break;
1187 case SRB_FUNCTION_DUMP_POINTERS:
1188 FUNCTION_MSG("SRB_FUNCTION_DUMP_POINTERS\n");
1189 FUNCTION_MSG("DataTransferLength = %d\n", srb->DataTransferLength);
1190 dump_pointers = srb->DataBuffer;
1191 FUNCTION_MSG(" Version = %d\n", dump_pointers->Version);
1192 FUNCTION_MSG(" Size = %d\n", dump_pointers->Size);
1193 FUNCTION_MSG(" DriverName = %S\n", dump_pointers->DriverName);
1194 FUNCTION_MSG(" AdapterObject = %p\n", dump_pointers->AdapterObject);
1195 FUNCTION_MSG(" MappedRegisterBase = %d\n", dump_pointers->MappedRegisterBase);
1196 FUNCTION_MSG(" CommonBufferSize = %d\n", dump_pointers->CommonBufferSize);
1197 FUNCTION_MSG(" MiniportPrivateDumpData = %p\n", dump_pointers->MiniportPrivateDumpData);
1198 FUNCTION_MSG(" SystemIoBusNumber = %d\n", dump_pointers->SystemIoBusNumber);
1199 FUNCTION_MSG(" AdapterInterfaceType = %d\n", dump_pointers->AdapterInterfaceType);
1200 FUNCTION_MSG(" MaximumTransferLength = %d\n", dump_pointers->MaximumTransferLength);
1201 FUNCTION_MSG(" NumberOfPhysicalBreaks = %d\n", dump_pointers->NumberOfPhysicalBreaks);
1202 FUNCTION_MSG(" AlignmentMask = %d\n", dump_pointers->AlignmentMask);
1203 FUNCTION_MSG(" NumberOfAccessRanges = %d\n", dump_pointers->NumberOfAccessRanges);
1204 FUNCTION_MSG(" NumberOfBuses = %d\n", dump_pointers->NumberOfBuses);
1205 FUNCTION_MSG(" Master = %d\n", dump_pointers->Master);
1206 FUNCTION_MSG(" MapBuffers = %d\n", dump_pointers->MapBuffers);
1207 FUNCTION_MSG(" MaximumNumberOfTargets = %d\n", dump_pointers->MaximumNumberOfTargets);
1209 dump_pointers->Version = DUMP_MINIPORT_VERSION_1;
1210 dump_pointers->Size = sizeof(MINIPORT_DUMP_POINTERS);
1211 RtlStringCchCopyW(dump_pointers->DriverName, DUMP_MINIPORT_NAME_LENGTH, L"xenvbd.sys");
1212 dump_pointers->AdapterObject = NULL;
1213 dump_pointers->MappedRegisterBase = 0;
1214 dump_pointers->CommonBufferSize = 0;
1215 dump_pointers->MiniportPrivateDumpData = xvdd;
1216 dump_pointers->MaximumTransferLength = 4 * 1024 * 1024;
1217 dump_pointers->NumberOfPhysicalBreaks = dump_pointers->MaximumTransferLength >> PAGE_SHIFT;
1218 dump_pointers->AlignmentMask = 0;
1219 dump_pointers->NumberOfAccessRanges = 0;
1220 dump_pointers->NumberOfBuses = 1;
1221 dump_pointers->Master = TRUE;
1222 dump_pointers->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
1223 dump_pointers->MaximumNumberOfTargets = 2;
1225 FUNCTION_MSG(" Version = %d\n", dump_pointers->Version);
1226 FUNCTION_MSG(" Size = %d\n", dump_pointers->Size);
1227 //FUNCTION_MSG(" DriverName = %S\n", dump_pointers->DriverName);
1228 FUNCTION_MSG(" AdapterObject = %p\n", dump_pointers->AdapterObject);
1229 FUNCTION_MSG(" MappedRegisterBase = %d\n", dump_pointers->MappedRegisterBase);
1230 FUNCTION_MSG(" CommonBufferSize = %d\n", dump_pointers->CommonBufferSize);
1231 FUNCTION_MSG(" MiniportPrivateDumpData = %p\n", dump_pointers->MiniportPrivateDumpData);
1232 FUNCTION_MSG(" SystemIoBusNumber = %d\n", dump_pointers->SystemIoBusNumber);
1233 FUNCTION_MSG(" AdapterInterfaceType = %d\n", dump_pointers->AdapterInterfaceType);
1234 FUNCTION_MSG(" MaximumTransferLength = %d\n", dump_pointers->MaximumTransferLength);
1235 FUNCTION_MSG(" NumberOfPhysicalBreaks = %d\n", dump_pointers->NumberOfPhysicalBreaks);
1236 FUNCTION_MSG(" AlignmentMask = %d\n", dump_pointers->AlignmentMask);
1237 FUNCTION_MSG(" NumberOfAccessRanges = %d\n", dump_pointers->NumberOfAccessRanges);
1238 FUNCTION_MSG(" NumberOfBuses = %d\n", dump_pointers->NumberOfBuses);
1239 FUNCTION_MSG(" Master = %d\n", dump_pointers->Master);
1240 FUNCTION_MSG(" MapBuffers = %d\n", dump_pointers->MapBuffers);
1241 FUNCTION_MSG(" MaximumNumberOfTargets = %d\n", dump_pointers->MaximumNumberOfTargets);
1243 srb->SrbStatus = SRB_STATUS_SUCCESS;
1244 SxxxPortNotification(RequestComplete, xvdd, srb);
1245 break;
1246 #endif
1247 case SRB_FUNCTION_SHUTDOWN:
1248 FUNCTION_MSG("SRB_FUNCTION_SHUTDOWN %p, xvdd->shadow_free = %d\n", srb, xvdd->shadow_free);
1249 srb->SrbStatus = SRB_STATUS_SUCCESS;
1250 SxxxPortNotification(RequestComplete, xvdd, srb);
1251 break;
1252 case SRB_FUNCTION_RESET_BUS:
1253 case SRB_FUNCTION_RESET_DEVICE:
1254 case SRB_FUNCTION_RESET_LOGICAL_UNIT:
1255 /* the path doesn't matter here - only ever one device*/
1256 FUNCTION_MSG("SRB_FUNCTION_RESET_XXX\n");
1257 XenVbd_ResetBus(xvdd, 0);
1258 srb->SrbStatus = SRB_STATUS_SUCCESS;
1259 SxxxPortNotification(RequestComplete, xvdd, srb);
1260 break;
1261 case SRB_FUNCTION_WMI:
1262 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1263 SxxxPortNotification(RequestComplete, xvdd, srb);
1264 break;
1265 case SRB_FUNCTION_IO_CONTROL:
1266 FUNCTION_MSG("SRB_FUNCTION_IO_CONTROL\n");
1267 sic = srb->DataBuffer;
1268 FUNCTION_MSG("ControlCode = %d\n", sic->ControlCode);
1269 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1270 SxxxPortNotification(RequestComplete, xvdd, srb);
1271 break;
1272 case 0x27:
1273 FUNCTION_MSG("SRB_FUNCTION_FREE_DUMP_POINTERS\n");
1274 srb->SrbStatus = SRB_STATUS_SUCCESS;
1275 SxxxPortNotification(RequestComplete, xvdd, srb);
1276 break;
1277 default:
1278 FUNCTION_MSG("Unhandled srb->Function = %08X\n", srb->Function);
1279 srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1280 SxxxPortNotification(RequestComplete, xvdd, srb);
1281 break;
1283 if ((PLIST_ENTRY)srb_entry == xvdd->srb_list.Flink && srb_entry->offset == prev_offset) {
1284 FUNCTION_MSG("Same entry\n");
1285 /* same entry was put back onto the head of the list unchanged, so we can't progress */
1286 break;
1289 if (notify) {
1290 notify = FALSE;
1291 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xvdd->ring, notify);
1292 if (notify) {
1293 XnNotify(xvdd->handle, xvdd->event_channel);
1296 return;