kern/122670: [ PATCH ] broken acd_get_progress = ioctl CDRIOCGETPROGRESS logic

Dan Lukes dan at obluda.cz
Fri Apr 11 19:50:02 UTC 2008


>Number:         122670
>Category:       kern
>Synopsis:       [ PATCH ] broken acd_get_progress = ioctl CDRIOCGETPROGRESS logic
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Apr 11 19:50:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Dan Lukes
>Release:        FreeBSD 6.3-STABLE i386
>Organization:
Obludarium
>Environment:
System: FreeBSD 6.3-STABLE i386: Tue Apr 8 02:07:56 CEST 2008
sys/dev/ata/atapi-cd.c,v 1.179.2.9 2007/11/22 07:50:36 sos Exp

BUT the same code is in RELENG-7 and HEAD, so it apply for it as well

>Description:

	Some CD / DVD operation take long time to complete
- for example BLANK or FORMAT. The application program call the apropriate
ioctl, then wait for the completion. The only avaiable function that can be
used for test of the completioness is ioctl CDRIOCGETPROGRESS
It is implemented in kernel's acd_get_progress function. 
Unfortunately, current logic of such function disallow the application
program to detect the command completion reliably.
	
 --------------------

Current logic description:

        acd_get_progress uses "READ CAPACITY" command. If the previous operation
is in progress, then READ CAPACITY is rejected. The acd_complete then will autoissue 
the REQUEST SENSE command to obtain sense data.

        If the returned sense key is 0 (NO SENSE) or 2 (NOT READY) then sense 
specific data will contain the operation progress data.

MINOR PROBLEM

        The code doesn't check the sense key value, despite the fact that other
values than 0|2 are possible and sense specific data has other meaning
in that case. The random data may be reported to caller as valid progress 
responses in such cases.

        The value of sense key needs to be checked before sense specific data are
interpreted as progress indicator value.

MAJOR PROBLEM

        If the command has been completed already, then READ CAPACITY didn't
fail and REQUEST SENSE has not been called at all.

        Unfortunately, the acd_get_progress code doesn't check this specific 
situation and return 0% as valid progress value. 

 --------------------

	It's hard for application program to use that value as sign of completion. The
burncd, the only base system program for blanking/formatting CD, wait for either 100%
or for >90% folowed by 0%. It's nice try, but it doesn't work for several CD/DVD 
writers. Some of them are so fast, so burncd miss all >=90% steps. Some of them use
too wide progress steps, so no >90% step issued.

	The burncd may wait for completion forever.

	It's not burncd fault - it do the best it can. Then only way to allow 
applications to use acd_get_progress reliably is to modify it's logic.


>How-To-Repeat:

	Try to blank or format (using ioctl CDRIOCBLANK or CDRIOCFORMAT, you may use
'burncd' for it) on PLEXTOR PX-716A or LITE-ON SHM-165H6S or several others. 
The operation will sucesfully completed, but burncd never ends waiting forever 
for command completion.


>Fix:

	All problems disapear with simple change in acd_get_progress logic - 
it may continue to return 0% for errors with one exception - the error 
"no command in progress" needs to be reported as 100% (in the fact, previous command
has been completed, so it's progress is 100%).

	The following fix handle both problems:

1. it doesn't return random progress values when device return sense
	code that contain sense specific code, but other
	than progress data

2. it return 100% when no command in progress instead of 0%


--- sys/dev/ata/atapi-cd.c.ORIG	2008-04-08 01:16:23.000000000 +0200
+++ sys/dev/ata/atapi-cd.c	2008-04-08 02:16:57.000000000 +0200
@@ -1219,6 +1219,7 @@
 		       0, 0, 0, 0, 0, 0, 0, 0 };
     struct ata_request *request;
     int8_t dummy[8];
+    int cc=0;
 
     if (!(request = ata_alloc_request()))
 	return ENOMEM;
@@ -1231,14 +1232,32 @@
     request->flags = ATA_R_ATAPI | ATA_R_READ;
     request->timeout = 30;
     ata_queue_request(request);
-    if (!request->error &&
-	request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID)
-	*finished = ((request->u.atapi.sense.specific2 |
-		     (request->u.atapi.sense.specific1 << 8)) * 100) / 65535;
-    else
-	*finished = 0;
+    
+    cc = ENXIO; /* in the case of error or improper sense key (so progress data are not avaiable) */
+    *finished = 0;
+    
+    if (!request->error) {
+        if (request->u.atapi.sense.key == 0 ) { 
+            /* possible only when REQUEST SENSE has not been called
+            * e.g. no command in progress / all commands completed) 
+            */
+            *finished = 100;
+            cc = 0;
+        } else if (request->u.atapi.sense.key == ATA_SENSE_NO_SENSE || request->u.atapi.sense.key == ATA_SENSE_NOT_READY) {
+            if (request->u.atapi.sense.specific & ATA_SENSE_SPEC_VALID ) {
+                /* we have valid progress data */
+                *finished = ((request->u.atapi.sense.specific2 |
+	            (request->u.atapi.sense.specific1 << 8)) * 100) / 65535;
+            } else {
+                /* operation in progres, but progress data not avaiable */
+                *finished = 0;
+            }
+            cc = 0;
+        }
+    }
+
     ata_free_request(request);
-    return 0;
+    return cc;
 }
 
 static int
--- patch ends here ---

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list