Index: dc395x_trm.c =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.c,v retrieving revision 1.76 retrieving revision 1.77 diff -u -u -r1.76 -r1.77 --- dc395x_trm.c 2002/02/28 04:21:55 1.76 +++ dc395x_trm.c 2002/02/28 11:18:37 1.77 @@ -12,7 +12,7 @@ //* Kurt Garloff //* (C) 1999-2000 Kurt Garloff //* License: GNU GPL -//* $Id: dc395x_trm.c,v 1.76 2002/02/28 04:21:55 garloff Exp $ +//* $Id: dc395x_trm.c,v 1.77 2002/02/28 11:18:37 garloff Exp $ //*********************************************************************** //* Tekram PCI SCSI adapter (DC395/U/UW/F or DC315/U) revision history //* @@ -98,6 +98,9 @@ //* 1.36 02/02/27 KG Use pci_map() instead of virt_to_bus(). //* Linux 2.5 Scsi_Host->host_lock locking //* Slight variation of chip bug worked around :-( +//* 1.37 02/02/28 KG Free SRB's SG lists on module exit +//* Alloc in many chunks instead of one big +//* and don't waste memory by alignment. //*********************************************************************** /* ************************************************************************* @@ -193,7 +196,7 @@ # define TRACEOUTALL(x...) do {} while (0) #endif #ifdef DC395x_DEBUGTRACE -# define DEBUGTRACEBUFSZ 944 +# define DEBUGTRACEBUFSZ 512 char DC395x_tracebuf[64]; char DC395x_traceoverflow[8] = {0,0,0,0,0,0,0,0}; # define TRACEPRINTF(x...) \ @@ -447,21 +450,16 @@ */ struct _SRB { - /* Align, so it can not cross a page boundary */ - SGentry SegmentX[DC395x_MAX_SG_LISTENTRY] __attribute__ ((aligned(512))); - /* - ** make a one entry of S/G list table - ** use it as use_sg case when at request_buffer case - */ - - /* Offset 0x200/0x200 (64/32bit arch) */ struct _SRB *pNextSRB; struct _DCB *pSRBDCB; - unsigned char* virt_addr; /* set by DC395x_update_SGlist */ + /* HW scatter list (up to 64 entries) */ + PSGE0 SegmentX; PSCSICMD pcmd; + + /* Offset 0x20/0x10 */ + unsigned char* virt_addr; /* set by DC395x_update_SGlist */ - /* Offset 0x220/0x210 */ DWORD SRBTotalXferLength; DWORD Xferred; /* Backup for the already xferred len */ @@ -471,7 +469,7 @@ BYTE SRBSGCount; BYTE SRBSGIndex; - /* Offset 0x230/0x220 */ + /* Offset 0x38/0x24 */ BYTE MsgInBuf[6]; BYTE MsgOutBuf[6]; @@ -480,7 +478,7 @@ BYTE MsgCnt; BYTE EndMessage; - /* Offset 0x240/0x230 */ + /* Offset 0x48/0x34 */ PBYTE pMsgPtr; BYTE TagNumber; @@ -492,10 +490,10 @@ //BYTE IORBFlag; /* 81h-Reset, 2-retry */ BYTE padding; WORD debugpos; - /* Offset 0x250/0x23c */ + /* Offset 0x58/0x40 */ #ifdef DC395x_DEBUGTRACE - char debugtrace[DEBUGTRACEBUFSZ]; - /* Offset 0x600/0x5f0 */ + char *debugtrace; + /* Offset 0x60/0x44 */ #endif }; typedef struct _SRB DC395X_TRM_SRB, *PSRB; @@ -623,10 +621,9 @@ BYTE MsgLen; BYTE DeviceCnt; - /* As every SRB is 1024 bytes (1536 with tracebuf), don't use too many */ - PSRB SRB_array; + /* As every SRB is 768 bytes, don't use too many */ + DC395X_TRM_SRB SRB_array[40]; DC395X_TRM_SRB TmpSRB; - /* 36 SRBs. 36864 bytes! (55296 with tracebuf) */ }; typedef struct _ACB DC395X_TRM_ACB, *PACB; @@ -5318,8 +5315,8 @@ // Restore SG stuff //printk ("Auto_ReqSense finished: Restore Counters ...\n"); pSRB->SRBTotalXferLength = pSRB->Xferred; - pSRB->SegmentX[0].address = pSRB->SegmentX[63].address; - pSRB->SegmentX[0].length = pSRB->SegmentX[63].length; + pSRB->SegmentX[0].address = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address; + pSRB->SegmentX[0].length = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length; if( (pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow) ) pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,pSRB->EndMessage,CHECK_CONDITION); @@ -5771,8 +5768,8 @@ memset (pcmd->sense_buffer, 0, sizeof(pcmd->sense_buffer)); /* Save some data */ - pSRB->SegmentX[63].address = pSRB->SegmentX[0].address; - pSRB->SegmentX[63].length = pSRB->SegmentX[0].length; + pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address = pSRB->SegmentX[0].address; + pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length = pSRB->SegmentX[0].length; pSRB->Xferred = pSRB->SRBTotalXferLength; /* pSRB->SegmentX : a one entry of S/G list table */ pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); @@ -5934,6 +5931,85 @@ } +/* Dynamically allocated memory handling */ + +#ifdef DC395x_DEBUGTRACE +/* Memory for trace buffers */ +void DC395x_free_tracebufs (PACB pACB, int SRBIdx) +{ + int srbidx; + const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ; + for (srbidx = 0; srbidx < SRBIdx; srbidx += bufs_per_page) + kfree (pACB->SRB_array[srbidx].debugtrace); +} + +int DC395x_alloc_tracebufs (PACB pACB) +{ + const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ; + int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE; + const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ; + int SRBIdx = 0; unsigned i = 0; + unsigned char *ptr; + //printk ("DC395x: Alloc %i pages for tracebufs\n", pages); + while (pages--) { + ptr = kmalloc (PAGE_SIZE, GFP_KERNEL); + if (!ptr) { + DC395x_free_tracebufs (pACB, SRBIdx); + return 1; + } + i = 0; + while (i < bufs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) + pACB->SRB_array[SRBIdx++].debugtrace + = ptr + (i++*DEBUGTRACEBUFSZ); + } + if (i < bufs_per_page) + pACB->TmpSRB.debugtrace = ptr + (i*DEBUGTRACEBUFSZ); + else + printk ("DC395x: No space for tmpSRB tracebuf reserved?!\n"); + return 0; +} +#endif + +/* Free SG tables */ +void DC395x_free_SG_tables (PACB pACB, int SRBIdx) +{ + int srbidx; + const unsigned SRBs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY * sizeof(SGentry)); + for (srbidx = 0; srbidx < SRBIdx; srbidx += SRBs_per_page) + kfree (pACB->SRB_array[srbidx].SegmentX); +} + +/* Allocate SG tables; as we have to pci_map them, an SG list (PSGE0) + * should never cross a page boundary */ +int DC395x_alloc_SG_tables (PACB pACB) +{ + const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) + * DC395x_MAX_SG_LISTENTRY * sizeof(SGentry); + int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE; + const unsigned SRBs_per_page = PAGE_SIZE + / (DC395x_MAX_SG_LISTENTRY * sizeof(SGentry)); + int SRBIdx = 0; unsigned i = 0; + PSGE0 ptr; + //printk ("DC395x: Alloc %i pages for SG tables\n", pages); + while (pages--) { + ptr = (PSGE0)kmalloc (PAGE_SIZE, GFP_KERNEL); + if (!ptr) { + DC395x_free_SG_tables (pACB, SRBIdx); + return 1; + } + i = 0; + while (i < SRBs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) + pACB->SRB_array[SRBIdx++].SegmentX + = ptr + (i++*DC395x_MAX_SG_LISTENTRY); + } + if (i < SRBs_per_page) + pACB->TmpSRB.SegmentX = ptr + (i*DC395x_MAX_SG_LISTENTRY); + else + printk ("DC395x: No space for tmpSRB SG table reserved?!\n"); + return 0; +} + + /* ********************************************************************* ** scsiio @@ -6021,12 +6097,19 @@ pACB->LUNchk = 1; /* ** link all device's SRB Q of this adapter - */ - pACB->SRB_array = kmalloc (sizeof(DC395X_TRM_SRB)*DC395x_MAX_SRB_CNT, GFP_KERNEL); - if (!pACB->SRB_array) { - printk ("DC395x: SRB allocation failed!\n"); + */ + + if (DC395x_alloc_SG_tables (pACB)) { + printk ("DC395x: SG table allocation failed!\n"); + return 1; + } +#ifdef DC395x_DEBUGTRACE + if (DC395x_alloc_tracebufs (pACB)) { + printk ("DC395x: SG trace buffer allocation failed!\n"); + DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT); return 1; } +#endif DC395x_linkSRB( pACB ); pACB->pFreeSRB = pACB->SRB_array; /* @@ -7469,6 +7552,10 @@ DC395x_ResetSCSIBus( pACB ); DC395x_read8 (TRM_S1040_SCSI_INTSTATUS); +#ifdef DC395x_DEBUGTRACE + DC395x_free_tracebufs (pACB, DC395x_MAX_SRB_CNT); +#endif + DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT); return( 0 ); } Index: dc395x_trm.h =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.h,v retrieving revision 1.37 retrieving revision 1.38 diff -u -u -r1.37 -r1.38 --- dc395x_trm.h 2002/02/28 04:32:41 1.37 +++ dc395x_trm.h 2002/02/28 11:18:37 1.38 @@ -8,7 +8,7 @@ ** ********************************************************************** */ -/* $Id: dc395x_trm.h,v 1.37 2002/02/28 04:32:41 garloff Exp $ */ +/* $Id: dc395x_trm.h,v 1.38 2002/02/28 11:18:37 garloff Exp $ */ /* ***************************************************** ** Tekram TRM_S1040 for DC395x driver, header file @@ -20,7 +20,7 @@ #include #define DC395x_BANNER "Tekram DC395U/UW/F DC315/U" -#define DC395x_VERSION "1.36, 2002-02-28" +#define DC395x_VERSION "1.37, 2002-02-28" /* Kernel version autodetection */ #include @@ -47,9 +47,9 @@ #define DC395x_MAX_ADAPTER_NUM 4 #define DC395x_MAX_SCSI_ID 16 #define DC395x_MAX_CMD_PER_LUN DC395x_MAX_QTAGS -#define DC395x_MAX_SG_TABLESIZE 64 -#define DC395x_MAX_SG_LISTENTRY 64 -#define DC395x_MAX_SRB_CNT 42 +#define DC395x_MAX_SG_TABLESIZE 64 /* HW limitation */ +#define DC395x_MAX_SG_LISTENTRY 64 /* Must be equal or lower to previous item */ +#define DC395x_MAX_SRB_CNT 63 //#define DC395x_MAX_CAN_QUEUE 7 * DC395x_MAX_QTAGS #define DC395x_MAX_CAN_QUEUE DC395x_MAX_SRB_CNT #define DC395x_END_SCAN 2