- Revert 44301
[reactos.git] / drivers / usb / nt4compat / usbdriver / bulkonly.c
1 /**
2 * bulkonly.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23 #include <ntddscsi.h>
24
25 #define OLYMPUS_CSW( pdev_EXT, staTUS ) \
26 ( ( ( pdev_EXT )->flags & UMSS_DEV_FLAG_OLYMPUS_DEV ) ? ( ( staTUS ) == CSW_OLYMPUS_SIGNATURE ) : FALSE )
27
28 BOOLEAN umss_clear_pass_through_length(PIO_PACKET io_packet);
29
30 NTSTATUS umss_bulkonly_send_sense_req(PUMSS_DEVICE_EXTENSION pdev_ext);
31
32 VOID umss_bulkonly_send_cbw_completion(IN PURB purb, IN PVOID context);
33
34 VOID umss_bulkonly_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext);
35
36 VOID umss_sync_submit_urb_completion(PURB purb, PVOID context);
37
38 NTSTATUS umss_sync_submit_urb(PUMSS_DEVICE_EXTENSION pdev_ext, PURB purb);
39
40 VOID umss_bulkonly_get_status(PUMSS_DEVICE_EXTENSION pdev_ext);
41
42 VOID umss_bulkonly_transfer_data_complete(PURB purb, PVOID reference);
43
44 VOID umss_bulkonly_reset_pipe_and_get_status(IN PVOID reference);
45
46 VOID umss_bulkonly_reset_recovery(IN PVOID reference);
47
48 VOID umss_bulkonly_get_status_complete(IN PURB purb, IN PVOID context);
49
50 /*++
51 Routine Description:
52
53 Handler for all I/O requests using bulk-only protocol.
54
55 Arguments:
56
57 DeviceExtension - Device extension for our FDO.
58
59 Return Value:
60
61 NONE
62
63 --*/
64 NTSTATUS
65 umss_bulkonly_startio(IN PUMSS_DEVICE_EXTENSION pdev_ext, IN PIO_PACKET io_packet)
66 {
67 PCOMMAND_BLOCK_WRAPPER cbw;
68 NTSTATUS status;
69
70 if (pdev_ext == NULL || io_packet == NULL || io_packet->pirp == NULL)
71 return STATUS_INVALID_PARAMETER;
72
73 pdev_ext->retry = TRUE;
74 RtlCopyMemory(&pdev_ext->io_packet, io_packet, sizeof(pdev_ext->io_packet));
75
76 // Setup the command block wrapper for this request
77 cbw = &pdev_ext->cbw;
78 cbw->dCBWSignature = CBW_SIGNATURE;
79 cbw->dCBWTag = 0;
80 cbw->dCBWDataTransferLength = io_packet->data_length;
81 cbw->bmCBWFlags = (io_packet->flags & USB_DIR_IN) ? 0x80 : 0;
82 cbw->bCBWLun = io_packet->lun;
83 cbw->bCBWLength = io_packet->cdb_length;
84 RtlCopyMemory(cbw->CBWCB, io_packet->cdb, sizeof(cbw->CBWCB));
85
86 RtlZeroMemory(&pdev_ext->csw, sizeof(pdev_ext->csw));
87 // Send the command block wrapper to the device.
88 // Calls UMSS_BulkOnlySendCBWComplete when transfer completes.
89 status = umss_bulk_transfer(pdev_ext,
90 USB_DIR_OUT,
91 cbw, sizeof(COMMAND_BLOCK_WRAPPER), umss_bulkonly_send_cbw_completion);
92
93 return status;
94 }
95
96
97 NTSTATUS
98 umss_bulk_transfer(IN PUMSS_DEVICE_EXTENSION pdev_ext,
99 IN UCHAR trans_dir, IN PVOID buf, IN ULONG buf_length, IN PURBCOMPLETION completion)
100 {
101 PURB purb;
102 NTSTATUS status;
103 DEV_HANDLE endp_handle;
104
105 if (pdev_ext == NULL || buf == NULL || completion == NULL)
106 return STATUS_INVALID_PARAMETER;
107
108 if (buf_length > (ULONG) MAX_BULK_TRANSFER_LENGTH)
109 return STATUS_INVALID_PARAMETER;
110
111 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
112
113 if (purb == NULL)
114 return STATUS_NO_MEMORY;
115
116 if (trans_dir == USB_DIR_OUT)
117 {
118 endp_handle = usb_make_handle((pdev_ext->dev_handle >> 16), pdev_ext->if_idx, pdev_ext->out_endp_idx);
119 }
120 else
121 {
122 endp_handle = usb_make_handle((pdev_ext->dev_handle >> 16), pdev_ext->if_idx, pdev_ext->in_endp_idx);
123 }
124
125 UsbBuildInterruptOrBulkTransferRequest(purb, endp_handle, buf, buf_length, completion, pdev_ext, 0);
126 dev_mgr_register_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb);
127 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
128 if (status == STATUS_PENDING)
129 {
130 return status;
131 }
132
133 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
134 if (purb)
135 {
136 usb_free_mem(purb);
137 purb = NULL;
138 }
139 return status;
140 }
141
142 VOID
143 umss_bulkonly_send_cbw_completion(IN PURB purb, IN PVOID context)
144 {
145 NTSTATUS status;
146 PUMSS_DEVICE_EXTENSION pdev_ext;
147
148 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
149
150 status = purb->status;
151 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
152
153 if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_SENSE)
154 {
155 usb_free_mem(purb->data_buffer);
156 purb->data_buffer = NULL;
157 purb->data_length = 0;
158 }
159
160 if (status != STATUS_SUCCESS)
161 {
162 if (usb_halted(status))
163 {
164 //Schedule a work-item to do a reset recovery
165 if (!umss_schedule_workitem
166 ((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
167 {
168 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
169 }
170 }
171 else
172 {
173 // Device failed CBW without stalling, so complete with error
174 umss_complete_request(pdev_ext, status);
175 }
176 }
177 else
178 {
179 // CBW was accepted by device, so start data phase of I/O operation
180 umss_bulkonly_transfer_data(pdev_ext);
181 }
182
183 usb_free_mem(purb);
184
185 purb = NULL;
186 return;
187 }
188
189 //can only be called at passive level
190 NTSTATUS
191 umss_sync_submit_urb(PUMSS_DEVICE_EXTENSION pdev_ext, PURB purb)
192 {
193 NTSTATUS status;
194
195 if (pdev_ext == NULL || purb == NULL)
196 return STATUS_INVALID_PARAMETER;
197
198 purb->completion = umss_sync_submit_urb_completion;
199 purb->context = (PVOID) pdev_ext;
200
201 dev_mgr_register_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb);
202 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
203 if (status == STATUS_PENDING)
204 {
205 KeWaitForSingleObject(&pdev_ext->sync_event, Executive, KernelMode, TRUE, NULL);
206 status = purb->status;
207 }
208 else
209 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
210
211 return status;
212 }
213
214 VOID
215 umss_sync_submit_urb_completion(PURB purb, PVOID context)
216 {
217 PUMSS_DEVICE_EXTENSION pdev_ext;
218
219 if (purb == NULL || context == NULL)
220 return;
221
222 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
223 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
224 KeSetEvent(&pdev_ext->sync_event, 0, FALSE);
225 return;
226 }
227
228 /*++
229 Routine Description:
230
231 Worker function used to execute a reset recovery after a stall.
232
233 Arguments:
234
235 Reference - Our device extension.
236
237 Return Value:
238
239 NONE
240
241 --*/
242 VOID
243 umss_bulkonly_reset_recovery(IN PVOID reference)
244 {
245 PUMSS_DEVICE_EXTENSION pdev_ext;
246 URB urb;
247 NTSTATUS status;
248 DEV_HANDLE endp_handle;
249
250 pdev_ext = (PUMSS_DEVICE_EXTENSION) reference;
251 usb_dbg_print(DBGLVL_MAXIMUM, ("umss_bulkonly_reset_recovery(): entering...\n"));
252 // Steps for reset recovery:
253 // 1. Send device a mass storage reset command on the default endpoint.
254 // 2. Reset the bulk-in endpoint.
255 // 3. Reset the bulk-out endpoint.
256 // 4. Complete the original I/O request with error.
257
258
259 // Build the mass storage reset command
260 UsbBuildVendorRequest(&urb, pdev_ext->dev_handle | 0xffff, //default pipe
261 NULL, //no extra data
262 0, //no size
263 0x21, //class, interface
264 BULK_ONLY_MASS_STORAGE_RESET,
265 0,
266 pdev_ext->pif_desc->bInterfaceNumber,
267 NULL, //completion
268 NULL, //context
269 0); //reference
270
271 // Send mass storage reset command to device
272 status = umss_sync_submit_urb(pdev_ext, &urb);
273
274 if (status != STATUS_SUCCESS)
275 {
276 usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_reset_recovery(): Reset Recovery failed!\n"));
277 }
278 else
279 {
280 //Reset Bulk-in endpoint
281 endp_handle = usb_make_handle((pdev_ext->dev_handle >> 16), pdev_ext->if_idx, pdev_ext->in_endp_idx);
282 status = umss_reset_pipe(pdev_ext, endp_handle);
283
284 if (!NT_SUCCESS(status))
285 {
286 usb_dbg_print(DBGLVL_MINIMUM,
287 ("umss_bulkonly_reset_recovery(): Unable to clear Bulk-in endpoint\n"));
288 }
289
290 //Reset Bulk-out endpoint
291 endp_handle = usb_make_handle((pdev_ext->dev_handle >> 16), pdev_ext->if_idx, pdev_ext->out_endp_idx);
292 status = umss_reset_pipe(pdev_ext, endp_handle);
293
294 if (!NT_SUCCESS(status))
295 {
296 usb_dbg_print(DBGLVL_MINIMUM,
297 ("umss_bulkonly_reset_recovery(): Unable to clear Bulk-out endpoint\n"));
298 }
299 }
300 umss_complete_request(pdev_ext, status);
301 }
302
303 /*++
304 Routine Description:
305
306 Schedules a bulk data transfer to/from the device.
307
308 Arguments:
309
310 DeviceExtension - Our FDO's device extension.
311
312 Return Value:
313
314 NONE
315
316 --*/
317 VOID
318 umss_bulkonly_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext)
319 {
320 PVOID data_buf;
321 ULONG data_buf_length;
322 NTSTATUS status;
323 UCHAR trans_dir = USB_DIR_IN; // FIXME: Initialize this properly!
324
325 // Steps for data phase
326 // 1. Get data buffer fragment (either SGD list, flat buffer, or none).
327 // 2. Schedule data transfer if neccessary.
328 // 3. Repeat 1-2 until all data transferred, or endpoint stalls.
329 // 4. Move to status phase.
330
331 // Get next data buffer element, if any
332 data_buf = umss_get_buffer(pdev_ext, &data_buf_length);
333
334 if (NULL == data_buf)
335 {
336 //No data to transfer, so move to status phase
337 umss_bulkonly_get_status(pdev_ext);
338 }
339 else
340 {
341 // Schedule the data transfer.
342 // Calls umss_bulkonly_transfer_data_complete when transfer completes.
343
344 if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL)
345 trans_dir = (UCHAR) ((pdev_ext->cbw.bmCBWFlags & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT);
346 else if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_SENSE)
347 trans_dir = USB_DIR_IN;
348
349 if ((status = umss_bulk_transfer(pdev_ext,
350 trans_dir,
351 data_buf,
352 data_buf_length,
353 umss_bulkonly_transfer_data_complete)) != STATUS_PENDING)
354 {
355 umss_complete_request(pdev_ext, status);
356 }
357 }
358 return;
359 }
360
361 /*++
362 Routine Description:
363 Completion handler for bulk data transfer requests.
364 --*/
365 VOID
366 umss_bulkonly_transfer_data_complete(PURB purb, PVOID reference)
367 {
368 NTSTATUS status;
369 PUMSS_DEVICE_EXTENSION pdev_ext;
370 pdev_ext = (PUMSS_DEVICE_EXTENSION) reference;
371
372 status = purb->status;
373
374 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
375
376 if (status != STATUS_SUCCESS)
377 {
378 //
379 // clear the data length if this is a scsi pass through request
380 //
381 umss_clear_pass_through_length(&pdev_ext->io_packet);
382
383 // Device failed data phase
384 // Check if we need to clear stalled pipe
385 if (usb_halted(status))
386 {
387 PULONG buf;
388 buf = usb_alloc_mem(NonPagedPool, 32);
389 if (!buf) return;
390
391 buf[0] = (ULONG) pdev_ext;
392 buf[1] = (ULONG) purb->endp_handle;
393
394 usb_dbg_print(DBGLVL_MINIMUM, ("umss_transfer_data_complete(): transfer data error!\n"));
395 if (!umss_schedule_workitem
396 ((PVOID) buf, umss_bulkonly_reset_pipe_and_get_status, pdev_ext->dev_mgr,
397 pdev_ext->dev_handle))
398 {
399 usb_free_mem(buf), buf = NULL;
400 usb_dbg_print(DBGLVL_MINIMUM,
401 ("umss_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
402 TRAP();
403 umss_complete_request(pdev_ext, status);
404 }
405 }
406 else
407 {
408 //finish our request
409 umss_complete_request(pdev_ext, status);
410 }
411 }
412 else
413 {
414 // Start next part of data phase
415 //umss_bulkonly_transfer_data( pdev_ext );
416 umss_bulkonly_get_status(pdev_ext);
417 //umss_complete_request( pdev_ext, status );
418 }
419
420 usb_free_mem(purb);
421 purb = NULL;
422
423 return; // STATUS_MORE_PROCESSING_REQUIRED;
424 }
425
426
427 VOID
428 umss_bulkonly_reset_pipe_and_get_status(IN PVOID reference)
429 {
430 PUMSS_DEVICE_EXTENSION pdev_ext;
431 DEV_HANDLE endp_handle;
432 NTSTATUS status;
433
434 usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_reset_pipe_and_get_status(): entering...\n"));
435
436 pdev_ext = (PUMSS_DEVICE_EXTENSION) (((PULONG) reference)[0]);
437 endp_handle = (DEV_HANDLE) ((PULONG) reference)[1];
438 usb_free_mem(reference);
439 reference = NULL;
440
441 // Reset the endpoint
442 if ((status = umss_reset_pipe(pdev_ext, endp_handle)) != STATUS_SUCCESS)
443 {
444 usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_reset_pipe_and_get_status(): reset pipe failed\n"));
445 umss_complete_request(pdev_ext, status);
446 return;
447 }
448 // Data phase is finished since the endpoint stalled, so go to status phase
449 usb_dbg_print(DBGLVL_MINIMUM,
450 ("umss_bulkonly_reset_pipe_and_get_status(): reset pipe succeeds, continue to get status\n"));
451 umss_bulkonly_get_status(pdev_ext);
452 }
453
454 VOID
455 umss_bulkonly_get_status(PUMSS_DEVICE_EXTENSION pdev_ext)
456 {
457 NTSTATUS status;
458 // Schedule bulk transfer to get command status wrapper from device
459 status = umss_bulk_transfer(pdev_ext,
460 USB_DIR_IN,
461 &(pdev_ext->csw),
462 sizeof(COMMAND_STATUS_WRAPPER), umss_bulkonly_get_status_complete);
463 if (status != STATUS_PENDING)
464 {
465 umss_complete_request(pdev_ext, status);
466 }
467 }
468
469 /*++
470 Routine Description:
471
472 Completion handler for bulk data transfer request.
473
474 Arguments:
475
476 DeviceObject - Previous device object.
477 Irp - Irp used for sending command.
478 Reference - Our FDO.
479
480 Return Value:
481
482 Driver-originated IRPs always return STATUS_MORE_PROCESSING_REQUIRED.
483
484 --*/
485 VOID
486 umss_bulkonly_get_status_complete(IN PURB purb, IN PVOID context)
487 {
488 NTSTATUS status;
489 PUMSS_DEVICE_EXTENSION pdev_ext;
490 PCOMMAND_STATUS_WRAPPER csw;
491
492 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
493 status = purb->status;
494
495 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
496
497 csw = &(pdev_ext->csw);
498 if (status == STATUS_SUCCESS &&
499 ((csw->dCSWSignature == CSW_SIGNATURE) || OLYMPUS_CSW(pdev_ext, csw->dCSWSignature)))
500 {
501 if (csw->bCSWStatus == CSW_STATUS_PASSED)
502 {
503 // Received valid CSW with good status
504
505 if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL &&
506 (pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE) && pdev_ext->io_packet.sense_data != NULL)
507 UMSS_FORGE_GOOD_SENSE(pdev_ext->io_packet.sense_data)
508 umss_complete_request(pdev_ext, STATUS_SUCCESS);
509 }
510 else if (csw->bCSWStatus == CSW_STATUS_FAILED)
511 {
512 // start a request sense if necessary
513 if ((pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE) &&
514 (pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL)
515 {
516 if (umss_bulkonly_send_sense_req(pdev_ext) != STATUS_PENDING)
517 {
518 // don't know how to handle.
519 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
520 }
521 else
522 {
523 // fall through to free the urb
524 }
525 }
526 else
527 {
528 // error occurred, reset device
529 if (!umss_schedule_workitem
530 ((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
531 {
532 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
533 }
534 }
535 }
536 else
537 {
538 // error occurred, reset device
539 if (!umss_schedule_workitem
540 ((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
541 {
542 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
543 }
544 }
545 }
546 else if ((status != STATUS_SUCCESS) && (usb_halted(status)) && (pdev_ext->retry))
547 {
548 // Device stalled CSW transfer, retry once before failing
549 PULONG buf;
550 pdev_ext->retry = FALSE;
551
552 buf = usb_alloc_mem(NonPagedPool, 32);
553 if (!buf) return;
554
555 buf[0] = (ULONG) pdev_ext;
556 buf[1] = (ULONG) purb->endp_handle;
557
558 if (!umss_schedule_workitem
559 ((PVOID) buf, umss_bulkonly_reset_pipe_and_get_status, pdev_ext->dev_mgr, pdev_ext->dev_handle))
560 {
561 usb_free_mem(buf), buf = NULL;
562 usb_dbg_print(DBGLVL_MINIMUM,
563 ("umss_bulkonly_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
564 TRAP();
565 umss_complete_request(pdev_ext, status);
566 }
567 }
568 else if (status != STATUS_CANCELLED)
569 {
570 // An error has occured. Reset the device.
571 if (!umss_schedule_workitem
572 ((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
573 {
574 usb_dbg_print(DBGLVL_MINIMUM,
575 ("umss_bulkonly_get_status_complete(): Failed to schedule work-item to reset pipe!\n"));
576 TRAP();
577 umss_complete_request(pdev_ext, status);
578 }
579 }
580 else
581 {
582 // the request is canceled
583 usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_get_status_complete(): the request is canceled\n"));
584 umss_complete_request(pdev_ext, STATUS_CANCELLED);
585 }
586
587 usb_free_mem(purb);
588 purb = NULL;
589
590 return;
591 }
592
593 /*++
594 Routine Description:
595
596 Queries Bulk-Only device for maximum LUN number
597
598 Arguments:
599
600 DeviceExtension - Our device extension.
601
602 Return Value:
603
604 Maximum LUN number for device, or 0 if error occurred.
605
606 --*/
607 CHAR
608 umss_bulkonly_get_maxlun(IN PUMSS_DEVICE_EXTENSION pdev_ext)
609 {
610 PURB purb = NULL;
611 UCHAR max_lun;
612 NTSTATUS status;
613
614 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
615
616 if (!purb)
617 {
618 usb_dbg_print(DBGLVL_MINIMUM,
619 ("umss_bulkonly_get_maxlun(): Failed to allocate URB, setting max LUN to 0\n"));
620 max_lun = 0;
621 }
622 else
623 {
624 // Build the get max lun command
625 UsbBuildVendorRequest(purb, (pdev_ext->dev_handle | 0xffff), &max_lun, sizeof(max_lun), 0xb1, //class, interface, in
626 BULK_ONLY_GET_MAX_LUN, 0, pdev_ext->pif_desc->bInterfaceNumber, NULL, NULL, 0);
627
628 // Send get max lun command to device
629 status = umss_sync_submit_urb(pdev_ext, purb);
630
631 if (status != STATUS_PENDING)
632 {
633 usb_dbg_print(DBGLVL_MINIMUM,
634 ("umss_bulkonly_get_maxlun(): Get Max LUN command failed, setting max LUN to 0!\n"));
635 max_lun = 0;
636 }
637 }
638
639 if (purb)
640 usb_free_mem(purb);
641
642 usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_get_maxlun(): Max LUN = %x\n", max_lun));
643
644 return max_lun;
645 }
646
647 PVOID
648 umss_get_buffer(PUMSS_DEVICE_EXTENSION pdev_ext, ULONG * buf_length)
649 {
650 PVOID buffer;
651
652 if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL)
653 {
654 buffer = (PVOID) pdev_ext->io_packet.data_buffer;
655 *buf_length = pdev_ext->io_packet.data_length;
656 }
657 else if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_SENSE)
658 {
659 buffer = (PVOID) pdev_ext->io_packet.sense_data;
660 *buf_length = pdev_ext->io_packet.sense_data_length;
661 }
662 else
663 {
664 buffer = NULL;
665 *buf_length = 0;
666 }
667
668 return buffer;
669 }
670
671 BOOLEAN
672 umss_bulkonly_build_sense_cdb(PUMSS_DEVICE_EXTENSION pdev_ext, PCOMMAND_BLOCK_WRAPPER cbw)
673 {
674 UCHAR sub_class;
675 PUCHAR cdb;
676
677 if (pdev_ext == NULL || cbw == NULL)
678 return FALSE;
679
680 cdb = cbw->CBWCB;
681 RtlZeroMemory(cdb, MAX_CDB_LENGTH);
682 sub_class = pdev_ext->pif_desc->bInterfaceSubClass;
683
684 cdb[0] = SFF_REQUEST_SENSEE;
685 cdb[1] = pdev_ext->io_packet.lun << 5;
686 cdb[4] = 18;
687
688 switch (sub_class)
689 {
690 case UMSS_SUBCLASS_SFF8070I:
691 case UMSS_SUBCLASS_UFI:
692 {
693 cbw->bCBWLength = 12;
694 break;
695 }
696 case UMSS_SUBCLASS_RBC:
697 case UMSS_SUBCLASS_SCSI_TCS:
698 {
699 cbw->bCBWLength = 6;
700 break;
701 }
702 default:
703 return FALSE;
704 }
705 return TRUE;
706 }
707
708 NTSTATUS
709 umss_bulkonly_send_sense_req(PUMSS_DEVICE_EXTENSION pdev_ext)
710 {
711 PCOMMAND_BLOCK_WRAPPER cbw;
712 NTSTATUS status;
713
714 if (pdev_ext == NULL || pdev_ext->io_packet.sense_data == NULL
715 || pdev_ext->io_packet.sense_data_length < 18)
716 return STATUS_INVALID_PARAMETER;
717
718 pdev_ext->retry = TRUE;
719
720 cbw = usb_alloc_mem(NonPagedPool, sizeof(COMMAND_BLOCK_WRAPPER));
721 if (!cbw) return STATUS_NO_MEMORY;
722
723 RtlZeroMemory(cbw, sizeof(COMMAND_BLOCK_WRAPPER));
724 pdev_ext->io_packet.flags &= ~IOP_FLAG_STAGE_MASK;
725 pdev_ext->io_packet.flags |= IOP_FLAG_STAGE_SENSE;
726
727 cbw->dCBWSignature = CBW_SIGNATURE;
728 cbw->dCBWTag = 0;
729 cbw->dCBWDataTransferLength = pdev_ext->io_packet.sense_data_length;
730 cbw->bmCBWFlags = USB_DIR_IN;
731 cbw->bCBWLun = 0;
732
733 if (umss_bulkonly_build_sense_cdb(pdev_ext, cbw) == FALSE)
734 {
735 usb_free_mem(cbw);
736 cbw = NULL;
737 return STATUS_UNSUCCESSFUL;
738 }
739
740 status = umss_bulk_transfer(pdev_ext,
741 USB_DIR_OUT,
742 cbw, sizeof(COMMAND_BLOCK_WRAPPER), umss_bulkonly_send_cbw_completion);
743
744 if (status != STATUS_PENDING)
745 {
746 usb_free_mem(cbw);
747 cbw = NULL;
748 }
749 return status;
750 }
751
752 BOOLEAN
753 umss_clear_pass_through_length(PIO_PACKET io_packet)
754 {
755 //
756 // clear the respective data length to meet request of scsi pass through requirement.
757 //
758
759 BOOLEAN sense_stage;
760 ULONG ctrl_code;
761 PIO_STACK_LOCATION cur_stack;
762 PSCSI_PASS_THROUGH pass_through;
763 PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
764
765 if (io_packet == NULL)
766 return FALSE;
767
768 if ((io_packet->flags & IOP_FLAG_SCSI_CTRL_TRANSFER) == 0)
769 return FALSE;
770
771 sense_stage = FALSE;
772 if (io_packet->flags & IOP_FLAG_STAGE_SENSE)
773 sense_stage = TRUE;
774
775 cur_stack = IoGetCurrentIrpStackLocation(io_packet->pirp);
776 ctrl_code = cur_stack->Parameters.DeviceIoControl.IoControlCode;
777 if (ctrl_code == IOCTL_SCSI_PASS_THROUGH_DIRECT)
778 {
779 pass_through_direct = io_packet->pirp->AssociatedIrp.SystemBuffer;
780 if (sense_stage)
781 pass_through_direct->SenseInfoLength = 0;
782 else
783 pass_through_direct->DataTransferLength = 0;
784 }
785 else if (ctrl_code == IOCTL_SCSI_PASS_THROUGH)
786 {
787 pass_through = io_packet->pirp->AssociatedIrp.SystemBuffer;
788 if (sense_stage)
789 pass_through->SenseInfoLength = 0;
790 else
791 pass_through->DataTransferLength = 0;
792 }
793 else
794 return FALSE;
795
796 return TRUE;
797 }