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

📄 aic7xxx_osm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * structure if it is available.		 */		cmd = scb->io_ctx;		if (scb->flags & SCB_SENSE) {			u_int sense_size;			sense_size = MIN(sizeof(struct scsi_sense_data)				       - ahc_get_sense_residual(scb),					 sizeof(cmd->sense_buffer));			memcpy(cmd->sense_buffer,			       ahc_get_sense_buf(ahc, scb), sense_size);			if (sense_size < sizeof(cmd->sense_buffer))				memset(&cmd->sense_buffer[sense_size], 0,				       sizeof(cmd->sense_buffer) - sense_size);			cmd->result |= (DRIVER_SENSE << 24);#ifdef AHC_DEBUG			if (ahc_debug & AHC_SHOW_SENSE) {				int i;				printf("Copied %d bytes of sense data:",				       sense_size);				for (i = 0; i < sense_size; i++) {					if ((i & 0xF) == 0)						printf("\n");					printf("0x%x ", cmd->sense_buffer[i]);				}				printf("\n");			}#endif		}		break;	}	case SCSI_STATUS_QUEUE_FULL:	{		/*		 * By the time the core driver has returned this		 * command, all other commands that were queued		 * to us but not the device have been returned.		 * This ensures that dev->active is equal to		 * the number of commands actually queued to		 * the device.		 */		dev->tag_success_count = 0;		if (dev->active != 0) {			/*			 * Drop our opening count to the number			 * of commands currently outstanding.			 */			dev->openings = 0;/*			ahc_print_path(ahc, scb);			printf("Dropping tag count to %d\n", dev->active); */			if (dev->active == dev->tags_on_last_queuefull) {				dev->last_queuefull_same_count++;				/*				 * If we repeatedly see a queue full				 * at the same queue depth, this				 * device has a fixed number of tag				 * slots.  Lock in this tag depth				 * so we stop seeing queue fulls from				 * this device.				 */				if (dev->last_queuefull_same_count				 == AHC_LOCK_TAGS_COUNT) {					dev->maxtags = dev->active;					ahc_print_path(ahc, scb);					printf("Locking max tag count at %d\n",					       dev->active);				}			} else {				dev->tags_on_last_queuefull = dev->active;				dev->last_queuefull_same_count = 0;			}			ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);			ahc_set_scsi_status(scb, SCSI_STATUS_OK);			ahc_platform_set_tags(ahc, &devinfo,				     (dev->flags & AHC_DEV_Q_BASIC)				   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);			break;		}		/*		 * Drop down to a single opening, and treat this		 * as if the target returned BUSY SCSI status.		 */		dev->openings = 1;		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);		ahc_platform_set_tags(ahc, &devinfo,			     (dev->flags & AHC_DEV_Q_BASIC)			   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);		break;	}	}}static voidahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd){	/*	 * Map CAM error codes into Linux Error codes.  We	 * avoid the conversion so that the DV code has the	 * full error information available when making	 * state change decisions.	 */	{		u_int new_status;		switch (ahc_cmd_get_transaction_status(cmd)) {		case CAM_REQ_INPROG:		case CAM_REQ_CMP:		case CAM_SCSI_STATUS_ERROR:			new_status = DID_OK;			break;		case CAM_REQ_ABORTED:			new_status = DID_ABORT;			break;		case CAM_BUSY:			new_status = DID_BUS_BUSY;			break;		case CAM_REQ_INVALID:		case CAM_PATH_INVALID:			new_status = DID_BAD_TARGET;			break;		case CAM_SEL_TIMEOUT:			new_status = DID_NO_CONNECT;			break;		case CAM_SCSI_BUS_RESET:		case CAM_BDR_SENT:			new_status = DID_RESET;			break;		case CAM_UNCOR_PARITY:			new_status = DID_PARITY;			break;		case CAM_CMD_TIMEOUT:			new_status = DID_TIME_OUT;			break;		case CAM_UA_ABORT:		case CAM_REQ_CMP_ERR:		case CAM_AUTOSENSE_FAIL:		case CAM_NO_HBA:		case CAM_DATA_RUN_ERR:		case CAM_UNEXP_BUSFREE:		case CAM_SEQUENCE_FAIL:		case CAM_CCB_LEN_ERR:		case CAM_PROVIDE_FAIL:		case CAM_REQ_TERMIO:		case CAM_UNREC_HBA_ERROR:		case CAM_REQ_TOO_BIG:			new_status = DID_ERROR;			break;		case CAM_REQUEUE_REQ:			new_status = DID_REQUEUE;			break;		default:			/* We should never get here */			new_status = DID_ERROR;			break;		}		ahc_cmd_set_transaction_status(cmd, new_status);	}	cmd->scsi_done(cmd);}static voidahc_linux_sem_timeout(u_long arg){	struct	ahc_softc *ahc;	u_long	s;	ahc = (struct ahc_softc *)arg;	ahc_lock(ahc, &s);	if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) {		ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE;		up(&ahc->platform_data->eh_sem);	}	ahc_unlock(ahc, &s);}static voidahc_linux_freeze_simq(struct ahc_softc *ahc){	ahc->platform_data->qfrozen++;	if (ahc->platform_data->qfrozen == 1) {		scsi_block_requests(ahc->platform_data->host);		/* XXX What about Twin channels? */		ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,					CAM_LUN_WILDCARD, SCB_LIST_NULL,					ROLE_INITIATOR, CAM_REQUEUE_REQ);	}}static voidahc_linux_release_simq(u_long arg){	struct ahc_softc *ahc;	u_long s;	int    unblock_reqs;	ahc = (struct ahc_softc *)arg;	unblock_reqs = 0;	ahc_lock(ahc, &s);	if (ahc->platform_data->qfrozen > 0)		ahc->platform_data->qfrozen--;	if (ahc->platform_data->qfrozen == 0)		unblock_reqs = 1;	ahc_unlock(ahc, &s);	/*	 * There is still a race here.  The mid-layer	 * should keep its own freeze count and use	 * a bottom half handler to run the queues	 * so we can unblock with our own lock held.	 */	if (unblock_reqs)		scsi_unblock_requests(ahc->platform_data->host);}static intahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag){	struct ahc_softc *ahc;	struct ahc_linux_device *dev;	struct scb *pending_scb;	u_int  saved_scbptr;	u_int  active_scb_index;	u_int  last_phase;	u_int  saved_scsiid;	u_int  cdb_byte;	int    retval;	int    was_paused;	int    paused;	int    wait;	int    disconnected;	unsigned long flags;	pending_scb = NULL;	paused = FALSE;	wait = FALSE;	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;	scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n",	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");	printf("CDB:");	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)		printf(" 0x%x", cmd->cmnd[cdb_byte]);	printf("\n");	ahc_lock(ahc, &flags);	/*	 * First determine if we currently own this command.	 * Start by searching the device queue.  If not found	 * there, check the pending_scb list.  If not found	 * at all, and the system wanted us to just abort the	 * command, return success.	 */	dev = scsi_transport_device_data(cmd->device);	if (dev == NULL) {		/*		 * No target device for this command exists,		 * so we must not still own the command.		 */		printf("%s:%d:%d:%d: Is not an active device\n",		       ahc_name(ahc), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		retval = SUCCESS;		goto no_cmd;	}	if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0	 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id,				       cmd->device->channel + 'A',				       cmd->device->lun,				       CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {		printf("%s:%d:%d:%d: Command found on untagged queue\n",		       ahc_name(ahc), cmd->device->channel, cmd->device->id,		       cmd->device->lun);		retval = SUCCESS;		goto done;	}	/*	 * See if we can find a matching cmd in the pending list.	 */	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {		if (pending_scb->io_ctx == cmd)			break;	}	if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {		/* Any SCB for this device will do for a target reset */		LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {		  	if (ahc_match_scb(ahc, pending_scb, scmd_id(cmd),					  scmd_channel(cmd) + 'A',					  CAM_LUN_WILDCARD,					  SCB_LIST_NULL, ROLE_INITIATOR))				break;		}	}	if (pending_scb == NULL) {		scmd_printk(KERN_INFO, cmd, "Command not found\n");		goto no_cmd;	}	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {		/*		 * We can't queue two recovery actions using the same SCB		 */		retval = FAILED;		goto  done;	}	/*	 * Ensure that the card doesn't do anything	 * behind our back and that we didn't "just" miss	 * an interrupt that would affect this cmd.	 */	was_paused = ahc_is_paused(ahc);	ahc_pause_and_flushwork(ahc);	paused = TRUE;	if ((pending_scb->flags & SCB_ACTIVE) == 0) {		scmd_printk(KERN_INFO, cmd, "Command already completed\n");		goto no_cmd;	}	printf("%s: At time of recovery, card was %spaused\n",	       ahc_name(ahc), was_paused ? "" : "not ");	ahc_dump_card_state(ahc);	disconnected = TRUE;	if (flag == SCB_ABORT) {		if (ahc_search_qinfifo(ahc, cmd->device->id,				       cmd->device->channel + 'A',				       cmd->device->lun,				       pending_scb->hscb->tag,				       ROLE_INITIATOR, CAM_REQ_ABORTED,				       SEARCH_COMPLETE) > 0) {			printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",			       ahc_name(ahc), cmd->device->channel,					cmd->device->id, cmd->device->lun);			retval = SUCCESS;			goto done;		}	} else if (ahc_search_qinfifo(ahc, cmd->device->id,				      cmd->device->channel + 'A',				      cmd->device->lun, pending_scb->hscb->tag,				      ROLE_INITIATOR, /*status*/0,				      SEARCH_COUNT) > 0) {		disconnected = FALSE;	}	if (disconnected && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {		struct scb *bus_scb;		bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG));		if (bus_scb == pending_scb)			disconnected = FALSE;		else if (flag != SCB_ABORT		      && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid		      && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb))			disconnected = FALSE;	}	/*	 * At this point, pending_scb is the scb associated with the	 * passed in command.  That command is currently active on the	 * bus, is in the disconnected state, or we're hoping to find	 * a command for the same target active on the bus to abuse to	 * send a BDR.  Queue the appropriate message based on which of	 * these states we are in.	 */	last_phase = ahc_inb(ahc, LASTPHASE);	saved_scbptr = ahc_inb(ahc, SCBPTR);	active_scb_index = ahc_inb(ahc, SCB_TAG);	saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);	if (last_phase != P_BUSFREE	 && (pending_scb->hscb->tag == active_scb_index	  || (flag == SCB_DEVICE_RESET	   && SCSIID_TARGET(ahc, saved_scsiid) == scmd_id(cmd)))) {		/*		 * We're active on the bus, so assert ATN		 * and hope that the target responds.		 */		pending_scb = ahc_lookup_scb(ahc, active_scb_index);		pending_scb->flags |= SCB_RECOVERY_SCB|flag;		ahc_outb(ahc, MSG_OUT, HOST_MSG);		ahc_outb(ahc, SCSISIGO, last_phase|ATNO);		scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n");		wait = TRUE;	} else if (disconnected) {		/*		 * Actually re-queue this SCB in an attempt		 * to select the device before it reconnects.		 * In either case (selection or reselection),		 * we will now issue the approprate message		 * to the timed-out device.		 *		 * Set the MK_MESSAGE control bit indicating		 * that we desire to send a message.  We		 * also set the disconnected flag since		 * in the paging case there is no guarantee		 * that our SCB control byte matches the		 * version on the card.  We don't want the		 * sequencer to abort the command thinking		 * an unsolicited reselection occurred.		 */		pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;		pending_scb->flags |= SCB_RECOVERY_SCB|flag;		/*		 * Remove any cached copy of this SCB in the		 * disconnected list in preparation for the		 * queuing of our abort SCB.  We use the		 * same element in the SCB, SCB_NEXT, for		 * both the qinfifo and the disconnected list.		 */		ahc_search_disc_list(ahc, cmd->device->id,				     cmd->device->channel + 'A',				     cmd->device->lun, pending_scb->hscb->tag,				     /*stop_on_first*/TRUE,				     /*remove*/TRUE,				     /*save_state*/FALSE);		/*		 * In the non-paging case, the sequencer will		 * never re-reference the in-core SCB.		 * To make sure we are notified during		 * reslection, set the MK_MESSAGE flag in		 * the card's copy of the SCB.		 */		if ((ahc->flags & AHC_PAGESCBS) == 0) {			ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag);			ahc_outb(ahc, SCB_CONTROL,				 ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE);		}		/*		 * Clear out any entries in the QINFIFO first		 * so we are the next SCB for this target		 * to run.		 */		ahc_search_qinfifo(ahc, cmd->device->id,				   cmd->device->channel + 'A',				   cmd->device->lun, SCB_LIST_NULL,				   ROLE_INITIATOR, CAM_REQUEUE_REQ,				   SEARCH_COMPLETE);		ahc_qinfifo_requeue_tail(ahc, pending_scb);		ahc_outb(ahc, SCBPTR, saved_scbptr);		ahc_print_path(ahc, pending_scb);		printf("Device is disconnected, re-queuing SCB\n");		wait = TRUE;	} else {		scmd_printk(KERN_INFO, cmd, "Unable t

⌨️ 快捷键说明

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