Skip to content

Commit 1ae948f

Browse files
bjking1martinkpetersen
authored andcommitted
scsi: aacraid: Fix command send race condition
This fixes a potential race condition observed on Power systems. Several places throughout the aacraid driver call aac_fib_send or similar to send a command to the aacraid adapter, then check the return code to determine if the command was actually sent to the adapter, then update the phase field in the scsi command scratch pad area to track that the firmware now owns this command. However, there is nothing that ensures that by the time the aac_fib_send function returns and we go to write to the scsi command, that the command hasn't already completed and the scsi command has been freed. This was causing random crashes in the TCP stack which was tracked down to be caused by memory that had been a struct request + scsi_cmnd being now used for an skbuff. Memory poisoning was enabled in the kernel to debug this which showed that the last owner of the memory that had been freed was aacraid and that it was a struct request. The memory that was corrupted was the exact data pattern of AAC_OWNER_FIRMWARE and it was at the same offset that aacraid writes, which is scsicmd->SCp.phase. The patch below resolves this issue. Cc: <[email protected]> Signed-off-by: Brian King <[email protected]> Tested-by: Wen Xiong <[email protected]> Reviewed-by: Dave Carroll <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent fa2d9d6 commit 1ae948f

File tree

1 file changed

+21
-33
lines changed

1 file changed

+21
-33
lines changed

drivers/scsi/aacraid/aachba.c

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
594594

595595
aac_fib_init(cmd_fibcontext);
596596
dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
597+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
597598

598599
dinfo->command = cpu_to_le32(VM_ContainerConfig);
599600
dinfo->type = cpu_to_le32(CT_READ_NAME);
@@ -611,10 +612,8 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
611612
/*
612613
* Check that the command queued to the controller
613614
*/
614-
if (status == -EINPROGRESS) {
615-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
615+
if (status == -EINPROGRESS)
616616
return 0;
617-
}
618617

619618
printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
620619
aac_fib_complete(cmd_fibcontext);
@@ -725,6 +724,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr)
725724

726725
dinfo->count = cpu_to_le32(scmd_id(scsicmd));
727726
dinfo->type = cpu_to_le32(FT_FILESYS);
727+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
728728

729729
status = aac_fib_send(ContainerCommand,
730730
fibptr,
@@ -736,9 +736,7 @@ static void _aac_probe_container1(void * context, struct fib * fibptr)
736736
/*
737737
* Check that the command queued to the controller
738738
*/
739-
if (status == -EINPROGRESS)
740-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
741-
else if (status < 0) {
739+
if (status < 0 && status != -EINPROGRESS) {
742740
/* Inherit results from VM_NameServe, if any */
743741
dresp->status = cpu_to_le32(ST_OK);
744742
_aac_probe_container2(context, fibptr);
@@ -766,6 +764,7 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru
766764
dinfo->count = cpu_to_le32(scmd_id(scsicmd));
767765
dinfo->type = cpu_to_le32(FT_FILESYS);
768766
scsicmd->SCp.ptr = (char *)callback;
767+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
769768

770769
status = aac_fib_send(ContainerCommand,
771770
fibptr,
@@ -777,10 +776,9 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru
777776
/*
778777
* Check that the command queued to the controller
779778
*/
780-
if (status == -EINPROGRESS) {
781-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
779+
if (status == -EINPROGRESS)
782780
return 0;
783-
}
781+
784782
if (status < 0) {
785783
scsicmd->SCp.ptr = NULL;
786784
aac_fib_complete(fibptr);
@@ -1126,6 +1124,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
11261124
dinfo->command = cpu_to_le32(VM_ContainerConfig);
11271125
dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
11281126
dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
1127+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
11291128

11301129
status = aac_fib_send(ContainerCommand,
11311130
cmd_fibcontext,
@@ -1138,10 +1137,8 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
11381137
/*
11391138
* Check that the command queued to the controller
11401139
*/
1141-
if (status == -EINPROGRESS) {
1142-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
1140+
if (status == -EINPROGRESS)
11431141
return 0;
1144-
}
11451142

11461143
printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
11471144
aac_fib_complete(cmd_fibcontext);
@@ -2335,16 +2332,14 @@ static int aac_read(struct scsi_cmnd * scsicmd)
23352332
* Alocate and initialize a Fib
23362333
*/
23372334
cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
2338-
2335+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
23392336
status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
23402337

23412338
/*
23422339
* Check that the command queued to the controller
23432340
*/
2344-
if (status == -EINPROGRESS) {
2345-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2341+
if (status == -EINPROGRESS)
23462342
return 0;
2347-
}
23482343

23492344
printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
23502345
/*
@@ -2429,16 +2424,14 @@ static int aac_write(struct scsi_cmnd * scsicmd)
24292424
* Allocate and initialize a Fib then setup a BlockWrite command
24302425
*/
24312426
cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
2432-
2427+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
24332428
status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
24342429

24352430
/*
24362431
* Check that the command queued to the controller
24372432
*/
2438-
if (status == -EINPROGRESS) {
2439-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2433+
if (status == -EINPROGRESS)
24402434
return 0;
2441-
}
24422435

24432436
printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status);
24442437
/*
@@ -2588,6 +2581,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
25882581
synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
25892582
synchronizecmd->count =
25902583
cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
2584+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
25912585

25922586
/*
25932587
* Now send the Fib to the adapter
@@ -2603,10 +2597,8 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
26032597
/*
26042598
* Check that the command queued to the controller
26052599
*/
2606-
if (status == -EINPROGRESS) {
2607-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2600+
if (status == -EINPROGRESS)
26082601
return 0;
2609-
}
26102602

26112603
printk(KERN_WARNING
26122604
"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
@@ -2666,6 +2658,7 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
26662658
pmcmd->cid = cpu_to_le32(sdev_id(sdev));
26672659
pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
26682660
cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
2661+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
26692662

26702663
/*
26712664
* Now send the Fib to the adapter
@@ -2681,10 +2674,8 @@ static int aac_start_stop(struct scsi_cmnd *scsicmd)
26812674
/*
26822675
* Check that the command queued to the controller
26832676
*/
2684-
if (status == -EINPROGRESS) {
2685-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
2677+
if (status == -EINPROGRESS)
26862678
return 0;
2687-
}
26882679

26892680
aac_fib_complete(cmd_fibcontext);
26902681
aac_fib_free(cmd_fibcontext);
@@ -3692,16 +3683,14 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
36923683
* Allocate and initialize a Fib then setup a BlockWrite command
36933684
*/
36943685
cmd_fibcontext = aac_fib_alloc_tag(dev, scsicmd);
3695-
3686+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
36963687
status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
36973688

36983689
/*
36993690
* Check that the command queued to the controller
37003691
*/
3701-
if (status == -EINPROGRESS) {
3702-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
3692+
if (status == -EINPROGRESS)
37033693
return 0;
3704-
}
37053694

37063695
printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status);
37073696
aac_fib_complete(cmd_fibcontext);
@@ -3739,15 +3728,14 @@ static int aac_send_hba_fib(struct scsi_cmnd *scsicmd)
37393728
if (!cmd_fibcontext)
37403729
return -1;
37413730

3731+
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
37423732
status = aac_adapter_hba(cmd_fibcontext, scsicmd);
37433733

37443734
/*
37453735
* Check that the command queued to the controller
37463736
*/
3747-
if (status == -EINPROGRESS) {
3748-
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
3737+
if (status == -EINPROGRESS)
37493738
return 0;
3750-
}
37513739

37523740
pr_warn("aac_hba_cmd_req: aac_fib_send failed with status: %d\n",
37533741
status);

0 commit comments

Comments
 (0)