Subject: port-i386/17618: CDIOCRESET ioctl on Toshiba CDROM@ahc0 hangs machine if no media
To: None <gnats-bugs@gnats.netbsd.org>
From: None <rafal@netbsd.org>
List: netbsd-bugs
Date: 07/17/2002 10:00:57
>Number:         17618
>Category:       port-i386
>Synopsis:       CDIOCRESET ioctl on Toshiba CDROM@ahc0 hangs machine if no media
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 17 07:01:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     
>Release:        NetBSD 1.6D
>Organization:
procrastinators anonymous
>Environment:
System: NetBSD cyclops 1.6D NetBSD 1.6D (CYCLOPS.mp) #16: Tue Jul 9 22:05:56 EDT 2002 rafal@cyclops:/extra/src-current/sys/arch/i386/compile/CYCLOPS.mp i386
Architecture: i386
Machine: i386
>Description:
	The GNOME CD player applet would hang my machine hard if I removed
	the CD from the drive or started it when there was no CD in the
	drive.

	I've gotten the problem down to a simple test program that (probably)
	could be trimmed even further... The culprit is the CDIOCRESET ioctl,
	which in turns does a Bus Device Reset at the SCSI level.  This logs
	a message about sending the BDR and then hangs the box (keyboard 
	still responds if running on a wscons console, but I'm unable to
	suspend/kill the process nor switch to a different virtual console.
	If in X, the keyboard/mouse *don't* respond and I'm still unable
	to get to a different virtual console).

	The controller is the following:
ahc0 at pci0 dev 16 function 0
ahc0: interrupting at apic 2 int 16 (irq 11)
ahc0: aic7890/91 Wide Channel A, SCSI Id=7, 16/255 SCBs

	The CDROM is:
cd0 at scsibus0 target 5 lun 0: <TOSHIBA, CD-ROM XM-6401TA, 1015> SCSI2 5/cdrom removable
cd0: sync (50.0ns offset 16), 8-bit (20.000MB/s) transfers

	There's also a CD-R/RW on the bus, and I haven't tried with that
	device yet:
cd1 at scsibus0 target 4 lun 0: <PLEXTOR, CD-R   PX-W124TS, 1.07> SCSI2 5/cdrom removable
cd1: sync (50.0ns offset 8), 8-bit (20.000MB/s) transfers

	FWIW, the SCSI chain only has those two devices and a SCSI ZIP drive;
	the system disks are all IDE, so the BDR shouldn't be interfering with
	normal system disk I/O.

>How-To-Repeat:
	Given:
		/dev/cdrom points to a device for a CDROM hanging off an
		`ahc' controller, as below:

rwxr-xr-x  1 root  wheel  10 Jul 10 22:42 /dev/cdrom@ -> /dev/rcd0d

		There is no media in that CDROM drive.

	Now:
		Run the following short program (best done on a wscons
		text console so results are more evident), and it should
		hang the PC (after printing the "Bus Device Reset" message
		from the ahc driver).

		I believe it should be sufficient to just to the CDIOCRESET
		ioctl, without the CDIOCREADSUBCHANNEL first, but have not
		verified this.

		(Note also that this is a SMP kernel, and has had the signal
		 trampoline changes from the trunk pulled up... I'm not sure
		 if either is relevant -- I'll see if I can reproduce this
		 with a "stock" uniprocessor kernel or an SMP kernel without
		 any hand-applied changes and append the results here later)

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/cdio.h>

main()
{
       int fd;
       struct ioc_read_subchannel subchnl;
       int errcode;

       if ((fd = open("/dev/cdrom", O_RDONLY)) < 0) {
	  perror("Open /dev/cdrom");
	  exit(1);
       }

       memset(&subchnl, 0, sizeof(struct ioc_read_subchannel));

       subchnl.address_format = CD_MSF_FORMAT;
       subchnl.data_format = CD_CURRENT_POSITION;
      
       subchnl.data_len = sizeof(struct cd_sub_channel_info);
       subchnl.data = malloc(sizeof(struct cd_sub_channel_info));

       if (ioctl(fd, CDIOCREADSUBCHANNEL, &subchnl) == -1) {
               free(subchnl.data);
	       perror("read CD subchannel");

	       printf("about to reset cdrom\n");
	       fflush(stdout);
	       sleep(3);

       	       if (ioctl(fd, CDIOCRESET, 0) == -1) {
		       perror("CD reset");
	       } else {
		       printf("cdrom reset OK\n");
		       fflush(stdout);
	       }
       }

       printf("CD data read ok!\n");
       free(subchnl.data);
       exit(0);
}

>Fix:
	Unknown.

>Release-Note:
>Audit-Trail:
>Unformatted:
 		kernel build from i386 smp branch with sigtramp changes 
 		from trunk applied.  Haven't yet tested with UP kernel.
 	
 		Sources from ~ Jul 9th (late evening US/Eastern)