Commit 72064a78 authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen
Browse files

ncr5380: Standardize reselection handling



Bring the two NCR5380_reselect() implementations into agreement.

Replace infinite loops in atari_NCR5380.c with timeouts, as per NCR5380.c.

Remove 'abort' flag in NCR5380.c as per atari_NCR5380.c -- if reselection
fails, there may be no MESSAGE IN phase so don't attempt data transfer.

During selection, don't interfere with the chip registers after a
reselection interrupt intervenes.

Clean up some trivial issues with code style, comments and printk.

Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Tested-by: default avatarOndrej Zary <linux@rainbow-software.org>
Tested-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 9db6024e
Loading
Loading
Loading
Loading
+64 −51
Original line number Diff line number Diff line
@@ -1182,6 +1182,10 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
	else
		udelay(2);

	/* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
	if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
		return -1;

	dprintk(NDEBUG_ARBITRATION, "scsi%d : won arbitration\n", instance->host_no);

	/* 
@@ -1953,12 +1957,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
						cmd->scsi_done(cmd);
					}

					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
					/* 
					 * Restore phase bits to 0 so an interrupted selection, 
					 * arbitration can resume.
					 */
					NCR5380_write(TARGET_COMMAND_REG, 0);

					/* Enable reselect interrupts */
					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
					return;
				case MESSAGE_REJECT:
					/* Accept message by clearing ACK */
@@ -2144,7 +2150,6 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
	unsigned char msg[3];
	unsigned char *data;
	struct scsi_cmnd *tmp = NULL, *prev;
	int abort = 0;

	/*
	 * Disable arbitration, etc. since the host adapter obviously
@@ -2154,7 +2159,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
	NCR5380_write(MODE_REG, MR_BASE);

	target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
	dprintk(NDEBUG_SELECTION, "scsi%d : reselect\n", instance->host_no);
	dprintk(NDEBUG_RESELECTION, "scsi%d : reselect\n", instance->host_no);

	/* 
	 * At this point, we have detected that our SCSI ID is on the bus,
@@ -2166,35 +2171,41 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
	 */

	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);

	/* FIXME: timeout too long, must fail to workqueue */	
	if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
		abort = 1;
		
	if (NCR5380_poll_politely(instance,
	                          STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
		return;
	}
	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);

	/*
	 * Wait for target to go into MSGIN.
	 * FIXME: timeout needed and fail to work queeu
	 */

	if (NCR5380_poll_politely(instance,
	                          STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0)
		abort = 1;
	                          STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
		do_abort(instance);
		return;
	}

	len = 1;
	data = msg;
	phase = PHASE_MSGIN;
	NCR5380_transfer_pio(instance, &phase, &len, &data);

	if (len) {
		do_abort(instance);
		return;
	}

	if (!(msg[0] & 0x80)) {
		printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
		shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
		spi_print_msg(msg);
		abort = 1;
	} else {
		/* Accept message by clearing ACK */
		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
		lun = (msg[0] & 0x07);
		printk("\n");
		do_abort(instance);
		return;
	}
	lun = msg[0] & 0x07;

	/*
	 * We need to add code for SCSI-II to track which devices have
@@ -2207,36 +2218,38 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
	 * just reestablished, and remove it from the disconnected queue.
	 */


		for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
			if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
			    ) {
	for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
	     tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble) {
		if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)) {
			if (prev) {
				REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
				prev->host_scribble = tmp->host_scribble;
			} else {
				REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
					hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
				hostdata->disconnected_queue =
					(struct scsi_cmnd *) tmp->host_scribble;
			}
			tmp->host_scribble = NULL;
			break;
		}
	}
	if (!tmp) {
			printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
		shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
		             target_mask, lun);
		/*
		 * Since we have an established nexus that we can't do anything with,
		 * we must abort it.
		 */
			abort = 1;
		}
		do_abort(instance);
		return;
	}

	if (abort) {
		do_abort(instance);
	} else {
	/* Accept message by clearing ACK */
	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);

	hostdata->connected = tmp;
		dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n", instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
	}
	dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n",
	        instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
}

/*
+29 −21
Original line number Diff line number Diff line
@@ -1446,11 +1446,9 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
	else
		udelay(2);

	if (hostdata->connected) {
		NCR5380_write(MODE_REG, MR_BASE);
		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
	/* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
	if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
		return -1;
	}

	dprintk(NDEBUG_ARBITRATION, "scsi%d: won arbitration\n", HOSTNO);

@@ -2223,13 +2221,15 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
						cmd->scsi_done(cmd);
					}

					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
					/*
					 * Restore phase bits to 0 so an interrupted selection,
					 * arbitration can resume.
					 */
					NCR5380_write(TARGET_COMMAND_REG, 0);

					/* Enable reselect interrupts */
					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);

					/* ++roman: For Falcon SCSI, release the lock on the
					 * ST-DMA here if no other commands are waiting on the
					 * disconnected queue.
@@ -2482,17 +2482,22 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
	 */

	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);

	while (NCR5380_read(STATUS_REG) & SR_SEL)
		;
	if (NCR5380_poll_politely(instance,
	                          STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
		return;
	}
	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);

	/*
	 * Wait for target to go into MSGIN.
	 */

	while (!(NCR5380_read(STATUS_REG) & SR_REQ))
		;
	if (NCR5380_poll_politely(instance,
	                          STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
		do_abort(instance);
		return;
	}

#if defined(CONFIG_SUN3) && defined(REAL_DMA)
	/* acknowledge toggle to MSGIN */
@@ -2505,15 +2510,21 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
	data = msg;
	phase = PHASE_MSGIN;
	NCR5380_transfer_pio(instance, &phase, &len, &data);

	if (len) {
		do_abort(instance);
		return;
	}
#endif

	if (!(msg[0] & 0x80)) {
		printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
		shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
		spi_print_msg(msg);
		printk("\n");
		do_abort(instance);
		return;
	}
	lun = (msg[0] & 0x07);
	lun = msg[0] & 0x07;

#if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3)
	/* If the phase is still MSGIN, the target wants to send some more
@@ -2541,7 +2552,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance)

	for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
	     tmp; prev = tmp, tmp = NEXT(tmp)) {
		if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
		if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
#ifdef SUPPORT_TAGS
		    && (tag == tmp->tag)
#endif
@@ -2559,16 +2570,13 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
	}

	if (!tmp) {
		printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
#ifdef SUPPORT_TAGS
		       "tag %d "
#endif
		       "not in disconnected_queue.\n",
		       HOSTNO, target_mask, lun
#ifdef SUPPORT_TAGS
		       , tag
		shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d tag %d not in disconnected queue.\n",
		             target_mask, lun, tag);
#else
		shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
		             target_mask, lun);
#endif
			);
		/*
		 * Since we have an established nexus that we can't do anything
		 * with, we must abort it.