Sending Large Packets and Reassembling over Serial
Let me dissect your program and show you precisely what is going on and why your approach is completely wrong:

Your first step is to throw 30,000 bytes at the serial port. Those go via the TX ringbuffer, which is (as you have changed it for some reason) 256 bytes:

buf = (char*)calloc(1,30000);

Serial.println("Writing to Serial3");
  for(i=0;i&lt;30000;i++){
    Serial3.write((byte)i);
    cksum+=j;
    j++;
    if(j&gt;255){j=0;}
  }


At this point 29744 bytes have left the hardware UART. 256 are still sat in the TX ringbuffer being sent out by the TX interrupt routine.  The first 256 bytes that were sent out were picked up by the RX interrupt routine and stored in the RX ringbuffer. The next 29488 bytes were discarded (they are now all over the carpet with your marbles).

 Serial.println(cksum);
 Serial.println("Reading from Serial2");


Now you try and read 30,000 bytes from the 256 byte RX ringbuffer. While you are doing that the remaining 256 bytes in the TX ringbuffer are being slowly sent out. You are now making some room in that RX ringbuffer since you are removing bytes from it, so some of the remaining 256 received bytes can now be stored in it. The first one of those happens to be 0x30.

 Serial2.readBytes(buf,30000);


Now you go and print out your array, which has only a tiny fraction of the 30,000 bytes you sent in it.

 cksum = 0;
  Serial.print("Buf is: ");
  for(i=0;i&lt;30000;i++){
    if(i&lt;300){ //only print out the first 300 characters
      Serial.print("[");
      Serial.print(buf[i],HEX);
      Serial.print("]");
    }
    if(buf[i] != j){
      Serial.print("\nMismatch at i = ");
      Serial.print(i);
      Serial.print("\nBuf is: ");
      Serial.print(buf[i-1],HEX);
      Serial.print(",");
      Serial.println(buf[i],HEX);
    }
    cksum+=buf[i];
    j++;
    if(j&gt;255){j=0;}
  }
  Serial.println("\n\nEnd");
  Serial.println(cksum);

}


The simple fact is, you are transmitting, en-masse, far more bytes than the Arduino's RX ringbuffer can hold. In order to receive more than the 256 bytes of the ringbuffer you have to read the bytes from that ringbuffer to make room for more to arrive. And since you are the one that is transmitting that means you have to do your receiving at the same time as the transmitting.

The only possible way that your arrangement of program could work would be if you increased the RX ringbuffer to greater than 30,000 bytes so it can store all the received bytes as you transmit them for you to then, afterwards, copy the contents of that ringbuffer into your own buffer.