From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1Nzc29-0002wZ-Bb for mharc-grub-devel@gnu.org; Wed, 07 Apr 2010 16:39:33 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Nzc27-0002wR-CS for grub-devel@gnu.org; Wed, 07 Apr 2010 16:39:31 -0400 Received: from [140.186.70.92] (port=40570 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Nzc23-0002w6-Jx for grub-devel@gnu.org; Wed, 07 Apr 2010 16:39:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1Nzc1x-0000iU-BQ for grub-devel@gnu.org; Wed, 07 Apr 2010 16:39:27 -0400 Received: from mail-bw0-f223.google.com ([209.85.218.223]:54947) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Nzc1w-0000iD-RP for grub-devel@gnu.org; Wed, 07 Apr 2010 16:39:21 -0400 Received: by bwz23 with SMTP id 23so1280246bwz.26 for ; Wed, 07 Apr 2010 13:39:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:subject:references:in-reply-to :x-enigmail-version:content-type; bh=mec2af82yr25+i9zTHkGRwfRpFOPZJMVtYDkqxbaMnE=; b=Bis158Fv0gReUl+qNhG2dEiyjb5af942ZsvlKpI0T64tgXelFHEcizF8SG+WlDHHgG vpPbgBJDAeWNupg2TUKnYTQqvKLXSv/h26pbNMRFcbo8Q8sQ/d5j2pC8j2wSVa9niWdH 5XO6bmIBmDDCDO474Lo998leFuKh99atCk1Q8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:x-enigmail-version:content-type; b=d6Un7P9DE0qH10MBV2qxnVa+1BB+IWK9NIzRxX17RsGJHke5zLLG7xAic7oZy82NP9 nvafx16lPngRyOd9PcGpqDMlABnxeo92tUVEHgt9k4ml4/eQ0A0UJPUqD1MSerAgvyWG xUq4HqTP9p5wFz20ChTVacTpkezidZ8pufEr4= Received: by 10.204.161.197 with SMTP id s5mr9838970bkx.90.1270672759731; Wed, 07 Apr 2010 13:39:19 -0700 (PDT) Received: from debian.bg45.phnet (123-166.203-62.cust.bluewin.ch [62.203.166.123]) by mx.google.com with ESMTPS id 14sm7163052bwz.6.2010.04.07.13.39.12 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 07 Apr 2010 13:39:17 -0700 (PDT) Message-ID: <4BBCED68.3080900@gmail.com> Date: Wed, 07 Apr 2010 22:39:04 +0200 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109) MIME-Version: 1.0 To: The development of GNU GRUB References: <1268605383.2839.26.camel@homenes1> <4BB657BB.60801@gmail.com> <1270669741.2732.129.camel@homenes1> In-Reply-To: <1270669741.2732.129.camel@homenes1> X-Enigmail-Version: 0.95.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="------------enigD4856BEE9B7A689BD5085B7B" X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: Re: [Patch] [bug #26237] multiple problems with usb devices X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 07 Apr 2010 20:39:31 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigD4856BEE9B7A689BD5085B7B Content-Type: multipart/mixed; boundary="------------060002040904040305040700" This is a multi-part message in MIME format. --------------060002040904040305040700 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Ale=C5=A1 Nesrsta wrote: > =20 > =20 >> + * So we should: >> + * - allow WritebackDoneHead interrupt (WDH) by proper setting of l= ast TD >> + * token - it is done above in transaction settings >> + * - detect setting of WDH bit in HcInterruptStatus register >> + * - compare HccaDoneHead value with address of last-1 TD. If it is= not >> + * equal, check ED for halt and if not so, reset WDH bit and wait= again >> + * - but it should not happen - debug it! >> Are the comments from you or any part copied from spec. We need no cop= y from spec as spec is available anyway and sentences copied from it may = cause copyright problems >> =20 > > It is not copy from specification, it is only inspired by OHCI > specification. I wrote it mainly for myself (and possibly others) to > explain what is the main change against previous algorithm, which is no= t > safe (from my point of view). It can be removed if it is not > interesting. > =20 Ok then. > "Copied" are "official" names of OHCI registers, bits etc., i.e. > HccaDoneHead, WDH bit, HcInterruptStatus etc. - but from my point of > view it could be no problem - it is "keyword" which is necessary to > "speak with the same language".=20 Ok, then. > And it should be aim of such > specifications, specially of such "free" specifications as USB > specifications are. Or not? > > =20 Normally yes, but the details of license may be a problem. Many specifications has a clause which forbids modification. GPL on the other hand forbids forbiding modifications. So they are incompatible. > > Some questions and others: > =20 > I am not so far oriented in such kind of development, so I am asking: > Will You correct my patch yourself (as maintainer of code) or should I > prepare new corrected code and related patch? And against which version= > - I noted that in meantime new official version was released... > =20 Normally we ask contributors to clean their patches themselves. But given the great importance of your changes I'll cleaned them up myself. You can find the partially cleaned version in attachment. I recommend using bzr trunk but USB code hasn't changed since few months due to lack of dev time > Did You tests on OHCI/UHCI and what was the result? > What HW are You using for testing - some real PC or qemu ? > > =20 I have a computer with integrated UHCI and OHCI+EHCI PCI card. Testing on it showed that your patch fixed UHCI but had no effect on OHCI. with OHCI grub_ohci_detect_dev always sees status =3D 0. I see the similar behaviour when testing usb on grub-yeeloong-firmware (but not when chinloaded by pmon). I guess some register initialisation is missing= =2E > It was little bit surprise for me that OHCI and UHCI drivers are not > using IRQ (and maybe also some other drivers). Is it intention of GRUB?= > Nothing against such philosophy, some things are easier in this way. > > =20 GRUB has chosen to be single thread for reducing complexity. But we have plans to add IRQs nevertheless because it will easier porting drivers and allow parallel uncompress and read. > I shortly read the UHCI specification and I was thought about my > comments of TD buffer size optimalization included in patch - such > optimization cannot be done simply because TD preparation code is commo= n > for OHCI and UHCI and: > - UHCI needs (as far as I understand) TD buffer size length up to packe= t > size only (<=3D64 bytes). > - In contradiction, OHCI allows up to 8Kbytes TD buffer size (if buffer= > is aligned to page). > So there is the question if it make sense to do any optimization for > OHCI - probably not. In fact slow data transfer and wasting of memory > caused by not optimized TD buffer is probably not so big problem. > > =20 Keep it simple in this case. > I read also part of EHCI specification. There is question if GRUB 2 > needs support of EHCI because: > 1. According to EHCI specification, each EHCI interface should normaly > have also OHCI (or UHCI ?) interface. So, any USB 2.0 interface should > work (slowly) via GRUB2 UHCI/OHCI support. > 2. EHCI is relative new HW - so it was usually used on PCs with BIOS > which supports booting from USB - so, probably, there is not necessary > to prepare special support in GRUB for such HW. But maybe I am wrong. > > =20 Unfortunately BIOS is far from being bugless especially in USB. We have seen e.g. 128GiB limits. On Yeeloong grub is the firmware. And this reasoning doesn't apply to PCI expansion cards. And on my laptop a bug in legacy support prevents UHCI controller from working properly w/o EHCI. > Best regards > Ales > > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel > > =20 --=20 Regards Vladimir '=CF=86-coder/phcoder' Serbinenko --------------060002040904040305040700 Content-Type: text/x-diff; name="usb.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline; filename="usb.diff" =3D=3D=3D modified file 'bus/usb/ohci.c' --- bus/usb/ohci.c 2010-01-20 19:40:30 +0000 +++ bus/usb/ohci.c 2010-03-13 08:08:37 +0000 @@ -254,20 +274,33 @@ break; } =20 - /* Generate no interrupts. */ + /* Generate no interrupts. */ token |=3D 7 << 21; =20 /* Set the token. */ token |=3D toggle << 24; token |=3D 1 << 25; =20 - buffer =3D (grub_uint32_t) data; - buffer_end =3D buffer + size - 1; + /* Set "Not accessed" error code */ + token |=3D 15 << 28; + =20 + /* Set correct buffer values in TD if zero transfer occurs */ + if (size)=20 + { + buffer =3D (grub_uint32_t) data; + buffer_end =3D buffer + size - 1; + td->buffer =3D grub_cpu_to_le32 (buffer); + td->buffer_end =3D grub_cpu_to_le32 (buffer_end); + } + else=20 + { + td->buffer =3D 0; + td->buffer_end =3D 0; + } =20 + /* Set the rest of TD */ td->token =3D grub_cpu_to_le32 (token); - td->buffer =3D grub_cpu_to_le32 (buffer); td->next_td =3D 0; - td->buffer_end =3D grub_cpu_to_le32 (buffer_end); } =20 static grub_usb_err_t @@ -283,6 +316,9 @@ grub_uint32_t status; grub_uint32_t control; grub_usb_err_t err; + + grub_uint8_t errcode =3D 0; + grub_ohci_td_t tderr =3D NULL; int i; =20 /* Allocate an Endpoint Descriptor. */ @@ -310,6 +346,18 @@ td_list[i].next_td =3D grub_cpu_to_le32 (&td_list[i + 1]); } =20 + /* The last-1 TD token we should change to enable interrupt when TD fi= nishes. + * As OHCI interrupts are disabled, it does only setting of WDH bit in= + * HcInterruptStatus register - and that is what we want to safely det= ect + * end of all transactions. */ + td_list[transfer->transcnt - 1].token &=3D ~(7 << 21); + + td_list[transfer->transcnt].token =3D 0; + td_list[transfer->transcnt].buffer =3D 0; + td_list[transfer->transcnt].buffer_end =3D 0; + td_list[transfer->transcnt].next_td =3D + (grub_uint32_t) &td_list[transfer->transcnt]; + =20 /* Setup the Endpoint Descriptor. */ =20 /* Set the device address. */ @@ -336,30 +384,48 @@ grub_dprintf ("ohci", "program OHCI\n"); =20 /* Program the OHCI to actually transfer. */ + + /* Disable the Control and Bulk lists. */ + control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); + control &=3D ~(3 << 4); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); + + /* Clear BulkListFilled and ControlListFilled. */ + status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); + status &=3D ~(3 << 1); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); + + /* Now we should wait for start of next frame. Because we are not usin= g + * interrupt, we reset SF bit and wait when it goes to 1. */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) =3D=3D= 0); + /* Now it should be safe to change CONTROL and BULK lists. */ + + /* This we do for safety's sake - it should be done in previous call + * of grub_ohci_transfer and nobody should change it in meantime... + * It should be done before start of control or bulk OHCI list. */ =20 + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears= WDH */ + switch (transfer->type) { case GRUB_USB_TRANSACTION_TYPE_BULK: { grub_dprintf ("ohci", "add to bulk list\n"); =20 - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - - /* Disable the Control and Bulk lists. */ - control &=3D ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - - /* Clear BulkListFilled. */ - status &=3D ~(1 << 2); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + /* Set BulkList Head and Current */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, (grub_uint32_t) ed); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); =20 /* Enable the Bulk list. */ + control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); control |=3D 1 << 5; grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); =20 /* Set BulkListFilled. */ + status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); status |=3D 1 << 2; grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); =20 @@ -368,22 +434,11 @@ =20 case GRUB_USB_TRANSACTION_TYPE_CONTROL: { - grub_dprintf ("ohci", "add to control list\n"); - status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - control =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - - /* Disable the Control and Bulk lists. */ - control &=3D ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - - /* Clear ControlListFilled. */ - status &=3D ~(1 << 1); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + /* Set ControlList Head and Current */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, (grub_uint32_t) ed); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD+1, - (grub_uint32_t) ed); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, + 0); =20 /* Enable the Control list. */ control |=3D 1 << 4; @@ -402,33 +457,72 @@ grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS)); =20 /* Wait until the transfer is completed or STALLs. */ - while ((ed->td_head & ~0xf) !=3D (ed->td_tail & ~0xf)) + do { grub_cpu_idle (); =20 - grub_dprintf ("ohci", "head=3D0x%02x tail=3D0x%02x\n", ed->td_head= , ed->td_tail); - - /* Detected a STALL. */ - if (ed->td_head & 1) - break; + /* Detected a HALT. */ + if (grub_le_to_cpu32 (&ed->td_head) & 1) + break; + =20 + /* The original style of detection of finished transaction looks hazar= deous. + while ((grub_le_to_cpu32 (grub_ohci_read_mem32 (&ed->td_head)) & ~0xf)= + !=3D (grub_le_to_cpu32 (grub_ohci_read_mem32 (&ed->td_tail)) & = ~0xf)); + */ + /* This should be according to OHCI specification: + * TD is finished and ED is updated when TD is retired and HcDoneHead + * register updated and, if allowed by WDH bit, written into HccaDoneH= ead. + * So we should: + * - allow WritebackDoneHead interrupt (WDH) by proper setting of last= TD + * token - it is done above in transaction settings + * - detect setting of WDH bit in HcInterruptStatus register + * - compare HccaDoneHead value with address of last-1 TD. If it is no= t + * equal, check ED for halt and if not so, reset WDH bit and wait ag= ain + * - but it should not happen - debug it! + */ + if ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x2) !=3D = 0) + { + if ((grub_le_to_cpu32 (o->hcca->donehead) & ~0xf) + =3D=3D (grub_uint32_t) &td_list[transfer->transcnt - 1]) + break; + + /* Done Head can be updated on some another place if ED is hal= ted. */ =20 + if (grub_le_to_cpu32 (&ed->td_head) & 1) + break; + + /* If there is not HALT in ED, it is not correct, so debug it,= reset + * donehead and WDH and continue waiting. */ + grub_dprintf ("ohci", "Incorrect HccaDoneHead=3D0x%08x", + o->hcca->donehead); + o->hcca->donehead =3D 0; + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + continue; + } } - - grub_dprintf ("ohci", "complete\n"); - -/* if (ed->td_head & 1) */ -/* err =3D GRUB_USB_ERR_STALL; */ -/* else if (ed->td */ - - - if (ed->td_head & 1) + while (1); + + /* + grub_dprintf ("ohci", "completed\n"); + */ + =20 + /* Additional debug - to be removed. */ + /* + grub_dprintf ("ohci", "DoneHead_reg=3D0x%08x DoneHead_HCCA=3D0x%08x\n"= , + grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD), + grub_le_to_cpu32 (o->hcca->donehead)); + */ + =20 + if (grub_le_to_cpu32 (ed->td_head) & 1) { - grub_uint8_t errcode; - grub_ohci_td_t tderr; - - tderr =3D (grub_ohci_td_t) grub_ohci_readreg32 (o, - GRUB_OHCI_REG_DONEHEAD); - errcode =3D tderr->token >> 28; - + tderr =3D (grub_ohci_td_t) + (grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD) & ~0xf)= ; + if (tderr =3D=3D 0) + /* If DONEHEAD=3D=3D0 it means that correct address is in HCCA. + * It should be always now! */ + tderr =3D (grub_ohci_td_t) (grub_le_to_cpu32 (o->hcca->donehead)= & ~0xf); + + errcode =3D grub_le_to_cpu32 (tderr->token) >> 28; + =20 switch (errcode) { case 0: @@ -515,9 +639,38 @@ =20 /* Clear BulkListFilled and ControlListFilled. */ status =3D grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - status &=3D ~((1 << 2) | (1 << 3)); + status &=3D ~(3 << 1); grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + =20 + /* Set ED to be skipped - for safety */ + ed->target |=3D grub_cpu_to_le32 (1 << 14); + + /* Now we should wait for start of next frame. Because we are not usin= g + * interrupt, we reset SF bit and wait when it goes to 1. */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) =3D=3D= 0); + /* Now it should be safe to change CONTROL and BULK lists. */ + =20 + /* Important cleaning. */ + o->hcca->donehead =3D 0; + /* Additional debug print. to be removed. + grub_dprintf ("ohci", "Before reset of WDH: INTSTATUS=3D0x%08x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS)); + */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears= WDH */ + /* Additional debug print. to be removed. + grub_dprintf ("ohci", "After reset of WDH: INTSTATUS=3D0x%08x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS)); + */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); + + grub_dprintf ("ohci", "OHCI finished, freeing, err=3D0x%02x\n", err); + =20 /* XXX */ grub_free (td_list); grub_free (ed); =3D=3D=3D modified file 'disk/scsi.c' --- disk/scsi.c 2010-03-05 14:29:28 +0000 +++ disk/scsi.c 2010-03-13 07:59:11 +0000 @@ -50,6 +50,57 @@ } =20 =0C +/* Check result of previous operation. */ +static grub_err_t +grub_scsi_request_sense (grub_scsi_t scsi) +{ + struct grub_scsi_request_sense rs; + struct grub_scsi_request_sense_data rsd; + grub_err_t err; + + rs.opcode =3D grub_scsi_cmd_request_sense; + rs.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + rs.reserved1 =3D 0; + rs.reserved2 =3D 0; + rs.alloc_length =3D 0x12; /* XXX: Hardcoded for now */ + rs.control =3D 0; + + err =3D scsi->dev->read (scsi, sizeof (rs), (char *) &rs, + sizeof (rsd), (char *) &rsd); + if (err) + return err; + + return GRUB_ERR_NONE; +} +/* Self commenting... */ +static grub_err_t +grub_scsi_test_unit_ready (grub_scsi_t scsi) +{ + struct grub_scsi_test_unit_ready tur; + grub_err_t err; + grub_err_t err_sense; + =20 + tur.opcode =3D grub_scsi_cmd_test_unit_ready; + tur.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + tur.reserved1 =3D 0; + tur.reserved2 =3D 0; + tur.reserved3 =3D 0; + tur.control =3D 0; + + err =3D scsi->dev->read (scsi, sizeof (tur), (char *) &tur, + 0, NULL); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + =20 + if (err) + return err; + + return GRUB_ERR_NONE; +} + /* Determine the the device is removable and the type of the device SCSI. */ static grub_err_t @@ -58,15 +109,23 @@ struct grub_scsi_inquiry iq; struct grub_scsi_inquiry_data iqd; grub_err_t err; + grub_err_t err_sense; =20 iq.opcode =3D grub_scsi_cmd_inquiry; iq.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; + iq.page =3D 0; iq.reserved =3D 0; iq.alloc_length =3D 0x24; /* XXX: Hardcoded for now */ - iq.reserved2 =3D 0; + iq.control =3D 0; =20 err =3D scsi->dev->read (scsi, sizeof (iq), (char *) &iq, sizeof (iqd), (char *) &iqd); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + if (err) return err; =20 @@ -83,13 +142,24 @@ struct grub_scsi_read_capacity rc; struct grub_scsi_read_capacity_data rcd; grub_err_t err; + grub_err_t err_sense; =20 rc.opcode =3D grub_scsi_cmd_read_capacity; rc.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; - grub_memset (rc.reserved, 0, sizeof (rc.reserved)); + rc.logical_block_addr =3D 0; + rc.reserved1 =3D 0; + rc.reserved2 =3D 0; + rc.PMI =3D 0; + rc.control =3D 0; =20 err =3D scsi->dev->read (scsi, sizeof (rc), (char *) &rc, sizeof (rcd), (char *) &rcd); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + if (err) return err; =20 @@ -107,6 +177,8 @@ { grub_scsi_t scsi; struct grub_scsi_read10 rd; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -118,7 +190,14 @@ rd.reserved2 =3D 0; rd.pad =3D 0; =20 - return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->= blocksize, buf); + err =3D scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi-= >blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 /* Send a SCSI request for DISK: read SIZE sectors starting with @@ -129,6 +208,8 @@ { grub_scsi_t scsi; struct grub_scsi_read12 rd; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -139,7 +220,14 @@ rd.reserved =3D 0; rd.control =3D 0; =20 - return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi->= blocksize, buf); + err =3D scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * scsi-= >blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 #if 0 @@ -151,6 +239,8 @@ { grub_scsi_t scsi; struct grub_scsi_write10 wr; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -162,7 +252,14 @@ wr.reserved2 =3D 0; wr.pad =3D 0; =20 - return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi-= >blocksize, buf); + err =3D scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi= ->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } =20 /* Send a SCSI request for DISK: write the data stored in BUF to SIZE @@ -173,6 +270,8 @@ { grub_scsi_t scsi; struct grub_scsi_write10 wr; + grub_err_t err; + grub_err_t err_sense; =20 scsi =3D disk->data; =20 @@ -183,7 +282,14 @@ wr.reserved =3D 0; wr.pad =3D 0; =20 - return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi-= >blocksize, buf); + err =3D scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi= ->blocksize, buf); + + /* Each SCSI command should be followed by Request Sense. + If not so, many devices STALLs or definitely freezes. */ + err_sense =3D grub_scsi_request_sense (scsi); + /* err_sense is ignored for now and Request Sense Data also... */ + + return err; } #endif =20 @@ -292,6 +398,16 @@ else disk->has_partitions =3D 1; =20 + + /* According to USB MS tests, issue Test Unit Ready until OK */ + /* XXX: there should be some timeout... */ + do + { + err =3D grub_scsi_test_unit_ready (scsi); + } + while (err =3D=3D GRUB_ERR_READ_ERROR); + + /* Read capacity of media */ err =3D grub_scsi_read_capacity (scsi); if (err) { @@ -302,12 +418,14 @@ =20 /* SCSI blocks can be something else than 512, although GRUB wants 512 byte blocks. */ - disk->total_sectors =3D ((scsi->size * scsi->blocksize) - << GRUB_DISK_SECTOR_BITS); + disk->total_sectors =3D ((grub_uint64_t)scsi->size + * (grub_uint64_t)scsi->blocksize) + >> GRUB_DISK_SECTOR_BITS; =20 - grub_dprintf ("scsi", "capacity=3D%llu, blksize=3D%d\n", - (unsigned long long) disk->total_sectors, - scsi->blocksize); + grub_dprintf ("scsi", "blocks=3D%u, blocksize=3D%u\n", + scsi->size, scsi->blocksize); + grub_dprintf ("scsi", "Disk total 512 sectors =3D %llu\n", + disk->total_sectors); =20 return GRUB_ERR_NONE; } =3D=3D=3D modified file 'disk/usbms.c' --- disk/usbms.c 2010-01-20 08:12:47 +0000 +++ disk/usbms.c 2010-03-13 07:59:11 +0000 @@ -125,14 +125,16 @@ { /* Bulk IN endpoint. */ usbms->in =3D endp; - grub_usb_clear_halt (usbdev, endp->endp_addr & 128); + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ usbms->in_maxsz =3D endp->maxpacket; } else if (!(endp->endp_addr & 128) && (endp->attrib & 3) =3D=3D 2)= { /* Bulk OUT endpoint. */ usbms->out =3D endp; - grub_usb_clear_halt (usbdev, endp->endp_addr & 128); + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ usbms->out_maxsz =3D endp->maxpacket; } } @@ -143,6 +145,9 @@ return 0; } =20 + /* XXX: Activate the first configuration. */ + grub_usb_set_configuration (usbdev, 1); + /* Query the amount of LUNs. */ err =3D grub_usb_control_msg (usbdev, 0xA1, 254, 0, i, 1, (char *) &luns); @@ -151,8 +156,8 @@ /* In case of a stall, clear the stall. */ if (err =3D=3D GRUB_USB_ERR_STALL) { - grub_usb_clear_halt (usbdev, usbms->in->endp_addr & 3); - grub_usb_clear_halt (usbdev, usbms->out->endp_addr & 3); + grub_usb_clear_halt (usbdev, usbms->in->endp_addr); + grub_usb_clear_halt (usbdev, usbms->out->endp_addr); } =20 /* Just set the amount of LUNs to one. */ @@ -164,8 +169,9 @@ =20 /* XXX: Check the magic values, does this really make sense? */ - grub_usb_control_msg (usbdev, (1 << 6) | 1, 255, - 0, i, 0, 0); + /* What is it? Removed. */ + /* grub_usb_control_msg (usbdev, (1 << 6) | 1, 255, + 0, i, 0, 0); */ =20 /* XXX: To make Qemu work? */ if (usbms->luns =3D=3D 0) @@ -174,12 +180,12 @@ usbms->next =3D grub_usbms_dev_list; grub_usbms_dev_list =3D usbms; =20 - /* XXX: Activate the first configuration. */ - grub_usb_set_configuration (usbdev, 1); - + /* Reset recovery procedure */ /* Bulk-Only Mass Storage Reset, after the reset commands will be accepted. */ grub_usbms_reset (usbdev, i); + grub_usb_clear_halt (usbdev, usbms->in->endp_addr); + grub_usb_clear_halt (usbdev, usbms->out->endp_addr); =20 return 0; } @@ -225,6 +231,7 @@ static grub_uint32_t tag =3D 0; grub_usb_err_t err =3D GRUB_USB_ERR_NONE; int retrycnt =3D 3 + 1; + grub_size_t i; =20 retry: retrycnt--; @@ -240,70 +247,86 @@ cbw.lun =3D scsi->lun << GRUB_SCSI_LUN_SHIFT; cbw.length =3D cmdsize; grub_memcpy (cbw.cbwcb, cmd, cmdsize); + =20 + /* Debug print of CBW content. */ + grub_dprintf ("usb", "CBW: sign=3D0x%08x tag=3D0x%08x len=3D0x%08x\n",= + cbw.signature, cbw.tag, cbw.transfer_length); + grub_dprintf ("usb", "CBW: flags=3D0x%02x lun=3D0x%02x CB_len=3D0x%02x= \n", + cbw.flags, cbw.lun, cbw.length); + grub_dprintf ("usb", "CBW: cmd:\n %02x %02x %02x %02x %02x %02x %02x %= 02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + cbw.cbwcb[ 0], cbw.cbwcb[ 1], cbw.cbwcb[ 2], cbw.cbwcb[ 3], + cbw.cbwcb[ 4], cbw.cbwcb[ 5], cbw.cbwcb[ 6], cbw.cbwcb[ 7], + cbw.cbwcb[ 8], cbw.cbwcb[ 9], cbw.cbwcb[10], cbw.cbwcb[11], + cbw.cbwcb[12], cbw.cbwcb[13], cbw.cbwcb[14], cbw.cbwcb[15]); =20 - /* Write the request. */ + /* Write the request. XXX: Error recovery should be corrected! */ err =3D grub_usb_bulk_write (dev->dev, dev->out->endp_addr & 15, sizeof (cbw), (char *) &cbw); if (err) { if (err =3D=3D GRUB_USB_ERR_STALL) { + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); grub_usb_clear_halt (dev->dev, dev->out->endp_addr); goto retry; } return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed")= ; } =20 - /* Read/write the data. */ - if (read_write =3D=3D 0) + /* Read/write the data, (maybe) according to specification. */ + if (size && (read_write =3D=3D 0)) { err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr & 15, siz= e, buf); - grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL); - if (err) - { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->in->endp_addr); - goto retry; - } - return grub_error (GRUB_ERR_READ_ERROR, - "can't read from USB Mass Storage device"); - } + grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL);=20 + if (err) goto CheckCSW; + /* Debug print of received data. */ + grub_dprintf ("usb", "buf:\n"); + if (size <=3D 256) + for (i=3D0; idev, dev->in->endp_addr & 15, si= ze, buf); + err =3D grub_usb_bulk_write (dev->dev, dev->out->endp_addr & 15, s= ize, buf); grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL); - if (err) - { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->out->endp_addr); - goto retry; - } - return grub_error (GRUB_ERR_WRITE_ERROR, - "can't write to USB Mass Storage device"); - } + grub_dprintf ("usb", "buf:\n"); + /* Debug print of sent data. */ + if (size <=3D 256) + for (i=3D0; idev, dev->in->endp_addr & 15, sizeof (status), (char *) &status); if (err) { - if (err =3D=3D GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + err =3D grub_usb_bulk_read (dev->dev, dev->in->endp_addr & 15, + sizeof (status), (char *) &status); + if (err) + { /* Bulk-only reset device. */ + grub_usbms_reset (dev->dev, dev->interface); + grub_usb_clear_halt (dev->dev, dev->in->endp_addr); + grub_usb_clear_halt (dev->dev, dev->out->endp_addr); goto retry; - } - return grub_error (GRUB_ERR_READ_ERROR, - "can't read status from USB Mass Storage device"); + } } =20 - /* XXX: Magic and check this code. */ + /* Debug print of CSW content. */ + grub_dprintf ("usb", "CSW: sign=3D0x%08x tag=3D0x%08x resid=3D0x%08x\n= ", + status.signature, status.tag, status.residue); + grub_dprintf ("usb", "CSW: status=3D0x%02x\n", status.status); + =20 + /* If phase error, do bulk-only reset device. */ if (status.status =3D=3D 2) { - /* XXX: Phase error, reset device. */ grub_usbms_reset (dev->dev, dev->interface); grub_usb_clear_halt (dev->dev, dev->in->endp_addr); grub_usb_clear_halt (dev->dev, dev->out->endp_addr); =3D=3D=3D modified file 'include/grub/scsicmd.h' --- include/grub/scsicmd.h 2008-08-27 15:05:00 +0000 +++ include/grub/scsicmd.h 2010-03-13 07:59:12 +0000 @@ -25,14 +25,24 @@ #define GRUB_SCSI_REMOVABLE_BIT 7 #define GRUB_SCSI_LUN_SHIFT 5 =20 +struct grub_scsi_test_unit_ready +{ + grub_uint8_t opcode; + grub_uint8_t lun; /* 7-5 LUN, 4-0 reserved */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t reserved3; + grub_uint8_t control; +} __attribute__((packed)); + struct grub_scsi_inquiry { grub_uint8_t opcode; - grub_uint8_t lun; - grub_uint16_t reserved; - grub_uint16_t alloc_length; - grub_uint8_t reserved2; - grub_uint8_t pad[5]; + grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 EVPD */ + grub_uint8_t page; /* page code if EVPD=3D1 */ + grub_uint8_t reserved; + grub_uint8_t alloc_length; + grub_uint8_t control; } __attribute__((packed)); =20 struct grub_scsi_inquiry_data @@ -47,12 +57,40 @@ char prodrev[4]; } __attribute__((packed)); =20 +struct grub_scsi_request_sense +{ + grub_uint8_t opcode; + grub_uint8_t lun; /* 7-5 LUN, 4-0 reserved */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t alloc_length; + grub_uint8_t control; +} __attribute__((packed)); + +struct grub_scsi_request_sense_data +{ + grub_uint8_t error_code; /* 7 Valid, 6-0 Err. code */ + grub_uint8_t segment_number; + grub_uint8_t sense_key; /*7 FileMark, 6 EndOfMedia, 5 ILI, 4-0 sense k= ey */ + grub_uint32_t information; + grub_uint8_t additional_sense_length; + grub_uint32_t cmd_specific_info; + grub_uint8_t additional_sense_code; + grub_uint8_t additional_sense_code_qualifier; + grub_uint8_t field_replaceable_unit_code; + grub_uint8_t sense_key_specific[3]; + /* there can be additional sense field */ +} __attribute__((packed)); + struct grub_scsi_read_capacity { grub_uint8_t opcode; - grub_uint8_t lun; - grub_uint8_t reserved[8]; - grub_uint8_t pad[2]; + grub_uint8_t lun; /* 7-5 LUN, 4-1 reserved, 0 reserved */ + grub_uint32_t logical_block_addr; /* only if PMI=3D1 */ + grub_uint8_t reserved1; + grub_uint8_t reserved2; + grub_uint8_t PMI; + grub_uint8_t control; } __attribute__((packed)); =20 struct grub_scsi_read_capacity_data @@ -106,11 +144,13 @@ typedef enum { grub_scsi_cmd_inquiry =3D 0x12, + grub_scsi_cmd_test_unit_ready =3D 0x00, grub_scsi_cmd_read_capacity =3D 0x25, grub_scsi_cmd_read10 =3D 0x28, grub_scsi_cmd_write10 =3D 0x2a, grub_scsi_cmd_read12 =3D 0xa8, - grub_scsi_cmd_write12 =3D 0xaa + grub_scsi_cmd_write12 =3D 0xaa, + grub_scsi_cmd_request_sense =3D 0x03 } grub_scsi_cmd_t; =20 typedef enum =3D=3D=3D modified file 'include/grub/usbtrans.h' --- include/grub/usbtrans.h 2009-02-08 17:58:32 +0000 +++ include/grub/usbtrans.h 2010-03-13 07:59:12 +0000 @@ -86,9 +86,9 @@ =20 #define GRUB_USB_REQ_HUB_GET_PORT_STATUS 0x00 =20 -#define GRUB_USB_FEATURE_ENDP_HALT 0x01 -#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x02 -#define GRUB_USB_FEATURE_TEST_MODE 0x04 +#define GRUB_USB_FEATURE_ENDP_HALT 0x00 +#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 +#define GRUB_USB_FEATURE_TEST_MODE 0x02 =20 #define GRUB_USB_HUB_STATUS_CONNECTED (1 << 0) #define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9) --------------060002040904040305040700-- --------------enigD4856BEE9B7A689BD5085B7B Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iF4EAREKAAYFAku87W4ACgkQNak7dOguQgkqVQD6AtcZdbbesaofKkPqoo9pz6hh mIRFDy9P8/ltNHTbMVQA/1sCgxP5hYMkERp/3qQDwfXms8fGApMTjtgkEkvvCd92 =lIW5 -----END PGP SIGNATURE----- --------------enigD4856BEE9B7A689BD5085B7B--