Commit 10f5aa01 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin K. Petersen
Browse files

scsi: aic7xxx: Do not reference SCSI command when resetting device



When sending a device reset we should not take a reference to the SCSI
command.

Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Link: https://lore.kernel.org/r/20231002154328.43718-8-hare@suse.de


Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 958230bc
Loading
Loading
Loading
Loading
+57 −51
Original line number Diff line number Diff line
@@ -366,7 +366,8 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
					 struct scsi_cmnd *cmd);
static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
static void ahc_linux_release_simq(struct ahc_softc *ahc);
static int  ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
static int  ahc_linux_queue_recovery_cmd(struct scsi_device *sdev,
					 struct scsi_cmnd *cmd);
static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
				     struct ahc_devinfo *devinfo);
@@ -728,7 +729,7 @@ ahc_linux_abort(struct scsi_cmnd *cmd)
{
	int error;

	error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
	error = ahc_linux_queue_recovery_cmd(cmd->device, cmd);
	if (error != SUCCESS)
		printk("aic7xxx_abort returns 0x%x\n", error);
	return (error);
@@ -742,7 +743,7 @@ ahc_linux_dev_reset(struct scsi_cmnd *cmd)
{
	int error;

	error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
	error = ahc_linux_queue_recovery_cmd(cmd->device, NULL);
	if (error != SUCCESS)
		printk("aic7xxx_dev_reset returns 0x%x\n", error);
	return (error);
@@ -2036,11 +2037,12 @@ ahc_linux_release_simq(struct ahc_softc *ahc)
}

static int
ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
ahc_linux_queue_recovery_cmd(struct scsi_device *sdev,
			     struct scsi_cmnd *cmd)
{
	struct ahc_softc *ahc;
	struct ahc_linux_device *dev;
	struct scb *pending_scb;
	struct scb *pending_scb = NULL, *scb;
	u_int  saved_scbptr;
	u_int  active_scb_index;
	u_int  last_phase;
@@ -2053,18 +2055,19 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
	int    disconnected;
	unsigned long flags;

	pending_scb = NULL;
	paused = FALSE;
	wait = FALSE;
	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
	ahc = *(struct ahc_softc **)sdev->host->hostdata;

	scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n",
	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
	sdev_printk(KERN_INFO, sdev, "Attempting to queue a%s message\n",
	       cmd ? "n ABORT" : " TARGET RESET");

	if (cmd) {
		printk("CDB:");
		for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
			printk(" 0x%x", cmd->cmnd[cdb_byte]);
		printk("\n");
	}

	ahc_lock(ahc, &flags);

@@ -2075,7 +2078,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
	 * at all, and the system wanted us to just abort the
	 * command, return success.
	 */
	dev = scsi_transport_device_data(cmd->device);
	dev = scsi_transport_device_data(sdev);

	if (dev == NULL) {
		/*
@@ -2083,13 +2086,12 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		 * so we must not still own the command.
		 */
		printk("%s:%d:%d:%d: Is not an active device\n",
		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
		       (u8)cmd->device->lun);
		       ahc_name(ahc), sdev->channel, sdev->id, (u8)sdev->lun);
		retval = SUCCESS;
		goto no_cmd;
	}

	if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
	if (cmd && (dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
	 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id,
				       cmd->device->channel + 'A',
				       (u8)cmd->device->lun,
@@ -2104,25 +2106,28 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
	/*
	 * 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)
	if (cmd) {
		LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
			if (scb->io_ctx == cmd) {
				pending_scb = scb;
				break;
			}

	if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {

		}
	} else {
		/* 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',
		LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
			if (ahc_match_scb(ahc, scb, sdev->id,
					  sdev->channel + 'A',
					  CAM_LUN_WILDCARD,
					  SCB_LIST_NULL, ROLE_INITIATOR))
					  SCB_LIST_NULL, ROLE_INITIATOR)) {
				pending_scb = scb;
				break;
			}
		}
	}

	if (pending_scb == NULL) {
		scmd_printk(KERN_INFO, cmd, "Command not found\n");
		sdev_printk(KERN_INFO, sdev, "Command not found\n");
		goto no_cmd;
	}

@@ -2153,22 +2158,22 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
	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,
	if (cmd) {
		if (ahc_search_qinfifo(ahc, sdev->id,
				       sdev->channel + 'A',
				       sdev->lun,
				       pending_scb->hscb->tag,
				       ROLE_INITIATOR, CAM_REQ_ABORTED,
				       SEARCH_COMPLETE) > 0) {
			printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
			       ahc_name(ahc), cmd->device->channel,
			       cmd->device->id, (u8)cmd->device->lun);
			       ahc_name(ahc), sdev->channel,
			       sdev->id, (u8)sdev->lun);
			retval = SUCCESS;
			goto done;
		}
	} else if (ahc_search_qinfifo(ahc, cmd->device->id,
				      cmd->device->channel + 'A',
				      cmd->device->lun,
	} else if (ahc_search_qinfifo(ahc, sdev->id,
				      sdev->channel + 'A',
				      sdev->lun,
				      pending_scb->hscb->tag,
				      ROLE_INITIATOR, /*status*/0,
				      SEARCH_COUNT) > 0) {
@@ -2181,7 +2186,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG));
		if (bus_scb == pending_scb)
			disconnected = FALSE;
		else if (flag != SCB_ABORT
		else if (!cmd
		      && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid
		      && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb))
			disconnected = FALSE;
@@ -2201,18 +2206,18 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
	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)))) {
	  || (!cmd && SCSIID_TARGET(ahc, saved_scsiid) == sdev->id))) {

		/*
		 * 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;
		pending_scb->flags |= SCB_RECOVERY_SCB;
		pending_scb->flags |= cmd ? SCB_ABORT : SCB_DEVICE_RESET;
		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");
		sdev_printk(KERN_INFO, sdev, "Device is active, asserting ATN\n");
		wait = TRUE;
	} else if (disconnected) {

@@ -2233,7 +2238,8 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		 * an unsolicited reselection occurred.
		 */
		pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
		pending_scb->flags |= SCB_RECOVERY_SCB;
		pending_scb->flags |= cmd ? SCB_ABORT : SCB_DEVICE_RESET;

		/*
		 * Remove any cached copy of this SCB in the
@@ -2242,9 +2248,9 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		 * 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,
		ahc_search_disc_list(ahc, sdev->id,
				     sdev->channel + 'A',
				     sdev->lun, pending_scb->hscb->tag,
				     /*stop_on_first*/TRUE,
				     /*remove*/TRUE,
				     /*save_state*/FALSE);
@@ -2267,9 +2273,9 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		 * 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,
		ahc_search_qinfifo(ahc, sdev->id,
				   sdev->channel + 'A',
				   (u8)sdev->lun, SCB_LIST_NULL,
				   ROLE_INITIATOR, CAM_REQUEUE_REQ,
				   SEARCH_COMPLETE);
		ahc_qinfifo_requeue_tail(ahc, pending_scb);
@@ -2278,7 +2284,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
		printk("Device is disconnected, re-queuing SCB\n");
		wait = TRUE;
	} else {
		scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n");
		sdev_printk(KERN_INFO, sdev, "Unable to deliver message\n");
		retval = FAILED;
		goto done;
	}