diff -rupN old/drivers/scsi/megaraid/megaraid_sas.c new/drivers/scsi/megaraid/megaraid_sas.c --- old/drivers/scsi/megaraid/megaraid_sas.c 2010-11-17 14:08:13.000000000 -0500 +++ new/drivers/scsi/megaraid/megaraid_sas.c 2010-11-17 14:08:46.000000000 -0500 @@ -75,6 +75,12 @@ static int megasas_get_pd_list(struct me static int megasas_issue_init_mfi(struct megasas_instance *instance); static int megasas_register_aen(struct megasas_instance *instance, u32 seq_num, u32 class_locale_word); + +static int megasas_check_cpx_support( struct megasas_instance *instance); +static u32 megasas_remove_cpx( struct megasas_instance *instance); +static int megasas_send_cpx_queue_data( struct megasas_instance *instance ); +static int megasas_handle_cpx_requests( struct megasas_instance *instance); + /* * PCI ID table for all supported controllers */ @@ -793,6 +799,10 @@ megasas_issue_polled(struct megasas_inst */ for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) { rmb(); + + /* FW using xor/copy as soon as we enable cpx */ + if ((instance->unload == 1) && instance->cpx_supported ) + megasas_handle_cpx_requests( instance); msleep(1); } @@ -1522,6 +1532,1092 @@ static void megaraid_sas_kill_hba(struct } } + +void xor_gen_15x1(u32 *buff_ptrs[16], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9; + u32 *s10, *s11, *s12, *s13, *s14, *s15; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + s14 = buff_ptrs[14]; + s15 = buff_ptrs[15]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]^s13[off]^s14[off]^s15[off]; +} + + +void xor_gen_14x1(u32 *buff_ptrs[15], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; + u32 *s9, *s10, *s11, *s12, *s13, *s14; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + s14 = buff_ptrs[14]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]^s13[off]^s14[off]; +} + + +void xor_gen_13x1(u32 *buff_ptrs[14], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7; + u32 *s8, *s9, *s10, *s11, *s12, *s13; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]^s13[off]; + +} + + +void xor_gen_12x1(u32 *buff_ptrs[13], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7; + u32 *s8, *s9, *s10, *s11, *s12; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]; +} + + +void xor_gen_11x1(u32 *buff_ptrs[12], u32 bytes) +{ + + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9, *s10, *s11; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off] ^ s9[off] ^ s10[off] ^ s11[off]; +} + + +void xor_gen_10x1(u32 *buff_ptrs[11], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9, *s10; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off] ^ s9[off] ^ s10[off]; + +} + + +void xor_gen_9x1(u32 *buff_ptrs[10], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off] ^ s9[off]; +} + + +void xor_gen_8x1(u32 *buff_ptrs[9], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^s5[off]^s6[off]^\ + s7[off]^s8[off]; +} + + +void xor_gen_7x1(u32 *buff_ptrs[8], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^s4[off]^\ + s5[off]^s6[off]^s7[off]; + +} + + +void xor_gen_6x1(u32 *buff_ptrs[7], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5, *s6; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]; +} + + +void xor_gen_5x1(u32 *buff_ptrs[6], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4, *s5; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off] ^ s2[off] ^ s3[off]^\ + s4[off] ^ s5[off]; +} + + +void xor_gen_4x1(u32 *buff_ptrs[5], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3, *s4; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off] ^ s2[off] ^ s3[off] ^ s4[off]; +} + + +void xor_gen_3x1(u32 *buff_ptrs[4], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2, *s3; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off] ^ s2[off] ^ s3[off]; +} + + +void xor_gen_2x1(u32 *buff_ptrs[3], u32 bytes) +{ + u32 off, words; + u32 *d, *s1, *s2; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off] ^ s2[off]; +} + + +void xor_gen_1x1(u32 *buff_ptrs[2], u32 bytes) +{ + u32 off, words; + u32 *d, *s1; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) + d[off] = s1[off]; + +} + + +u8 xor_chk_15x1(u32 *buff_ptrs[16], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; + u32 *s9, *s10, *s11, *s12, *s13, *s14, *s15; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + s14 = buff_ptrs[14]; + s15 = buff_ptrs[15]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^ + s12[off]^s13[off]^s14[off]^s15[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_14x1(u32 *buff_ptrs[15], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6; + u32 *s7, *s8, *s9, *s10, *s11, *s12, *s13, *s14; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + s14 = buff_ptrs[14]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off] ^ s1[off] ^ s2[off] ^ s3[off]^\ + s4[off] ^ s5[off] ^ s6[off] ^ s7[off]^\ + s8[off] ^ s9[off] ^ s10[off] ^ s11[off]^\ + s12[off] ^ s13[off] ^ s14[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_13x1(u32 *buff_ptrs[14], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7; + u32 *s8, *s9, *s10, *s11, *s12, *s13; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + s13 = buff_ptrs[13]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^s4[off]^\ + s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]^s13[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; + +} + + +u8 xor_chk_12x1(u32 *buff_ptrs[13], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6; + u32 *s7, *s8, *s9, *s10, *s11, *s12; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + s12 = buff_ptrs[12]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]^s12[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_11x1(u32 *buff_ptrs[12], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5; + u32 *s6, *s7, *s8, *s9, *s10, *s11; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + s11 = buff_ptrs[11]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]^s11[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_10x1(u32 *buff_ptrs[11], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5; + u32 *s6, *s7, *s8, *s9, *s10; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + s10 = buff_ptrs[10]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^s4[off]^\ + s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]^s10[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_9x1(u32 *buff_ptrs[10], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4; + u32 *s5, *s6, *s7, *s8, *s9; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + s9 = buff_ptrs[9]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]^\ + s8[off]^s9[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_8x1(u32 *buff_ptrs[9], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + s8 = buff_ptrs[8]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]^s8[off]; + + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_7x1(u32 *buff_ptrs[8], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6, *s7; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + s7 = buff_ptrs[7]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]^s7[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_6x1(u32 *buff_ptrs[7], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5, *s6; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + s6 = buff_ptrs[6]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off]^s1[off]^s2[off]^s3[off]^\ + s4[off]^s5[off]^s6[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + +u8 xor_chk_5x1(u32 *buff_ptrs[6], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4, *s5; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + s5 = buff_ptrs[5]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off] ^ s1[off] ^ s2[off]^\ + s3[off] ^ s4[off] ^ s5[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_4x1(u32 *buff_ptrs[5], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3, *s4; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + s4 = buff_ptrs[4]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off] ^ s1[off] ^ s2[off] ^ s3[off] ^ s4[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_3x1(u32 *buff_ptrs[4], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2, *s3; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + s3 = buff_ptrs[3]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off] ^ s1[off] ^ s2[off] ^ s3[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + return xor_result; +} + + +u8 xor_chk_2x1(u32 *buff_ptrs[3], u32 bytes) +{ + u32 off, words; + u32 r, *d, *s1, *s2; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + s2 = buff_ptrs[2]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + r = d[off] ^ s1[off] ^ s2[off]; + if (r) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] ^= r; + } + } + + return xor_result; +} + +u8 xor_chk_1x1(u32 *buff_ptrs[2], u32 bytes) +{ + u32 off, words; + u32 *d, *s1; + u8 xor_result = MR_CPX_STATUS_SUCCESS; + + d = buff_ptrs[0]; + s1 = buff_ptrs[1]; + + for (words = bytes/4, off = 0; words > 0; words--, off++) { + if (d[off] != s1[off]) { + xor_result = MR_CPX_STATUS_INCONSISTENT; + d[off] = s1[off]; + } + } + + return xor_result; +} + +void (*xor_gen_funcs[MAX_MR_ROW_SIZE])(u32 **, u32) = { + xor_gen_1x1, + xor_gen_2x1, + xor_gen_3x1, + xor_gen_4x1, + xor_gen_5x1, + xor_gen_6x1, + xor_gen_7x1, + xor_gen_8x1, + xor_gen_9x1, + xor_gen_10x1, + xor_gen_11x1, + xor_gen_12x1, + xor_gen_13x1, + xor_gen_14x1, + xor_gen_15x1, +}; + +u8 (*xor_check_funcs[MAX_MR_ROW_SIZE])(u32 **, u32) = { + xor_chk_1x1, + xor_chk_2x1, + xor_chk_3x1, + xor_chk_4x1, + xor_chk_5x1, + xor_chk_6x1, + xor_chk_7x1, + xor_chk_8x1, + xor_chk_9x1, + xor_chk_10x1, + xor_chk_11x1, + xor_chk_12x1, + xor_chk_13x1, + xor_chk_14x1, + xor_chk_15x1, +}; + +static inline u8 megasas_scan_set_bit(u32 bitmap) +{ + u8 bit = 0; + while (bitmap) { + if (bitmap & 1) + return bit; + + bitmap >>= 1; + bit++; + } + return ~0; +} + +/** +* megasas_do_cpx_xor - completes the xor operation +* @xor_des : soruce and dest buffers details. +* @host_mem : previously mapped memory for fw +* @host_mem_len : mapped memory length in bytes. +* +* @return 0 on success != 0 on failure +* +**/ +static u8 megasas_do_cpx_xor( struct mr_cpx_xor_descriptor *xor_des, + const u8 *host_mem, const u32 host_mem_len) +{ + + u32 buff_valid_bit_map = xor_des->buff_valid_bitmap; + u32 *buf_ptr_list[MAX_MR_ROW_SIZE]; + u32 tx_count = xor_des->size; + u8 dest_idx, buf_idx, bit; + u8 is_op_gen; + u8 status = MR_CPX_STATUS_SUCCESS; + + /* make the first buffer ptr as the destination.*/ + if ( xor_des->op == MR_CPX_XOR_OP_GEN_P || + xor_des->op == MR_CPX_XOR_OP_CHECK_P ) + dest_idx = xor_des->p_idx; + else + dest_idx = xor_des->q_idx; + + buf_ptr_list[0] = (u32 *)(host_mem + xor_des->buff_list[dest_idx]); + + is_op_gen = MR_CPX_XOR_OP_IS_GEN(xor_des->op); + + if ( xor_des->buff_list[dest_idx]+tx_count > host_mem_len) { + printk(KERN_ERR "1st host memory over flow detected.\n"); + return MR_CPX_STATUS_FAILURE; + } + + /* + * For XOR_OP_CHECK_P, our check routine expects + * bufPtrs[0] to be both parity + * source and parity destination; clear + * out the P-index from our working bitmap + * so that the source-buffer scan loop below + * doesn't include P as one of the + * explicit source buffers in bufPtrs[]. + */ + if ( !is_op_gen) + buff_valid_bit_map &= ~(1<p_idx); + + /* populate buf_ptr_list with valid buffer pointers.*/ + for ( buf_idx = 1 ; buff_valid_bit_map != 0 ; buf_idx++ ) { + bit = megasas_scan_set_bit( buff_valid_bit_map); + buf_ptr_list[buf_idx] = + (u32 *)(host_mem + (u32)xor_des->buff_list[bit]); + if ( xor_des->buff_list[bit]+tx_count > host_mem_len) { + printk(KERN_ERR "host memory over flow detected.\n"); + return MR_CPX_STATUS_FAILURE; + } + buff_valid_bit_map &= ~(1 << bit); + } + /* call the xor gen fuctions.*/ + if ( is_op_gen ) + (*xor_gen_funcs[buf_idx-2])(buf_ptr_list, tx_count); + else + status = + (*xor_check_funcs[buf_idx-2])(buf_ptr_list, tx_count); + + return status; +} + +static u8 megasas_copy( struct page *page, u32 page_offset, + u32 sge_offset, u8 *host_ptr, u32 len, u8 dir) +{ + u8 *page_addr; + u32 off; + u32 bytes_copied; + u32 remaining; + + remaining = len; + off = page_offset+sge_offset; + + /* kmap_atomic maps single page size but os sg element can have size + more than page size, handle it.**/ + + while (remaining > 0 ) { + + bytes_copied = + min((size_t)remaining, + (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); + + page_addr = + kmap_atomic(page + (off >> PAGE_SHIFT), KM_SOFTIRQ0); + if ( page_addr == NULL ) { + printk(KERN_NOTICE "kmap_atomic is failed.\n"); + return MR_CPX_STATUS_FAILURE; + } + if ( dir == MR_CPX_DIR_WRITE ) + memcpy( host_ptr, + page_addr+(off & ~PAGE_MASK), + bytes_copied ); + else + memcpy( page_addr+(off & ~PAGE_MASK), + host_ptr, + bytes_copied ); + + kunmap_atomic ( page_addr, KM_SOFTIRQ0 ); + + host_ptr += bytes_copied; + remaining -= bytes_copied; + off += bytes_copied; + } + + return MR_CPX_STATUS_SUCCESS; +} + +/** +* megasas_do_cpx_copy - Completes the copy opreation +* @instance : Driver soft state. +* @cpy_des : input for copying the data. +* +* @return 0 on success != 0 on failure +* +*/ + +static u8 megasas_do_cpx_copy( struct megasas_instance *instance, + struct mr_cpx_copy_descriptor *cpy_des) +{ + u8 status = MR_CPX_STATUS_SUCCESS ; + u32 total_remaining_len = cpy_des->total_byte_count; + u32 row_remaining_length; + u32 os_sge_sz = 0, os_sge_offset = 0, os_sge_idx = 0, os_sge_len; + u8 sge_cnt, row_idx, *fw_ptr = NULL, host_skip_count_handled; + struct scsi_cmnd *os_cmd; + struct scatterlist *os_sgl; + struct megasas_cmd *mega_cmd; + struct megasas_io_frame *ldio; + + if ( cpy_des->mfi_cmd_cxt >= instance->max_fw_cmds ) { + printk(KERN_NOTICE "invalid context - 0x%x shoul be < 0x%x \n", + cpy_des->mfi_cmd_cxt, instance->max_fw_cmds ); + return MR_CPX_STATUS_FAILURE; + } + + mega_cmd = + (struct megasas_cmd *)instance->cmd_list[cpy_des->mfi_cmd_cxt]; + os_cmd = mega_cmd->scmd; + ldio = (struct megasas_io_frame *)mega_cmd->frame; + sge_cnt = ldio->sge_count; + + host_skip_count_handled = 0; + row_idx = 0; + row_remaining_length = 0; + + scsi_for_each_sg(os_cmd, os_sgl, sge_cnt, os_sge_idx) { + + os_sge_len = sg_dma_len(os_sgl); + + if ( !host_skip_count_handled && + cpy_des->host_skip_count < (os_sge_sz += os_sge_len)) { + + os_sge_offset = + cpy_des->host_skip_count - ( os_sge_sz -os_sge_len ); + os_sge_len -= os_sge_offset; + host_skip_count_handled = 1; + } else if (!host_skip_count_handled && + cpy_des->host_skip_count == os_sge_sz ) { + os_sge_offset = 0; + host_skip_count_handled = 1; + continue; + } + + if ( !host_skip_count_handled ) + continue; + + for ( ; total_remaining_len && row_idx < MAX_MR_ROW_SIZE; + row_idx++ ) { + + if ( !row_remaining_length ) { + fw_ptr = + (u8 *)(instance->host_mem_virt+cpy_des->copy_buf[row_idx].buf); + row_remaining_length = cpy_des->copy_buf[row_idx].size; + } + + status = megasas_copy( sg_page(os_sgl), + os_sgl->offset, + os_sge_offset, + fw_ptr, + MIN(os_sge_len, row_remaining_length), + cpy_des->dir); + if (status) + break; + + total_remaining_len -= + MIN(os_sge_len, row_remaining_length); + + if ( os_sge_len <= row_remaining_length ) { + fw_ptr += os_sge_len; + row_remaining_length -= os_sge_len; + if (!(row_remaining_length)) + row_idx++; + os_sge_offset = 0; + break; + }else{ + os_sge_len -= row_remaining_length; + os_sge_offset += row_remaining_length; + row_remaining_length = 0; + } + + } + if ( row_idx >= MAX_MR_ROW_SIZE && total_remaining_len ) + printk(KERN_NOTICE "row_idx=0x%x,remaining_len= 0x%x\n", + row_idx, total_remaining_len); + + if (total_remaining_len == 0 || + status == MR_CPX_STATUS_FAILURE ) + break; + } + + if ( os_sge_idx >= sge_cnt && total_remaining_len ) + printk(KERN_NOTICE "sge_idx = 0x%x, remaining_len = 0x%x \n", + os_sge_idx, total_remaining_len); + + return status; + +} +/** +* megasas_handle_cpx_requests - Manages the fw queues +* @instance : Driver soft state. +* +* @return 0 on success != 0 on failure +* +*/ +static int megasas_handle_cpx_requests( struct megasas_instance *instance) +{ + struct mr_cpx_request_queue *req_q = instance->cpx_request_queue; + u32 producer_idx, consumer_idx; + u8 retval = 0; + unsigned long flags; + + producer_idx = req_q->producer_idx; + consumer_idx = req_q->consumer_idx; + + while ((producer_idx != consumer_idx) && + (instance->adprecovery == MEGASAS_HBA_OPERATIONAL)) { + union mr_cpx_descriptor *cpx_des = + &instance->cpx_dscrptr[consumer_idx]; + union mr_cpx_response_data rsp_data; + + if ( cpx_des->cpx_copy_desc.hdr.type == + MR_CPX_DESCRIPTOR_TYPE_COPY ) + retval = megasas_do_cpx_copy(instance, + (struct mr_cpx_copy_descriptor *)cpx_des ); + + else if (cpx_des->cpx_copy_desc.hdr.type == + MR_CPX_DESCRIPTOR_TYPE_XOR ) + retval = megasas_do_cpx_xor( + (struct mr_cpx_xor_descriptor *)cpx_des, + (u8 *)instance->host_mem_virt, + instance->host_mem_len ); + else{ + printk(KERN_ERR "Got invalid descriptor type...\n"); + retval = MR_CPX_STATUS_FAILURE; + break; + } + + rsp_data.r.status = retval; + rsp_data.r.context = cpx_des->cpx_copy_desc.hdr.context; + rsp_data.r.type = cpx_des->cpx_copy_desc.hdr.type; + + /* notify fw.*/ + spin_lock_irqsave(&instance->hba_lock, flags); + writel( ~0, &instance->reg_set->inbound_high_queue_port); + writel( rsp_data.w, &instance->reg_set->inbound_low_queue_port); + spin_unlock_irqrestore(&instance->hba_lock, flags); + + consumer_idx++; + if ( consumer_idx == instance->cpx_dscrptr_cnt ) + consumer_idx = 0; + + } + req_q->consumer_idx = producer_idx; + + return 0; +} + /** * megasas_complete_cmd_dpc - Returns FW's controller structure * @instance_addr: Address of adapter soft state @@ -1569,6 +2665,9 @@ static void megasas_complete_cmd_dpc(uns spin_unlock_irqrestore(&instance->completion_lock, flags); + if ( instance->cpx_supported ) + megasas_handle_cpx_requests( instance); + /* * Check if we can restore can_queue */ @@ -2359,6 +3458,17 @@ process_fw_state_change_wq(struct work_s *instance->consumer = 0; *instance->producer = 0; } + if (instance->cpx_supported){ + instance->cpx_request_queue->consumer_idx = + instance->cpx_request_queue->producer_idx = 0; + + if ( megasas_check_cpx_support( instance ) == 0 ){ + if ( megasas_send_cpx_queue_data( instance ) ){ + printk(KERN_NOTICE "Send cpx failed.\n"); + megasas_remove_cpx(instance); + } + } + } megasas_issue_init_mfi(instance); @@ -3111,6 +4221,180 @@ megasas_get_ctrl_info(struct megasas_ins return ret; } + +/** + * megasas_check_cpx_support : Tries to get the host memory address if fails then cpx + not supported else cpx supported. + * @instance: Adapter soft state + * + * @return 0 on success non-zero on failure. + */ +static int megasas_check_cpx_support( struct megasas_instance *instance) +{ + struct megasas_cmd *cmd; + struct megasas_dcmd_frame *dcmd; + struct mr_cpx_init_data *cpx_init_data; + dma_addr_t cpx_init_data_h; + int retval = 0; + + cmd = megasas_get_cmd(instance); + if (!cmd) { + printk(KERN_DEBUG "Failed to get cmd\n"); + return -ENOMEM; + } + + cpx_init_data = pci_alloc_consistent(instance->pdev, + sizeof( struct mr_cpx_init_data), &cpx_init_data_h); + + if (cpx_init_data == NULL) { + printk(KERN_DEBUG "Failed to alloc mem for cpx_init_data. \n"); + megasas_return_cmd(instance, cmd); + return -ENOMEM; + } + + dcmd = &cmd->frame->dcmd; + dcmd->flags = 0; + dcmd->opcode = MR_DCMD_CTRL_MISC_CPX_INIT_DATA_GET; + dcmd->data_xfer_len = sizeof(struct mr_cpx_init_data ); + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xff; + dcmd->sge_count = 1; + dcmd->sgl.sge32[0].phys_addr = cpx_init_data_h; + dcmd->sgl.sge32[0].length = sizeof(struct mr_cpx_init_data); + + retval = megasas_issue_polled ( instance, cmd ); + + if (retval == 0 && cmd->frame->hdr.cmd_status == 0) { + instance->host_mem_phys = cpx_init_data->phys_addr_cache_buf; + instance->host_mem_len = cpx_init_data->size; + instance->cpx_dscrptr_cnt = cpx_init_data->cpx_desc_count; + + if ( instance->host_mem_len == 0 || + instance->host_mem_phys == 0 || + !instance->cpx_dscrptr_cnt ){ + + printk(KERN_ERR "No host_mem_phys/cpx_descriptor\n"); + retval = 1; + } + } else { + printk(KERN_NOTICE "megasas: cpx is not supported.\n"); + retval = 1; + } + + instance->cpx_supported = (retval ? 0:1); + + pci_free_consistent(instance->pdev, + sizeof(struct mr_cpx_init_data), + cpx_init_data, cpx_init_data_h); + + megasas_return_cmd(instance, cmd); + + return retval; +} + +/** + * megasas_send_cpx_queue_data : Sends the queue setup info to fw. + * @instance: Adapter soft state + * + * @return 0 on success non-zero on failure. + */ + +static int megasas_send_cpx_queue_data( struct megasas_instance *instance ) +{ + + struct megasas_cmd *cmd; + struct megasas_dcmd_frame *dcmd; + int retval = 0; + + cmd = megasas_get_cmd(instance); + if (!cmd) { + printk(KERN_DEBUG "Failed to get cmd\n"); + return -ENOMEM; + } + + dcmd = &cmd->frame->dcmd; + dcmd->flags = 0; + dcmd->opcode = MR_DCMD_CTRL_MISC_CPX_QUEUE_DATA; + dcmd->data_xfer_len = sizeof( struct mr_cpx_queue_data ); + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xff; + dcmd->sge_count = 1; + dcmd->mbox.w[0] = instance->cpx_request_queue_h; + dcmd->mbox.w[1] = 0; + dcmd->mbox.w[2] = instance->cpx_dscrptr_cnt; + + retval = megasas_issue_polled ( instance, cmd ); + + megasas_return_cmd( instance, cmd); + + if ( retval == 0 ) { + instance->cpx_request_queue->consumer_idx = + instance->cpx_request_queue->producer_idx = 0; + instance->cpx_supported = 1; + } + + return retval; +} + +static u32 megasas_get_cpx_mem_len( u16 max_fw_cmds ) +{ + return (sizeof( struct mr_cpx_request_queue ) + + sizeof( union mr_cpx_descriptor ) * ( max_fw_cmds) ); +} + +static u32 megasas_remove_cpx( struct megasas_instance *instance) +{ + if ( instance->host_mem_virt ) + iounmap(instance->host_mem_virt); + + if ( instance->cpx_request_queue ) + pci_free_consistent(instance->pdev, + megasas_get_cpx_mem_len( instance->cpx_dscrptr_cnt), + instance->cpx_request_queue, + instance->cpx_request_queue_h ); + + instance->cpx_supported = 0; + + return 0; +} + +/* should have host_mem_phys intialized before calling this function.*/ +static int megasas_init_cpx( struct megasas_instance *instance) +{ + instance->host_mem_virt = ioremap(instance->host_mem_phys, + instance->host_mem_len); + if ( instance->host_mem_virt == NULL ) { + printk(KERN_ERR "megasas: Failed to ioremap host memory.\n"); + goto error_unload; + } + + /* allocate memory for indices and descriptors response array's */ + instance->cpx_request_queue = + pci_alloc_consistent( instance->pdev, + megasas_get_cpx_mem_len (instance->cpx_dscrptr_cnt), + &instance->cpx_request_queue_h ); + + if ( instance->cpx_request_queue == NULL ) { + printk(KERN_ERR "Out of DMA memory for cpx operations.\n"); + goto error_unload; + } + + /*initialize queues*/ + instance->cpx_dscrptr = + (union mr_cpx_descriptor *)((u8 *)instance->cpx_request_queue + + (sizeof(instance->cpx_request_queue->consumer_idx)*2 )); + + if ( megasas_send_cpx_queue_data( instance ) ) { + printk(KERN_ERR " Sending cpx queue data to FW failed.\n"); + goto error_unload; + } + return 0; + +error_unload: + megasas_remove_cpx( instance ); + return -1; +} + /** * megasas_issue_init_mfi - Initializes the FW * @instance: Adapter soft state @@ -3353,6 +4637,10 @@ static int megasas_init_mfi(struct megas printk(KERN_DEBUG "megasas: Can't allocate version buffer\n"); } + if ( megasas_check_cpx_support( instance ) == 0 ) + if ( megasas_init_cpx( instance ) ) + printk(KERN_ERR "Error in initilizing cpx.\n"); + if (megasas_issue_init_mfi(instance)) goto fail_fw_init; @@ -3455,6 +4743,8 @@ static void megasas_release_mfi(struct m iounmap(instance->reg_set); + megasas_remove_cpx( instance ); + pci_release_selected_regions(instance->pdev, pci_select_bars(instance->pdev, IORESOURCE_MEM)); } @@ -4141,6 +5431,15 @@ megasas_resume(struct pci_dev *pdev) if (megasas_transition_to_ready(instance)) goto fail_ready_state; + if ( megasas_check_cpx_support( instance ) == 0 ) { + if ( megasas_send_cpx_queue_data( instance ) ) { + printk(KERN_ERR "Send cpx queue to FW failed.\n"); + megasas_remove_cpx(instance); + }else + instance->cpx_request_queue->consumer_idx = + instance->cpx_request_queue->producer_idx = 0; + } + if (megasas_issue_init_mfi(instance)) goto fail_init_mfi; diff -rupN old/drivers/scsi/megaraid/megaraid_sas.h new/drivers/scsi/megaraid/megaraid_sas.h --- old/drivers/scsi/megaraid/megaraid_sas.h 2010-11-15 04:45:34.000000000 -0500 +++ new/drivers/scsi/megaraid/megaraid_sas.h 2010-11-17 02:18:53.000000000 -0500 @@ -144,6 +144,14 @@ #define MR_DCMD_CLUSTER_RESET_LD 0x08010200 #define MR_DCMD_PD_LIST_QUERY 0x02010100 +#define MR_DCMD_CTRL_MISC_CPX 0x0100e200 +#define MR_DCMD_CTRL_MISC_CPX_INIT_DATA_GET 0x0100e201 +#define MR_DCMD_CTRL_MISC_CPX_QUEUE_DATA 0x0100e202 +#define MR_DCMD_CTRL_MISC_CPX_UNREGISTER 0x0100e203 +#define MAX_MR_ROW_SIZE 32 +#define MR_CPX_DIR_WRITE 1 +#define MR_CPX_DIR_READ 0 +#define MR_CPX_VERSION 1 /* * MFI command completion codes */ @@ -1256,6 +1264,174 @@ struct megasas_evt_detail { } __attribute__ ((packed)); +#define MIN(a, b) ((a) < (b) ? (a):(b)) + + +/* +* enumerates type of descriptor +*/ + +enum MR_CPX_DESCRIPTOR_TYPE { + MR_CPX_DESCRIPTOR_TYPE_COPY = 1, + MR_CPX_DESCRIPTOR_TYPE_XOR = 2 +}; + +/* +* status information of copy or xor operation +*/ +enum MR_CPX_STATUS { + MR_CPX_STATUS_SUCCESS = 0, + MR_CPX_STATUS_INCONSISTENT = 1, + MR_CPX_STATUS_FAILURE = 2, +}; + +/* +* define the XOR opcodes +*/ +enum MR_CPX_XOR_OP { + MR_CPX_XOR_OP_GEN_P = 0x01, + MR_CPX_XOR_OP_GEN_Q = 0x02, /* generate Q buffer */ + MR_CPX_XOR_OP_GEN_PQ = 0x03, /* generate P+Q buffers */ + MR_CPX_XOR_OP_CHECK_P = 0x11, /* check P buffer */ + MR_CPX_XOR_OP_CHECK_Q = 0x12, /* check Q buffer */ + MR_CPX_XOR_OP_CHECK_PQ = 0x13, /* check P+Q buffers */ +}; + +#define MR_CPX_XOR_OP_IS_CHECK(xorOp) ((xorOp & 0x10) != 0) +#define MR_CPX_XOR_OP_IS_GEN(xorOp) (!MR_CPX_XOR_OP_IS_CHECK(xorOp)) +#define MR_CPX_XOR_OP_IS_P(xorOp) ((xorOp & 0x01) != 0) +#define MR_CPX_XOR_OP_IS_Q(xorOp) ((xorOp & 0x02) != 0) +#define MR_CPX_XOR_OP_IS_PQ(xorOp) ((xorOp & 0x03) == 3) + +/* +* this data is passed to driver during driver init. +*/ +struct mr_cpx_init_data { + u32 cpx_desc_count; + u32 size; + u64 phys_addr_cache_buf; + +} __attribute__ ((packed)); + +/* +* header passed with each descriptor +*/ +struct mr_cpx_header { + u32 context : 24; + u32 type : 4; + u32 resvd : 4; +} __attribute__ ((packed)); + +/* +* xor descriptor data +*/ +struct mr_cpx_xor_descriptor { + struct mr_cpx_header hdr; + enum MR_CPX_XOR_OP op; + u32 size; + u32 buff_valid_bitmap; + u8 p_idx; + u8 q_idx; + u8 pad[2]; + u32 buff_list[MAX_MR_ROW_SIZE]; + u32 mult_list[MAX_MR_ROW_SIZE]; +} __attribute__ ((packed)); + + +/* +* copy buffer for each transfer. each such tranfer between +* user spare host address and firmware allocated cache data. +*/ +struct mr_cpx_copy_mr_buffer { + u32 buf; + u32 size; +} __attribute__ ((packed)); + +/* +* copy descriptor data +*/ +struct mr_cpx_copy_descriptor { + struct mr_cpx_header hdr; + u32 mfi_cmd_cxt; + u32 total_byte_count; + u32 host_skip_count; + u8 dir; + u8 pad[3]; + struct mr_cpx_copy_mr_buffer copy_buf[MAX_MR_ROW_SIZE]; +} __attribute__ ((packed)) ; + +/* +* users of this interface must allocate memory for the size of +* this structure while allocating memory for descriptors +*/ +union mr_cpx_descriptor { + struct mr_cpx_xor_descriptor cpx_xor_desc; + struct mr_cpx_copy_descriptor cpx_copy_desc; + u8 pad[512]; +} __attribute__ ((packed)); + + +/* +* request queue. +* firmware manages producerindex, driver manages consumerindex. +* number of decriptors is kept as variable. driver must use +* max host commands supported for allocation. +*/ +struct mr_cpx_request_queue { + u32 consumer_idx; + u32 producer_idx; + union mr_cpx_descriptor cpxdescriptor[1]; +} __attribute__ ((packed)); + + +/* +* response data. this data will be posted by driver after copy/xor +* operation is compete. +*/ +union mr_cpx_response_data { + struct { + u32 context : 24; + u32 status : 4; + u32 type : 4; + } r; + u32 w; +} __attribute__ ((packed)); + + +/* +* response queue. +* driver manages producerindex, firmware manages consumerindex. +* number of decriptors is kept as variable. driver must use +* max host commands supported for allocation. +*/ +struct mr_cpx_response_queue { + u32 consumer_idx; + u32 producer_idx; + union mr_cpx_response_data cpx_resp_data[1]; +} __attribute__ ((packed)); + + +/* +* the size of each of the structure within this is determined at run time. +* this structure is for document purpose and shows that the structures +* lay as shown below in memory +*/ +struct mr_cpx_queues { + struct mr_cpx_request_queue requestqueue; + struct mr_cpx_response_queue responsequeue; +} __attribute__ ((packed)); + +/* +* driver sends this queue data during mfi init. firmware +* will not use the interface if the versions do not match. +*/ +struct mr_cpx_queue_data { + u32 version; + u32 count_queue_entries; + u64 phys_addr_cpx_queues; +} __attribute__ ((packed)); + + struct megasas_aen_event { struct work_struct hotplug_work; struct megasas_instance *instance; @@ -1330,6 +1506,15 @@ struct megasas_instance { struct timer_list io_completion_timer; struct list_head internal_reset_pending_q; + + u32 cpx_supported; + struct mr_cpx_request_queue *cpx_request_queue; + dma_addr_t cpx_request_queue_h; + union mr_cpx_descriptor *cpx_dscrptr; + u32 cpx_dscrptr_cnt; + u64 host_mem_phys; + u32 host_mem_len; + u8 *host_mem_virt; }; enum {