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: Hannes Reinecke <hare@suse.de> Link: https://lore.kernel.org/r/20231002154328.43718-8-hare@suse.de Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
958230bcdd
commit
10f5aa018f
@ -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");
|
||||
|
||||
printk("CDB:");
|
||||
for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
|
||||
printk(" 0x%x", cmd->cmnd[cdb_byte]);
|
||||
printk("\n");
|
||||
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)
|
||||
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))
|
||||
if (cmd) {
|
||||
LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
|
||||
if (scb->io_ctx == cmd) {
|
||||
pending_scb = scb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Any SCB for this device will do for a target reset */
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user