* RE: aaccli - adding a disk to an existing container...
From: Toby Moxham @ 2006-04-10 13:26 UTC (permalink / raw)
To: Salyzyn, Mark, linux-scsi
In-Reply-To: <547AF3BD0F3F0B4CBDC379BAC7E4189F0255FB76@otce2k03.adaptec.com>
Hi Mark,
Thanks for the responce, i will wait for the process to finish (which looks
as thought it make take a day or two!) and see what it reports then. I have
looked throught the adaptec documentation and this is very little concerning
expansion.
Thanks for the help!
Toby
-----Original Message-----
From: Salyzyn, Mark [mailto:mark_salyzyn@adaptec.com]
Sent: 10 April 2006 14:13
To: toby@digitalmischief.co.uk; linux-scsi@vger.kernel.org
Subject: RE: aaccli - adding a disk to an existing container...
You need to contact Adaptec Technical Support, or read the Adaptec
Documentation regarding array expansion. Please note that aaccli is no
longer supported and has been replaced by arcconf.
The array size for a RAID-5 is (n-1)*slice size. The new size is not
available until the build has completed, during that time it appears
that aaccli is reporting what it can to justify the older size with the
newer physical components while in this transitional state. I am unsure
of the operation of the /extend_fs switch for aaccli, I believe it is
only for the windoze file system; the actions you take under Linux will
be incantations around fdisk(8).
If I were you, I'd wait for the build to complete before worrying, it
has already started and any other actions you take until it is completed
could affect the integrity of the data. If the data is unimportant, just
build a fresh 4 drive RAID-5 and you can use the disk space immediately
;->
Sincerely -- Mark Salyzyn
> -----Original Message-----
> From: linux-scsi-owner@vger.kernel.org
> [mailto:linux-scsi-owner@vger.kernel.org] On Behalf Of Toby Moxham
> Sent: Monday, April 10, 2006 8:15 AM
> To: linux-scsi@vger.kernel.org
> Subject: aaccli - adding a disk to an existing container...
>
>
>
>
>
> Hi,
>
> I have an Adaptec 2610SA sata raid card I inititally
> configured it with 3x
> 300gb drives in a Raid 5 configuration. I now have added another 300gb
> drive.
>
> Using AAC CLI in Slackware linux... i have issued the command
> container
> reconfigure 0 (0,3,0) to add the fourth disk to the array, It
> is currently
> in progress in doing this .
>
> however when i now do container list i get this :-
>
> Executing: container list
> Num Total Oth Chunk Scsi Partition
> Label Type Size Ctr Size Usage B:ID:L Offset:Size
> ----- ------ ------ --- ------ ------- ------ -------------
> 0 Reconf 558GB Open
> /dev/sda RAID_ARRAY
> 62 RAID-5 558GB 64KB None 0:00:0 64.0KB: 186GB
> 0:01:0 64.0KB: 186GB
> 0:02:0 64.0KB: 186GB
> 0:03:0 64.0KB: 186GB
>
> I assume that what has happened is that the 558GB array is
> being distributed
> across the four disks. (or is it because the task is still in
> progress?)
>
> However i also want to grow the size of the array to max of
> the four disks.
> (rather than leaving free space on each disk)
>
> Do i need to use /extend_fs switch (looks as thought this is only for
> windows) or do i need to use the partition resize.
>
> Any help would be appreciated.
>
> Thanks
> Toby Moxham
> --
> No virus found in this outgoing message.
> Checked by AVG Free Edition.
> Version: 7.1.385 / Virus Database: 268.4.0/306 - Release
> Date: 09/04/2006
>
> --
> No virus found in this outgoing message.
> Checked by AVG Free Edition.
> Version: 7.1.385 / Virus Database: 268.4.0/306 - Release
> Date: 09/04/2006
>
> -
> To unsubscribe from this list: send the line "unsubscribe
> linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
No virus found in this incoming message.
Checked by AVG Free Edition.
Version: 7.1.385 / Virus Database: 268.4.0/306 - Release Date: 09/04/2006
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.385 / Virus Database: 268.4.0/306 - Release Date: 09/04/2006
^ permalink raw reply
* RE: aaccli - adding a disk to an existing container...
From: Salyzyn, Mark @ 2006-04-10 13:13 UTC (permalink / raw)
To: toby, linux-scsi
You need to contact Adaptec Technical Support, or read the Adaptec
Documentation regarding array expansion. Please note that aaccli is no
longer supported and has been replaced by arcconf.
The array size for a RAID-5 is (n-1)*slice size. The new size is not
available until the build has completed, during that time it appears
that aaccli is reporting what it can to justify the older size with the
newer physical components while in this transitional state. I am unsure
of the operation of the /extend_fs switch for aaccli, I believe it is
only for the windoze file system; the actions you take under Linux will
be incantations around fdisk(8).
If I were you, I'd wait for the build to complete before worrying, it
has already started and any other actions you take until it is completed
could affect the integrity of the data. If the data is unimportant, just
build a fresh 4 drive RAID-5 and you can use the disk space immediately
;->
Sincerely -- Mark Salyzyn
> -----Original Message-----
> From: linux-scsi-owner@vger.kernel.org
> [mailto:linux-scsi-owner@vger.kernel.org] On Behalf Of Toby Moxham
> Sent: Monday, April 10, 2006 8:15 AM
> To: linux-scsi@vger.kernel.org
> Subject: aaccli - adding a disk to an existing container...
>
>
>
>
>
> Hi,
>
> I have an Adaptec 2610SA sata raid card I inititally
> configured it with 3x
> 300gb drives in a Raid 5 configuration. I now have added another 300gb
> drive.
>
> Using AAC CLI in Slackware linux... i have issued the command
> container
> reconfigure 0 (0,3,0) to add the fourth disk to the array, It
> is currently
> in progress in doing this .
>
> however when i now do container list i get this :-
>
> Executing: container list
> Num Total Oth Chunk Scsi Partition
> Label Type Size Ctr Size Usage B:ID:L Offset:Size
> ----- ------ ------ --- ------ ------- ------ -------------
> 0 Reconf 558GB Open
> /dev/sda RAID_ARRAY
> 62 RAID-5 558GB 64KB None 0:00:0 64.0KB: 186GB
> 0:01:0 64.0KB: 186GB
> 0:02:0 64.0KB: 186GB
> 0:03:0 64.0KB: 186GB
>
> I assume that what has happened is that the 558GB array is
> being distributed
> across the four disks. (or is it because the task is still in
> progress?)
>
> However i also want to grow the size of the array to max of
> the four disks.
> (rather than leaving free space on each disk)
>
> Do i need to use /extend_fs switch (looks as thought this is only for
> windows) or do i need to use the partition resize.
>
> Any help would be appreciated.
>
> Thanks
> Toby Moxham
> --
> No virus found in this outgoing message.
> Checked by AVG Free Edition.
> Version: 7.1.385 / Virus Database: 268.4.0/306 - Release
> Date: 09/04/2006
>
> --
> No virus found in this outgoing message.
> Checked by AVG Free Edition.
> Version: 7.1.385 / Virus Database: 268.4.0/306 - Release
> Date: 09/04/2006
>
> -
> To unsubscribe from this list: send the line "unsubscribe
> linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* aaccli - adding a disk to an existing container...
From: Toby Moxham @ 2006-04-10 12:14 UTC (permalink / raw)
To: linux-scsi
Hi,
I have an Adaptec 2610SA sata raid card I inititally configured it with 3x
300gb drives in a Raid 5 configuration. I now have added another 300gb
drive.
Using AAC CLI in Slackware linux... i have issued the command container
reconfigure 0 (0,3,0) to add the fourth disk to the array, It is currently
in progress in doing this .
however when i now do container list i get this :-
Executing: container list
Num Total Oth Chunk Scsi Partition
Label Type Size Ctr Size Usage B:ID:L Offset:Size
----- ------ ------ --- ------ ------- ------ -------------
0 Reconf 558GB Open
/dev/sda RAID_ARRAY
62 RAID-5 558GB 64KB None 0:00:0 64.0KB: 186GB
0:01:0 64.0KB: 186GB
0:02:0 64.0KB: 186GB
0:03:0 64.0KB: 186GB
I assume that what has happened is that the 558GB array is being distributed
across the four disks. (or is it because the task is still in progress?)
However i also want to grow the size of the array to max of the four disks.
(rather than leaving free space on each disk)
Do i need to use /extend_fs switch (looks as thought this is only for
windows) or do i need to use the partition resize.
Any help would be appreciated.
Thanks
Toby Moxham
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.385 / Virus Database: 268.4.0/306 - Release Date: 09/04/2006
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.385 / Virus Database: 268.4.0/306 - Release Date: 09/04/2006
^ permalink raw reply
* Amazing Mortgages at low rates
From: Deidre Nix @ 2006-04-10 11:36 UTC (permalink / raw)
To: linux-scsi
Homeowner
You have been pre-approved for a $413,786 Home Loan at a 3.72 Fixed Rate.
This offer is being extended to you unconditionally and your credit is in no way a factor.
To take Advantage of this Limited Time opportunity
All we ask is that you visit our Website and complete
The 1 minute post Approval Form
http://www5.ki9k.com/was.asp
Best Wishes,
Stephanie Landis
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Stefan Richter @ 2006-04-10 10:19 UTC (permalink / raw)
To: Denis Vlasenko; +Cc: linux-scsi, gibbs, linux-kernel
In-Reply-To: <200604101156.30717.vda@ilport.com.ua>
Denis Vlasenko wrote:
> On Monday 10 April 2006 11:43, Stefan Richter wrote:
>> It is obviously necessary to modify the Makefile to have aic7?xx_osm_o.o
>> and aic7?xx_inline.o linked to an appropriate .ko file.
>
> I did compile test my changes.
Sure, if you #include .c files (which is awkward), there are no
additional .o files which would need to be added to the Makefile.
--
Stefan Richter
-=====-=-==- -=-- -=-=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Stefan Richter @ 2006-04-10 10:16 UTC (permalink / raw)
To: Hannes Reinecke
Cc: Rolf Eike Beer, Denis Vlasenko, SCSI List, linux-kernel, gibbs
In-Reply-To: <443A2CDB.5060404@suse.de>
Hannes Reinecke wrote:
> Re multiplatform development: aic7{9,x}xx have ceased to be
> multiplatfrom since the integration of scsi_transport_spi.
> So I wouldn't worry too much about it.
Then it may be possible to save even more than 80k of text.
--
Stefan Richter
-=====-=-==- -=-- -=-=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Hannes Reinecke @ 2006-04-10 10:00 UTC (permalink / raw)
To: Stefan Richter
Cc: Rolf Eike Beer, Denis Vlasenko, SCSI List, linux-kernel, gibbs
In-Reply-To: <443A2805.6000806@s5r6.in-berlin.de>
Stefan Richter wrote:
> Rolf Eike Beer wrote:
>> Denis Vlasenko wrote:
>>> I am leaving it up to maintainer to decide. After all, the driver
>>> is for multiple OSes, other OS may lack mdelay().
>> The comment says about multiple milliseconds sleeps which just don't happen.
>
> Given what ah{c,d}_delay are (OS dependent wrappers) and how they are
> used (definitely not for multi-msec delays), they should just be changed
> into a #define ah{c,d}_delay(us) udelay(us) or into void inline
> ah{c,d}_delay(long us) {udelay(us);}.
I'd rather do a #define. Inlining simple functions is quite unneccessary
here.
Re multiplatform development: aic7{9,x}xx have ceased to be
multiplatfrom since the integration of scsi_transport_spi.
So I wouldn't worry too much about it.
Cheers,
Hannes
--
Dr. Hannes Reinecke hare@suse.de
SuSE Linux Products GmbH S390 & zSeries
Maxfeldstraße 5 +49 911 74053 688
90409 Nürnberg http://www.suse.de
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Stefan Richter @ 2006-04-10 9:40 UTC (permalink / raw)
To: Rolf Eike Beer; +Cc: Denis Vlasenko, SCSI List, linux-kernel, gibbs
In-Reply-To: <200604100919.23244.eike-kernel@sf-tec.de>
Rolf Eike Beer wrote:
> Denis Vlasenko wrote:
>> I am leaving it up to maintainer to decide. After all, the driver
>> is for multiple OSes, other OS may lack mdelay().
>
> The comment says about multiple milliseconds sleeps which just don't happen.
Given what ah{c,d}_delay are (OS dependent wrappers) and how they are
used (definitely not for multi-msec delays), they should just be changed
into a #define ah{c,d}_delay(us) udelay(us) or into void inline
ah{c,d}_delay(long us) {udelay(us);}.
--
Stefan Richter
-=====-=-==- -=-- -=-=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Denis Vlasenko @ 2006-04-10 8:56 UTC (permalink / raw)
To: Stefan Richter; +Cc: linux-scsi, gibbs, linux-kernel
In-Reply-To: <443A1AA5.8060707@s5r6.in-berlin.de>
On Monday 10 April 2006 11:43, Stefan Richter wrote:
> Denis Vlasenko wrote:
> ...
> > +++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_core.c Sun Apr 9 21:49:25 2006
> ...
> > +#include "aic79xx_osm_o.c"
> > +#include "aic79xx_inline.c"
> ...
> > +++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_core.c Sun Apr 9 21:49:25 2006
> ...
> > +#include "aic7xxx_osm_o.c"
> > +#include "aic7xxx_inline.c"
> ...
>
> Instead of including c files with function definitions, you should add
> function prototypes to header files (it seems you already did so) and
> include only the header files. Include these header files in the c files
> which call the functions as well as in the c files which define the
> functions.
I will do this if maintainer will inform me that he wants it done.
Or maybe he wants it done in some other way, who knows?
I am not lazy, I am just not good at reading other peoples' minds.
> It is obviously necessary to modify the Makefile to have aic7?xx_osm_o.o
> and aic7?xx_inline.o linked to an appropriate .ko file.
I did compile test my changes.
> Furthermore, aic7?xx_inline.c are not very fitting file names since they
> do not contain inline functions. aic7?xx_osm_o.c are somewhat strange
> names either. Can't you move the functions into existing c files? E.g.
I can, but I won't without maintainer's consent.
> into those which contain most of the calls to the now de-inlined
> functions. From the point of view of cross-OS driver maintenance (but
> not necessarily from the point of view of Linux driver maintenance), it
> may be useful to distinguish between functions used across OSs and those
> used only in Linux when deciding where to move the functions.
--
vda
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Stefan Richter @ 2006-04-10 8:43 UTC (permalink / raw)
To: Denis Vlasenko; +Cc: linux-scsi, gibbs, linux-kernel
In-Reply-To: <200604100844.12151.vda@ilport.com.ua>
Denis Vlasenko wrote:
...
> +++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_core.c Sun Apr 9 21:49:25 2006
...
> +#include "aic79xx_osm_o.c"
> +#include "aic79xx_inline.c"
...
> +++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_core.c Sun Apr 9 21:49:25 2006
...
> +#include "aic7xxx_osm_o.c"
> +#include "aic7xxx_inline.c"
...
Instead of including c files with function definitions, you should add
function prototypes to header files (it seems you already did so) and
include only the header files. Include these header files in the c files
which call the functions as well as in the c files which define the
functions.
It is obviously necessary to modify the Makefile to have aic7?xx_osm_o.o
and aic7?xx_inline.o linked to an appropriate .ko file.
Furthermore, aic7?xx_inline.c are not very fitting file names since they
do not contain inline functions. aic7?xx_osm_o.c are somewhat strange
names either. Can't you move the functions into existing c files? E.g.
into those which contain most of the calls to the now de-inlined
functions. From the point of view of cross-OS driver maintenance (but
not necessarily from the point of view of Linux driver maintenance), it
may be useful to distinguish between functions used across OSs and those
used only in Linux when deciding where to move the functions.
--
Stefan Richter
-=====-=-==- -=-- -=-=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Denis Vlasenko @ 2006-04-10 7:54 UTC (permalink / raw)
To: Rolf Eike Beer; +Cc: SCSI List, linux-kernel, gibbs
In-Reply-To: <200604100919.23244.eike-kernel@sf-tec.de>
On Monday 10 April 2006 10:19, Rolf Eike Beer wrote:
> [Full quote and readded CC adresses. My fault, pressed wrong button]
>
> Denis Vlasenko wrote:
> > On Monday 10 April 2006 10:03, Rolf Eike Beer wrote:
> > > Am Montag, 10. April 2006 07:49 schrieben Sie:
> > > > On Monday 10 April 2006 08:44, Denis Vlasenko wrote:
> > > > > I also spotted two bugs in the process, patches
> > > > > for those will follow.
> > > >
> > > > ahd_delay(usec) is buggy. Just think how would it work
> > > > with usec == 1024*100 + 1...
> > >
> > > This is unneeded. The biggest argument this function is ever called with
> > > is 1000.
> >
> > I know.
> >
> > > I would suggest to delete this function completely. If one ever has to
> > > wait for a longer period mdelay() is the right function to call.
> >
> > I am leaving it up to maintainer to decide. After all, the driver
> > is for multiple OSes, other OS may lack mdelay().
>
> The comment says about multiple milliseconds sleeps which just don't happen.
# grep -r ah._delay.[A-Z] .
./aic7xxx_core.c: ahc_delay(AHC_BUSRESET_DELAY);
./aic79xx_core.c: ahd_delay(AHD_BUSRESET_DELAY);
./aic79xx_core.c: ahd_delay(AHD_BUSRESET_DELAY);
I am not sure that this constant won't be redefined to something large.
If maintainer knows better, he can take care of it.
I just fixed an obvious latent bug.
--
vda
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Rolf Eike Beer @ 2006-04-10 7:19 UTC (permalink / raw)
To: Denis Vlasenko, SCSI List, linux-kernel, gibbs
In-Reply-To: <200604101015.36869.vda@ilport.com.ua>
[-- Attachment #1: Type: text/plain, Size: 904 bytes --]
[Full quote and readded CC adresses. My fault, pressed wrong button]
Denis Vlasenko wrote:
> On Monday 10 April 2006 10:03, Rolf Eike Beer wrote:
> > Am Montag, 10. April 2006 07:49 schrieben Sie:
> > > On Monday 10 April 2006 08:44, Denis Vlasenko wrote:
> > > > I also spotted two bugs in the process, patches
> > > > for those will follow.
> > >
> > > ahd_delay(usec) is buggy. Just think how would it work
> > > with usec == 1024*100 + 1...
> >
> > This is unneeded. The biggest argument this function is ever called with
> > is 1000.
>
> I know.
>
> > I would suggest to delete this function completely. If one ever has to
> > wait for a longer period mdelay() is the right function to call.
>
> I am leaving it up to maintainer to decide. After all, the driver
> is for multiple OSes, other OS may lack mdelay().
The comment says about multiple milliseconds sleeps which just don't happen.
Eike
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Denis Vlasenko @ 2006-04-10 5:49 UTC (permalink / raw)
To: linux-scsi; +Cc: gibbs, linux-kernel
In-Reply-To: <200604100844.12151.vda@ilport.com.ua>
[-- Attachment #1: Type: text/plain, Size: 271 bytes --]
On Monday 10 April 2006 08:44, Denis Vlasenko wrote:
> I also spotted two bugs in the process, patches
> for those will follow.
ahd_delay(usec) is buggy. Just think how would it work
with usec == 1024*100 + 1...
Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
--
vda
[-- Attachment #2: 2.6.16.aic7_42.patch --]
[-- Type: text/x-diff, Size: 1113 bytes --]
Fix yet another bug
diff -urpN linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic79xx_osm_o.c linux-2.6.16.aic7_3/drivers/scsi/aic7xxx/aic79xx_osm_o.c
--- linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic79xx_osm_o.c Sun Apr 9 21:53:01 2006
+++ linux-2.6.16.aic7_3/drivers/scsi/aic7xxx/aic79xx_osm_o.c Sun Apr 9 22:25:30 2006
@@ -28,9 +28,11 @@ ahd_delay(long usec)
* multi-millisecond waits. Wait at most
* 1024us per call.
*/
+ udelay(usec & 1023);
+ usec >>= 10;
while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
+ udelay(1024);
+ usec--;
}
}
diff -urpN linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic7xxx_osm_o.c linux-2.6.16.aic7_3/drivers/scsi/aic7xxx/aic7xxx_osm_o.c
--- linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic7xxx_osm_o.c Sun Apr 9 21:54:39 2006
+++ linux-2.6.16.aic7_3/drivers/scsi/aic7xxx/aic7xxx_osm_o.c Sun Apr 9 22:24:59 2006
@@ -14,9 +14,11 @@ ahc_delay(long usec)
* multi-millisecond waits. Wait at most
* 1024us per call.
*/
+ udelay(usec & 1023);
+ usec >>= 10;
while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
+ udelay(1024);
+ usec--;
}
}
^ permalink raw reply
* Re: [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Denis Vlasenko @ 2006-04-10 5:46 UTC (permalink / raw)
To: linux-scsi; +Cc: gibbs, linux-kernel
In-Reply-To: <200604100844.12151.vda@ilport.com.ua>
[-- Attachment #1: Type: text/plain, Size: 242 bytes --]
On Monday 10 April 2006 08:44, Denis Vlasenko wrote:
> I also spotted two bugs in the process, patches
> for those will follow.
Fix ahc_pci_write_config's (wrong order of arguments).
Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
--
vda
[-- Attachment #2: 2.6.16.aic7_41.patch --]
[-- Type: text/x-diff, Size: 1255 bytes --]
Fix a bug uncovered by previous change
diff -urpN linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_pci.c Sun Apr 9 22:11:13 2006
+++ linux-2.6.16.aic7_2/drivers/scsi/aic7xxx/aic7xxx_pci.c Sun Apr 9 22:09:45 2006
@@ -2036,12 +2036,12 @@ ahc_pci_resume(struct ahc_softc *ahc)
* that the OS doesn't know about and rely on our chip
* reset handler to handle the rest.
*/
- ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
- ahc->bus_softc.pci_softc.devconfig);
- ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
- ahc->bus_softc.pci_softc.command);
- ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
- ahc->bus_softc.pci_softc.csize_lattime);
+ ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+ ahc->bus_softc.pci_softc.devconfig, /*bytes*/4);
+ ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+ ahc->bus_softc.pci_softc.command, /*bytes*/1);
+ ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
+ ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1);
if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
struct seeprom_descriptor sd;
u_int sxfrctl1;
^ permalink raw reply
* [PATCH] deinline some functions in aic7xxx drivers, save 80k of text
From: Denis Vlasenko @ 2006-04-10 5:44 UTC (permalink / raw)
To: linux-scsi, gibbs, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 745 bytes --]
Hi Justin, hi scsi crowd,
I moved a bunch of inlined functions from
aic79xx_osm.h and aic79xx_inline.h to
aic79xx_osm_o.c and aic79xx_inline.c and #included
them from aic79xx_core.c. This is a bit ugly,
but I was not sure where would maintainer
like them to be moved to.
Same for aic7xxx. End result is:
# size */aic7*xx.o
text data bss dec hex filename
144078 11617 600 156295 26287 aic7xxx.old/aic79xx.o
108610 16289 564 125463 1ea17 aic7xxx.old/aic7xxx.o
85255 11617 600 97472 17cc0 aic7xxx/aic79xx.o
83395 16289 564 100248 18798 aic7xxx/aic7xxx.o
I also spotted two bugs in the process, patches
for those will follow.
Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
--
vda
[-- Attachment #2: 2.6.16.aic7_4.patch --]
[-- Type: text/x-diff, Size: 69799 bytes --]
# size */aic7*xx.o
text data bss dec hex filename
144078 11617 600 156295 26287 aic7xxx.old/aic79xx.o
108610 16289 564 125463 1ea17 aic7xxx.old/aic7xxx.o
85255 11617 600 97472 17cc0 aic7xxx/aic79xx.o
83395 16289 564 100248 18798 aic7xxx/aic7xxx.o
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_core.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_core.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_core.c Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_core.c Sun Apr 9 21:49:25 2006
@@ -50,6 +50,9 @@
#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
#endif
+/* Were inlined, but moved out-of-line because they are HUGE: */
+#include "aic79xx_osm_o.c"
+#include "aic79xx_inline.c"
/***************************** Lookup Tables **********************************/
char *ahd_chip_names[] =
@@ -241,7 +244,7 @@ static int ahd_handle_target_cmd(struct
/******************************** Private Inlines *****************************/
static __inline void ahd_assert_atn(struct ahd_softc *ahd);
static __inline int ahd_currently_packetized(struct ahd_softc *ahd);
-static __inline int ahd_set_active_fifo(struct ahd_softc *ahd);
+static int ahd_set_active_fifo(struct ahd_softc *ahd);
static __inline void
ahd_assert_atn(struct ahd_softc *ahd)
@@ -278,7 +281,7 @@ ahd_currently_packetized(struct ahd_soft
return (packetized);
}
-static __inline int
+static int
ahd_set_active_fifo(struct ahd_softc *ahd)
{
u_int active_fifo;
@@ -7131,7 +7134,7 @@ ahd_resume(struct ahd_softc *ahd)
* scbid that should be restored once manipualtion
* of the TCL entry is complete.
*/
-static __inline u_int
+static u_int
ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
{
/*
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_inline.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_inline.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_inline.c Thu Jan 1 03:00:00 1970
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_inline.c Sun Apr 9 21:49:25 2006
@@ -0,0 +1,460 @@
+/*
+ * Routines shareable across OS platforms.
+ *
+ * Formerly inlined routines from aic79xx_inline.h are moved here.
+ * This file is #included into aic79xx_core.c
+ */
+
+/************************ Sequencer Execution Control *************************/
+void
+ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
+{
+ if (ahd->src_mode == src && ahd->dst_mode == dst)
+ return;
+#ifdef AHD_DEBUG
+ if (ahd->src_mode == AHD_MODE_UNKNOWN
+ || ahd->dst_mode == AHD_MODE_UNKNOWN)
+ panic("Setting mode prior to saving it.\n");
+ if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+ printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
+ ahd_build_mode_state(ahd, src, dst));
+#endif
+ ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
+ ahd->src_mode = src;
+ ahd->dst_mode = dst;
+}
+
+void
+ahd_update_modes(struct ahd_softc *ahd)
+{
+ ahd_mode_state mode_ptr;
+ ahd_mode src;
+ ahd_mode dst;
+
+ mode_ptr = ahd_inb(ahd, MODE_PTR);
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+ printf("Reading mode 0x%x\n", mode_ptr);
+#endif
+ ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
+ ahd_known_modes(ahd, src, dst);
+}
+
+ahd_mode_state
+ahd_save_modes(struct ahd_softc *ahd)
+{
+ if (ahd->src_mode == AHD_MODE_UNKNOWN
+ || ahd->dst_mode == AHD_MODE_UNKNOWN)
+ ahd_update_modes(ahd);
+
+ return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
+}
+
+void
+ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
+{
+ ahd_mode src;
+ ahd_mode dst;
+
+ ahd_extract_mode_state(ahd, state, &src, &dst);
+ ahd_set_modes(ahd, src, dst);
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted. If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+void
+ahd_unpause(struct ahd_softc *ahd)
+{
+ /*
+ * Automatically restore our modes to those saved
+ * prior to the first change of the mode.
+ */
+ if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
+ && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
+ if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
+ ahd_reset_cmds_pending(ahd);
+ ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
+ }
+
+ if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
+ ahd_outb(ahd, HCNTRL, ahd->unpause);
+
+ ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
+}
+
+/*********************** Scatter Gather List Handling *************************/
+void *
+ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+ void *sgptr, dma_addr_t addr, bus_size_t len, int last)
+{
+ scb->sg_count++;
+ if (sizeof(dma_addr_t) > 4
+ && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+ struct ahd_dma64_seg *sg;
+
+ sg = (struct ahd_dma64_seg *)sgptr;
+ sg->addr = ahd_htole64(addr);
+ sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
+ return (sg + 1);
+ } else {
+ struct ahd_dma_seg *sg;
+
+ sg = (struct ahd_dma_seg *)sgptr;
+ sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
+ sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
+ | (last ? AHD_DMA_LAST_SEG : 0));
+ return (sg + 1);
+ }
+}
+
+void
+ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
+{
+ /* XXX Handle target mode SCBs. */
+ scb->crc_retry_count = 0;
+ if ((scb->flags & SCB_PACKETIZED) != 0) {
+ /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
+ scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
+ } else {
+ if (ahd_get_transfer_length(scb) & 0x01)
+ scb->hscb->task_attribute = SCB_XFERLEN_ODD;
+ else
+ scb->hscb->task_attribute = 0;
+ }
+
+ if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
+ || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
+ scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
+ ahd_htole32(scb->sense_busaddr);
+}
+
+void
+ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ /*
+ * Copy the first SG into the "current" data ponter area.
+ */
+ if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+ struct ahd_dma64_seg *sg;
+
+ sg = (struct ahd_dma64_seg *)scb->sg_list;
+ scb->hscb->dataptr = sg->addr;
+ scb->hscb->datacnt = sg->len;
+ } else {
+ struct ahd_dma_seg *sg;
+ uint32_t *dataptr_words;
+
+ sg = (struct ahd_dma_seg *)scb->sg_list;
+ dataptr_words = (uint32_t*)&scb->hscb->dataptr;
+ dataptr_words[0] = sg->addr;
+ dataptr_words[1] = 0;
+ if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
+ uint64_t high_addr;
+
+ high_addr = ahd_le32toh(sg->len) & 0x7F000000;
+ scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
+ }
+ scb->hscb->datacnt = sg->len;
+ }
+ /*
+ * Note where to find the SG entries in bus space.
+ * We also set the full residual flag which the
+ * sequencer will clear as soon as a data transfer
+ * occurs.
+ */
+ scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
+}
+
+/*********************** Miscelaneous Support Functions ***********************/
+uint16_t
+ahd_inw(struct ahd_softc *ahd, u_int port)
+{
+ /*
+ * Read high byte first as some registers increment
+ * or have other side effects when the low byte is
+ * read.
+ */
+ return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
+}
+
+void
+ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
+{
+ /*
+ * Write low byte first to accomodate registers
+ * such as PRGMCNT where the order maters.
+ */
+ ahd_outb(ahd, port, value & 0xFF);
+ ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+}
+
+uint32_t
+ahd_inl(struct ahd_softc *ahd, u_int port)
+{
+ return ((ahd_inb(ahd, port))
+ | (ahd_inb(ahd, port+1) << 8)
+ | (ahd_inb(ahd, port+2) << 16)
+ | (ahd_inb(ahd, port+3) << 24));
+}
+
+void
+ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
+{
+ ahd_outb(ahd, port, (value) & 0xFF);
+ ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
+ ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
+ ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
+}
+
+uint64_t
+ahd_inq(struct ahd_softc *ahd, u_int port)
+{
+ return ((ahd_inb(ahd, port))
+ | (ahd_inb(ahd, port+1) << 8)
+ | (ahd_inb(ahd, port+2) << 16)
+ | (ahd_inb(ahd, port+3) << 24)
+ | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
+ | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
+ | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
+ | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
+}
+
+void
+ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
+{
+ ahd_outb(ahd, port, value & 0xFF);
+ ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+ ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
+ ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
+ ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
+ ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
+ ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
+ ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
+}
+
+struct scb *
+ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
+{
+ struct scb* scb;
+
+ if (tag >= AHD_SCB_MAX)
+ return (NULL);
+ scb = ahd->scb_data.scbindex[tag];
+ if (scb != NULL)
+ ahd_sync_scb(ahd, scb,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ return (scb);
+}
+
+void
+ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
+{
+ struct hardware_scb *q_hscb;
+ struct map_node *q_hscb_map;
+ uint32_t saved_hscb_busaddr;
+
+ /*
+ * Our queuing method is a bit tricky. The card
+ * knows in advance which HSCB (by address) to download,
+ * and we can't disappoint it. To achieve this, the next
+ * HSCB to download is saved off in ahd->next_queued_hscb.
+ * When we are called to queue "an arbitrary scb",
+ * we copy the contents of the incoming HSCB to the one
+ * the sequencer knows about, swap HSCB pointers and
+ * finally assign the SCB to the tag indexed location
+ * in the scb_array. This makes sure that we can still
+ * locate the correct SCB by SCB_TAG.
+ */
+ q_hscb = ahd->next_queued_hscb;
+ q_hscb_map = ahd->next_queued_hscb_map;
+ saved_hscb_busaddr = q_hscb->hscb_busaddr;
+ memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+ q_hscb->hscb_busaddr = saved_hscb_busaddr;
+ q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
+
+ /* Now swap HSCB pointers. */
+ ahd->next_queued_hscb = scb->hscb;
+ ahd->next_queued_hscb_map = scb->hscb_map;
+ scb->hscb = q_hscb;
+ scb->hscb_map = q_hscb_map;
+
+ /* Now define the mapping from tag to SCB in the scbindex */
+ ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+void
+ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+ ahd_swap_with_next_hscb(ahd, scb);
+
+ if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
+ panic("Attempt to queue invalid SCB tag %x\n",
+ SCB_GET_TAG(scb));
+
+ /*
+ * Keep a history of SCBs we've downloaded in the qinfifo.
+ */
+ ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
+ ahd->qinfifonext++;
+
+ if (scb->sg_count != 0)
+ ahd_setup_data_scb(ahd, scb);
+ else
+ ahd_setup_noxfer_scb(ahd, scb);
+ ahd_setup_scb_common(ahd, scb);
+
+ /*
+ * Make sure our data is consistent from the
+ * perspective of the adapter.
+ */
+ ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+#ifdef AHD_DEBUG
+ if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
+ uint64_t host_dataptr;
+
+ host_dataptr = ahd_le64toh(scb->hscb->dataptr);
+ printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+ ahd_name(ahd),
+ SCB_GET_TAG(scb), scb->hscb->scsiid,
+ ahd_le32toh(scb->hscb->hscb_busaddr),
+ (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
+ (u_int)(host_dataptr & 0xFFFFFFFF),
+ ahd_le32toh(scb->hscb->datacnt));
+ }
+#endif
+ /* Tell the adapter about the newly queued SCB */
+ ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+}
+
+/************************** Interrupt Processing ******************************/
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHD_RUN_QOUTFIFO 0x1
+#define AHD_RUN_TQINFIFO 0x2
+u_int
+ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
+{
+ u_int retval;
+
+ retval = 0;
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+ /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
+ /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
+ if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
+ == ahd->qoutfifonext_valid_tag)
+ retval |= AHD_RUN_QOUTFIFO;
+#ifdef AHD_TARGET_MODE
+ if ((ahd->flags & AHD_TARGETROLE) != 0
+ && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
+ ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+ ahd->shared_data_map.dmamap,
+ ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
+ if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
+ retval |= AHD_RUN_TQINFIFO;
+ }
+#endif
+ return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+int
+ahd_intr(struct ahd_softc *ahd)
+{
+ u_int intstat;
+
+ if ((ahd->pause & INTEN) == 0) {
+ /*
+ * Our interrupt is not enabled on the chip
+ * and may be disabled for re-entrancy reasons,
+ * so just return. This is likely just a shared
+ * interrupt.
+ */
+ return (0);
+ }
+
+ /*
+ * Instead of directly reading the interrupt status register,
+ * infer the cause of the interrupt by checking our in-core
+ * completion queues. This avoids a costly PCI bus read in
+ * most cases.
+ */
+ if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
+ && (ahd_check_cmdcmpltqueues(ahd) != 0))
+ intstat = CMDCMPLT;
+ else
+ intstat = ahd_inb(ahd, INTSTAT);
+
+ if ((intstat & INT_PEND) == 0)
+ return (0);
+
+ if (intstat & CMDCMPLT) {
+ ahd_outb(ahd, CLRINT, CLRCMDINT);
+
+ /*
+ * Ensure that the chip sees that we've cleared
+ * this interrupt before we walk the output fifo.
+ * Otherwise, we may, due to posted bus writes,
+ * clear the interrupt after we finish the scan,
+ * and after the sequencer has added new entries
+ * and asserted the interrupt again.
+ */
+ if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+ if (ahd_is_paused(ahd)) {
+ /*
+ * Potentially lost SEQINT.
+ * If SEQINTCODE is non-zero,
+ * simulate the SEQINT.
+ */
+ if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
+ intstat |= SEQINT;
+ }
+ } else {
+ ahd_flush_device_writes(ahd);
+ }
+ ahd_run_qoutfifo(ahd);
+ ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
+ ahd->cmdcmplt_total++;
+#ifdef AHD_TARGET_MODE
+ if ((ahd->flags & AHD_TARGETROLE) != 0)
+ ahd_run_tqinfifo(ahd, /*paused*/FALSE);
+#endif
+ }
+
+ /*
+ * Handle statuses that may invalidate our cached
+ * copy of INTSTAT separately.
+ */
+ if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
+ /* Hot eject. Do nothing */
+ } else if (intstat & HWERRINT) {
+ ahd_handle_hwerrint(ahd);
+ } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
+ ahd->bus_intr(ahd);
+ } else {
+
+ if ((intstat & SEQINT) != 0)
+ ahd_handle_seqint(ahd, intstat);
+
+ if ((intstat & SCSIINT) != 0)
+ ahd_handle_scsiint(ahd, intstat);
+ }
+ return (1);
+}
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_inline.h linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_inline.h
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_inline.h Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_inline.h Sun Apr 9 21:49:25 2006
@@ -63,18 +63,18 @@ static __inline ahd_mode_state ahd_build
static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
ahd_mode_state state,
ahd_mode *src, ahd_mode *dst);
-static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
+void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
ahd_mode dst);
-static __inline void ahd_update_modes(struct ahd_softc *ahd);
+void ahd_update_modes(struct ahd_softc *ahd);
static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
ahd_mode dstmode, const char *file,
int line);
-static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
-static __inline void ahd_restore_modes(struct ahd_softc *ahd,
+ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
+void ahd_restore_modes(struct ahd_softc *ahd,
ahd_mode_state state);
static __inline int ahd_is_paused(struct ahd_softc *ahd);
static __inline void ahd_pause(struct ahd_softc *ahd);
-static __inline void ahd_unpause(struct ahd_softc *ahd);
+void ahd_unpause(struct ahd_softc *ahd);
static __inline void
ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
@@ -100,40 +100,6 @@ ahd_extract_mode_state(struct ahd_softc
}
static __inline void
-ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
-{
- if (ahd->src_mode == src && ahd->dst_mode == dst)
- return;
-#ifdef AHD_DEBUG
- if (ahd->src_mode == AHD_MODE_UNKNOWN
- || ahd->dst_mode == AHD_MODE_UNKNOWN)
- panic("Setting mode prior to saving it.\n");
- if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
- ahd_build_mode_state(ahd, src, dst));
-#endif
- ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
- ahd->src_mode = src;
- ahd->dst_mode = dst;
-}
-
-static __inline void
-ahd_update_modes(struct ahd_softc *ahd)
-{
- ahd_mode_state mode_ptr;
- ahd_mode src;
- ahd_mode dst;
-
- mode_ptr = ahd_inb(ahd, MODE_PTR);
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
- printf("Reading mode 0x%x\n", mode_ptr);
-#endif
- ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
- ahd_known_modes(ahd, src, dst);
-}
-
-static __inline void
ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
ahd_mode dstmode, const char *file, int line)
{
@@ -146,26 +112,6 @@ ahd_assert_modes(struct ahd_softc *ahd,
#endif
}
-static __inline ahd_mode_state
-ahd_save_modes(struct ahd_softc *ahd)
-{
- if (ahd->src_mode == AHD_MODE_UNKNOWN
- || ahd->dst_mode == AHD_MODE_UNKNOWN)
- ahd_update_modes(ahd);
-
- return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
-}
-
-static __inline void
-ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
-{
- ahd_mode src;
- ahd_mode dst;
-
- ahd_extract_mode_state(ahd, state, &src, &dst);
- ahd_set_modes(ahd, src, dst);
-}
-
#define AHD_ASSERT_MODES(ahd, source, dest) \
ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
@@ -199,129 +145,17 @@ ahd_pause(struct ahd_softc *ahd)
;
}
-/*
- * Allow the sequencer to continue program execution.
- * We check here to ensure that no additional interrupt
- * sources that would cause the sequencer to halt have been
- * asserted. If, for example, a SCSI bus reset is detected
- * while we are fielding a different, pausing, interrupt type,
- * we don't want to release the sequencer before going back
- * into our interrupt handler and dealing with this new
- * condition.
- */
-static __inline void
-ahd_unpause(struct ahd_softc *ahd)
-{
- /*
- * Automatically restore our modes to those saved
- * prior to the first change of the mode.
- */
- if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
- && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
- if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
- ahd_reset_cmds_pending(ahd);
- ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
- }
-
- if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
- ahd_outb(ahd, HCNTRL, ahd->unpause);
-
- ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
-}
-
/*********************** Scatter Gather List Handling *************************/
-static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
void *sgptr, dma_addr_t addr,
bus_size_t len, int last);
-static __inline void ahd_setup_scb_common(struct ahd_softc *ahd,
+void ahd_setup_scb_common(struct ahd_softc *ahd,
struct scb *scb);
-static __inline void ahd_setup_data_scb(struct ahd_softc *ahd,
+void ahd_setup_data_scb(struct ahd_softc *ahd,
struct scb *scb);
static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd,
struct scb *scb);
-static __inline void *
-ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
- void *sgptr, dma_addr_t addr, bus_size_t len, int last)
-{
- scb->sg_count++;
- if (sizeof(dma_addr_t) > 4
- && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
- struct ahd_dma64_seg *sg;
-
- sg = (struct ahd_dma64_seg *)sgptr;
- sg->addr = ahd_htole64(addr);
- sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
- return (sg + 1);
- } else {
- struct ahd_dma_seg *sg;
-
- sg = (struct ahd_dma_seg *)sgptr;
- sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
- sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
- | (last ? AHD_DMA_LAST_SEG : 0));
- return (sg + 1);
- }
-}
-
-static __inline void
-ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
-{
- /* XXX Handle target mode SCBs. */
- scb->crc_retry_count = 0;
- if ((scb->flags & SCB_PACKETIZED) != 0) {
- /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
- scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
- } else {
- if (ahd_get_transfer_length(scb) & 0x01)
- scb->hscb->task_attribute = SCB_XFERLEN_ODD;
- else
- scb->hscb->task_attribute = 0;
- }
-
- if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
- || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
- scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
- ahd_htole32(scb->sense_busaddr);
-}
-
-static __inline void
-ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- /*
- * Copy the first SG into the "current" data ponter area.
- */
- if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
- struct ahd_dma64_seg *sg;
-
- sg = (struct ahd_dma64_seg *)scb->sg_list;
- scb->hscb->dataptr = sg->addr;
- scb->hscb->datacnt = sg->len;
- } else {
- struct ahd_dma_seg *sg;
- uint32_t *dataptr_words;
-
- sg = (struct ahd_dma_seg *)scb->sg_list;
- dataptr_words = (uint32_t*)&scb->hscb->dataptr;
- dataptr_words[0] = sg->addr;
- dataptr_words[1] = 0;
- if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
- uint64_t high_addr;
-
- high_addr = ahd_le32toh(sg->len) & 0x7F000000;
- scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
- }
- scb->hscb->datacnt = sg->len;
- }
- /*
- * Note where to find the SG entries in bus space.
- * We also set the full residual flag which the
- * sequencer will clear as soon as a data transfer
- * occurs.
- */
- scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
-}
-
static __inline void
ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
{
@@ -427,18 +261,12 @@ static __inline struct ahd_initiator_tin
char channel, u_int our_id,
u_int remote_id,
struct ahd_tmode_tstate **tstate);
-static __inline uint16_t
- ahd_inw(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outw(struct ahd_softc *ahd, u_int port,
- u_int value);
-static __inline uint32_t
- ahd_inl(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outl(struct ahd_softc *ahd, u_int port,
- uint32_t value);
-static __inline uint64_t
- ahd_inq(struct ahd_softc *ahd, u_int port);
-static __inline void ahd_outq(struct ahd_softc *ahd, u_int port,
- uint64_t value);
+uint16_t ahd_inw(struct ahd_softc *ahd, u_int port);
+void ahd_outw(struct ahd_softc *ahd, u_int port, u_int value);
+uint32_t ahd_inl(struct ahd_softc *ahd, u_int port);
+void ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value);
+uint64_t ahd_inq(struct ahd_softc *ahd, u_int port);
+void ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value);
static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd);
static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd);
@@ -457,9 +285,11 @@ static __inline uint32_t
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
static __inline uint64_t
ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
-static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd,
+struct scb *
+ ahd_lookup_scb(struct ahd_softc *ahd, u_int tag);
+void ahd_swap_with_next_hscb(struct ahd_softc *ahd,
struct scb *scb);
-static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
+void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
static __inline uint8_t *
ahd_get_sense_buf(struct ahd_softc *ahd,
struct scb *scb);
@@ -519,72 +349,6 @@ do { \
dst->hscb->lun = src->hscb->lun; \
} while (0)
-static __inline uint16_t
-ahd_inw(struct ahd_softc *ahd, u_int port)
-{
- /*
- * Read high byte first as some registers increment
- * or have other side effects when the low byte is
- * read.
- */
- return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
-}
-
-static __inline void
-ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
-{
- /*
- * Write low byte first to accomodate registers
- * such as PRGMCNT where the order maters.
- */
- ahd_outb(ahd, port, value & 0xFF);
- ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
-}
-
-static __inline uint32_t
-ahd_inl(struct ahd_softc *ahd, u_int port)
-{
- return ((ahd_inb(ahd, port))
- | (ahd_inb(ahd, port+1) << 8)
- | (ahd_inb(ahd, port+2) << 16)
- | (ahd_inb(ahd, port+3) << 24));
-}
-
-static __inline void
-ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
-{
- ahd_outb(ahd, port, (value) & 0xFF);
- ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
- ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
- ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
-}
-
-static __inline uint64_t
-ahd_inq(struct ahd_softc *ahd, u_int port)
-{
- return ((ahd_inb(ahd, port))
- | (ahd_inb(ahd, port+1) << 8)
- | (ahd_inb(ahd, port+2) << 16)
- | (ahd_inb(ahd, port+3) << 24)
- | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
- | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
- | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
- | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
-}
-
-static __inline void
-ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
-{
- ahd_outb(ahd, port, value & 0xFF);
- ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
- ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
- ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
- ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
- ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
- ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
- ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
-}
-
static __inline u_int
ahd_get_scbptr(struct ahd_softc *ahd)
{
@@ -719,104 +483,6 @@ ahd_inq_scbram(struct ahd_softc *ahd, u_
| ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
}
-static __inline struct scb *
-ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
-{
- struct scb* scb;
-
- if (tag >= AHD_SCB_MAX)
- return (NULL);
- scb = ahd->scb_data.scbindex[tag];
- if (scb != NULL)
- ahd_sync_scb(ahd, scb,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- return (scb);
-}
-
-static __inline void
-ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
-{
- struct hardware_scb *q_hscb;
- struct map_node *q_hscb_map;
- uint32_t saved_hscb_busaddr;
-
- /*
- * Our queuing method is a bit tricky. The card
- * knows in advance which HSCB (by address) to download,
- * and we can't disappoint it. To achieve this, the next
- * HSCB to download is saved off in ahd->next_queued_hscb.
- * When we are called to queue "an arbitrary scb",
- * we copy the contents of the incoming HSCB to the one
- * the sequencer knows about, swap HSCB pointers and
- * finally assign the SCB to the tag indexed location
- * in the scb_array. This makes sure that we can still
- * locate the correct SCB by SCB_TAG.
- */
- q_hscb = ahd->next_queued_hscb;
- q_hscb_map = ahd->next_queued_hscb_map;
- saved_hscb_busaddr = q_hscb->hscb_busaddr;
- memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
- q_hscb->hscb_busaddr = saved_hscb_busaddr;
- q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
-
- /* Now swap HSCB pointers. */
- ahd->next_queued_hscb = scb->hscb;
- ahd->next_queued_hscb_map = scb->hscb_map;
- scb->hscb = q_hscb;
- scb->hscb_map = q_hscb_map;
-
- /* Now define the mapping from tag to SCB in the scbindex */
- ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
-}
-
-/*
- * Tell the sequencer about a new transaction to execute.
- */
-static __inline void
-ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
-{
- ahd_swap_with_next_hscb(ahd, scb);
-
- if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
- panic("Attempt to queue invalid SCB tag %x\n",
- SCB_GET_TAG(scb));
-
- /*
- * Keep a history of SCBs we've downloaded in the qinfifo.
- */
- ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
- ahd->qinfifonext++;
-
- if (scb->sg_count != 0)
- ahd_setup_data_scb(ahd, scb);
- else
- ahd_setup_noxfer_scb(ahd, scb);
- ahd_setup_scb_common(ahd, scb);
-
- /*
- * Make sure our data is consistent from the
- * perspective of the adapter.
- */
- ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
-#ifdef AHD_DEBUG
- if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
- uint64_t host_dataptr;
-
- host_dataptr = ahd_le64toh(scb->hscb->dataptr);
- printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
- ahd_name(ahd),
- SCB_GET_TAG(scb), scb->hscb->scsiid,
- ahd_le32toh(scb->hscb->hscb_busaddr),
- (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
- (u_int)(host_dataptr & 0xFFFFFFFF),
- ahd_le32toh(scb->hscb->datacnt));
- }
-#endif
- /* Tell the adapter about the newly queued SCB */
- ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
-}
-
static __inline uint8_t *
ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
{
@@ -832,8 +498,8 @@ ahd_get_sense_bufaddr(struct ahd_softc *
/************************** Interrupt Processing ******************************/
static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
-static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
-static __inline int ahd_intr(struct ahd_softc *ahd);
+u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
+int ahd_intr(struct ahd_softc *ahd);
static __inline void
ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
@@ -855,126 +521,6 @@ ahd_sync_tqinfifo(struct ahd_softc *ahd,
op);
}
#endif
-}
-
-/*
- * See if the firmware has posted any completed commands
- * into our in-core command complete fifos.
- */
-#define AHD_RUN_QOUTFIFO 0x1
-#define AHD_RUN_TQINFIFO 0x2
-static __inline u_int
-ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
-{
- u_int retval;
-
- retval = 0;
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
- /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
- /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
- if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
- == ahd->qoutfifonext_valid_tag)
- retval |= AHD_RUN_QOUTFIFO;
-#ifdef AHD_TARGET_MODE
- if ((ahd->flags & AHD_TARGETROLE) != 0
- && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
- ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
- ahd->shared_data_map.dmamap,
- ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
- /*len*/sizeof(struct target_cmd),
- BUS_DMASYNC_POSTREAD);
- if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
- retval |= AHD_RUN_TQINFIFO;
- }
-#endif
- return (retval);
-}
-
-/*
- * Catch an interrupt from the adapter
- */
-static __inline int
-ahd_intr(struct ahd_softc *ahd)
-{
- u_int intstat;
-
- if ((ahd->pause & INTEN) == 0) {
- /*
- * Our interrupt is not enabled on the chip
- * and may be disabled for re-entrancy reasons,
- * so just return. This is likely just a shared
- * interrupt.
- */
- return (0);
- }
-
- /*
- * Instead of directly reading the interrupt status register,
- * infer the cause of the interrupt by checking our in-core
- * completion queues. This avoids a costly PCI bus read in
- * most cases.
- */
- if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
- && (ahd_check_cmdcmpltqueues(ahd) != 0))
- intstat = CMDCMPLT;
- else
- intstat = ahd_inb(ahd, INTSTAT);
-
- if ((intstat & INT_PEND) == 0)
- return (0);
-
- if (intstat & CMDCMPLT) {
- ahd_outb(ahd, CLRINT, CLRCMDINT);
-
- /*
- * Ensure that the chip sees that we've cleared
- * this interrupt before we walk the output fifo.
- * Otherwise, we may, due to posted bus writes,
- * clear the interrupt after we finish the scan,
- * and after the sequencer has added new entries
- * and asserted the interrupt again.
- */
- if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
- if (ahd_is_paused(ahd)) {
- /*
- * Potentially lost SEQINT.
- * If SEQINTCODE is non-zero,
- * simulate the SEQINT.
- */
- if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
- intstat |= SEQINT;
- }
- } else {
- ahd_flush_device_writes(ahd);
- }
- ahd_run_qoutfifo(ahd);
- ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
- ahd->cmdcmplt_total++;
-#ifdef AHD_TARGET_MODE
- if ((ahd->flags & AHD_TARGETROLE) != 0)
- ahd_run_tqinfifo(ahd, /*paused*/FALSE);
-#endif
- }
-
- /*
- * Handle statuses that may invalidate our cached
- * copy of INTSTAT separately.
- */
- if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
- /* Hot eject. Do nothing */
- } else if (intstat & HWERRINT) {
- ahd_handle_hwerrint(ahd);
- } else if ((intstat & (PCIINT|SPLTINT)) != 0) {
- ahd->bus_intr(ahd);
- } else {
-
- if ((intstat & SEQINT) != 0)
- ahd_handle_seqint(ahd, intstat);
-
- if ((intstat & SCSIINT) != 0)
- ahd_handle_scsiint(ahd, intstat);
- }
- return (1);
}
#endif /* _AIC79XX_INLINE_H_ */
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm.c Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm.c Sun Apr 9 21:49:25 2006
@@ -468,7 +468,7 @@ ahd_linux_queue(struct scsi_cmnd * cmd,
return rtn;
}
-static inline struct scsi_target **
+static struct scsi_target **
ahd_linux_target_in_softc(struct scsi_target *starget)
{
struct ahd_softc *ahd =
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm.h linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm.h
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm.h Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm.h Sun Apr 9 22:00:31 2006
@@ -226,22 +226,9 @@ typedef struct timer_list ahd_timer_t;
#define ahd_timer_init init_timer
#define ahd_timer_stop del_timer_sync
typedef void ahd_linux_callback_t (u_long);
-static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec,
+void ahd_timer_reset(ahd_timer_t *timer, int usec,
ahd_callback_t *func, void *arg);
-static __inline void
-ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
-{
- struct ahd_softc *ahd;
-
- ahd = (struct ahd_softc *)arg;
- del_timer(timer);
- timer->data = (u_long)arg;
- timer->expires = jiffies + (usec * HZ)/1000000;
- timer->function = (ahd_linux_callback_t*)func;
- add_timer(timer);
-}
-
/***************************** SMP support ************************************/
#include <linux/spinlock.h>
@@ -399,111 +386,19 @@ struct ahd_platform_data {
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
-static __inline void ahd_delay(long);
-static __inline void
-ahd_delay(long usec)
-{
- /*
- * udelay on Linux can have problems for
- * multi-millisecond waits. Wait at most
- * 1024us per call.
- */
- while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
- }
-}
-
+void ahd_delay(long);
/***************************** Low Level I/O **********************************/
-static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port);
-static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port);
-static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
-static __inline void ahd_outw_atomic(struct ahd_softc * ahd,
+uint8_t ahd_inb(struct ahd_softc * ahd, long port);
+uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port);
+void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
+void ahd_outw_atomic(struct ahd_softc * ahd,
long port, uint16_t val);
-static __inline void ahd_outsb(struct ahd_softc * ahd, long port,
+void ahd_outsb(struct ahd_softc * ahd, long port,
uint8_t *, int count);
-static __inline void ahd_insb(struct ahd_softc * ahd, long port,
+void ahd_insb(struct ahd_softc * ahd, long port,
uint8_t *, int count);
-static __inline uint8_t
-ahd_inb(struct ahd_softc * ahd, long port)
-{
- uint8_t x;
-
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- x = readb(ahd->bshs[0].maddr + port);
- } else {
- x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
- }
- mb();
- return (x);
-}
-
-static __inline uint16_t
-ahd_inw_atomic(struct ahd_softc * ahd, long port)
-{
- uint8_t x;
-
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- x = readw(ahd->bshs[0].maddr + port);
- } else {
- x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
- }
- mb();
- return (x);
-}
-
-static __inline void
-ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
-{
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- writeb(val, ahd->bshs[0].maddr + port);
- } else {
- outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
- }
- mb();
-}
-
-static __inline void
-ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
-{
- if (ahd->tags[0] == BUS_SPACE_MEMIO) {
- writew(val, ahd->bshs[0].maddr + port);
- } else {
- outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
- }
- mb();
-}
-
-static __inline void
-ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- ahd_outb(ahd, port, *array++);
-}
-
-static __inline void
-ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- *array++ = ahd_inb(ahd, port);
-}
-
/**************************** Initialization **********************************/
int ahd_linux_register_host(struct ahd_softc *,
struct scsi_host_template *);
@@ -613,6 +508,7 @@ void ahd_linux_pci_exit(void);
int ahd_pci_map_registers(struct ahd_softc *ahd);
int ahd_pci_map_int(struct ahd_softc *ahd);
+void ahd_BUG_bad_pci_rw_size(void);
static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
int reg, int width);
@@ -640,7 +536,7 @@ ahd_pci_read_config(ahd_dev_softc_t pci,
return (retval);
}
default:
- panic("ahd_pci_read_config: Read size too big");
+ ahd_BUG_bad_pci_rw_size();
/* NOTREACHED */
return (0);
}
@@ -664,7 +560,7 @@ ahd_pci_write_config(ahd_dev_softc_t pci
pci_write_config_dword(pci, reg, value);
break;
default:
- panic("ahd_pci_write_config: Write size too big");
+ ahd_BUG_bad_pci_rw_size();
/* NOTREACHED */
}
}
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm_o.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm_o.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic79xx_osm_o.c Thu Jan 1 03:00:00 1970
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic79xx_osm_o.c Sun Apr 9 21:53:01 2006
@@ -0,0 +1,114 @@
+/*
+ * Adaptec AIC79xx device driver for Linux.
+ *
+ * Formerly inlined routines from aic79xx_osm.h are moved here.
+ * This file is #included into aic79xx_core.c
+ */
+
+/***************************** Timer Facilities *******************************/
+void
+ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg)
+{
+ struct ahd_softc *ahd;
+
+ ahd = (struct ahd_softc *)arg;
+ del_timer(timer);
+ timer->data = (u_long)arg;
+ timer->expires = jiffies + (usec * HZ)/1000000;
+ timer->function = (ahd_linux_callback_t*)func;
+ add_timer(timer);
+}
+
+/************************** OS Utility Wrappers *******************************/
+void
+ahd_delay(long usec)
+{
+ /*
+ * udelay on Linux can have problems for
+ * multi-millisecond waits. Wait at most
+ * 1024us per call.
+ */
+ while (usec > 0) {
+ udelay(usec % 1024);
+ usec -= 1024;
+ }
+}
+
+/***************************** Low Level I/O **********************************/
+uint8_t
+ahd_inb(struct ahd_softc * ahd, long port)
+{
+ uint8_t x;
+
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ x = readb(ahd->bshs[0].maddr + port);
+ } else {
+ x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+ }
+ mb();
+ return (x);
+}
+
+uint16_t
+ahd_inw_atomic(struct ahd_softc * ahd, long port)
+{
+ uint8_t x;
+
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ x = readw(ahd->bshs[0].maddr + port);
+ } else {
+ x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+ }
+ mb();
+ return (x);
+}
+
+void
+ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
+{
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ writeb(val, ahd->bshs[0].maddr + port);
+ } else {
+ outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+ }
+ mb();
+}
+
+void
+ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
+{
+ if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+ writew(val, ahd->bshs[0].maddr + port);
+ } else {
+ outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+ }
+ mb();
+}
+
+void
+ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ ahd_outb(ahd, port, *array++);
+}
+
+void
+ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ *array++ = ahd_inb(ahd, port);
+}
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_core.c Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_core.c Sun Apr 9 21:49:25 2006
@@ -50,6 +50,10 @@
#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
#endif
+/* Were inlined, but moved out-of-line because they are HUGE: */
+#include "aic7xxx_osm_o.c"
+#include "aic7xxx_inline.c"
+
/***************************** Lookup Tables **********************************/
char *ahc_chip_names[] =
{
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_inline.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_inline.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_inline.c Thu Jan 1 03:00:00 1970
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_inline.c Sun Apr 9 21:49:25 2006
@@ -0,0 +1,311 @@
+/*
+ * Routines shareable across OS platforms.
+ *
+ * Formerly inlined routines from aic7xxx_inline.h are moved here.
+ * This file is #included into aic7xxx_core.c
+ */
+
+/*********************** Miscelaneous Support Functions ***********************/
+uint16_t
+ahc_inw(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
+}
+
+void
+ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+}
+
+uint32_t
+ahc_inl(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24));
+}
+
+void
+ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
+{
+ ahc_outb(ahc, port, (value) & 0xFF);
+ ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
+}
+
+uint64_t
+ahc_inq(struct ahc_softc *ahc, u_int port)
+{
+ return ((ahc_inb(ahc, port))
+ | (ahc_inb(ahc, port+1) << 8)
+ | (ahc_inb(ahc, port+2) << 16)
+ | (ahc_inb(ahc, port+3) << 24)
+ | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
+ | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
+ | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
+ | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
+}
+
+void
+ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
+{
+ ahc_outb(ahc, port, value & 0xFF);
+ ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+ ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
+ ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
+ ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
+ ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
+ ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
+ ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
+ */
+struct scb *
+ahc_get_scb(struct ahc_softc *ahc)
+{
+ struct scb *scb;
+
+ if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
+ ahc_alloc_scbs(ahc);
+ scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
+ if (scb == NULL)
+ return (NULL);
+ }
+ SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
+ return (scb);
+}
+
+/*
+ * Return an SCB resource to the free list.
+ */
+void
+ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+ struct hardware_scb *hscb;
+
+ hscb = scb->hscb;
+ /* Clean up for the next user */
+ ahc->scb_data->scbindex[hscb->tag] = NULL;
+ scb->flags = SCB_FREE;
+ hscb->control = 0;
+
+ SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
+
+ /* Notify the OSM that a resource is now available. */
+ ahc_platform_scb_free(ahc, scb);
+}
+
+struct scb *
+ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
+{
+ struct scb* scb;
+
+ scb = ahc->scb_data->scbindex[tag];
+ if (scb != NULL)
+ ahc_sync_scb(ahc, scb,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ return (scb);
+}
+
+void
+ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
+{
+ struct hardware_scb *q_hscb;
+ u_int saved_tag;
+
+ /*
+ * Our queuing method is a bit tricky. The card
+ * knows in advance which HSCB to download, and we
+ * can't disappoint it. To achieve this, the next
+ * SCB to download is saved off in ahc->next_queued_scb.
+ * When we are called to queue "an arbitrary scb",
+ * we copy the contents of the incoming HSCB to the one
+ * the sequencer knows about, swap HSCB pointers and
+ * finally assign the SCB to the tag indexed location
+ * in the scb_array. This makes sure that we can still
+ * locate the correct SCB by SCB_TAG.
+ */
+ q_hscb = ahc->next_queued_scb->hscb;
+ saved_tag = q_hscb->tag;
+ memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+ if ((scb->flags & SCB_CDB32_PTR) != 0) {
+ q_hscb->shared_data.cdb_ptr =
+ ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
+ + offsetof(struct hardware_scb, cdb32));
+ }
+ q_hscb->tag = saved_tag;
+ q_hscb->next = scb->hscb->tag;
+
+ /* Now swap HSCB pointers. */
+ ahc->next_queued_scb->hscb = scb->hscb;
+ scb->hscb = q_hscb;
+
+ /* Now define the mapping from tag to SCB in the scbindex */
+ ahc->scb_data->scbindex[scb->hscb->tag] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+void
+ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+ ahc_swap_with_next_hscb(ahc, scb);
+
+ if (scb->hscb->tag == SCB_LIST_NULL
+ || scb->hscb->next == SCB_LIST_NULL)
+ panic("Attempt to queue invalid SCB tag %x:%x\n",
+ scb->hscb->tag, scb->hscb->next);
+
+ /*
+ * Setup data "oddness".
+ */
+ scb->hscb->lun &= LID;
+ if (ahc_get_transfer_length(scb) & 0x1)
+ scb->hscb->lun |= SCB_XFERLEN_ODD;
+
+ /*
+ * Keep a history of SCBs we've downloaded in the qinfifo.
+ */
+ ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+
+ /*
+ * Make sure our data is consistent from the
+ * perspective of the adapter.
+ */
+ ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ /* Tell the adapter about the newly queued SCB */
+ if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+ ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+ } else {
+ if ((ahc->features & AHC_AUTOPAUSE) == 0)
+ ahc_pause(ahc);
+ ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+ if ((ahc->features & AHC_AUTOPAUSE) == 0)
+ ahc_unpause(ahc);
+ }
+}
+
+/************************** Interrupt Processing ******************************/
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHC_RUN_QOUTFIFO 0x1
+#define AHC_RUN_TQINFIFO 0x2
+u_int
+ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
+{
+ u_int retval;
+
+ retval = 0;
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+ /*offset*/ahc->qoutfifonext, /*len*/1,
+ BUS_DMASYNC_POSTREAD);
+ if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
+ retval |= AHC_RUN_QOUTFIFO;
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0
+ && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
+ ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+ ahc->shared_data_dmamap,
+ ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
+ /*len*/sizeof(struct target_cmd),
+ BUS_DMASYNC_POSTREAD);
+ if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
+ retval |= AHC_RUN_TQINFIFO;
+ }
+#endif
+ return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+int
+ahc_intr(struct ahc_softc *ahc)
+{
+ u_int intstat;
+
+ if ((ahc->pause & INTEN) == 0) {
+ /*
+ * Our interrupt is not enabled on the chip
+ * and may be disabled for re-entrancy reasons,
+ * so just return. This is likely just a shared
+ * interrupt.
+ */
+ return (0);
+ }
+ /*
+ * Instead of directly reading the interrupt status register,
+ * infer the cause of the interrupt by checking our in-core
+ * completion queues. This avoids a costly PCI bus read in
+ * most cases.
+ */
+ if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
+ && (ahc_check_cmdcmpltqueues(ahc) != 0))
+ intstat = CMDCMPLT;
+ else {
+ intstat = ahc_inb(ahc, INTSTAT);
+ }
+
+ if ((intstat & INT_PEND) == 0) {
+#if AHC_PCI_CONFIG > 0
+ if (ahc->unsolicited_ints > 500) {
+ ahc->unsolicited_ints = 0;
+ if ((ahc->chip & AHC_PCI) != 0
+ && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+ ahc->bus_intr(ahc);
+ }
+#endif
+ ahc->unsolicited_ints++;
+ return (0);
+ }
+ ahc->unsolicited_ints = 0;
+
+ if (intstat & CMDCMPLT) {
+ ahc_outb(ahc, CLRINT, CLRCMDINT);
+
+ /*
+ * Ensure that the chip sees that we've cleared
+ * this interrupt before we walk the output fifo.
+ * Otherwise, we may, due to posted bus writes,
+ * clear the interrupt after we finish the scan,
+ * and after the sequencer has added new entries
+ * and asserted the interrupt again.
+ */
+ ahc_flush_device_writes(ahc);
+ ahc_run_qoutfifo(ahc);
+#ifdef AHC_TARGET_MODE
+ if ((ahc->flags & AHC_TARGETROLE) != 0)
+ ahc_run_tqinfifo(ahc, /*paused*/FALSE);
+#endif
+ }
+
+ /*
+ * Handle statuses that may invalidate our cached
+ * copy of INTSTAT separately.
+ */
+ if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
+ /* Hot eject. Do nothing */
+ } else if (intstat & BRKADRINT) {
+ ahc_handle_brkadrint(ahc);
+ } else if ((intstat & (SEQINT|SCSIINT)) != 0) {
+
+ ahc_pause_bug_fix(ahc);
+
+ if ((intstat & SEQINT) != 0)
+ ahc_handle_seqint(ahc, intstat);
+
+ if ((intstat & SCSIINT) != 0)
+ ahc_handle_scsiint(ahc, intstat);
+ }
+ return (1);
+}
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_inline.h linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_inline.h Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_inline.h Sun Apr 9 21:49:25 2006
@@ -238,24 +238,20 @@ static __inline struct ahc_initiator_tin
char channel, u_int our_id,
u_int remote_id,
struct ahc_tmode_tstate **tstate);
-static __inline uint16_t
- ahc_inw(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outw(struct ahc_softc *ahc, u_int port,
- u_int value);
-static __inline uint32_t
- ahc_inl(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outl(struct ahc_softc *ahc, u_int port,
- uint32_t value);
-static __inline uint64_t
- ahc_inq(struct ahc_softc *ahc, u_int port);
-static __inline void ahc_outq(struct ahc_softc *ahc, u_int port,
- uint64_t value);
-static __inline struct scb*
- ahc_get_scb(struct ahc_softc *ahc);
-static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
-static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
+uint16_t ahc_inw(struct ahc_softc *ahc, u_int port);
+void ahc_outw(struct ahc_softc *ahc, u_int port, u_int value);
+uint32_t ahc_inl(struct ahc_softc *ahc, u_int port);
+void ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value);
+uint64_t ahc_inq(struct ahc_softc *ahc, u_int port);
+void ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value);
+struct scb*
+ ahc_get_scb(struct ahc_softc *ahc);
+void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
+struct scb *
+ ahc_lookup_scb(struct ahc_softc *ahc, u_int tag);
+void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
struct scb *scb);
-static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
+void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
static __inline struct scsi_sense_data *
ahc_get_sense_buf(struct ahc_softc *ahc,
struct scb *scb);
@@ -297,193 +293,6 @@ ahc_fetch_transinfo(struct ahc_softc *ah
return (&(*tstate)->transinfo[remote_id]);
}
-static __inline uint16_t
-ahc_inw(struct ahc_softc *ahc, u_int port)
-{
- return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
-}
-
-static __inline void
-ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
-{
- ahc_outb(ahc, port, value & 0xFF);
- ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
-}
-
-static __inline uint32_t
-ahc_inl(struct ahc_softc *ahc, u_int port)
-{
- return ((ahc_inb(ahc, port))
- | (ahc_inb(ahc, port+1) << 8)
- | (ahc_inb(ahc, port+2) << 16)
- | (ahc_inb(ahc, port+3) << 24));
-}
-
-static __inline void
-ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
-{
- ahc_outb(ahc, port, (value) & 0xFF);
- ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
- ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
- ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
-}
-
-static __inline uint64_t
-ahc_inq(struct ahc_softc *ahc, u_int port)
-{
- return ((ahc_inb(ahc, port))
- | (ahc_inb(ahc, port+1) << 8)
- | (ahc_inb(ahc, port+2) << 16)
- | (ahc_inb(ahc, port+3) << 24)
- | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
- | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
- | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
- | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
-}
-
-static __inline void
-ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
-{
- ahc_outb(ahc, port, value & 0xFF);
- ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
- ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
- ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
- ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
- ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
- ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
- ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
-}
-
-/*
- * Get a free scb. If there are none, see if we can allocate a new SCB.
- */
-static __inline struct scb *
-ahc_get_scb(struct ahc_softc *ahc)
-{
- struct scb *scb;
-
- if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
- ahc_alloc_scbs(ahc);
- scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
- if (scb == NULL)
- return (NULL);
- }
- SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
- return (scb);
-}
-
-/*
- * Return an SCB resource to the free list.
- */
-static __inline void
-ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
-{
- struct hardware_scb *hscb;
-
- hscb = scb->hscb;
- /* Clean up for the next user */
- ahc->scb_data->scbindex[hscb->tag] = NULL;
- scb->flags = SCB_FREE;
- hscb->control = 0;
-
- SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
-
- /* Notify the OSM that a resource is now available. */
- ahc_platform_scb_free(ahc, scb);
-}
-
-static __inline struct scb *
-ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
-{
- struct scb* scb;
-
- scb = ahc->scb_data->scbindex[tag];
- if (scb != NULL)
- ahc_sync_scb(ahc, scb,
- BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
- return (scb);
-}
-
-static __inline void
-ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
-{
- struct hardware_scb *q_hscb;
- u_int saved_tag;
-
- /*
- * Our queuing method is a bit tricky. The card
- * knows in advance which HSCB to download, and we
- * can't disappoint it. To achieve this, the next
- * SCB to download is saved off in ahc->next_queued_scb.
- * When we are called to queue "an arbitrary scb",
- * we copy the contents of the incoming HSCB to the one
- * the sequencer knows about, swap HSCB pointers and
- * finally assign the SCB to the tag indexed location
- * in the scb_array. This makes sure that we can still
- * locate the correct SCB by SCB_TAG.
- */
- q_hscb = ahc->next_queued_scb->hscb;
- saved_tag = q_hscb->tag;
- memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
- if ((scb->flags & SCB_CDB32_PTR) != 0) {
- q_hscb->shared_data.cdb_ptr =
- ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
- + offsetof(struct hardware_scb, cdb32));
- }
- q_hscb->tag = saved_tag;
- q_hscb->next = scb->hscb->tag;
-
- /* Now swap HSCB pointers. */
- ahc->next_queued_scb->hscb = scb->hscb;
- scb->hscb = q_hscb;
-
- /* Now define the mapping from tag to SCB in the scbindex */
- ahc->scb_data->scbindex[scb->hscb->tag] = scb;
-}
-
-/*
- * Tell the sequencer about a new transaction to execute.
- */
-static __inline void
-ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
-{
- ahc_swap_with_next_hscb(ahc, scb);
-
- if (scb->hscb->tag == SCB_LIST_NULL
- || scb->hscb->next == SCB_LIST_NULL)
- panic("Attempt to queue invalid SCB tag %x:%x\n",
- scb->hscb->tag, scb->hscb->next);
-
- /*
- * Setup data "oddness".
- */
- scb->hscb->lun &= LID;
- if (ahc_get_transfer_length(scb) & 0x1)
- scb->hscb->lun |= SCB_XFERLEN_ODD;
-
- /*
- * Keep a history of SCBs we've downloaded in the qinfifo.
- */
- ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
-
- /*
- * Make sure our data is consistent from the
- * perspective of the adapter.
- */
- ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
-
- /* Tell the adapter about the newly queued SCB */
- if ((ahc->features & AHC_QUEUE_REGS) != 0) {
- ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
- } else {
- if ((ahc->features & AHC_AUTOPAUSE) == 0)
- ahc_pause(ahc);
- ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
- if ((ahc->features & AHC_AUTOPAUSE) == 0)
- ahc_unpause(ahc);
- }
-}
-
static __inline struct scsi_sense_data *
ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
{
@@ -506,8 +315,8 @@ ahc_get_sense_bufaddr(struct ahc_softc *
/************************** Interrupt Processing ******************************/
static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
-static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline int ahc_intr(struct ahc_softc *ahc);
+u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
+int ahc_intr(struct ahc_softc *ahc);
static __inline void
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
@@ -528,122 +337,6 @@ ahc_sync_tqinfifo(struct ahc_softc *ahc,
op);
}
#endif
-}
-
-/*
- * See if the firmware has posted any completed commands
- * into our in-core command complete fifos.
- */
-#define AHC_RUN_QOUTFIFO 0x1
-#define AHC_RUN_TQINFIFO 0x2
-static __inline u_int
-ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
-{
- u_int retval;
-
- retval = 0;
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
- /*offset*/ahc->qoutfifonext, /*len*/1,
- BUS_DMASYNC_POSTREAD);
- if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
- retval |= AHC_RUN_QOUTFIFO;
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0
- && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
- ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
- ahc->shared_data_dmamap,
- ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
- /*len*/sizeof(struct target_cmd),
- BUS_DMASYNC_POSTREAD);
- if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
- retval |= AHC_RUN_TQINFIFO;
- }
-#endif
- return (retval);
-}
-
-/*
- * Catch an interrupt from the adapter
- */
-static __inline int
-ahc_intr(struct ahc_softc *ahc)
-{
- u_int intstat;
-
- if ((ahc->pause & INTEN) == 0) {
- /*
- * Our interrupt is not enabled on the chip
- * and may be disabled for re-entrancy reasons,
- * so just return. This is likely just a shared
- * interrupt.
- */
- return (0);
- }
- /*
- * Instead of directly reading the interrupt status register,
- * infer the cause of the interrupt by checking our in-core
- * completion queues. This avoids a costly PCI bus read in
- * most cases.
- */
- if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
- && (ahc_check_cmdcmpltqueues(ahc) != 0))
- intstat = CMDCMPLT;
- else {
- intstat = ahc_inb(ahc, INTSTAT);
- }
-
- if ((intstat & INT_PEND) == 0) {
-#if AHC_PCI_CONFIG > 0
- if (ahc->unsolicited_ints > 500) {
- ahc->unsolicited_ints = 0;
- if ((ahc->chip & AHC_PCI) != 0
- && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
- ahc->bus_intr(ahc);
- }
-#endif
- ahc->unsolicited_ints++;
- return (0);
- }
- ahc->unsolicited_ints = 0;
-
- if (intstat & CMDCMPLT) {
- ahc_outb(ahc, CLRINT, CLRCMDINT);
-
- /*
- * Ensure that the chip sees that we've cleared
- * this interrupt before we walk the output fifo.
- * Otherwise, we may, due to posted bus writes,
- * clear the interrupt after we finish the scan,
- * and after the sequencer has added new entries
- * and asserted the interrupt again.
- */
- ahc_flush_device_writes(ahc);
- ahc_run_qoutfifo(ahc);
-#ifdef AHC_TARGET_MODE
- if ((ahc->flags & AHC_TARGETROLE) != 0)
- ahc_run_tqinfifo(ahc, /*paused*/FALSE);
-#endif
- }
-
- /*
- * Handle statuses that may invalidate our cached
- * copy of INTSTAT separately.
- */
- if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
- /* Hot eject. Do nothing */
- } else if (intstat & BRKADRINT) {
- ahc_handle_brkadrint(ahc);
- } else if ((intstat & (SEQINT|SCSIINT)) != 0) {
-
- ahc_pause_bug_fix(ahc);
-
- if ((intstat & SEQINT) != 0)
- ahc_handle_seqint(ahc, intstat);
-
- if ((intstat & SCSIINT) != 0)
- ahc_handle_scsiint(ahc, intstat);
- }
- return (1);
}
#endif /* _AIC7XXX_INLINE_H_ */
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm.c Sun Apr 9 21:49:25 2006
@@ -393,7 +393,7 @@ static int ahc_linux_unit;
/********************************* Inlines ************************************/
static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
-static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
+static int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
struct ahc_dma_seg *sg,
dma_addr_t addr, bus_size_t len);
@@ -418,7 +418,7 @@ ahc_linux_unmap_scb(struct ahc_softc *ah
}
}
-static __inline int
+static int
ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len)
{
@@ -492,7 +492,7 @@ ahc_linux_queue(struct scsi_cmnd * cmd,
return rtn;
}
-static inline struct scsi_target **
+static struct scsi_target **
ahc_linux_target_in_softc(struct scsi_target *starget)
{
struct ahc_softc *ahc =
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Mar 20 07:53:29 2006
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm.h Sun Apr 9 22:00:33 2006
@@ -387,82 +387,15 @@ struct ahc_platform_data {
#define malloc(size, type, flags) kmalloc(size, flags)
#define free(ptr, type) kfree(ptr)
-static __inline void ahc_delay(long);
-static __inline void
-ahc_delay(long usec)
-{
- /*
- * udelay on Linux can have problems for
- * multi-millisecond waits. Wait at most
- * 1024us per call.
- */
- while (usec > 0) {
- udelay(usec % 1024);
- usec -= 1024;
- }
-}
-
+void ahc_delay(long);
/***************************** Low Level I/O **********************************/
-static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
-static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
-static __inline void ahc_outsb(struct ahc_softc * ahc, long port,
- uint8_t *, int count);
-static __inline void ahc_insb(struct ahc_softc * ahc, long port,
- uint8_t *, int count);
-
-static __inline uint8_t
-ahc_inb(struct ahc_softc * ahc, long port)
-{
- uint8_t x;
-
- if (ahc->tag == BUS_SPACE_MEMIO) {
- x = readb(ahc->bsh.maddr + port);
- } else {
- x = inb(ahc->bsh.ioport + port);
- }
- mb();
- return (x);
-}
-
-static __inline void
-ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
-{
- if (ahc->tag == BUS_SPACE_MEMIO) {
- writeb(val, ahc->bsh.maddr + port);
- } else {
- outb(val, ahc->bsh.ioport + port);
- }
- mb();
-}
-
-static __inline void
-ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- ahc_outb(ahc, port, *array++);
-}
-
-static __inline void
-ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
-{
- int i;
-
- /*
- * There is probably a more efficient way to do this on Linux
- * but we don't use this for anything speed critical and this
- * should work.
- */
- for (i = 0; i < count; i++)
- *array++ = ahc_inb(ahc, port);
-}
+uint8_t ahc_inb(struct ahc_softc * ahc, long port);
+void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
+void ahc_outsb(struct ahc_softc * ahc, long port,
+ uint8_t *, int count);
+void ahc_insb(struct ahc_softc * ahc, long port,
+ uint8_t *, int count);
/**************************** Initialization **********************************/
int ahc_linux_register_host(struct ahc_softc *,
@@ -569,6 +502,7 @@ void ahc_linux_pci_exit(void);
int ahc_pci_map_registers(struct ahc_softc *ahc);
int ahc_pci_map_int(struct ahc_softc *ahc);
+void ahc_BUG_bad_pci_rw_size(void);
static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
int reg, int width);
@@ -596,7 +530,7 @@ ahc_pci_read_config(ahc_dev_softc_t pci,
return (retval);
}
default:
- panic("ahc_pci_read_config: Read size too big");
+ ahc_BUG_bad_pci_rw_size();
/* NOTREACHED */
return (0);
}
@@ -620,7 +554,7 @@ ahc_pci_write_config(ahc_dev_softc_t pci
pci_write_config_dword(pci, reg, value);
break;
default:
- panic("ahc_pci_write_config: Write size too big");
+ ahc_BUG_bad_pci_rw_size();
/* NOTREACHED */
}
}
diff -urpN linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm_o.c linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm_o.c
--- linux-2.6.16.org/drivers/scsi/aic7xxx/aic7xxx_osm_o.c Thu Jan 1 03:00:00 1970
+++ linux-2.6.16.aic7/drivers/scsi/aic7xxx/aic7xxx_osm_o.c Sun Apr 9 21:54:39 2006
@@ -0,0 +1,75 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Formerly inlined routines from aic7xxx_osm.h are moved here.
+ * This file is #included into aic7xxx_core.c
+ */
+
+/************************** OS Utility Wrappers *******************************/
+void
+ahc_delay(long usec)
+{
+ /*
+ * udelay on Linux can have problems for
+ * multi-millisecond waits. Wait at most
+ * 1024us per call.
+ */
+ while (usec > 0) {
+ udelay(usec % 1024);
+ usec -= 1024;
+ }
+}
+
+/***************************** Low Level I/O **********************************/
+uint8_t
+ahc_inb(struct ahc_softc * ahc, long port)
+{
+ uint8_t x;
+
+ if (ahc->tag == BUS_SPACE_MEMIO) {
+ x = readb(ahc->bsh.maddr + port);
+ } else {
+ x = inb(ahc->bsh.ioport + port);
+ }
+ mb();
+ return (x);
+}
+
+void
+ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
+{
+ if (ahc->tag == BUS_SPACE_MEMIO) {
+ writeb(val, ahc->bsh.maddr + port);
+ } else {
+ outb(val, ahc->bsh.ioport + port);
+ }
+ mb();
+}
+
+void
+ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ ahc_outb(ahc, port, *array++);
+}
+
+void
+ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+ int i;
+
+ /*
+ * There is probably a more efficient way to do this on Linux
+ * but we don't use this for anything speed critical and this
+ * should work.
+ */
+ for (i = 0; i < count; i++)
+ *array++ = ahc_inb(ahc, port);
+}
^ permalink raw reply
* [PATCH 05/10] scsi tgt: kernel/user interface changes
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
Simplify the tgt kernel/user interface.
- merge the tgt command structure with the the event structure for simplicity.
- add a new event type for task management.
- remove some of unused event types.
- send task attributes to user-space daemon.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_tgt_if.c | 52 ++++++++++++++++++------------------------
drivers/scsi/scsi_tgt_lib.c | 10 ++++----
drivers/scsi/scsi_tgt_priv.h | 4 ++-
include/scsi/scsi_tgt_if.h | 50 ++++++++++++++++++++--------------------
4 files changed, 54 insertions(+), 62 deletions(-)
5804be31dad9a5ca05bef0ff2674cde90299ac3d
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 38b35da..a31c8d5 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -35,15 +35,15 @@
static int tgtd_pid;
static struct sock *nl_sk;
-static int send_event_res(uint16_t type, struct tgt_event *p,
- void *data, int dlen, gfp_t flags, pid_t pid)
+static int send_event_rsp(uint16_t type, struct tgt_event *p, gfp_t flags,
+ pid_t pid)
{
struct tgt_event *ev;
struct nlmsghdr *nlh;
struct sk_buff *skb;
uint32_t len;
- len = NLMSG_SPACE(sizeof(*ev) + dlen);
+ len = NLMSG_SPACE(sizeof(*ev));
skb = alloc_skb(len, flags);
if (!skb)
return -ENOMEM;
@@ -52,8 +52,6 @@ static int send_event_res(uint16_t type,
ev = NLMSG_DATA(nlh);
memcpy(ev, p, sizeof(*ev));
- if (dlen)
- memcpy(ev->data, data, dlen);
return netlink_unicast(nl_sk, skb, pid, 0);
}
@@ -64,10 +62,12 @@ int scsi_tgt_uspace_send(struct scsi_cmn
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct tgt_event *ev;
- struct tgt_cmd *tcmd;
int err, len;
- len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct tgt_cmd));
+ /* FIXME: we need scsi core to do that. */
+ memcpy(cmd->cmnd, cmd->data_cmnd, MAX_COMMAND_SIZE);
+
+ len = NLMSG_SPACE(sizeof(*ev));
/*
* TODO: add MAX_COMMAND_SIZE to ev and add mempool
*/
@@ -82,17 +82,13 @@ int scsi_tgt_uspace_send(struct scsi_cmn
ev->k.cmd_req.host_no = shost->host_no;
ev->k.cmd_req.cid = cmd->request->tag;
ev->k.cmd_req.data_len = cmd->request_bufflen;
+ memcpy(ev->k.cmd_req.scb, cmd->cmnd, sizeof(ev->k.cmd_req.scb));
+ memcpy(ev->k.cmd_req.lun, lun, sizeof(ev->k.cmd_req.lun));
+ ev->k.cmd_req.attribute = cmd->tag;
dprintk("%d %u %u\n", ev->k.cmd_req.host_no, ev->k.cmd_req.cid,
ev->k.cmd_req.data_len);
- /* FIXME: we need scsi core to do that. */
- memcpy(cmd->cmnd, cmd->data_cmnd, MAX_COMMAND_SIZE);
-
- tcmd = (struct tgt_cmd *) ev->data;
- memcpy(tcmd->scb, cmd->cmnd, sizeof(tcmd->scb));
- memcpy(tcmd->lun, lun, sizeof(struct scsi_lun));
-
err = netlink_unicast(nl_sk, skb, tgtd_pid, 0);
if (err < 0)
printk(KERN_ERR "scsi_tgt_uspace_send: could not send skb %d\n",
@@ -104,15 +100,13 @@ int scsi_tgt_uspace_send_status(struct s
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct tgt_event ev;
- char dummy[sizeof(struct tgt_cmd)];
memset(&ev, 0, sizeof(ev));
ev.k.cmd_done.host_no = shost->host_no;
ev.k.cmd_done.cid = cmd->request->tag;
ev.k.cmd_done.result = cmd->result;
- return send_event_res(TGT_KEVENT_CMD_DONE, &ev, dummy, sizeof(dummy),
- gfp_mask, tgtd_pid);
+ return send_event_rsp(TGT_KEVENT_CMD_DONE, &ev, gfp_mask, tgtd_pid);
}
static int event_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -124,19 +118,17 @@ static int event_recv_msg(struct sk_buff
nlh->nlmsg_pid, current->pid);
switch (nlh->nlmsg_type) {
- case TGT_UEVENT_TGTD_BIND:
+ case TGT_UEVENT_REQ:
tgtd_pid = NETLINK_CREDS(skb)->pid;
break;
- case TGT_UEVENT_CMD_RES:
+ case TGT_UEVENT_CMD_RSP:
/* TODO: handle multiple cmds in one event */
- err = scsi_tgt_kspace_exec(ev->u.cmd_res.host_no,
- ev->u.cmd_res.cid,
- ev->u.cmd_res.result,
- ev->u.cmd_res.len,
- ev->u.cmd_res.offset,
- ev->u.cmd_res.uaddr,
- ev->u.cmd_res.rw,
- ev->u.cmd_res.try_map);
+ err = scsi_tgt_kspace_exec(ev->u.cmd_rsp.host_no,
+ ev->u.cmd_rsp.cid,
+ ev->u.cmd_rsp.result,
+ ev->u.cmd_rsp.len,
+ ev->u.cmd_rsp.uaddr,
+ ev->u.cmd_rsp.rw);
break;
default:
eprintk("unknown type %d\n", nlh->nlmsg_type);
@@ -166,12 +158,12 @@ static int event_recv_skb(struct sk_buff
* TODO for passthru commands the lower level should
* probably handle the result or we should modify this
*/
- if (nlh->nlmsg_type != TGT_UEVENT_CMD_RES) {
+ if (nlh->nlmsg_type != TGT_UEVENT_CMD_RSP) {
struct tgt_event ev;
memset(&ev, 0, sizeof(ev));
- ev.k.event_res.err = err;
- send_event_res(TGT_KEVENT_RESPONSE, &ev, NULL, 0,
+ ev.k.event_rsp.err = err;
+ send_event_rsp(TGT_KEVENT_RSP, &ev,
GFP_KERNEL | __GFP_NOFAIL,
nlh->nlmsg_pid);
}
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 8746236..3549e7c 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -315,7 +315,7 @@ static int scsi_map_user_pages(struct sc
while (len > 0) {
dprintk("%lx %u\n", (unsigned long) uaddr, len);
- bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw, 1);
+ bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
if (IS_ERR(bio)) {
err = PTR_ERR(bio);
dprintk("fail to map %lx %u %d %x\n",
@@ -438,16 +438,16 @@ static int scsi_tgt_copy_sense(struct sc
return 0;
}
-int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len, u64 offset,
- unsigned long uaddr, u8 rw, u8 try_map)
+int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
+ unsigned long uaddr, u8 rw)
{
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
struct request *rq;
int err = 0;
- dprintk("%d %u %d %u %llu %lx %u %u\n", host_no, cid, result,
- len, (unsigned long long) offset, uaddr, rw, try_map);
+ dprintk("%d %u %d %u %lx %u\n", host_no, cid, result,
+ len, uaddr, rw);
/* TODO: replace with a O(1) alg */
shost = scsi_host_lookup(host_no);
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 4236e50..fcf2ec6 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -21,5 +21,5 @@ extern int scsi_tgt_if_init(void);
extern int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t flags);
extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t flags);
extern int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
- u64 offset, unsigned long uaddr, u8 rw,
- u8 try_map);
+ unsigned long uaddr, u8 rw);
+
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index da3a808..ebca452 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -24,65 +24,65 @@
enum tgt_event_type {
/* user -> kernel */
- TGT_UEVENT_TGTD_BIND,
- TGT_UEVENT_TARGET_SETUP,
- TGT_UEVENT_CMD_RES,
+ TGT_UEVENT_REQ,
+ TGT_UEVENT_CMD_RSP,
+ TGT_UEVENT_TSK_MGMT_RSP,
/* kernel -> user */
- TGT_KEVENT_RESPONSE,
+ TGT_KEVENT_RSP,
TGT_KEVENT_CMD_REQ,
TGT_KEVENT_CMD_DONE,
+ TGT_KEVENT_TSK_MGMT_REQ,
};
struct tgt_event {
/* user-> kernel */
union {
struct {
- int pk_fd;
- } tgtd_bind;
+ int type;
+ int host_no;
+ } event_req;
struct {
int host_no;
uint32_t cid;
uint32_t len;
int result;
uint64_t uaddr;
- uint64_t offset;
uint8_t rw;
- uint8_t try_map;
- } cmd_res;
+ } cmd_rsp;
+ struct {
+ int host_no;
+ int mid;
+ int result;
+ } tsk_mgmt_rsp;
} u;
/* kernel -> user */
union {
struct {
int err;
- } event_res;
+ } event_rsp;
struct {
int host_no;
uint32_t cid;
uint32_t data_len;
- uint64_t dev_id;
+ uint8_t scb[16];
+ uint8_t lun[8];
+ int attribute;
} cmd_req;
struct {
int host_no;
uint32_t cid;
int result;
} cmd_done;
+ struct {
+ int host_no;
+ int mid;
+ uint64_t tag;
+ uint8_t lun[8];
+ int function;
+ } tsk_mgmt_req;
} k;
- /*
- * I think a pointer is a unsigned long but this struct
- * gets passed around from the kernel to userspace and
- * back again so to handle some ppc64 setups where userspace is
- * 32 bits but the kernel is 64 we do this odd thing
- */
- uint64_t data[0];
-} __attribute__ ((aligned (sizeof(uint64_t))));
-
-struct tgt_cmd {
- uint8_t scb[16];
- uint8_t lun[8];
- int tags;
} __attribute__ ((aligned (sizeof(uint64_t))));
-
#endif
--
1.1.5
^ permalink raw reply related
* [PATCH 09/10] scsi tgt: add task management function support
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
This patch addes task management function support to tgt.
- add callback to task management function to scsi_host_template
structure. It is used notify LLDs of the completion of a TMF request.
- this patch doesn't use a single queue for TMF requests and SCSI
commands yet. We'll work on it later on.
- when LLDs queue scsi commands to tgt (scsi_tgt_queue_command), they
need to specify unique 'tag' for each command for ABORT_TASK.
- when tgt aborts a command, it calls eh_abort_handler in
scsi_host_template structure. Would be better to add
tgt_eh_abort_handler for LLDs support target and initiator modes at
the same time?
tgt TMF works in the followings:
- When LLDs queue scsi commands to tgt (scsi_tgt_queue_command), they
need to specify unique 'tag' for each command.
- LLDs call 'int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *host, int,
u64 tag, struct scsi_lun *lun, void *data)'.
- int (* tsk_mgmt_response)(u64 data, int result) is added to
scsi_host_template.
When an initiator sends a task management request, the LLD calls
scsi_tgt_tsk_mgmt_request. the LLD can use whatever it wants for the
data arg. The data arg is used later as the arg in the
tsk_mgmt_response callback.
tgt core just sends the task management request to user space
(by using TGT_KEVENT_TSK_MGMT_REQ).
In the case of ABORT_TASK, tgtd finds a single command to abort and
sends TGT_UEVENT_CMD_RSP and TGT_UEVENT_TSK_MGMT_RSP events.
tgt core calls eh_abort_handler for TGT_UEVENT_CMD_RSP and then
tsk_mgmt_response for TGT_UEVENT_TSK_MGMT_RSP.
If tgtd fails to find a command to abort, it sends only
TGT_UEVENT_TSK_MGMT_RSP event (no TGT_UEVENT_CMD_RSP event).
In the case of the rests task management function (like
ABORT_TASK_SET), tgt needs to abort multiple commands. Thus, tgtd
finds multiple commands to abort and sends multiple TGT_UEVENT_CMD_RSP
events and a single TGT_UEVENT_TSK_MGMT_RSP event. tgt core calls
eh_abort_handler multiple times and tsk_mgmt_response once.
eh_abort_handler enables LLDs to safely free resource related with a
command to abort.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_tgt_if.c | 43 +++++++++++++++---
drivers/scsi/scsi_tgt_lib.c | 103 +++++++++++++++++++++++++++++-------------
drivers/scsi/scsi_tgt_priv.h | 11 +++-
include/scsi/scsi_host.h | 3 +
include/scsi/scsi_tgt.h | 6 ++
include/scsi/scsi_tgt_if.h | 7 ++-
6 files changed, 125 insertions(+), 48 deletions(-)
b9579b62f8d6309815a60da2e6f9a7638df074aa
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index a31c8d5..ba1b75b 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -56,7 +56,8 @@ static int send_event_rsp(uint16_t type,
return netlink_unicast(nl_sk, skb, pid, 0);
}
-int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t gfp_mask)
+int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag,
+ gfp_t flags)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct sk_buff *skb;
@@ -71,7 +72,7 @@ int scsi_tgt_uspace_send(struct scsi_cmn
/*
* TODO: add MAX_COMMAND_SIZE to ev and add mempool
*/
- skb = alloc_skb(NLMSG_SPACE(len), gfp_mask);
+ skb = alloc_skb(NLMSG_SPACE(len), flags);
if (!skb)
return -ENOMEM;
@@ -85,9 +86,11 @@ int scsi_tgt_uspace_send(struct scsi_cmn
memcpy(ev->k.cmd_req.scb, cmd->cmnd, sizeof(ev->k.cmd_req.scb));
memcpy(ev->k.cmd_req.lun, lun, sizeof(ev->k.cmd_req.lun));
ev->k.cmd_req.attribute = cmd->tag;
+ ev->k.cmd_req.tag = tag;
- dprintk("%d %u %u\n", ev->k.cmd_req.host_no, ev->k.cmd_req.cid,
- ev->k.cmd_req.data_len);
+ dprintk("%p %d %u %u %x %llx\n", cmd, shost->host_no, ev->k.cmd_req.cid,
+ ev->k.cmd_req.data_len, cmd->tag,
+ (unsigned long long) ev->k.cmd_req.tag);
err = netlink_unicast(nl_sk, skb, tgtd_pid, 0);
if (err < 0)
@@ -109,6 +112,24 @@ int scsi_tgt_uspace_send_status(struct s
return send_event_rsp(TGT_KEVENT_CMD_DONE, &ev, gfp_mask, tgtd_pid);
}
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data)
+{
+ struct tgt_event ev;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.k.tsk_mgmt_req.host_no = host_no;
+ ev.k.tsk_mgmt_req.function = function;
+ ev.k.tsk_mgmt_req.tag = tag;
+ memcpy(ev.k.tsk_mgmt_req.lun, scsilun, sizeof(ev.k.tsk_mgmt_req.lun));
+ ev.k.tsk_mgmt_req.mid = (u64) data;
+
+ dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) tag,
+ (unsigned long long) ev.k.tsk_mgmt_req.mid);
+
+ return send_event_rsp(TGT_KEVENT_TSK_MGMT_REQ, &ev, GFP_KERNEL, tgtd_pid);
+}
+
static int event_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct tgt_event *ev = NLMSG_DATA(nlh);
@@ -130,6 +151,11 @@ static int event_recv_msg(struct sk_buff
ev->u.cmd_rsp.uaddr,
ev->u.cmd_rsp.rw);
break;
+ case TGT_UEVENT_TSK_MGMT_RSP:
+ err = scsi_tgt_kspace_tsk_mgmt(ev->u.tsk_mgmt_rsp.host_no,
+ ev->u.tsk_mgmt_rsp.mid,
+ ev->u.tsk_mgmt_rsp.result);
+ break;
default:
eprintk("unknown type %d\n", nlh->nlmsg_type);
err = -EINVAL;
@@ -143,6 +169,7 @@ static int event_recv_skb(struct sk_buff
int err;
uint32_t rlen;
struct nlmsghdr *nlh;
+ struct tgt_event ev;
while (skb->len >= NLMSG_SPACE(0)) {
nlh = (struct nlmsghdr *) skb->data;
@@ -158,9 +185,11 @@ static int event_recv_skb(struct sk_buff
* TODO for passthru commands the lower level should
* probably handle the result or we should modify this
*/
- if (nlh->nlmsg_type != TGT_UEVENT_CMD_RSP) {
- struct tgt_event ev;
-
+ switch (nlh->nlmsg_type) {
+ case TGT_UEVENT_CMD_RSP:
+ case TGT_UEVENT_TSK_MGMT_RSP:
+ break;
+ default:
memset(&ev, 0, sizeof(ev));
ev.k.event_rsp.err = err;
send_event_rsp(TGT_KEVENT_RSP, &ev,
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 2cbc749..5a98fc4 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -49,6 +49,7 @@ struct scsi_tgt_cmd {
struct list_head hash_list;
struct request *rq;
+ u64 tag;
};
#define TGT_HASH_ORDER 4
@@ -106,7 +107,6 @@ static void scsi_tgt_cmd_destroy(void *d
cmd->request->flags &= ~1UL;
scsi_unmap_user_pages(tcmd);
- scsi_tgt_uspace_send_status(cmd, GFP_KERNEL);
kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
}
@@ -118,19 +118,11 @@ static void init_scsi_tgt_cmd(struct req
struct list_head *head;
static u32 tag = 0;
- tcmd->lun = rq->end_io_data;
- bio_list_init(&tcmd->xfer_list);
- bio_list_init(&tcmd->xfer_done_list);
-
spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
rq->tag = tag++;
head = &qdata->cmd_hash[cmd_hashfn(rq->tag)];
list_add(&tcmd->hash_list, head);
spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
-
- tcmd->rq = rq;
- rq->end_io_data = tcmd;
- rq->flags |= REQ_DONTPREP;
}
static void scsi_tgt_uspace_send_fn(void *data)
@@ -148,33 +140,22 @@ retry:
if (list_empty(&qdata->cmd_req))
return;
- tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
- if (!tcmd) {
- err = -ENOMEM;
- goto out;
- }
-
mutex_lock(&qdata->cmd_req_mutex);
spin_lock_irqsave(&qdata->cmd_req_lock, flags);
if (list_empty(&qdata->cmd_req)) {
spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
mutex_unlock(&qdata->cmd_req_mutex);
- kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
goto out;
}
rq = list_entry_rq(qdata->cmd_req.next);
list_del_init(&rq->queuelist);
spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
- if ((rq->flags & REQ_DONTPREP)) {
- kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
- tcmd = rq->end_io_data;
- } else
- init_scsi_tgt_cmd(rq, tcmd);
-
+ tcmd = rq->end_io_data;
+ init_scsi_tgt_cmd(rq, tcmd);
cmd = rq->special;
- err = scsi_tgt_uspace_send(cmd, tcmd->lun, GFP_ATOMIC);
+ err = scsi_tgt_uspace_send(cmd, tcmd->lun, tcmd->tag, GFP_ATOMIC);
if (err < 0) {
eprintk("failed to send: %p %d\n", cmd, err);
@@ -266,20 +247,35 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
* @scsilun: scsi lun
* @noblock: set to nonzero if the command should be queued
**/
-void scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
- int noblock)
+int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
+ u64 tag)
{
struct request_queue *q = cmd->request->q;
struct scsi_tgt_queuedata *qdata = q->queuedata;
unsigned long flags;
+ struct scsi_tgt_cmd *tcmd;
+
+ /*
+ * It would be better to allocate scsi_tgt_cmd structure in
+ * scsi_host_get_command and not to fail due to OOM.
+ */
+ tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
+ if (!tcmd)
+ return -ENOMEM;
+ cmd->request->end_io_data = tcmd;
- cmd->request->end_io_data = scsilun;
+ bio_list_init(&tcmd->xfer_list);
+ bio_list_init(&tcmd->xfer_done_list);
+ tcmd->lun = scsilun;
+ tcmd->tag = tag;
+ tcmd->rq = cmd->request;
spin_lock_irqsave(&qdata->cmd_req_lock, flags);
list_add_tail(&cmd->request->queuelist, &qdata->cmd_req);
spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
queue_work(scsi_tgtd, &qdata->uspace_send_work);
+ return 0;
}
EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
@@ -293,12 +289,7 @@ static void scsi_tgt_cmd_done(struct scs
dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
- /* don't we have to call this if result is set or not */
- if (cmd->result) {
- scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC);
- return;
- }
-
+ scsi_tgt_uspace_send_status(cmd, GFP_ATOMIC);
INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy, cmd);
queue_work(scsi_tgtd, &tcmd->work);
}
@@ -495,6 +486,18 @@ static int scsi_tgt_copy_sense(struct sc
return 0;
}
+static int scsi_tgt_abort_cmd(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+ int err;
+
+ err = host->hostt->eh_abort_handler(cmd);
+ if (err)
+ eprintk("fail to abort %p\n", cmd);
+
+ scsi_tgt_cmd_destroy(cmd);
+ return err;
+}
+
static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u32 cid)
{
struct scsi_tgt_queuedata *qdata = q->queuedata;
@@ -545,6 +548,10 @@ int scsi_tgt_kspace_exec(int host_no, u3
dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+ if (result == TASK_ABORTED) {
+ scsi_tgt_abort_cmd(shost, cmd);
+ goto done;
+ }
/*
* store the userspace values here, the working values are
* in the request_* values
@@ -585,6 +592,38 @@ done:
return err;
}
+int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
+ tag, scsilun, data);
+ if (err < 0)
+ eprintk("The task management request lost!\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
+
+int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
+{
+ struct Scsi_Host *shost;
+ int err;
+
+ dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %d\n", host_no);
+ return -EINVAL;
+ }
+ err = shost->hostt->tsk_mgmt_response(mid, result);
+ scsi_host_put(shost);
+
+ return err;
+}
+
static int __init scsi_tgt_init(void)
{
int err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 6fedcec..77a1d06 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -4,18 +4,21 @@ struct Scsi_Host;
struct task_struct;
/* tmp - will replace with SCSI logging stuff */
-#define dprintk(fmt, args...) \
+#define eprintk(fmt, args...) \
do { \
printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
} while (0)
-#define eprintk dprintk
+#define dprintk eprintk
extern void scsi_tgt_if_exit(void);
extern int scsi_tgt_if_init(void);
-extern int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun, gfp_t flags);
+extern int scsi_tgt_uspace_send(struct scsi_cmnd *cmd, struct scsi_lun *lun,
+ u64 tag, gfp_t flags);
extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, gfp_t flags);
extern int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
unsigned long uaddr, u8 rw);
-
+extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+ struct scsi_lun *scsilun, void *data);
+extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 8b799db..eca5721 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -153,6 +153,9 @@ struct scsi_host_template {
int (* transfer_data)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
+ /* Used as callback for the completion of task management request. */
+ int (* tsk_mgmt_response)(u64 mid, int result);
+
/*
* This is an error handling strategy routine. You don't need to
* define one of these if you don't want to - there is a default
diff --git a/include/scsi/scsi_tgt.h b/include/scsi/scsi_tgt.h
index 91ad6bc..2d65be7 100644
--- a/include/scsi/scsi_tgt.h
+++ b/include/scsi/scsi_tgt.h
@@ -6,6 +6,8 @@ struct Scsi_Host;
struct scsi_cmnd;
struct scsi_lun;
-extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd);
+extern struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *);
extern int scsi_tgt_alloc_queue(struct Scsi_Host *);
-extern void scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, int);
+extern int scsi_tgt_queue_command(struct scsi_cmnd *, struct scsi_lun *, u64);
+extern int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *, int, u64, struct scsi_lun *,
+ void *);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index ebca452..63b2e3a 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -52,7 +52,7 @@ struct tgt_event {
} cmd_rsp;
struct {
int host_no;
- int mid;
+ uint64_t mid;
int result;
} tsk_mgmt_rsp;
} u;
@@ -69,6 +69,7 @@ struct tgt_event {
uint8_t scb[16];
uint8_t lun[8];
int attribute;
+ uint64_t tag;
} cmd_req;
struct {
int host_no;
@@ -77,10 +78,10 @@ struct tgt_event {
} cmd_done;
struct {
int host_no;
- int mid;
+ int function;
uint64_t tag;
uint8_t lun[8];
- int function;
+ uint64_t mid;
} tsk_mgmt_req;
} k;
--
1.1.5
^ permalink raw reply related
* [PATCH 04/10] block layer: use blk_rq_bio_prep in init_request_from_bio
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: axboe, James.Bottomley; +Cc: linux-scsi
Patch to use blk_rq_bio_prep in init_request_from_bio. And remove
blk_rq_bio_prep's flags copying. The first three bits have not been
the same for some time so that has been broken. The user of
blk_rq_bio_prep will setup the request flags so if it wanted failfast
or to be a barrier it will set the correct flag itself.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
block/ll_rw_blk.c | 11 ++---------
1 files changed, 2 insertions(+), 9 deletions(-)
4b387c65f0645e86794c06eb3e734b0ec6e5733c
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 13c40a0..da2c57d 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -2765,16 +2765,12 @@ static void init_request_from_bio(struct
req->errors = 0;
req->hard_sector = req->sector = bio->bi_sector;
- req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio);
- req->current_nr_sectors = req->hard_cur_sectors = bio_cur_sectors(bio);
- req->nr_phys_segments = bio_phys_segments(req->q, bio);
- req->nr_hw_segments = bio_hw_segments(req->q, bio);
- req->buffer = bio_data(bio); /* see ->buffer comment above */
req->waiting = NULL;
- req->bio = req->biotail = bio;
req->ioprio = bio_prio(bio);
req->rq_disk = bio->bi_bdev->bd_disk;
req->start_time = jiffies;
+
+ blk_rq_bio_prep(req->q, req, bio);
}
static int __make_request(request_queue_t *q, struct bio *bio)
@@ -3403,9 +3399,6 @@ EXPORT_SYMBOL(end_request);
void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio)
{
- /* first three bits are identical in rq->flags and bio->bi_rw */
- rq->flags |= (bio->bi_rw & 7);
-
rq->nr_phys_segments = bio_phys_segments(q, bio);
rq->nr_hw_segments = bio_hw_segments(q, bio);
rq->current_nr_sectors = bio_cur_sectors(bio);
--
1.1.5
^ permalink raw reply related
* [PATCH 02/10] block layer: add partial mappings support to bio_map_user
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: axboe, James.Bottomley; +Cc: linux-scsi
This is the updated patch for partial mappings support.
- bio_map_user_iov always allows partial mappings.
- The two users (blk_rq_map_user and blk_rq_map_user_iov) will fails
if the bio is partially mapped.
- Added a length argument to blk_rq_map_user_iov in order to avoid
including sg.h in ll_rw_blk.c for struct sg_iovec.
This is a resend:
http://marc.theaimsgroup.com/?l=linux-scsi&m=114086655400806&w=2
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
block/ll_rw_blk.c | 29 ++++++++++++++++++-----------
block/scsi_ioctl.c | 3 ++-
fs/bio.c | 14 +-------------
include/linux/blkdev.h | 3 ++-
4 files changed, 23 insertions(+), 26 deletions(-)
d43dcc5c747b5896c795e1fe1f8a6d5df525daa6
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 03d9c82..6849859 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -2291,19 +2291,20 @@ int blk_rq_map_user(request_queue_t *q,
else
bio = bio_copy_user(q, uaddr, len, reading);
- if (!IS_ERR(bio)) {
- rq->bio = rq->biotail = bio;
- blk_rq_bio_prep(q, rq, bio);
+ if (IS_ERR(bio))
+ return PTR_ERR(bio);
- rq->buffer = rq->data = NULL;
- rq->data_len = len;
- return 0;
+ if (bio->bi_size != len) {
+ bio_endio(bio, bio->bi_size, 0);
+ bio_unmap_user(bio);
+ return -EINVAL;
}
- /*
- * bio is the err-ptr
- */
- return PTR_ERR(bio);
+ rq->bio = rq->biotail = bio;
+ blk_rq_bio_prep(q, rq, bio);
+ rq->buffer = rq->data = NULL;
+ rq->data_len = len;
+ return 0;
}
EXPORT_SYMBOL(blk_rq_map_user);
@@ -2329,7 +2330,7 @@ EXPORT_SYMBOL(blk_rq_map_user);
* unmapping.
*/
int blk_rq_map_user_iov(request_queue_t *q, struct request *rq,
- struct sg_iovec *iov, int iov_count)
+ struct sg_iovec *iov, int iov_count, unsigned int len)
{
struct bio *bio;
@@ -2343,6 +2344,12 @@ int blk_rq_map_user_iov(request_queue_t
if (IS_ERR(bio))
return PTR_ERR(bio);
+ if (bio->bi_size != len) {
+ bio_endio(bio, bio->bi_size, 0);
+ bio_unmap_user(bio);
+ return -EINVAL;
+ }
+
rq->bio = rq->biotail = bio;
blk_rq_bio_prep(q, rq, bio);
rq->buffer = rq->data = NULL;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 24f7af9..ef9900d 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -274,7 +274,8 @@ static int sg_io(struct file *file, requ
goto out;
}
- ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count);
+ ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count,
+ hdr->dxfer_len);
kfree(iov);
} else if (hdr->dxfer_len)
ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len);
diff --git a/fs/bio.c b/fs/bio.c
index d8259d9..f51a873 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -749,7 +749,6 @@ struct bio *bio_map_user_iov(request_que
int write_to_vm)
{
struct bio *bio;
- int len = 0, i;
bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm);
@@ -764,18 +763,7 @@ struct bio *bio_map_user_iov(request_que
*/
bio_get(bio);
- for (i = 0; i < iov_count; i++)
- len += iov[i].iov_len;
-
- if (bio->bi_size == len)
- return bio;
-
- /*
- * don't support partial mappings
- */
- bio_endio(bio, bio->bi_size, 0);
- bio_unmap_user(bio);
- return ERR_PTR(-EINVAL);
+ return bio;
}
static void __bio_unmap_user(struct bio *bio)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 860e7a4..619ef1d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -611,7 +611,8 @@ extern void blk_queue_activity_fn(reques
extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int);
extern int blk_rq_unmap_user(struct bio *, unsigned int);
extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t);
-extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int);
+extern int blk_rq_map_user_iov(request_queue_t *, struct request *,
+ struct sg_iovec *, int, unsigned int);
extern int blk_execute_rq(request_queue_t *, struct gendisk *,
struct request *, int);
extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *,
--
1.1.5
^ permalink raw reply related
* [PATCH 00/10] scsi tgt: updates (repost)
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley, axboe; +Cc: linux-scsi
This is the repost of the patches to synchronize the scsi-target-2.6
git tree with the latest code in the tgt subversion repository.
Jens, can you take a look at the block layer patches please?
^ permalink raw reply
* [PATCH 10/10] scsi tgt: add NET dependence to Kconfig
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
> From: "Jun'ichi Nomura" <j-nomura@ce.jp.nec.com>:
scsi_tgt_if.c depends on CONFIG_NET for using netlink.
So it would be nice if the Kconfig entry checks it.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
731f4924dd33579ffa5ff45ad03b7b7e933f728b
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d09c792..5b5eeb4 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -29,7 +29,7 @@ config SCSI
config SCSI_TGT
tristate "SCSI target support"
- depends on SCSI && EXPERIMENTAL
+ depends on SCSI && NET && EXPERIMENTAL
---help---
If you want to use SCSI target mode drivers enable this option.
If you choose M, the module will be called scsi_tgt.
--
1.1.5
^ permalink raw reply related
* [PATCH 03/10] scsi tgt: use the original bio_map_user interface
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
Return to the original bio_map_user interface.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_tgt_lib.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
2c78c6353dc183a16ef3e12b9c5618dd5b89679c
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 8746236..941dd64 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -315,7 +315,7 @@ static int scsi_map_user_pages(struct sc
while (len > 0) {
dprintk("%lx %u\n", (unsigned long) uaddr, len);
- bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw, 1);
+ bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
if (IS_ERR(bio)) {
err = PTR_ERR(bio);
dprintk("fail to map %lx %u %d %x\n",
--
1.1.5
^ permalink raw reply related
* [PATCH 07/10] scsi tgt: remove blk_queue_end_tag
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
Remove blk_queue_end_tag() in scsi_host_put_command() because tgt
doesn't use the elevator code.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
fd45c05acbc00cd21fa7c82f6aed5a5ef3e5b98a
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 3cf02b1..9c22465 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -352,8 +352,6 @@ void scsi_host_put_command(struct Scsi_H
spin_unlock(&shost->free_list_lock);
spin_lock(q->queue_lock);
- if (blk_rq_tagged(rq))
- blk_queue_end_tag(q, rq);
__blk_put_request(q, rq);
spin_unlock_irqrestore(q->queue_lock, flags);
--
1.1.5
^ permalink raw reply related
* [PATCH 06/10] scsi tgt: fix double lock in scsi_uspace_request_fn
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
Fix double lock in scsi_uspace_request_fn.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_tgt_lib.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
1ddfd113a764450e7998cc16dd07dcc37077b05b
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 8746236..5d76078 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -136,7 +136,7 @@ requeue:
spin_lock_irq(q->queue_lock);
/* need to track cnts and plug */
blk_requeue_request(q, rq);
- spin_lock_irq(q->queue_lock);
+ spin_unlock_irq(q->queue_lock);
}
/**
--
1.1.5
^ permalink raw reply related
* [PATCH 08/10] scsi tgt: replace the elevator code
From: FUJITA Tomonori @ 2006-04-10 1:49 UTC (permalink / raw)
To: James.Bottomley; +Cc: linux-scsi
tgt uses the elevator code to send SCSI commands to the user-space
daemon (q->request_fn sends netlink packets including commands).
This patch replaces the elevator code with a simple list.
This is mainly because tgt also needs to send TMF requests to the
user-space daemon (the daemon does all the SCSI state machine
stuff). tgt must send SCSI commands and TMF requests in an exact order
so that it would be preferable to use a single queue (per host) for
both. To uses the elevator code for TMF requests, tgt needs to
allocate request structures for them. That's wasteful because request
structures is useless for TMF requests, which don't perform any I/Os.
We basically have a netdev queue of events to send to userspace so by
using the request_queue and netdev queue we are basically double
queueing and wasting resources and it is affecting performance
We like to use shared memory stuff between kernel and user spaces
instead of netlink in the future. These queues would go away.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_tgt_lib.c | 180 ++++++++++++++++++++++++++++++------------
drivers/scsi/scsi_tgt_priv.h | 4 -
2 files changed, 129 insertions(+), 55 deletions(-)
c4bb05742e1834d664a7d8e721ecea71d42fd7f7
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 274d929..2cbc749 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -20,7 +20,7 @@
* 02110-1301 USA
*/
#include <linux/blkdev.h>
-#include <linux/elevator.h>
+#include <linux/hash.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <scsi/scsi.h>
@@ -46,6 +46,24 @@ struct scsi_tgt_cmd {
struct bio_list xfer_done_list;
struct bio_list xfer_list;
struct scsi_lun *lun;
+
+ struct list_head hash_list;
+ struct request *rq;
+};
+
+#define TGT_HASH_ORDER 4
+#define cmd_hashfn(cid) hash_long((cid), TGT_HASH_ORDER)
+
+struct scsi_tgt_queuedata {
+ struct Scsi_Host *shost;
+ struct list_head cmd_hash[1 << TGT_HASH_ORDER];
+ spinlock_t cmd_hash_lock;
+
+ struct work_struct uspace_send_work;
+
+ spinlock_t cmd_req_lock;
+ struct mutex cmd_req_mutex;
+ struct list_head cmd_req;
};
static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
@@ -68,9 +86,16 @@ static void scsi_tgt_cmd_destroy(void *d
{
struct scsi_cmnd *cmd = data;
struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
+ struct scsi_tgt_queuedata *qdata = cmd->request->q->queuedata;
+ unsigned long flags;
dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
rq_data_dir(cmd->request));
+
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_del(&tcmd->hash_list);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+
/*
* We must set rq->flags here because bio_map_user and
* blk_rq_bio_prep ruined ti.
@@ -88,55 +113,84 @@ static void scsi_tgt_cmd_destroy(void *d
static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd)
{
+ struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
+ unsigned long flags;
+ struct list_head *head;
+ static u32 tag = 0;
+
tcmd->lun = rq->end_io_data;
bio_list_init(&tcmd->xfer_list);
bio_list_init(&tcmd->xfer_done_list);
-}
-
-static int scsi_uspace_prep_fn(struct request_queue *q, struct request *rq)
-{
- struct scsi_tgt_cmd *tcmd;
- tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
- if (!tcmd)
- return BLKPREP_DEFER;
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ rq->tag = tag++;
+ head = &qdata->cmd_hash[cmd_hashfn(rq->tag)];
+ list_add(&tcmd->hash_list, head);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
- init_scsi_tgt_cmd(rq, tcmd);
+ tcmd->rq = rq;
rq->end_io_data = tcmd;
rq->flags |= REQ_DONTPREP;
- return BLKPREP_OK;
}
-static void scsi_uspace_request_fn(struct request_queue *q)
+static void scsi_tgt_uspace_send_fn(void *data)
{
+ struct request_queue *q = data;
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
struct request *rq;
struct scsi_cmnd *cmd;
struct scsi_tgt_cmd *tcmd;
+ unsigned long flags;
+ int err;
- /*
- * TODO: just send everthing in the queue to userspace in
- * one vector instead of multiple calls
- */
- while ((rq = elv_next_request(q)) != NULL) {
- cmd = rq->special;
- tcmd = rq->end_io_data;
+retry:
+ err = 0;
+ if (list_empty(&qdata->cmd_req))
+ return;
- /* the completion code kicks us in case we hit this */
- if (blk_queue_start_tag(q, rq))
- break;
+ tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
+ if (!tcmd) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ mutex_lock(&qdata->cmd_req_mutex);
- spin_unlock_irq(q->queue_lock);
- if (scsi_tgt_uspace_send(cmd, tcmd->lun, GFP_ATOMIC) < 0)
- goto requeue;
- spin_lock_irq(q->queue_lock);
+ spin_lock_irqsave(&qdata->cmd_req_lock, flags);
+ if (list_empty(&qdata->cmd_req)) {
+ spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
+ mutex_unlock(&qdata->cmd_req_mutex);
+ kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
+ goto out;
}
+ rq = list_entry_rq(qdata->cmd_req.next);
+ list_del_init(&rq->queuelist);
+ spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
- return;
-requeue:
- spin_lock_irq(q->queue_lock);
- /* need to track cnts and plug */
- blk_requeue_request(q, rq);
- spin_unlock_irq(q->queue_lock);
+ if ((rq->flags & REQ_DONTPREP)) {
+ kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
+ tcmd = rq->end_io_data;
+ } else
+ init_scsi_tgt_cmd(rq, tcmd);
+
+ cmd = rq->special;
+ err = scsi_tgt_uspace_send(cmd, tcmd->lun, GFP_ATOMIC);
+ if (err < 0) {
+ eprintk("failed to send: %p %d\n", cmd, err);
+
+ spin_lock_irqsave(&qdata->cmd_req_lock, flags);
+ list_add(&rq->queuelist, &qdata->cmd_req);
+ spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
+ }
+
+ mutex_unlock(&qdata->cmd_req_mutex);
+out:
+ /* TODO: proper error handling */
+ if (err < 0)
+ queue_delayed_work(scsi_tgtd, &qdata->uspace_send_work,
+ HZ / 10);
+ else
+ goto retry;
}
/**
@@ -150,13 +204,13 @@ int scsi_tgt_alloc_queue(struct Scsi_Hos
{
struct scsi_tgt_queuedata *queuedata;
struct request_queue *q;
- int err;
+ int err, i;
/*
* Do we need to send a netlink event or should uspace
* just respond to the hotplug event?
*/
- q = __scsi_alloc_queue(shost, scsi_uspace_request_fn);
+ q = __scsi_alloc_queue(shost, NULL);
if (!q)
return -ENOMEM;
@@ -168,19 +222,12 @@ int scsi_tgt_alloc_queue(struct Scsi_Hos
queuedata->shost = shost;
q->queuedata = queuedata;
- elevator_exit(q->elevator);
- err = elevator_init(q, "noop");
- if (err)
- goto free_data;
-
- blk_queue_prep_rq(q, scsi_uspace_prep_fn);
/*
* this is a silly hack. We should probably just queue as many
* command as is recvd to userspace. uspace can then make
* sure we do not overload the HBA
*/
q->nr_requests = shost->hostt->can_queue;
- blk_queue_init_tags(q, shost->hostt->can_queue, NULL);
/*
* We currently only support software LLDs so this does
* not matter for now. Do we need this for the cards we support?
@@ -189,10 +236,17 @@ int scsi_tgt_alloc_queue(struct Scsi_Hos
blk_queue_dma_alignment(q, 0);
shost->uspace_req_q = q;
+ for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++)
+ INIT_LIST_HEAD(&queuedata->cmd_hash[i]);
+ spin_lock_init(&queuedata->cmd_hash_lock);
+
+ INIT_LIST_HEAD(&queuedata->cmd_req);
+ spin_lock_init(&queuedata->cmd_req_lock);
+ INIT_WORK(&queuedata->uspace_send_work, scsi_tgt_uspace_send_fn, q);
+ mutex_init(&queuedata->cmd_req_mutex);
+
return 0;
-free_data:
- kfree(queuedata);
cleanup_queue:
blk_cleanup_queue(q);
return err;
@@ -215,14 +269,17 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
void scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
int noblock)
{
- /*
- * For now this just calls the request_fn from this context.
- * For HW llds though we do not want to execute from here so
- * the elevator code needs something like a REQ_TGT_CMD or
- * REQ_MSG_DONT_UNPLUG_IMMED_BECUASE_WE_WILL_HANDLE_IT
- */
+ struct request_queue *q = cmd->request->q;
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
+ unsigned long flags;
+
cmd->request->end_io_data = scsilun;
- elv_add_request(cmd->request->q, cmd->request, ELEVATOR_INSERT_BACK, 1);
+
+ spin_lock_irqsave(&qdata->cmd_req_lock, flags);
+ list_add_tail(&cmd->request->queuelist, &qdata->cmd_req);
+ spin_unlock_irqrestore(&qdata->cmd_req_lock, flags);
+
+ queue_work(scsi_tgtd, &qdata->uspace_send_work);
}
EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
@@ -438,6 +495,27 @@ static int scsi_tgt_copy_sense(struct sc
return 0;
}
+static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u32 cid)
+{
+ struct scsi_tgt_queuedata *qdata = q->queuedata;
+ struct request *rq = NULL;
+ struct list_head *head;
+ struct scsi_tgt_cmd *tcmd;
+ unsigned long flags;
+
+ head = &qdata->cmd_hash[cmd_hashfn(cid)];
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_for_each_entry(tcmd, head, hash_list) {
+ if (tcmd->rq->tag == cid) {
+ rq = tcmd->rq;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+
+ return rq;
+}
+
int scsi_tgt_kspace_exec(int host_no, u32 cid, int result, u32 len,
unsigned long uaddr, u8 rw)
{
@@ -456,7 +534,7 @@ int scsi_tgt_kspace_exec(int host_no, u3
return -EINVAL;
}
- rq = blk_queue_find_tag(shost->uspace_req_q, cid);
+ rq = tgt_cmd_hash_lookup(shost->uspace_req_q, cid);
if (!rq) {
printk(KERN_ERR "Could not find cid %u\n", cid);
err = -EINVAL;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index fcf2ec6..6fedcec 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -11,10 +11,6 @@ do { \
#define eprintk dprintk
-struct scsi_tgt_queuedata {
- struct Scsi_Host *shost;
-};
-
extern void scsi_tgt_if_exit(void);
extern int scsi_tgt_if_init(void);
--
1.1.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox