title: Occasional OSX kernel panic in RetrieveINQUIRYData()
body: <p>I have a SCSI driver which calls <code>IOSCSIPrimaryCommandsDevice::RetrieveINQUIRYData()</code> as part of the startup process. Sometimes, after unplugging, ejecting, re-inserting and generally abusing the device during testing, a kernel panic occurs in there.</p>
  
  <p>The <a href="http://forge.voodooprojects.org/svn/chameleon/trunk/i386/include/IOKit/scsi/IOSCSIPrimaryCommandsDevice.h" rel="nofollow">signature</a> of this function is:</p>
  
  <pre><code>bool RetrieveINQUIRYData (
      UInt8 EVPD,
      UInt8 inquiryPage,
      UInt8 * inquiryBuffer,
      UInt16 * dataSize);
  </code></pre>
  
  <p>The routine which calls this starts like this. It is modelled after PublishUnitSerialNumber from <a href="https://www.opensource.apple.com/source/IOSCSIArchitectureModelFamily/IOSCSIArchitectureModelFamily-136.3.4/IOSCSIArchitectureModel/IOSCSITargetDevice.cpp" rel="nofollow">IOSCSITargetDevice.cpp</a></p>
  
  <pre><code>void MyDriverClass::PublishUnitSerialNumber ( IOService *             object )
  {
      bool                            result                                  = false;
      SCSICmd_INQUIRY_Page80_Header * data                                    = NULL;
      IOBufferMemoryDescriptor *      buffer                                  = NULL;
      OSString *                      string                                  = NULL;
      char                            serialNumber[kINQUIRY_MaximumDataSize]  = { 0 };
      UInt16                          length                                  = 0;
      SInt16                          serialLength                            = 0;
  
      DEBUG_LOG("%s[%p]::%s(%p)\n", getName(), this, __FUNCTION__, object);
  
      buffer = IOBufferMemoryDescriptor::withCapacity ( kINQUIRY_MaximumDataSize, kIODirectionIn );
      require( buffer != NULL, ErrorExit );
  
      data = (SCSICmd_INQUIRY_Page80_Header*) buffer-&gt;getBytesNoCopy();
      length = kINQUIRY_MaximumDataSize;
  
      require(data != NULL, ReleaseBuffer);
  
      bzero ( data, kINQUIRY_MaximumDataSize );
  
      result = RetrieveINQUIRYData ( 0x01,
                                        kINQUIRY_Page80_PageCode,
                                        ( UInt8 * ) data,
                                        &amp;length ); //PANIC IN HERE!
  
      require ( result, ReleaseBuffer );
      require ( ( data-&gt;PAGE_CODE == kINQUIRY_Page80_PageCode ), ReleaseBuffer );
  </code></pre>
  
  <p>This works most of the time, it's only occasionally that it panics. The GDB backtrace is faily unhelpful, as there are no symbols in that function, so all I know is that it's after another function call. I also can't find the source for this function - I think it's part of the closed-source IOKit code.</p>
  
  <pre><code>#0  Debugger (message=0x8001003b &lt;Address 0x8001003b out of bounds&gt;) at /SourceCache/xnu/xnu-1504.15.3/osfmk/i386/AT386/model_dep.c:867
  #1  0xffffff8000204d15 in panic (str=0xffffff800057ecb8 "Kernel trap at 0x%016llx, type %d=%s, registers:\nCR0: 0x%016llx, CR2: 0x%016llx, CR3: 0x%016llx, CR4: 0x%016llx\nRAX: 0x%016llx, RBX: 0x%016llx, RCX: 0x%016llx, RDX: 0x%016llx\nRSP: 0x%016llx, RBP: 0x%0"...) at /SourceCache/xnu/xnu-1504.15.3/osfmk/kern/debug.c:303
  #2  0xffffff80002d1208 in panic_trap [inlined] () at :1100
  #3  0xffffff80002d1208 in kernel_trap (state=&lt;value temporarily unavailable, due to optimizations&gt;) at /SourceCache/xnu/xnu-1504.15.3/osfmk/i386/trap.c:1001
  #4  0xffffff80002e3f4a in trap_from_kernel () at pmap.h:215
  #5  0xffffff7f808040b6 in ?? ()
  #6  0xffffff7f80804b8b in ?? ()
  #7  0xffffff7f80f1324c in com_company_driver_myDriver::PublishUnitSerialNumber (this=0xffffff80130e0600, object=0xffffff8015375000) at /Volumes/user/src/driver/MyDriver.cpp:106
  #8  0xffffff7f80f13553 in com_company_driver_myDriver::start (this=0xffffff80130e0600, provider=0xffffff8015375000) at /Volumes/user/src/driver/MyDriver.cpp:53
  #9  0xffffff800052d5a6 in IOService::startCandidate (this=0x2710, service=0xe) at /SourceCache/xnu/xnu-1504.15.3/iokit/Kernel/IOService.cpp:2879
  #10 0xffffff800052dcb1 in IOService::probeCandidates (this=0xffffff8015375000, matches=&lt;value temporarily unavailable, due to optimizations&gt;) at /SourceCache/xnu/xnu-1504.15.3/iokit/Kernel/IOService.cpp:2798
  ...
  ...
  </code></pre>
  
  <p>Is there something I should be checking or doing before calling <code>RetrieveINQUIRYData()</code> that I am not doing in the above code? From what I can see, all the pointers are checked for NULL, the lengths are set to constants and the only other argument is the literal for EVPD.</p>