Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
3d4253d9
Commit
3d4253d9
authored
Jun 23, 2006
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SCSI] qlogicpti: Convert to new SBUS device framework.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
7bd5ed5d
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
186 additions
and
175 deletions
+186
-175
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.c
+186
-175
No files found.
drivers/scsi/qlogicpti.c
View file @
3d4253d9
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
* Copyright (C) 1996
David S. Miller (davem@caipfs.rutgers.edu
)
* Copyright (C) 1996
, 2006 David S. Miller (davem@davemloft.net
)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
...
...
@@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#define MAX_TARGETS 16
#define MAX_LUNS 8
/* 32 for 1.31 F/W */
...
...
@@ -57,7 +55,6 @@
static
struct
qlogicpti
*
qptichain
=
NULL
;
static
DEFINE_SPINLOCK
(
qptichain_lock
);
static
int
qptis_running
=
0
;
#define PACKB(a, b) (((a)<<4)|(b))
...
...
@@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return
0
;
}
/* Detect all PTI Qlogic ISP's in the machine. */
static
int
__init
qlogicpti_detect
(
struct
scsi_host_template
*
tpnt
)
{
struct
qlogicpti
*
qpti
;
struct
Scsi_Host
*
qpti_host
;
struct
sbus_bus
*
sbus
;
struct
sbus_dev
*
sdev
;
int
nqptis
=
0
,
nqptis_in_use
=
0
;
tpnt
->
proc_name
=
"qlogicpti"
;
for_each_sbus
(
sbus
)
{
for_each_sbusdev
(
sdev
,
sbus
)
{
/* Is this a red snapper? */
if
(
strcmp
(
sdev
->
prom_name
,
"ptisp"
)
&&
strcmp
(
sdev
->
prom_name
,
"PTI,ptisp"
)
&&
strcmp
(
sdev
->
prom_name
,
"QLGC,isp"
)
&&
strcmp
(
sdev
->
prom_name
,
"SUNW,isp"
))
continue
;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
* Skip over them in such cases so we survive.
*/
if
(
sdev
->
irqs
[
0
]
==
0
)
{
printk
(
"qpti%d: Adapter reports no interrupt, "
"skipping over this card."
,
nqptis
);
continue
;
}
/* Yep, register and allocate software state. */
qpti_host
=
scsi_register
(
tpnt
,
sizeof
(
struct
qlogicpti
));
if
(
!
qpti_host
)
{
printk
(
"QPTI: Cannot register PTI Qlogic ISP SCSI host"
);
continue
;
}
qpti
=
(
struct
qlogicpti
*
)
qpti_host
->
hostdata
;
/* We are wide capable, 16 targets. */
qpti_host
->
max_id
=
MAX_TARGETS
;
/* Setup back pointers and misc. state. */
qpti
->
qhost
=
qpti_host
;
qpti
->
sdev
=
sdev
;
qpti
->
qpti_id
=
nqptis
++
;
qpti
->
prom_node
=
sdev
->
prom_node
;
prom_getstring
(
qpti
->
prom_node
,
"name"
,
qpti
->
prom_name
,
sizeof
(
qpti
->
prom_name
));
/* This is not correct, actually. There's a switch
* on the PTI cards that put them into "emulation"
* mode- i.e., report themselves as QLGC,isp
* instead of PTI,ptisp. The only real substantive
* difference between non-pti and pti cards is
* the tmon register. Which is possibly even
* there for Qlogic cards, but non-functional.
*/
qpti
->
is_pti
=
(
strcmp
(
qpti
->
prom_name
,
"QLGC,isp"
)
!=
0
);
qpti_chain_add
(
qpti
);
if
(
qpti_map_regs
(
qpti
)
<
0
)
goto
fail_unlink
;
if
(
qpti_register_irq
(
qpti
)
<
0
)
goto
fail_unmap_regs
;
qpti_get_scsi_id
(
qpti
);
qpti_get_bursts
(
qpti
);
qpti_get_clock
(
qpti
);
/* Clear out scsi_cmnd array. */
memset
(
qpti
->
cmd_slots
,
0
,
sizeof
(
qpti
->
cmd_slots
));
if
(
qpti_map_queues
(
qpti
)
<
0
)
goto
fail_free_irq
;
/* Load the firmware. */
if
(
qlogicpti_load_firmware
(
qpti
))
goto
fail_unmap_queues
;
if
(
qpti
->
is_pti
)
{
/* Check the PTI status reg. */
if
(
qlogicpti_verify_tmon
(
qpti
))
goto
fail_unmap_queues
;
}
/* Reset the ISP and init res/req queues. */
if
(
qlogicpti_reset_hardware
(
qpti_host
))
goto
fail_unmap_queues
;
printk
(
"(Firmware v%d.%d.%d)"
,
qpti
->
fware_majrev
,
qpti
->
fware_minrev
,
qpti
->
fware_micrev
);
{
char
buffer
[
60
];
prom_getstring
(
qpti
->
prom_node
,
"isp-fcode"
,
buffer
,
60
);
if
(
buffer
[
0
])
printk
(
"(Firmware %s)"
,
buffer
);
if
(
prom_getbool
(
qpti
->
prom_node
,
"differential"
))
qpti
->
differential
=
1
;
}
printk
(
" [%s Wide, using %s interface]
\n
"
,
(
qpti
->
ultra
?
"Ultra"
:
"Fast"
),
(
qpti
->
differential
?
"differential"
:
"single ended"
));
nqptis_in_use
++
;
continue
;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
RES_QUEUE_LEN
),
qpti
->
res_cpu
,
qpti
->
res_dvma
);
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
QLOGICPTI_REQ_QUEUE_LEN
),
qpti
->
req_cpu
,
qpti
->
req_dvma
);
#undef QSIZE
fail_free_irq:
free_irq
(
qpti
->
irq
,
qpti
);
fail_unmap_regs:
sbus_iounmap
(
qpti
->
qregs
,
qpti
->
sdev
->
reg_addrs
[
0
].
reg_size
);
if
(
qpti
->
is_pti
)
sbus_iounmap
(
qpti
->
sreg
,
sizeof
(
unsigned
char
));
fail_unlink:
qpti_chain_del
(
qpti
);
scsi_unregister
(
qpti
->
qhost
);
}
}
if
(
nqptis
)
printk
(
"QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.
\n
"
,
nqptis
,
nqptis_in_use
);
qptis_running
=
nqptis_in_use
;
return
nqptis
;
}
static
int
qlogicpti_release
(
struct
Scsi_Host
*
host
)
{
struct
qlogicpti
*
qpti
=
(
struct
qlogicpti
*
)
host
->
hostdata
;
/* Remove visibility from IRQ handlers. */
qpti_chain_del
(
qpti
);
/* Shut up the card. */
sbus_writew
(
0
,
qpti
->
qregs
+
SBUS_CTRL
);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq
(
qpti
->
irq
,
qpti
);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
RES_QUEUE_LEN
),
qpti
->
res_cpu
,
qpti
->
res_dvma
);
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
QLOGICPTI_REQ_QUEUE_LEN
),
qpti
->
req_cpu
,
qpti
->
req_dvma
);
#undef QSIZE
sbus_iounmap
(
qpti
->
qregs
,
qpti
->
sdev
->
reg_addrs
[
0
].
reg_size
);
if
(
qpti
->
is_pti
)
sbus_iounmap
(
qpti
->
sreg
,
sizeof
(
unsigned
char
));
return
0
;
}
const
char
*
qlogicpti_info
(
struct
Scsi_Host
*
host
)
{
static
char
buf
[
80
];
...
...
@@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return
return_status
;
}
static
struct
scsi_host_template
driver
_template
=
{
.
detect
=
qlogicpti_detect
,
.
release
=
qlogicpti_release
,
static
struct
scsi_host_template
qpti
_template
=
{
.
module
=
THIS_MODULE
,
.
name
=
"qlogicpti"
,
.
info
=
qlogicpti_info
,
.
queuecommand
=
qlogicpti_queuecommand_slow
,
.
eh_abort_handler
=
qlogicpti_abort
,
...
...
@@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.
use_clustering
=
ENABLE_CLUSTERING
,
};
static
int
__devinit
qpti_sbus_probe
(
struct
of_device
*
dev
,
const
struct
of_device_id
*
match
)
{
static
int
nqptis
;
struct
sbus_dev
*
sdev
=
to_sbus_device
(
&
dev
->
dev
);
struct
device_node
*
dp
=
dev
->
node
;
struct
scsi_host_template
*
tpnt
=
match
->
data
;
struct
Scsi_Host
*
host
;
struct
qlogicpti
*
qpti
;
char
*
fcode
;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
*/
if
(
sdev
->
irqs
[
0
]
==
0
)
return
-
ENODEV
;
host
=
scsi_host_alloc
(
tpnt
,
sizeof
(
struct
qlogicpti
));
if
(
!
host
)
return
-
ENOMEM
;
qpti
=
(
struct
qlogicpti
*
)
host
->
hostdata
;
host
->
max_id
=
MAX_TARGETS
;
qpti
->
qhost
=
host
;
qpti
->
sdev
=
sdev
;
qpti
->
qpti_id
=
nqptis
;
qpti
->
prom_node
=
sdev
->
prom_node
;
strcpy
(
qpti
->
prom_name
,
sdev
->
ofdev
.
node
->
name
);
qpti
->
is_pti
=
strcmp
(
qpti
->
prom_name
,
"QLGC,isp"
);
if
(
qpti_map_regs
(
qpti
)
<
0
)
goto
fail_unlink
;
if
(
qpti_register_irq
(
qpti
)
<
0
)
goto
fail_unmap_regs
;
qpti_get_scsi_id
(
qpti
);
qpti_get_bursts
(
qpti
);
qpti_get_clock
(
qpti
);
/* Clear out scsi_cmnd array. */
memset
(
qpti
->
cmd_slots
,
0
,
sizeof
(
qpti
->
cmd_slots
));
if
(
qpti_map_queues
(
qpti
)
<
0
)
goto
fail_free_irq
;
/* Load the firmware. */
if
(
qlogicpti_load_firmware
(
qpti
))
goto
fail_unmap_queues
;
if
(
qpti
->
is_pti
)
{
/* Check the PTI status reg. */
if
(
qlogicpti_verify_tmon
(
qpti
))
goto
fail_unmap_queues
;
}
/* Reset the ISP and init res/req queues. */
if
(
qlogicpti_reset_hardware
(
host
))
goto
fail_unmap_queues
;
if
(
scsi_add_host
(
host
,
&
dev
->
dev
))
goto
fail_unmap_queues
;
printk
(
"(Firmware v%d.%d.%d)"
,
qpti
->
fware_majrev
,
qpti
->
fware_minrev
,
qpti
->
fware_micrev
);
fcode
=
of_get_property
(
dp
,
"isp-fcode"
,
NULL
);
if
(
fcode
&&
fcode
[
0
])
printk
(
"(Firmware %s)"
,
fcode
);
if
(
of_find_property
(
dp
,
"differential"
,
NULL
)
!=
NULL
)
qpti
->
differential
=
1
;
printk
(
" [%s Wide, using %s interface]
\n
"
,
(
qpti
->
ultra
?
"Ultra"
:
"Fast"
),
(
qpti
->
differential
?
"differential"
:
"single ended"
));
dev_set_drvdata
(
&
sdev
->
ofdev
.
dev
,
qpti
);
qpti_chain_add
(
qpti
);
scsi_scan_host
(
host
);
nqptis
++
;
return
0
;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
RES_QUEUE_LEN
),
qpti
->
res_cpu
,
qpti
->
res_dvma
);
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
QLOGICPTI_REQ_QUEUE_LEN
),
qpti
->
req_cpu
,
qpti
->
req_dvma
);
#undef QSIZE
fail_unmap_regs:
sbus_iounmap
(
qpti
->
qregs
,
qpti
->
sdev
->
reg_addrs
[
0
].
reg_size
);
if
(
qpti
->
is_pti
)
sbus_iounmap
(
qpti
->
sreg
,
sizeof
(
unsigned
char
));
fail_free_irq:
free_irq
(
qpti
->
irq
,
qpti
);
fail_unlink:
scsi_host_put
(
host
);
return
-
ENODEV
;
}
static
int
__devexit
qpti_sbus_remove
(
struct
of_device
*
dev
)
{
struct
qlogicpti
*
qpti
=
dev_get_drvdata
(
&
dev
->
dev
);
qpti_chain_del
(
qpti
);
scsi_remove_host
(
qpti
->
qhost
);
/* Shut up the card. */
sbus_writew
(
0
,
qpti
->
qregs
+
SBUS_CTRL
);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq
(
qpti
->
irq
,
qpti
);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
RES_QUEUE_LEN
),
qpti
->
res_cpu
,
qpti
->
res_dvma
);
sbus_free_consistent
(
qpti
->
sdev
,
QSIZE
(
QLOGICPTI_REQ_QUEUE_LEN
),
qpti
->
req_cpu
,
qpti
->
req_dvma
);
#undef QSIZE
sbus_iounmap
(
qpti
->
qregs
,
qpti
->
sdev
->
reg_addrs
[
0
].
reg_size
);
if
(
qpti
->
is_pti
)
sbus_iounmap
(
qpti
->
sreg
,
sizeof
(
unsigned
char
));
scsi_host_put
(
qpti
->
qhost
);
return
0
;
}
static
struct
of_device_id
qpti_match
[]
=
{
{
.
name
=
"ptisp"
,
.
data
=
&
qpti_template
,
},
{
.
name
=
"PTI,ptisp"
,
.
data
=
&
qpti_template
,
},
{
.
name
=
"QLGC,isp"
,
.
data
=
&
qpti_template
,
},
{
.
name
=
"SUNW,isp"
,
.
data
=
&
qpti_template
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
qpti_match
);
static
struct
of_platform_driver
qpti_sbus_driver
=
{
.
name
=
"qpti"
,
.
match_table
=
qpti_match
,
.
probe
=
qpti_sbus_probe
,
.
remove
=
__devexit_p
(
qpti_sbus_remove
),
};
#include "scsi_module.c"
static
int
__init
qpti_init
(
void
)
{
return
of_register_driver
(
&
qpti_sbus_driver
,
&
sbus_bus_type
);
}
static
void
__exit
qpti_exit
(
void
)
{
of_unregister_driver
(
&
qpti_sbus_driver
);
}
MODULE_DESCRIPTION
(
"QlogicISP SBUS driver"
);
MODULE_AUTHOR
(
"David S. Miller (davem@davemloft.net)"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
"2.0"
);
module_init
(
qpti_init
);
module_exit
(
qpti_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment