patch-2.4.14 linux/drivers/scsi/cpqfcTSworker.c
Next file: linux/drivers/scsi/cyberstorm.c
Previous file: linux/drivers/scsi/cpqfcTSstructs.h
Back to the patch index
Back to the overall index
- Lines: 1103
- Date:
Thu Oct 25 13:53:50 2001
- Orig file:
v2.4.13/linux/drivers/scsi/cpqfcTSworker.c
- Orig date:
Mon Aug 27 12:41:44 2001
diff -u --recursive --new-file v2.4.13/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
@@ -703,8 +703,7 @@
{
// printk(" *Terminating x_ID %Xh on %Xh* ",
// x_ID, Exchanges->fcExchange[x_ID].status);
- cpqfcTSCompleteExchange( fcChip, x_ID);
-
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
}
} // end of ABTS case
@@ -2061,7 +2060,7 @@
Done:
// Regardless of whether the Reply is valid or not, the
// the exchange is done - complete
- cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
+ cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
Quit:
return;
@@ -2146,7 +2145,7 @@
// Regardless of whether the Reply is valid or not, the
// the exchange is done - complete
- cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete
+ cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
Quit:
return;
@@ -2328,7 +2327,7 @@
!(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
& 0x80000000))
{
- cpqfcTSCompleteExchange( fcChip, ExchangeID);
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
}
else
{
@@ -2370,7 +2369,7 @@
((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
(fchs->s_id & 0xFFFFFF)) )
{
- cpqfcTSCompleteExchange( fcChip, ExchangeID );
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
}
}
}
@@ -2409,7 +2408,7 @@
// already completed the exchange...
// printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
- cpqfcTSCompleteExchange( fcChip, ExchangeID );
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
}
}
} // end of ABTS check
@@ -2672,7 +2671,7 @@
printk("completing x_ID %X on status %Xh\n",
ExchangeID, Exchanges->fcExchange[ExchangeID].status);
#endif
- cpqfcTSCompleteExchange( fcChip, ExchangeID);
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
}
}
else // Xchange setup failed...
@@ -2915,6 +2914,22 @@
Done:
}
+static void
+call_scsi_done(Scsi_Cmnd *Cmnd)
+{
+ // We have to reinitialize sent_command here, so the scsi-mid
+ // layer won't re-use the scsi command leaving it set incorrectly.
+ // (incorrectly for our purposes...it's normally unused.)
+
+ if (Cmnd->SCp.sent_command != 0) { // was it a passthru?
+ Cmnd->SCp.sent_command = 0;
+ Cmnd->result &= 0xff00ffff;
+ Cmnd->result |= (DID_PASSTHROUGH << 16); // prevents retry
+ }
+ if (Cmnd->scsi_done != NULL)
+ (*Cmnd->scsi_done)(Cmnd);
+}
+
// After successfully getting a "Process Login" (PRLI) from an
// FC port, we want to Discover the LUNs so that we know the
// addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
@@ -3035,8 +3050,7 @@
Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry
// printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
- if( Cmnd->scsi_done != NULL)
- (*Cmnd->scsi_done)(Cmnd);
+ call_scsi_done(Cmnd);
}
}
}
@@ -3083,7 +3097,9 @@
// Complete the "bad target" commands (normally only used during
// initialization, since we aren't supposed to call "scsi_done"
- // inside the queuecommand() function).
+ // inside the queuecommand() function). (this is overly contorted,
+ // scsi_done can be safely called from queuecommand for
+ // this bad target case. May want to simplify this later)
for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
{
@@ -3092,8 +3108,7 @@
Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
cpqfcHBAdata->BadTargetCmnd[i] = NULL;
Cmnd->result = (DID_BAD_TARGET << 16);
- if( Cmnd->scsi_done != NULL)
- (*Cmnd->scsi_done)(Cmnd);
+ call_scsi_done(Cmnd);
}
else
break;
@@ -3153,7 +3168,7 @@
if( i >= TACH_SEST_LEN ) // Link Service Exchange
{
- cpqfcTSCompleteExchange( fcChip, i); // Don't "abort" LinkService
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // Don't "abort" LinkService
}
else // SEST Exchange TO -- may post ABTS to Worker Thread Que
@@ -3511,11 +3526,14 @@
(Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
{
Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
- if( Cmnd->scsi_done != NULL)
- (*Cmnd->scsi_done)(Cmnd);
- else
+ if( Cmnd->scsi_done == NULL)
+ {
printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
pLoggedInPort->port_id);
+ Cmnd->SCp.sent_command = 0;
+ }
+ else
+ call_scsi_done(Cmnd);
*SCptr = NULL; // free this slot for next use
}
}
@@ -4035,10 +4053,11 @@
static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
static ULONG build_SEST_sgList(
+ struct pci_dev *pcidev,
ULONG *SESTalPairStart,
Scsi_Cmnd *Cmnd,
ULONG *sgPairs,
- PSGPAGES sgPages // link list of TL Ext. S/G pages from O/S Pool
+ PSGPAGES *sgPages_head // link list of TL Ext. S/G pages from O/S Pool
);
static int build_FCP_payload( Scsi_Cmnd *Cmnd,
@@ -4202,7 +4221,6 @@
// assign tmp ptr (shorthand)
CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs;
-
if( Cmnd != NULL ) // (necessary for ABTS cases)
{
Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
@@ -4575,21 +4593,26 @@
pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
- pIWE->Hdr_Addr = virt_to_bus( dataHDR );
+ pIWE->Hdr_Addr = fcChip->SEST->base +
+ ((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] -
+ (unsigned long)fcChip->SEST);
+
pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0,
sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status
-
- pIWE->RSP_Addr = virt_to_bus(
- &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
+
+ pIWE->RSP_Addr = fcChip->SEST->base +
+ ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
+ (unsigned long)fcChip->SEST);
// Do we need local or extended gather list?
// depends on size - we can handle 3 len/addr pairs
// locally.
fcp_dl = build_SEST_sgList(
+ cpqfcHBAdata->PciDev,
&pIWE->GLen1,
Cmnd, // S/G list
&sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
@@ -4690,16 +4713,16 @@
pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
- pIRE->RSP_Addr = virt_to_bus(
- &fcChip->SEST->RspHDR[ *fcExchangeIndex ]);
-
+ pIRE->RSP_Addr = fcChip->SEST->base +
+ ((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] -
+ (unsigned long)fcChip->SEST);
// Do we need local or extended gather list?
// depends on size - we can handle 3 len/addr pairs
// locally.
fcp_dl = build_SEST_sgList(
+ cpqfcHBAdata->PciDev,
&pIRE->SLen1,
Cmnd, // SCSI command Data desc. with S/G list
&sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
@@ -4806,6 +4829,7 @@
// locally.
fcp_dl = build_SEST_sgList(
+ cpqfcHBAdata->PciDev,
&pTWE->SLen1,
Cmnd, // S/G list
&sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
@@ -4900,17 +4924,24 @@
// VALid entry:Dir outbound:enable CM:enal INT:
pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
- pTRE->Hdr_Addr = virt_to_bus( dataHDR );
+ pTRE->Hdr_Addr = // bus address of dataHDR;
+ fcChip->SEST->base +
+ ((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
+ (unsigned long)fcChip->SEST);
+
pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
- pTRE->RSP_Addr = virt_to_bus( rspHDR );
-
+ pTRE->RSP_Addr = // bus address of rspHDR
+ fcChip->SEST->base +
+ ((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
+ (unsigned long)fcChip->SEST);
// Do we need local or extended gather list?
// depends on size - we can handle 3 len/addr pairs
// locally.
fcp_dl = build_SEST_sgList(
+ cpqfcHBAdata->PciDev,
&pTRE->GLen1,
Cmnd, // S/G list
&sgPairs, // return # of pairs in S/G list (from "Data" descriptor)
@@ -5001,8 +5032,10 @@
// len & flags according to command type above
pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len
- pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr
- // of frame to send
+ pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
+ fcChip->exch_dma_handle + (unsigned long)CMDfchs -
+ (unsigned long)Exchanges;
+
pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
// Exchange is complete except for "fix-up" fields to be set
@@ -5017,7 +5050,7 @@
printk( "FC Error: SEST build Pool Allocation failed\n");
#endif
// return resources...
- cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex); // SEST build failed
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex); // SEST build failed
}
}
else // no Exchanges available
@@ -5059,7 +5092,61 @@
}
+static dma_addr_t
+cpqfc_pci_map_sg_page(
+ struct pci_dev *pcidev,
+ ULONG *hw_paddr, // where to put phys addr for HW use
+ void *sgp_vaddr, // the virtual address of the sg page
+ dma_addr_t *umap_paddr, // where to put phys addr for unmap
+ unsigned int *maplen, // where to store sg entry length
+ int PairCount) // number of sg pairs used in the page.
+{
+ unsigned long aligned_addr = (unsigned long) sgp_vaddr;
+
+ *maplen = PairCount * 8;
+ aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+ aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
+
+ *umap_paddr = pci_map_single(pcidev, (void *) aligned_addr,
+ *maplen, PCI_DMA_TODEVICE);
+ *hw_paddr = (ULONG) *umap_paddr;
+
+# if BITS_PER_LONG > 32
+ if( *umap_paddr >>32 ) {
+ printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n",
+ (void*)umap_paddr);
+ return 0;
+ }
+# endif
+ return *umap_paddr;
+}
+
+static void
+cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
+ unsigned long contigaddr, int len, int dir,
+ struct scatterlist *sgl, int use_sg,
+ PSGPAGES *sgPages_head,
+ int allocated_pages)
+{
+ PSGPAGES i, next;
+
+ if (contigaddr != (unsigned long) NULL)
+ pci_unmap_single(pcidev, contigaddr, len, dir);
+
+ if (sgl != NULL)
+ pci_unmap_sg(pcidev, sgl, use_sg, dir);
+ for (i=*sgPages_head; i != NULL ;i = next)
+ {
+ pci_unmap_single(pcidev, i->busaddr, i->maplen,
+ scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+ i->busaddr = (dma_addr_t) NULL;
+ i->maplen = 0L;
+ next = i->next;
+ kfree(i);
+ }
+ *sgPages_head = NULL;
+}
// This routine builds scatter/gather lists into SEST entries
// INPUTS:
@@ -5077,263 +5164,380 @@
//#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
+static int ap_hi_water = TL_DANGER_SGPAGES;
+
static ULONG build_SEST_sgList(
+ struct pci_dev *pcidev,
ULONG *SESTalPairStart, // the 3 len/address buffers in SEST
Scsi_Cmnd *Cmnd,
ULONG *sgPairs,
- PSGPAGES sgPages) // link list of TL Ext. S/G pages from O/S Pool
+ PSGPAGES *sgPages_head) // link list of TL Ext. S/G pages from O/S Pool
{
ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
ULONG* alPair = SESTalPairStart;
- ULONG alignedPageAddress; // TL hardware alignment requirement
+ ULONG* ext_sg_page_phys_addr_place = NULL;
int PairCount;
- unsigned long ulBuff;
+ unsigned long ulBuff, contigaddr;
ULONG total_data_len=0; // (in bytes)
ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
ULONG thisMappingLen;
- struct scatterlist *sgl; // S/G list (Linux format)
-
+ struct scatterlist *sgl = NULL; // S/G list (Linux format)
+ int sg_count, totalsgs;
+ dma_addr_t busaddr;
+ unsigned long thislen, offset;
+ PSGPAGES *sgpage = sgPages_head;
+ PSGPAGES prev_page = NULL;
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+ contigaddr = (unsigned long) NULL;
if( !Cmnd->use_sg ) // no S/G list?
{
- *sgPairs = 1; // use "local" S/G pair in SEST entry
- // (for now, ignore address bits above #31)
- *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length
- ulBuff = virt_to_bus( Cmnd->request_buffer);
-#if BITS_PER_LONG > 32
- if( ulBuff >>32 )
- {
- printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff );
- return 0;
- }
-#endif
- *alPair = (ULONG)ulBuff;
- return bytes_to_go;
- }
+ if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
+ {
+ *sgPairs = 1; // use "local" S/G pair in SEST entry
+ // (for now, ignore address bits above #31)
+ *alPair++ = bytes_to_go; // bits 18-0, length
- // [TBD - update for Linux to support > 32 bits addressing]
- // since the format for local & extended S/G lists is different,
- // check if S/G pairs exceeds 3.
- *sgPairs = Cmnd->use_sg;
- sgl = (struct scatterlist*)Cmnd->request_buffer;
-
- if( *sgPairs <= 3 ) // need "local" SEST list
+ if (bytes_to_go != 0) {
+ contigaddr = ulBuff = pci_map_single(pcidev,
+ Cmnd->request_buffer,
+ Cmnd->request_bufflen,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ // printk("ms %p ", ulBuff);
+ }
+ else {
+ // No data transfer, (e.g.: Test Unit Ready)
+ // printk("btg=0 ");
+ *sgPairs = 0;
+ memset(alPair, 0, sizeof(*alPair));
+ return 0;
+ }
+
+# if BITS_PER_LONG > 32
+ if( ulBuff >>32 ) {
+ printk("FATAL! Tachyon DMA address %p "
+ "exceeds 32 bits\n", (void*)ulBuff );
+ return 0;
+ }
+# endif
+ *alPair = (ULONG)ulBuff;
+ return bytes_to_go;
+ }
+ else // We have a single large (too big) contiguous buffer.
+ { // We will have to break it up. We'll use the scatter
+ // gather code way below, but use contigaddr instead
+ // of sg_dma_addr(). (this is a very rare case).
+
+ unsigned long btg;
+ contigaddr = pci_map_single(pcidev, Cmnd->request_buffer,
+ Cmnd->request_bufflen,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+ // printk("contigaddr = %p, len = %d\n",
+ // (void *) contigaddr, bytes_to_go);
+ totalsgs = 0;
+ for (btg = bytes_to_go; btg > 0; ) {
+ btg -= ( btg > TL_MAX_SG_ELEM_LEN ?
+ TL_MAX_SG_ELEM_LEN : btg );
+ totalsgs++;
+ }
+ sgl = NULL;
+ *sgPairs = totalsgs;
+ }
+ }
+ else // we do have a scatter gather list
+ {
+ // [TBD - update for Linux to support > 32 bits addressing]
+ // since the format for local & extended S/G lists is different,
+ // check if S/G pairs exceeds 3.
+ // *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+
+ sgl = (struct scatterlist*)Cmnd->request_buffer;
+ sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+ // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
+ if( sg_count <= 3 ) {
+
+ // we need to be careful here that no individual mapping
+ // is too large, and if any is, that breaking it up
+ // doesn't push us over 3 sgs, or, if it does, that we
+ // handle that case. Tachyon can take 0x7FFFF bits for length,
+ // but sg structure uses "unsigned int", on the face of it,
+ // up to 0xFFFFFFFF or even more.
+
+ int i;
+ unsigned long thislen;
+
+ totalsgs = 0;
+ for (i=0;i<sg_count;i++) {
+ thislen = sg_dma_len(&sgl[i]);
+ while (thislen >= TL_MAX_SG_ELEM_LEN) {
+ totalsgs++;
+ thislen -= TL_MAX_SG_ELEM_LEN;
+ }
+ if (thislen > 0) totalsgs++;
+ }
+ *sgPairs = totalsgs;
+ } else totalsgs = 999; // as a first estimate, definitely >3,
+
+ // if (totalsgs != sg_count)
+ // printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+ }
+
+ // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
+ if( totalsgs <= 3 ) // can (must) use "local" SEST list
{
while( bytes_to_go)
{
- thisMappingLen = sgl->length; // we want them ALL on every pass
- bytes_to_go = bytes_to_go - thisMappingLen;
+ offset = 0L;
- // we have L/A pair; L = thisMappingLen, A = physicalAddress
- // load into SEST...
- total_data_len += thisMappingLen & 0x7ffff; // mask in valid bits
- // per SEST format
- *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length
-// physicalAddress.HighPart <= 19; // shift to bit 19
-
- // pick up bits 44-32 of upper 64-bit address
- // and load into 31-19 LBAU (upper addr) of SEST entry
-// *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
- // on Tachlite TS's local S/G, we can handle 13 extra address bits
- // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
-
- alPair++;
-
- ulBuff = virt_to_bus( sgl->address);
-#if BITS_PER_LONG > 32
- if( ulBuff >>32 )
- {
- printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
- return 0;
- }
-#endif
- *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
+ if ( WE_HAVE_SG_LIST )
+ thisMappingLen = sg_dma_len(sgl);
+ else // or contiguous buffer?
+ thisMappingLen = bytes_to_go;
- ++sgl; // next S/G pair
-#ifdef DBG_SEST_SGLIST
- printk(" thisLen %d ", thisMappingLen);
- printk(" remain %d\n", bytes_to_go);
-#endif
+ while (thisMappingLen > 0)
+ {
+ thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
+ TL_MAX_SG_ELEM_LEN : thisMappingLen;
+ bytes_to_go = bytes_to_go - thislen;
- }
- }
+ // we have L/A pair; L = thislen, A = physicalAddress
+ // load into SEST...
+
+ total_data_len += thislen;
+ *alPair = thislen; // bits 18-0, length
+
+ alPair++;
+ if ( WE_HAVE_SG_LIST )
+ ulBuff = sg_dma_address(sgl) + offset;
+ else
+ ulBuff = contigaddr + offset;
+ offset += thislen;
+# if BITS_PER_LONG > 32
+ if( ulBuff >>32 ) {
+ printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n",
+ (void*)ulBuff );
+ printk("%s = %p, offset = %ld\n",
+ WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
+ WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
+ offset);
+ return 0;
+ }
+# endif
+ *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
+ thisMappingLen -= thislen;
+ }
+
+ if ( WE_HAVE_SG_LIST ) ++sgl; // next S/G pair
+ else if (bytes_to_go != 0) printk("BTG not zero!\n");
+
+# ifdef DBG_SEST_SGLIST
+ printk("L=%d ", thisMappingLen);
+ printk("btg=%d ", bytes_to_go);
+# endif
+ }
+ // printk("i:%d\n", *sgPairs);
+ }
else // more than 3 pairs requires Extended S/G page (Pool Allocation)
{
// clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
-
-
-
for( i=2; i<6; i++)
alPair[i] = 0;
PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation
-
+ totalsgs = 0;
while( bytes_to_go )
{
-
-
- // Per SEST format, we can support 524287 byte lenghts per
+ // Per SEST format, we can support 524287 byte lengths per
// S/G pair. Typical user buffers are 4k, and very rarely
// exceed 12k due to fragmentation of physical memory pages.
// However, on certain O/S system (not "user") buffers (on platforms
- // with huge memories like 256Meg), it's possible to exceed this
- // length in a single S/G address/len mapping.
- //
- // Check for Tachyon length boundary
- //
- if( sgl->length > 0x7ffff )
- {
- // never ask for more than we can handle
- thisMappingLen = sgl->length & 0x7ffff;
- }
+ // with huge memories), it's possible to exceed this
+ // length in a single S/G address/len mapping, so we have to handle
+ // that.
+
+ offset = 0L;
+ if ( WE_HAVE_SG_LIST )
+ thisMappingLen = sg_dma_len(sgl);
else
- thisMappingLen = sgl->length;
-
+ thisMappingLen = bytes_to_go;
-
- // should we load into "this" extended S/G page, or allocate
- // new page?
-
- if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+ while (thisMappingLen > 0)
{
- // have we exceeded the max possible extended pages?
- if( AllocatedPages >= TL_MAX_SGPAGES)
- {
- printk("Error: aborted loop on %d Ext. S/G page allocations\n",
- AllocatedPages);
-
- total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
- break; // failed
- }
-
- // Allocate the TL Extended S/G list page from O/S pool. We have
- // to allocated twice what we want to ensure required TL alignment
- // (Tachlite TL/TS User Man. Rev 6.0, p 168)
- // We store the original allocated PVOID so we can free later
-
- sgPages->PoolPage[ AllocatedPages] =
- kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment
-
-
- if( !sgPages->PoolPage[ AllocatedPages] ) // Allocation failed?
- {
-
- printk("Error: Allocation failed @ %d S/G page allocations\n",
- AllocatedPages);
-
- total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
- break; // give up
- }
- // clear out memory we just allocated
- memset( sgPages->PoolPage[AllocatedPages], 0,
- TL_EXT_SG_PAGE_BYTELEN*2);
-
+ thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ?
+ TL_MAX_SG_ELEM_LEN : thisMappingLen;
+ // printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
- // align the memory - TL requires sizeof() Ext. S/G page alignment.
- // We doubled the actual required size so we could mask off LSBs
- // to get desired offset
-
- ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]);
-
-#if BITS_PER_LONG > 32
- if( ulBuff >>32 )
- {
- printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n",
- (void*)ulBuff );
- return 0;
- }
-#endif
-
- ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary
- ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs
-
- alignedPageAddress = (ULONG)ulBuff;
-#ifdef DBG_SEST_SGLIST
- printk("new PoolPage: %p, alignedPageAddress %lXh\n",
- sgPages->PoolPage[AllocatedPages], ulBuff);
-#endif
-
+ // should we load into "this" extended S/G page, or allocate
+ // new page?
- // set pointer, in SEST if first Ext. S/G page, or in last pair
- // of linked Ext. S/G pages...
- // (Only 32-bit PVOIDs, so just load lower 32 bits)
- // NOTE: the Len field must be '0' if this is the first Ext. S/G
- // pointer in SEST, and not 0 otherwise.
- if( alPair == SESTalPairStart) // initial Ext. S/G list?
- *alPair = 0;
- else // not the SEST entry... Len must be non-0, so
- // arbitrarily set it to number bytes remaining
- *alPair = ( bytes_to_go & 0x7ffff);
-
-#ifdef DBG_SEST_SGLIST
- printk("PairCount %d @%p even %Xh, ",
- PairCount, alPair, *alPair);
-#endif
- alPair++; // next DWORD
+ if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+ {
+ // Now, we have to map the previous page, (triggering buffer bounce)
+ // The first time thru the loop, there won't be a previous page.
+ if (prev_page != NULL) // is there a prev page?
+ {
+ // this code is normally kind of hard to trigger,
+ // you have to use up more than 256 scatter gather
+ // elements to get here. Cranking down TL_MAX_SG_ELEM_LEN
+ // to an absurdly low value (128 bytes or so) to artificially
+ // break i/o's into a zillion pieces is how I tested it.
+ busaddr = cpqfc_pci_map_sg_page(pcidev,
+ ext_sg_page_phys_addr_place,
+ prev_page->page,
+ &prev_page->busaddr,
+ &prev_page->maplen,
+ PairCount);
+ }
+ // Allocate the TL Extended S/G list page. We have
+ // to allocate twice what we want to ensure required TL alignment
+ // (Tachlite TL/TS User Man. Rev 6.0, p 168)
+ // We store the original allocated PVOID so we can free later
+ *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
+ if ( ! *sgpage )
+ {
+ printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
+ AllocatedPages);
+ total_data_len = 0; // failure!! Ext. S/G is All-or-none affair
+
+ // unmap the previous mappings, if any.
+
+ cpqfc_undo_SEST_mappings(pcidev, contigaddr,
+ Cmnd->request_bufflen,
+ scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
+ sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
+
+ // FIXME: testing shows that if we get here,
+ // it's bad news. (this has been this way for a long
+ // time though, AFAIK. Not that that excuses it.)
- *alPair = alignedPageAddress; // TL needs 32-bit physical
-#ifdef DBG_SEST_SGLIST
- printk("odd %Xh\n", *alPair);
-#endif
-
- // now reset the pointer to the ACTUAL (Extended) S/G page
- // which will accept the Len/ PhysicalAddress pairs
- alPair = bus_to_virt(alignedPageAddress);
-
- AllocatedPages++;
- PairCount = 1; // starting new Ext. S/G page
- } // end of new TL Ext. S/G page allocation
+ return 0; // give up (and probably hang the system)
+ }
+ // clear out memory we just allocated
+ memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
+ (*sgpage)->next = NULL;
+ (*sgpage)->busaddr = (dma_addr_t) NULL;
+ (*sgpage)->maplen = 0L;
+
+ // align the memory - TL requires sizeof() Ext. S/G page alignment.
+ // We doubled the actual required size so we could mask off LSBs
+ // to get desired offset
+
+ ulBuff = (unsigned long) (*sgpage)->page;
+ ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+ ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
+
+ // set pointer, in SEST if first Ext. S/G page, or in last pair
+ // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just
+ // load lower 32 bits)
+ // NOTE: the Len field must be '0' if this is the first Ext. S/G
+ // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+ *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+
+# ifdef DBG_SEST_SGLIST
+ printk("PairCount %d @%p even %Xh, ",
+ PairCount, alPair, *alPair);
+# endif
+
+ // Save the place where we need to store the physical
+ // address of this scatter gather page which we get when we map it
+ // (and mapping we can do only after we fill it in.)
+ alPair++; // next DWORD, will contain phys addr of the ext page
+ ext_sg_page_phys_addr_place = alPair;
+
+ // Now, set alPair = the virtual addr of the (Extended) S/G page
+ // which will accept the Len/ PhysicalAddress pairs
+ alPair = (ULONG *) ulBuff;
-
- *alPair = thisMappingLen; // bits 18-0, length (range check above)
-
-
-// physicalAddress.HighPart <= 19; // shift to bit 19
-
- // pick up bits 44-32 of upper 64-bit address
- // and load into 31-19 LBAU (upper addr) of SEST entry
-// *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8));
+ AllocatedPages++;
+ if (AllocatedPages >= ap_hi_water)
+ {
+ // This message should rarely, if ever, come out.
+ // Previously (cpqfc version <= 2.0.5) the driver would
+ // just puke if more than 4 SG pages were used, and nobody
+ // ever complained about that. This only comes out if
+ // more than 8 pages are used.
+
+ printk(KERN_WARNING
+ "cpqfc: Possible danger. %d scatter gather pages used.\n"
+ "cpqfc: detected seemingly extreme memory "
+ "fragmentation or huge data transfers.\n",
+ AllocatedPages);
+ ap_hi_water = AllocatedPages+1;
+ }
+
+ PairCount = 1; // starting new Ext. S/G page
+ prev_page = (*sgpage); // remember this page, for next time thru
+ sgpage = &((*sgpage)->next);
+ } // end of new TL Ext. S/G page allocation
+ *alPair = thislen; // bits 18-0, length (range check above)
-#ifdef DBG_SEST_SGLIST
- printk("PairCount %d @%p, even %Xh, ",
- PairCount, alPair, *alPair);
-#endif
+# ifdef DBG_SEST_SGLIST
+ printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+# endif
- alPair++; // next DWORD
- // on Tachlite TS's local S/G, we can handle 13 extra address bits
- // i.e., bits 31-19 are actually bits 44-32 of physicalAddress
+ alPair++; // next DWORD, physical address
+ if ( WE_HAVE_SG_LIST )
+ ulBuff = sg_dma_address(sgl) + offset;
+ else
+ ulBuff = contigaddr + offset;
+ offset += thislen;
- ulBuff = virt_to_bus( sgl->address);
-#if BITS_PER_LONG > 32
- if( ulBuff >>32 )
- {
- printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff );
- return 0;
- }
-#endif
- *alPair = (ULONG)ulBuff; // lower 32 bits (31-0)
+# if BITS_PER_LONG > 32
+ if( ulBuff >>32 )
+ {
+ printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
+ printk("%s = %p, offset = %ld\n",
+ WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
+ WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
+ offset);
+ return 0;
+ }
+# endif
+ *alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
-#ifdef DBG_SEST_SGLIST
- printk("odd %Xh\n", *alPair);
-#endif
- alPair++; // next DWORD
+# ifdef DBG_SEST_SGLIST
+ printk("odd %Xh\n", *alPair);
+# endif
+ alPair++; // next DWORD, next address/length pair
+ PairCount++; // next Length/Address pair
- PairCount++; // next Length/Address pair
- bytes_to_go -= thisMappingLen;
- total_data_len += thisMappingLen;
- sgl++; // next S/G pair
- }
+ // if (PairCount > pc_hi_water)
+ // {
+ // printk("pc hi = %d ", PairCount);
+ // pc_hi_water = PairCount;
+ // }
+ bytes_to_go -= thislen;
+ total_data_len += thislen;
+ thisMappingLen -= thislen;
+ totalsgs++;
+ } // while (thisMappingLen > 0)
+ if ( WE_HAVE_SG_LIST ) sgl++; // next S/G pair
+ } // while (bytes_to_go)
+
+ // printk("Totalsgs=%d\n", totalsgs);
+ *sgPairs = totalsgs;
+
+ // PCI map (and bounce) the last (and usually only) extended SG page
+ busaddr = cpqfc_pci_map_sg_page(pcidev,
+ ext_sg_page_phys_addr_place,
+ prev_page->page,
+ &prev_page->busaddr,
+ &prev_page->maplen,
+ PairCount);
}
return total_data_len;
}
@@ -5584,7 +5788,7 @@
if( CompleteExchange || // flag from Reply frames
pExchange->status ) // typically, can get FRAME_TO
{
- cpqfcTSCompleteExchange( fcChip, ExchangeID);
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
}
}
@@ -5594,7 +5798,7 @@
if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng)
{
- cpqfcTSCompleteExchange( fcChip, ExchangeID);
+ cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
}
else
@@ -5738,9 +5942,46 @@
return i;
}
+static void
+cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
+ PTACHYON fcChip,
+ ULONG x_ID)
+{
+ // Unmaps the memory regions used to hold the scatter gather lists
+ PSGPAGES i;
+ // Were there any such regions needing unmapping?
+ if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+ return; // No such regions, we're outta here.
+
+ // for each extended scatter gather region needing unmapping...
+ for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
+ pci_unmap_single(pcidev, i->busaddr, i->maplen,
+ scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+}
+// Called also from cpqfcTScontrol.o, so can't be static
+void
+cpqfc_pci_unmap(struct pci_dev *pcidev,
+ Scsi_Cmnd *cmd,
+ PTACHYON fcChip,
+ ULONG x_ID)
+{
+ // Undo the DMA mappings
+ if (cmd->use_sg) { // Used scatter gather list for data buffer?
+ cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
+ pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ // printk("umsg %d\n", cmd->use_sg);
+ }
+ else if (cmd->request_bufflen) {
+ // printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
+ pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
+ cmd->request_bufflen,
+ scsi_to_pci_dma_dir(cmd->sc_data_direction));
+ }
+}
// We call this routine to free an Exchange for any reason:
// completed successfully, completed with error, aborted, etc.
@@ -5751,10 +5992,12 @@
//scompleteexchange
void cpqfcTSCompleteExchange(
+ struct pci_dev *pcidev,
PTACHYON fcChip,
ULONG x_ID)
{
FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+ int already_unmapped = 0;
if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
{
@@ -5883,9 +6126,38 @@
// case for. Need code maintenance! Return "ERROR"
else
{
- printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n",
+ unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
+ printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p",
Exchanges->fcExchange[ x_ID ].status, x_ID,
Exchanges->fcExchange[ x_ID ].Cmnd);
+
+ if (stat & INVALID_ARGS) printk(" INVALID_ARGS ");
+ if (stat & LNKDWN_OSLS) printk(" LNKDWN_OSLS ");
+ if (stat & LNKDWN_LASER) printk(" LNKDWN_LASER ");
+ if (stat & OUTQUE_FULL) printk(" OUTQUE_FULL ");
+ if (stat & DRIVERQ_FULL) printk(" DRIVERQ_FULL ");
+ if (stat & SEST_FULL) printk(" SEST_FULL ");
+ if (stat & BAD_ALPA) printk(" BAD_ALPA ");
+ if (stat & OVERFLOW) printk(" OVERFLOW ");
+ if (stat & COUNT_ERROR) printk(" COUNT_ERROR ");
+ if (stat & LINKFAIL_RX) printk(" LINKFAIL_RX ");
+ if (stat & ABORTSEQ_NOTIFY) printk(" ABORTSEQ_NOTIFY ");
+ if (stat & LINKFAIL_TX) printk(" LINKFAIL_TX ");
+ if (stat & HOSTPROG_ERR) printk(" HOSTPROG_ERR ");
+ if (stat & FRAME_TO) printk(" FRAME_TO ");
+ if (stat & INV_ENTRY) printk(" INV_ENTRY ");
+ if (stat & SESTPROG_ERR) printk(" SESTPROG_ERR ");
+ if (stat & OUTBOUND_TIMEOUT) printk(" OUTBOUND_TIMEOUT ");
+ if (stat & INITIATOR_ABORT) printk(" INITIATOR_ABORT ");
+ if (stat & MEMPOOL_FAIL) printk(" MEMPOOL_FAIL ");
+ if (stat & FC2_TIMEOUT) printk(" FC2_TIMEOUT ");
+ if (stat & TARGET_ABORT) printk(" TARGET_ABORT ");
+ if (stat & EXCHANGE_QUEUED) printk(" EXCHANGE_QUEUED ");
+ if (stat & PORTID_CHANGED) printk(" PORTID_CHANGED ");
+ if (stat & DEVICE_REMOVED) printk(" DEVICE_REMOVED ");
+ if (stat & SFQ_FRAME) printk(" SFQ_FRAME ");
+ printk("\n");
+
Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
}
}
@@ -5896,6 +6168,10 @@
cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result)
}
+ cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
+ fcChip, x_ID); // undo DMA mappings.
+ already_unmapped = 1;
+
// OK, we've set the Scsi "->result" field, so proceed with calling
// Linux Scsi "done" (if not NULL), and free any kernel memory we
// may have allocated for the exchange.
@@ -5910,17 +6186,17 @@
if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
{
PCI_TRACE(0xAC)
- (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done)
- (Exchanges->fcExchange[ x_ID ].Cmnd);
+ call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
}
else
{
-
+ Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
// printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
}
}
else{
+ Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
Exchanges->fcExchange[ x_ID ].type,
Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);
@@ -5930,22 +6206,23 @@
// Now, clean up non-Scsi_Cmnd items...
CleanUpSestResources:
-
+
+ if (!already_unmapped)
+ cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd,
+ fcChip, x_ID); // undo DMA mappings.
+
// Was an Extended Scatter/Gather page allocated? We know
// this by checking DWORD 4, bit 31 ("LOC") of SEST entry
if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
{
- int i = 0;
+ PSGPAGES p, next;
// extended S/G list was used -- Free the allocated ext. S/G pages
-
- while( fcChip->SEST->sgPages[x_ID].PoolPage[i] &&
- (i < TL_MAX_SGPAGES) )
- {
- kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]);
- fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL;
- i++;
+ for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+ next = p->next;
+ kfree(p);
}
+ fcChip->SEST->sgPages[x_ID] = NULL;
}
Exchanges->fcExchange[ x_ID ].Cmnd = NULL;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)