⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide-cd.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
	{ 0x5302, "Medium removal prevented" },	{ 0x5700, "Unable to recover table of contents" },	{ 0x5a00, "Operator request or state change input (unspecified)" },	{ 0x5a01, "Operator medium removal request" },	{ 0x5b00, "Threshold condition met" },	{ 0x5c00, "Status change" },	{ 0x6300, "End of user area encountered on this track" },	{ 0x6400, "Illegal mode for this track" },	{ 0xbf00, "Loss of streaming" },};#endif/**************************************************************************** * Generic packet command support and error handling routines. */staticvoid cdrom_analyze_sense_data (ide_drive_t *drive, 			       struct atapi_request_sense *reqbuf,			       struct packet_command *failed_command){	/* Don't print not ready or unit attention errors for READ_SUBCHANNEL.	   Workman (and probably other programs) uses this command to poll	   the drive, and we don't want to fill the syslog	   with useless errors. */	if (failed_command &&	    failed_command->c[0] == SCMD_READ_SUBCHANNEL &&	    (reqbuf->sense_key == NOT_READY ||	     reqbuf->sense_key == UNIT_ATTENTION))		return;#if VERBOSE_IDE_CD_ERRORS	{		int i;		char *s;		char buf[80];		printk ("ATAPI device %s:\n", drive->name);		printk ("  Error code: 0x%02x\n", reqbuf->error_code);		if (reqbuf->sense_key >= 0 &&		    reqbuf->sense_key < ARY_LEN (sense_key_texts))			s = sense_key_texts[reqbuf->sense_key];		else			s = "(bad sense key)";		printk ("  Sense key: 0x%02x - %s\n", reqbuf->sense_key, s);		if (reqbuf->asc == 0x40) {			sprintf (buf, "Diagnostic failure on component 0x%02x",				 reqbuf->ascq);			s = buf;		} else {			int lo, hi;			int key = (reqbuf->asc << 8);			if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) )				key |= reqbuf->ascq;			lo = 0;			hi = ARY_LEN (sense_data_texts);			s = NULL;			while (hi > lo) {				int mid = (lo + hi) / 2;				if (sense_data_texts[mid].asc_ascq == key) {					s = sense_data_texts[mid].text;					break;				}				else if (sense_data_texts[mid].asc_ascq > key)					hi = mid;				else					lo = mid+1;			}		}		if (s == NULL) {			if (reqbuf->asc > 0x80)				s = "(vendor-specific error)";			else				s = "(reserved error code)";		}		printk ("  Additional sense data: 0x%02x, 0x%02x  - %s\n",			reqbuf->asc, reqbuf->ascq, s);		if (failed_command != NULL) {			printk ("  Failed packet command: ");			for (i=0; i<sizeof (failed_command->c); i++)				printk ("%02x ", failed_command->c[i]);			printk ("\n");		}		if (reqbuf->sense_key == ILLEGAL_REQUEST &&		    (reqbuf->sense_key_specific[0] & 0x80) != 0) {			printk ("  Error in %s byte %d",				(reqbuf->sense_key_specific[0] & 0x40) != 0				? "command packet"				: "command data",				(reqbuf->sense_key_specific[1] << 8) +				reqbuf->sense_key_specific[2]);			if ((reqbuf->sense_key_specific[0] & 0x40) != 0) {				printk (" bit %d",					reqbuf->sense_key_specific[0] & 0x07);			}			printk ("\n");		}	}#else /* not VERBOSE_IDE_CD_ERRORS */	/* Suppress printing unit attention and `in progress of becoming ready'	   errors when we're not being verbose. */	if (reqbuf->sense_key == UNIT_ATTENTION ||	    (reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 ||						reqbuf->asc == 0x3a)))		return;	printk ("%s: code: 0x%02x  key: 0x%02x  asc: 0x%02x  ascq: 0x%02x\n",		drive->name,		reqbuf->error_code, reqbuf->sense_key,		reqbuf->asc, reqbuf->ascq);#endif /* not VERBOSE_IDE_CD_ERRORS */}/* Fix up a possibly partially-processed request so that we can   start it over entirely, or even put it back on the request queue. */static void restore_request (struct request *rq){	if (rq->buffer != rq->bh->b_data) {		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;		rq->buffer = rq->bh->b_data;		rq->nr_sectors += n;		rq->sector -= n;	}	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;}static void cdrom_queue_request_sense (ide_drive_t *drive, 				       struct semaphore *sem,				       struct atapi_request_sense *reqbuf,				       struct packet_command *failed_command){	struct request *rq;	struct packet_command *pc;	int len;	/* If the request didn't explicitly specify where	   to put the sense data, use the statically allocated structure. */	if (reqbuf == NULL)		reqbuf = &drive->cdrom_info.sense_data;	/* Make up a new request to retrieve sense information. */	pc = &HWIF(drive)->request_sense_pc;	memset (pc, 0, sizeof (*pc));	/* The request_sense structure has an odd number of (16-bit) words,	   which won't work well with 32-bit transfers.  However, we don't care	   about the last two bytes, so just truncate the structure down	   to an even length. */	len = sizeof (*reqbuf) / 4;	len *= 4;	pc->c[0] = REQUEST_SENSE;	pc->c[4] = len;	pc->buffer = (char *)reqbuf;	pc->buflen = len;	pc->sense_data = (struct atapi_request_sense *)failed_command;	/* stuff the sense request in front of our current request */	rq = &HWIF(drive)->request_sense_request;	ide_init_drive_cmd (rq);	rq->cmd = REQUEST_SENSE_COMMAND;	rq->buffer = (char *)pc;	rq->sem = sem;	(void) ide_do_drive_cmd (drive, rq, ide_preempt);}static void cdrom_end_request (int uptodate, ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {		struct packet_command *pc = (struct packet_command *)			                      rq->buffer;		cdrom_analyze_sense_data (drive,					  (struct atapi_request_sense *)					  	(pc->buffer - pc->c[4]), 					  (struct packet_command *)					  	pc->sense_data);	}	ide_end_request (uptodate, HWGROUP(drive));}/* Mark that we've seen a media change, and invalidate our internal   buffers. */static void cdrom_saw_media_change (ide_drive_t *drive){	CDROM_STATE_FLAGS (drive)->media_changed = 1;	CDROM_STATE_FLAGS (drive)->toc_valid = 0;	drive->cdrom_info.nsectors_buffered = 0;}/* Returns 0 if the request should be continued.   Returns 1 if the request was ended. */static int cdrom_decode_status (ide_drive_t *drive, int good_stat,				int *stat_ret){	struct request *rq = HWGROUP(drive)->rq;	int stat, err, sense_key, cmd;	/* Check for errors. */	stat = GET_STAT();	*stat_ret = stat;	if (OK_STAT (stat, good_stat, BAD_R_STAT))		return 0;	/* Got an error. */	err = IN_BYTE (IDE_ERROR_REG);	sense_key = err >> 4;	if (rq == NULL)		printk ("%s : missing request in cdrom_decode_status\n",			drive->name);	else {		cmd = rq->cmd;		if (cmd == REQUEST_SENSE_COMMAND) {			/* We got an error trying to get sense info			   from the drive (probably while trying			   to recover from a former error).  Just give up. */			struct packet_command *pc = (struct packet_command *)				                      rq->buffer;			pc->stat = 1;			cdrom_end_request (1, drive);			ide_error (drive, "request sense failure", stat);			return 1;		} else if (cmd == PACKET_COMMAND) {			/* All other functions, except for READ. */			struct packet_command *pc = (struct packet_command *)				                      rq->buffer;			struct semaphore *sem = NULL;			/* Check for tray open. */			if (sense_key == NOT_READY) {				cdrom_saw_media_change (drive);				/* Print an error message to the syslog.				   Exception: don't print anything if this				   is a read subchannel command.  This is				   because workman constantly polls the drive				   with this command, and we don't want				   to uselessly fill up the syslog. */				if (pc->c[0] != SCMD_READ_SUBCHANNEL)					printk ("%s : tray open or drive not ready\n",						drive->name);			} else if (sense_key == UNIT_ATTENTION) {				/* Check for media change. */				cdrom_saw_media_change (drive);				printk ("%s: media changed\n", drive->name);			} else {				/* Otherwise, print an error. */				ide_dump_status (drive, "packet command error",						 stat);			}						/* Set the error flag and complete the request.			   Then, if we have a CHECK CONDITION status,			   queue a request sense command.  We must be careful,			   though: we don't want the thread in			   cdrom_queue_packet_command to wake up until			   the request sense has completed.  We do this			   by transferring the semaphore from the packet			   command request to the request sense request. */			if ((stat & ERR_STAT) != 0) {				sem = rq->sem;				rq->sem = NULL;			}			pc->stat = 1;			cdrom_end_request (1, drive);			if ((stat & ERR_STAT) != 0)				cdrom_queue_request_sense (drive, sem,							   pc->sense_data, pc);		} else {			/* Handle errors from READ requests. */			if (sense_key == NOT_READY) {				/* Tray open. */				cdrom_saw_media_change (drive);				/* Fail the request. */				printk ("%s : tray open\n", drive->name);				cdrom_end_request (0, drive);			} else if (sense_key == UNIT_ATTENTION) {				/* Media change. */				cdrom_saw_media_change (drive);				/* Arrange to retry the request.				   But be sure to give up if we've retried				   too many times. */				if (++rq->errors > ERROR_MAX)					cdrom_end_request (0, drive);			} else if (sense_key == ILLEGAL_REQUEST ||				   sense_key == DATA_PROTECT) {				/* No point in retrying after an illegal				   request or data protect error.*/				ide_dump_status (drive, "command error", stat);				cdrom_end_request (0, drive);			} else if ((err & ~ABRT_ERR) != 0) {				/* Go to the default handler				   for other errors. */				ide_error (drive, "cdrom_decode_status", stat);				return 1;			} else if ((++rq->errors > ERROR_MAX)) {				/* We've racked up too many retries.  Abort. */				cdrom_end_request (0, drive);			}			/* If we got a CHECK_CONDITION status,			   queue a request sense command. */			if ((stat & ERR_STAT) != 0)				cdrom_queue_request_sense (drive,							   NULL, NULL, NULL);		}	}	/* Retry, or handle the next request. */	return 1;}/* Set up the device registers for transferring a packet command on DEV,   expecting to later transfer XFERLEN bytes.  HANDLER is the routine   which actually transfers the command to the drive.  If this is a   drq_interrupt device, this routine will arrange for HANDLER to be   called when the interrupt from the drive arrives.  Otherwise, HANDLER   will be called immediately after the drive is prepared for the transfer. */static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,				       ide_handler_t *handler){	/* Wait for the controller to be idle. */	if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;	/* Set up the controller registers. */	OUT_BYTE (0, IDE_FEATURE_REG);	OUT_BYTE (0, IDE_NSECTOR_REG);	OUT_BYTE (0, IDE_SECTOR_REG);	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);	OUT_BYTE (drive->ctl, IDE_CONTROL_REG);	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {		ide_set_handler (drive, handler, WAIT_CMD);		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */	} else {		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */		(*handler) (drive);	}	return 0;}/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.   The device registers must have already been prepared   by cdrom_start_packet_command.   HANDLER is the interrupt handler to call when the command completes   or there's data ready. */static int cdrom_transfer_packet_command (ide_drive_t *drive,                                          char *cmd_buf, int cmd_len,					  ide_handler_t *handler){	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {		/* Here we should have been called after receiving an interrupt		   from the device.  DRQ should how be set. */		int stat_dum;		/* Check for errors. */		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;	} else {		/* Otherwise, we must wait for DRQ to get set. */		if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))			return 1;	}	/* Arm the interrupt handler. */	ide_set_handler (drive, handler, WAIT_CMD);	/* Send the command to the device. */	cdrom_out_bytes (drive, cmd_buf, cmd_len);	return 0;}/**************************************************************************** * Block read functions. *//* * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector * buffer.  Once the first sector is added, any subsequent sectors are * assumed to be continuous (until the buffer is cleared).  For the first * sector added, SECTOR is its sector number.  (SECTOR is then ignored until * the buffer is cleared.) */static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,                                  int sectors_to_transfer){	struct cdrom_info *info = &drive->cdrom_info;	/* Number of sectors to read into the buffer. */	int sectors_to_buffer = MIN (sectors_to_transfer,				     (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -				       info->nsectors_buffered);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -