Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Samuel Holland and committed by
Martin K. Petersen
05f7f1b9 d133b441

+81 -86
+25 -31
drivers/scsi/3w-9xxx.c
··· 303 303 304 304 /* Initialize sglist */ 305 305 memset(&sglist, 0, sizeof(TW_SG_Entry)); 306 - sglist[0].length = TW_SECTOR_SIZE; 307 - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; 306 + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); 307 + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); 308 308 309 - if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { 309 + if (tw_dev->generic_buffer_phys[request_id] & TW_ALIGNMENT_9000_SGL) { 310 310 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); 311 311 goto out; 312 312 } ··· 440 440 441 441 /* Initialize sglist */ 442 442 memset(&sglist, 0, sizeof(TW_SG_Entry)); 443 - sglist[0].length = TW_SECTOR_SIZE; 444 - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; 443 + sglist[0].length = cpu_to_le32(TW_SECTOR_SIZE); 444 + sglist[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); 445 445 446 446 /* Mark internal command */ 447 447 tw_dev->srb[request_id] = NULL; ··· 501 501 Sunday 12:00AM */ 502 502 local_time = (ktime_get_real_seconds() - (sys_tz.tz_minuteswest * 60)); 503 503 div_u64_rem(local_time - (3 * 86400), 604800, &schedulertime); 504 - schedulertime = cpu_to_le32(schedulertime % 604800); 505 504 506 - memcpy(param->data, &schedulertime, sizeof(u32)); 505 + memcpy(param->data, &(__le32){cpu_to_le32(schedulertime)}, sizeof(__le32)); 507 506 508 507 /* Mark internal command */ 509 508 tw_dev->srb[request_id] = NULL; ··· 1003 1004 if (print_host) 1004 1005 printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", 1005 1006 tw_dev->host->host_no, 1006 - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, 1007 - full_command_packet->header.status_block.error, 1008 - error_str[0] == '\0' ? 1009 - twa_string_lookup(twa_error_table, 1010 - full_command_packet->header.status_block.error) : error_str, 1007 + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, 1008 + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), 1011 1009 full_command_packet->header.err_specific_desc); 1012 1010 else 1013 1011 printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", 1014 - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, 1015 - full_command_packet->header.status_block.error, 1016 - error_str[0] == '\0' ? 1017 - twa_string_lookup(twa_error_table, 1018 - full_command_packet->header.status_block.error) : error_str, 1012 + TW_MESSAGE_SOURCE_CONTROLLER_ERROR, error, 1013 + error_str[0] ? error_str : twa_string_lookup(twa_error_table, error), 1019 1014 full_command_packet->header.err_specific_desc); 1020 1015 } 1021 1016 ··· 1126 1133 tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); 1127 1134 tw_initconnect->request_id = request_id; 1128 1135 tw_initconnect->message_credits = cpu_to_le16(message_credits); 1129 - tw_initconnect->features = set_features; 1130 1136 1131 1137 /* Turn on 64-bit sgl support if we need to */ 1132 - tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; 1138 + set_features |= sizeof(dma_addr_t) > 4 ? 1 : 0; 1133 1139 1134 - tw_initconnect->features = cpu_to_le32(tw_initconnect->features); 1140 + tw_initconnect->features = cpu_to_le32(set_features); 1135 1141 1136 1142 if (set_features & TW_EXTENDED_INIT_CONNECT) { 1137 1143 tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; ··· 1343 1351 1344 1352 /* Report residual bytes for single sgl */ 1345 1353 if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { 1346 - if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) 1347 - scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); 1354 + u32 length = le32_to_cpu(full_command_packet->command.newcommand.sg_list[0].length); 1355 + 1356 + if (length < scsi_bufflen(cmd)) 1357 + scsi_set_resid(cmd, scsi_bufflen(cmd) - length); 1348 1358 } 1349 1359 1350 1360 /* Now complete the io */ ··· 1388 1394 if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { 1389 1395 newcommand = &full_command_packet->command.newcommand; 1390 1396 newcommand->request_id__lunl = 1391 - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); 1397 + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id); 1392 1398 if (length) { 1393 1399 newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache)); 1394 1400 newcommand->sg_list[0].length = cpu_to_le32(length); 1395 1401 } 1396 1402 newcommand->sgl_entries__lunh = 1397 - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); 1403 + TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0); 1398 1404 } else { 1399 1405 oldcommand = &full_command_packet->command.oldcommand; 1400 1406 oldcommand->request_id = request_id; ··· 1829 1835 if (srb) { 1830 1836 command_packet->unit = srb->device->id; 1831 1837 command_packet->request_id__lunl = 1832 - cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); 1838 + TW_REQ_LUN_IN(srb->device->lun, request_id); 1833 1839 } else { 1834 1840 command_packet->request_id__lunl = 1835 - cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); 1841 + TW_REQ_LUN_IN(0, request_id); 1836 1842 command_packet->unit = 0; 1837 1843 } 1838 1844 ··· 1864 1870 } 1865 1871 } 1866 1872 } 1867 - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); 1873 + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])); 1868 1874 } 1869 1875 } else { 1870 1876 /* Internal cdb post */ 1871 1877 for (i = 0; i < use_sg; i++) { 1872 - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); 1873 - command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length); 1878 + command_packet->sg_list[i].address = sglistarg[i].address; 1879 + command_packet->sg_list[i].length = sglistarg[i].length; 1874 1880 if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { 1875 1881 TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); 1876 1882 goto out; 1877 1883 } 1878 1884 } 1879 - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); 1885 + command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg); 1880 1886 } 1881 1887 1882 1888 if (srb) { ··· 2101 2107 TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), 2102 2108 (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, 2103 2109 TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), 2104 - le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, 2110 + le32_to_cpu(*(__le32 *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, 2105 2111 TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); 2106 2112 2107 2113 /* Try to enable MSI */
+56 -55
drivers/scsi/3w-9xxx.h
··· 435 435 436 436 /* request_id: 12, lun: 4 */ 437 437 #define TW_REQ_LUN_IN(lun, request_id) \ 438 - (((lun << 12) & 0xf000) | (request_id & 0xfff)) 439 - #define TW_LUN_OUT(lun) ((lun >> 12) & 0xf) 438 + cpu_to_le16(((lun << 12) & 0xf000) | (request_id & 0xfff)) 439 + #define TW_LUN_OUT(lun) ((le16_to_cpu(lun) >> 12) & 0xf) 440 440 441 441 /* Macros */ 442 442 #define TW_CONTROL_REG_ADDR(x) (x->base_addr) ··· 483 483 #define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109) 484 484 #define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62) 485 485 #define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0) 486 - #define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) 487 486 488 487 #if IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) 489 - typedef u64 twa_addr_t; 488 + typedef __le64 twa_addr_t; 489 + #define TW_CPU_TO_SGL(x) cpu_to_le64(x) 490 490 #else 491 - typedef u32 twa_addr_t; 491 + typedef __le32 twa_addr_t; 492 + #define TW_CPU_TO_SGL(x) cpu_to_le32(x) 492 493 #endif 493 494 494 495 /* Scatter Gather List Entry */ 495 496 typedef struct TAG_TW_SG_Entry { 496 - twa_addr_t address; 497 - u32 length; 497 + twa_addr_t address; 498 + __le32 length; 498 499 } __packed TW_SG_Entry; 499 500 500 501 /* Command Packet */ 501 502 typedef struct TW_Command { 502 - unsigned char opcode__sgloffset; 503 - unsigned char size; 504 - unsigned char request_id; 505 - unsigned char unit__hostid; 503 + u8 opcode__sgloffset; 504 + u8 size; 505 + u8 request_id; 506 + u8 unit__hostid; 506 507 /* Second DWORD */ 507 - unsigned char status; 508 - unsigned char flags; 508 + u8 status; 509 + u8 flags; 509 510 union { 510 - unsigned short block_count; 511 - unsigned short parameter_count; 511 + __le16 block_count; 512 + __le16 parameter_count; 512 513 } byte6_offset; 513 514 union { 514 515 struct { 515 - u32 lba; 516 - TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; 517 - twa_addr_t padding; 516 + __le32 lba; 517 + TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; 518 + twa_addr_t padding; 518 519 } io; 519 520 struct { 520 - TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; 521 - u32 padding; 522 - twa_addr_t padding2; 521 + TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; 522 + __le32 padding; 523 + twa_addr_t padding2; 523 524 } param; 524 525 } byte8_offset; 525 526 } TW_Command; 526 527 527 528 /* Command Packet for 9000+ controllers */ 528 529 typedef struct TAG_TW_Command_Apache { 529 - unsigned char opcode__reserved; 530 - unsigned char unit; 531 - unsigned short request_id__lunl; 532 - unsigned char status; 533 - unsigned char sgl_offset; 534 - unsigned short sgl_entries__lunh; 535 - unsigned char cdb[16]; 536 - TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH]; 537 - unsigned char padding[TW_PADDING_LENGTH]; 530 + u8 opcode__reserved; 531 + u8 unit; 532 + __le16 request_id__lunl; 533 + u8 status; 534 + u8 sgl_offset; 535 + __le16 sgl_entries__lunh; 536 + u8 cdb[16]; 537 + TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH]; 538 + u8 padding[TW_PADDING_LENGTH]; 538 539 } TW_Command_Apache; 539 540 540 541 /* New command packet header */ 541 542 typedef struct TAG_TW_Command_Apache_Header { 542 543 unsigned char sense_data[TW_SENSE_DATA_LENGTH]; 543 544 struct { 544 - char reserved[4]; 545 - unsigned short error; 546 - unsigned char padding; 547 - unsigned char severity__reserved; 545 + u8 reserved[4]; 546 + __le16 error; 547 + u8 padding; 548 + u8 severity__reserved; 548 549 } status_block; 549 550 unsigned char err_specific_desc[98]; 550 551 struct { 551 - unsigned char size_header; 552 - unsigned char reserved[2]; 553 - unsigned char size_sense; 552 + u8 size_header; 553 + u8 reserved[2]; 554 + u8 size_sense; 554 555 } header_desc; 555 556 } TW_Command_Apache_Header; 556 557 ··· 566 565 567 566 /* Initconnection structure */ 568 567 typedef struct TAG_TW_Initconnect { 569 - unsigned char opcode__reserved; 570 - unsigned char size; 571 - unsigned char request_id; 572 - unsigned char res2; 573 - unsigned char status; 574 - unsigned char flags; 575 - unsigned short message_credits; 576 - u32 features; 577 - unsigned short fw_srl; 578 - unsigned short fw_arch_id; 579 - unsigned short fw_branch; 580 - unsigned short fw_build; 581 - u32 result; 568 + u8 opcode__reserved; 569 + u8 size; 570 + u8 request_id; 571 + u8 res2; 572 + u8 status; 573 + u8 flags; 574 + __le16 message_credits; 575 + __le32 features; 576 + __le16 fw_srl; 577 + __le16 fw_arch_id; 578 + __le16 fw_branch; 579 + __le16 fw_build; 580 + __le32 result; 582 581 } TW_Initconnect; 583 582 584 583 /* Event info structure */ ··· 619 618 620 619 /* GetParam descriptor */ 621 620 typedef struct { 622 - unsigned short table_id; 623 - unsigned short parameter_id; 624 - unsigned short parameter_size_bytes; 625 - unsigned short actual_parameter_size_bytes; 626 - unsigned char data[]; 621 + __le16 table_id; 622 + __le16 parameter_id; 623 + __le16 parameter_size_bytes; 624 + __le16 actual_parameter_size_bytes; 625 + u8 data[]; 627 626 } TW_Param_Apache, *PTW_Param_Apache; 628 627 629 628 /* Response queue */