Re: [RFC] results of endianness review of qla2xxx

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 18 Apr 2008, Al Viro wrote:

> On Fri, Apr 18, 2008 at 11:17:58AM -0700, Andrew Vasquez wrote:
> > > 7) qla2x00_async_event():
> > > 		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
> > > 		...
> > > 		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
> > > 		handles[1] = le32_to_cpu(
> > > 		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
> > > and then those values are passed to qla2x00_process_completed_request() which
> > > expects a host-endian (and uses it as index in array, among other things).
> > 
> > THis is correct (though a bit confuscated), each of the two 16bit
> > mailbox-registers makes-up a 32bit LE value, which is converted to
> > cpu-endian and passed to qla2x00_process_completed_request().
> 
> Um, no.  First of all, other branches in that switch clearly assume
> that mb[] is already host-endian.  But leaving that aside, what you
> are doing here will _not_ work even if mb[1] and mb[2] are l-e in
> this case.
> 
> Look what happens:
> * l-e host:
> 	handles[0] = (mb[2] << 16) | mb[1], which is equal to
> (le16_to_cpu(mb[2]) << 16) | le16_to_cpu(mb[1])
> * on b-e host:
> 	handles[0] = swab32((mb[2] << 16) | mb[1]), which is equal to
> (swab16(mb[1]) << 16) | swab16(mb[2]), which is equal to
> (le16_to_cpu(mb[1]) << 16) | le16_to_cpu(mb[2])
> 
> IOW, resulting host-endian value will be different with the same contents
> in mb[].  Put it another way, suppose you have mb[1] == 0, mb[2] == 0x101.
> Then on l-e you'll get handles[0] == 0x10100 and on b-e - 0x101.  The latter
> will pass the check for index being too high, the former will fail...
> 
> BTW, RD_MAILBOX_REG() boils down to readw(), which is definitely host-endian.
> And we have
>                         mb[0] = MBA_SCSI_COMPLETION;
>                         mb[1] = MSW(stat);
>                         mb[2] = RD_MAILBOX_REG(ha, reg, 2);
>                         qla2x00_async_event(ha, mb);
> so there's at least one path reaching qla2x00_async_event() with mb[0]
> equal to MBA_SCSI_COMPLETION and mb[2] containing host-endian...  Looking
> at the contents of stat and the things we do to it (switch (stat & 0xff) right
> outside that code), mb[1] is host-endian as well...  AFAICS, the same holds
> for all codepaths - contents of mb[] is host-endian.

Yes, all mb[] "values" are going to be in host-endian format.

But, what's missing here is an understanding of what mb[2] and mb[1]
are representing during MBA_SCSI_COMPLETION and MBA_CMPLT_2_32BIT
handling.  Upon command submission, a 32bit handle (cookie) is
associated with each IOCB:

	...
	cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr;
	cmd_pkt->handle = handle;
	/* Zero out remaining portion of packet. */
	clr_ptr = (uint32_t *)cmd_pkt + 2;
	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);

	/* Set target ID and LUN number*/
	SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
	cmd_pkt->lun = cpu_to_le16(sp->cmd->device->lun);
	...

Notice that the 'handle'-value is assigned to the command-IOCB
structure in host-endian format and *not* the typical little-endian
form used to fill-in the other non-byte-sized members of the
structure.  So, for example, start with a hypothetical 'handle' value
of 0x12345678.  On an BE machine, the layout in memory of the value
written to the structure will be:

	mem[0]	mem[1]	mem[2]	mem[3]
	------	------	-----	------
	12	34	56	78

On an LE machine:

	mem[0]	mem[1]	mem[2]	mem[3]
	------	------	-----	------
	78	56	34	12

'handle' sent as a host-endian value is done for a reason, as
typically, firmware reports IOCB completion via a structure called the
status-IOCB [2]:

	#define STATUS_TYPE     0x03            /* Status entry. */
	typedef struct {
		uint8_t entry_type;             /* Entry type. */
		uint8_t entry_count;            /* Entry count. */
		uint8_t sys_define;             /* System defined. */
		uint8_t entry_status;           /* Entry Status. */
		uint32_t handle;                /* System handle. */
		uint16_t scsi_status;           /* SCSI status. */
		...

where, during creation of the status-IOCB by firmware, the
'handle'-value (at offset 0x4) is copied from the 'handle' specified
from the command-IOCB.  Since this 'handle' is a a simple index (in
host-endian format) into the outstanding_cmds array of the HBA,
there's really no reason to convert the value to little-endian format
at submission time, then convert from little-endian to host-endian
form during status-IOCB handling within the driver [3]:

	...
	/* Fast path completion. */
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
		qla2x00_process_completed_request(ha, sts->handle);

		return;
	}

So, getting back to MBA_SCSI_COMPLETION and MBA_CMPLT_2_32BIT
completions, the "value" of the mailbox registers returned by firmware
are:

	mb[1]: mem[1] << 8 | mem[0]
	mb[2]: mem[3] << 8 | mem[2]

which on an LE machine result in:

	mb[1]: 0x5678
	mb[2]: 0x1234

	handle[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
	handle[0] = (0x1234 << 16) | 0x5678)
	handle[0] = 0x12345678

and on an BE machine the values are:

	mb[1]: 0x3412
	mb[2]: 0x7856

	handle[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
	handle[0] = swab32((0x7856 << 16) | 0x3412)
	handle[0] = swab32(0x78563412)
	handle[0] = 0x12345678

> > > 9) qla2x00_clear_nvram_protection():
> > >         wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base));
> > > 	stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base,
> > > 		    __constant_cpu_to_le16(0x1234), 100000);
> > > 	wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base));
> > > 	if (stat != QLA_SUCCESS || wprot != 0x1234) {
> > > Odd, since qla2x00_get_nvram_word() returns a host-endian and 
> > > qla2x00_write_nvram_word_tmo() expects one (this stuff is bit-banging
> > > 16bit values through).
> > 
> > Odd, yes.  I was never happy with this endianess intermixing, but
> > after numerous cycles within our qual-testing, this code works in both
> > big and little-endian systems...
> 
> It looks like check that location is writable; what happens if you replace
> the first instance with 0x1234 and the second (in wprot == ...) with
> cpu_to_le16(0x1234)?  One "we won't find it there by accident, must've been
> successful write" value seems to be as good as other, unless something else
> is going on...

One would hope so, yes...

Anyway, hope that helped...

--
av

[1] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/scsi/qla2xxx/qla_iocb.c;h=5489d5024673a326b5345f5545151a7dab37a533;hb=HEAD#l346

[2] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/scsi/qla2xxx/qla_def.h;h=094d95f0764c6027cb421e4d3e5da9bf17012dfd;hb=HEAD#l1259

[3] http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/scsi/qla2xxx/qla_isr.c;h=285479b62d8f02084ad0daebc12ab249f16348c0;hb=HEAD#l944
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux