diff options
author | Samuel Holland <samuel@sholland.org> | 2021-04-27 18:59:15 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2021-05-15 18:01:34 -0400 |
commit | 05f7f1b9ee8273eab805da3d5e2d064872aa75b1 (patch) | |
tree | 10e035dceb00bbbf649dfa00204df4619503feaf /drivers/scsi/3w-9xxx.c | |
parent | d133b441488d30b0ee1848238a1f6e8da643e19c (diff) |
scsi: 3w-9xxx: Fix endianness issues in command packets
The controller expects all data it sends/receives to be little-endian.
Therefore, the packet struct definitions should use the __le16/32/64
types. Once those are correct, sparse reports several issues with the
driver code, which are fixed here as well.
The main issue observed was at the call to scsi_set_resid(), where the
byteswapped parameter would eventually trigger the alignment check at
drivers/scsi/sd.c:2009. At that point, the kernel would continuously
complain about an "Unaligned partial completion", and no further I/O could
occur.
This gets the controller working on big endian powerpc64.
Link: https://lore.kernel.org/r/20210427235915.39211-4-samuel@sholland.org
Signed-off-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/3w-9xxx.c')
-rw-r--r-- | drivers/scsi/3w-9xxx.c | 56 |
1 files changed, 25 insertions, 31 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index c91e20515767..2b4b629a6e96 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -303,10 +303,10 @@ static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) /* Initialize sglist */ memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { + if (tw_dev->generic_buffer_phys[request_id] & TW_ALIGNMENT_9000_SGL) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); goto out; } @@ -440,8 +440,8 @@ static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) /* Initialize sglist */ memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); /* Mark internal command */ tw_dev->srb[request_id] = NULL; @@ -501,9 +501,8 @@ static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) Sunday 12:00AM */ local_time = (ktime_get_real_seconds() - (sys_tz.tz_minuteswest * 60)); div_u64_rem(local_time - (3 * 86400), 604800, &schedulertime); - schedulertime = cpu_to_le32(schedulertime % 604800); - memcpy(param->data, &schedulertime, sizeof(u32)); + memcpy(param->data, &(__le32){cpu_to_le32(schedulertime)}, sizeof(__le32)); /* Mark internal command */ tw_dev->srb[request_id] = NULL; @@ -1004,19 +1003,13 @@ static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_ if (print_host) printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", tw_dev->host->host_no, - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), full_command_packet->header.err_specific_desc); else printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), full_command_packet->header.err_specific_desc); } @@ -1133,12 +1126,11 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); tw_initconnect->request_id = request_id; tw_initconnect->message_credits = cpu_to_le16(message_credits); - tw_initconnect->features = set_features; /* Turn on 64-bit sgl support if we need to */ - tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; + set_features |= sizeof(dma_addr_t) > 4 ? 1 : 0; - tw_initconnect->features = cpu_to_le32(tw_initconnect->features); + tw_initconnect->features = cpu_to_le32(set_features); if (set_features & TW_EXTENDED_INIT_CONNECT) { tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; @@ -1351,8 +1343,10 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance) /* Report residual bytes for single sgl */ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { - if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) - scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); + u32 length = le32_to_cpu(full_command_packet->command.newcommand.sg_list[0].length); + + if (length < scsi_bufflen(cmd)) + scsi_set_resid(cmd, scsi_bufflen(cmd) - length); } /* Now complete the io */ @@ -1394,13 +1388,13 @@ static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_comm if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { newcommand = &full_command_packet->command.newcommand; newcommand->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id); if (length) { newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache)); newcommand->sg_list[0].length = cpu_to_le32(length); } newcommand->sgl_entries__lunh = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0); } else { oldcommand = &full_command_packet->command.oldcommand; oldcommand->request_id = request_id; @@ -1835,10 +1829,10 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, if (srb) { command_packet->unit = srb->device->id; command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); + TW_REQ_LUN_IN(srb->device->lun, request_id); } else { command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); + TW_REQ_LUN_IN(0, request_id); command_packet->unit = 0; } @@ -1870,19 +1864,19 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, } } } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])); } } else { /* Internal cdb post */ for (i = 0; i < use_sg; i++) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); - command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length); + command_packet->sg_list[i].address = sglistarg[i].address; + command_packet->sg_list[i].length = sglistarg[i].length; if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); goto out; } } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg); } if (srb) { @@ -2107,7 +2101,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), - le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, + le32_to_cpu(*(__le32 *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); /* Try to enable MSI */ |