mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
adv_pci.c:
adw_pci.c: Update comments describing supported chips/cards. adwcam.c: adwlib.c: adwlib.h: Handle more error return codes from the firmware. Break out the bus reset code into its own function. Usa a constant for the bus reset hold delay. Fix an interrupt race problem in adw_idle_cmd_send by incorporating the poll loop for command completion. Approved by: jkh@FreeBSDorg
This commit is contained in:
parent
1285d5557c
commit
58d246367e
5 changed files with 115 additions and 99 deletions
|
|
@ -12,20 +12,21 @@
|
|||
* ABP930 - Bus-Master PCI (16 CDB) *
|
||||
* ABP930U - Bus-Master PCI Ultra (16 CDB)
|
||||
* ABP930UA - Bus-Master PCI Ultra (16 CDB)
|
||||
* ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
|
||||
* ABP960 - Bus-Master PCI MAC/PC (16 CDB) **
|
||||
* ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
|
||||
* ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
|
||||
* ABP3960UA - Bus-Master PCI MAC/PC (240 CDB)
|
||||
* ABP960U - Bus-Master PCI MAC/PC (16 CDB) **
|
||||
*
|
||||
* Single Channel Products:
|
||||
* ABP940 - Bus-Master PCI (240 CDB)
|
||||
* ABP940U - Bus-Master PCI Ultra (240 CDB)
|
||||
* ABP970 - Bus-Master PCI MAC/PC (240 CDB)
|
||||
* ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
|
||||
* ABP940 - Bus-Master PCI (240 CDB)
|
||||
* ABP940U - Bus-Master PCI Ultra (240 CDB)
|
||||
* ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
|
||||
* ABP3960UA - Bus-Master PCI MAC/PC (240 CDB)
|
||||
* ABP970 - Bus-Master PCI MAC/PC (240 CDB)
|
||||
* ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
|
||||
*
|
||||
* Dual Channel Products:
|
||||
* ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
|
||||
* ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
|
||||
* ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
|
||||
* ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
|
||||
*
|
||||
* Footnotes:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
*
|
||||
* ABP[3]940UW - Bus-Master PCI Ultra-Wide (253 CDB)
|
||||
* ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB/Channel)
|
||||
* ABP970UW - Bus-Master PCI Ultra-Wide (253 CDB)
|
||||
* ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
|
||||
* ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
|
||||
*
|
||||
* Copyright (c) 1998, 1999, 2000 Justin Gibbs.
|
||||
* All rights reserved.
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
|
||||
u_long adw_unit;
|
||||
|
||||
static __inline cam_status adwccbstatus(union ccb*);
|
||||
static __inline struct acb* adwgetacb(struct adw_softc *adw);
|
||||
static __inline void adwfreeacb(struct adw_softc *adw,
|
||||
struct acb *acb);
|
||||
|
|
@ -101,6 +102,12 @@ static void adw_handle_device_reset(struct adw_softc *adw,
|
|||
static void adw_handle_bus_reset(struct adw_softc *adw,
|
||||
int initiated);
|
||||
|
||||
static __inline cam_status
|
||||
adwccbstatus(union ccb* ccb)
|
||||
{
|
||||
return (ccb->ccb_h.status & CAM_STATUS_MASK);
|
||||
}
|
||||
|
||||
static __inline struct acb*
|
||||
adwgetacb(struct adw_softc *adw)
|
||||
{
|
||||
|
|
@ -324,7 +331,7 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
|||
splx(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
acb->state |= ACB_ACTIVE;
|
||||
ccb->ccb_h.status |= CAM_SIM_QUEUED;
|
||||
LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
|
||||
|
|
@ -393,7 +400,7 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
|
|||
if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
|
||||
switch (csio->tag_action) {
|
||||
case MSG_SIMPLE_Q_TAG:
|
||||
acb->queue.scsi_cntl = 0;
|
||||
acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
|
||||
break;
|
||||
case MSG_HEAD_OF_Q_TAG:
|
||||
acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
|
||||
|
|
@ -401,6 +408,9 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
|
|||
case MSG_ORDERED_Q_TAG:
|
||||
acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
|
||||
break;
|
||||
default:
|
||||
acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
|
||||
|
|
@ -498,9 +508,8 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
|
|||
{
|
||||
adw_idle_cmd_status_t status;
|
||||
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
|
||||
ccb->ccb_h.target_id);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
|
||||
ccb->ccb_h.target_id);
|
||||
if (status == ADW_IDLE_CMD_SUCCESS) {
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
if (bootverbose) {
|
||||
|
|
@ -748,28 +757,17 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
|
|||
}
|
||||
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
|
||||
{
|
||||
adw_idle_cmd_status_t status;
|
||||
int failure;
|
||||
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
|
||||
/*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS) {
|
||||
failure = adw_reset_bus(adw);
|
||||
if (failure != 0) {
|
||||
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
DELAY(100);
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS) {
|
||||
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
}
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
if (bootverbose) {
|
||||
xpt_print_path(adw->path);
|
||||
printf("Bus Reset Delivered\n");
|
||||
} else {
|
||||
if (bootverbose) {
|
||||
xpt_print_path(adw->path);
|
||||
printf("Bus Reset Delivered\n");
|
||||
}
|
||||
ccb->ccb_h.status = CAM_REQ_CMP;
|
||||
}
|
||||
xpt_done(ccb);
|
||||
break;
|
||||
|
|
@ -1385,8 +1383,16 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
|
|||
case QHSTA_M_UNEXPECTED_BUS_FREE:
|
||||
ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
|
||||
break;
|
||||
case QHSTA_M_SCSI_BUS_RESET:
|
||||
case QHSTA_M_SCSI_BUS_RESET_UNSOL:
|
||||
ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
|
||||
break;
|
||||
case QHSTA_M_BUS_DEVICE_RESET:
|
||||
ccb->ccb_h.status = CAM_BDR_SENT;
|
||||
break;
|
||||
case QHSTA_M_QUEUE_ABORTED:
|
||||
/* BDR or Bus Reset */
|
||||
printf("Saw Queue Aborted\n");
|
||||
ccb->ccb_h.status = adw->last_reset;
|
||||
break;
|
||||
case QHSTA_M_SXFR_SDMA_ERR:
|
||||
|
|
@ -1397,23 +1403,10 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
|
|||
case QHSTA_M_WTM_TIMEOUT:
|
||||
case QHSTA_M_SXFR_WD_TMO:
|
||||
{
|
||||
adw_idle_cmd_status_t status;
|
||||
|
||||
/* The SCSI bus hung in a phase */
|
||||
ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
|
||||
/*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS)
|
||||
panic("%s: Bus Reset during WD timeout failed",
|
||||
adw_name(adw));
|
||||
DELAY(100);
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END,
|
||||
/*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS)
|
||||
panic("%s: Bus Reset during WD timeout failed",
|
||||
adw_name(adw));
|
||||
xpt_print_path(adw->path);
|
||||
printf("Watch Dog timer expired. Reseting bus\n");
|
||||
adw_reset_bus(adw);
|
||||
break;
|
||||
}
|
||||
case QHSTA_M_SXFR_XFR_PH_ERR:
|
||||
|
|
@ -1445,6 +1438,11 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
|
|||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
if ((acb->state & ACB_RECOVERY_ACB) != 0) {
|
||||
if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
|
||||
|| ccb->ccb_h.status == CAM_BDR_SENT)
|
||||
ccb->ccb_h.status = CAM_CMD_TIMEOUT;
|
||||
}
|
||||
if (ccb->ccb_h.status != CAM_REQ_CMP) {
|
||||
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
|
||||
ccb->ccb_h.status |= CAM_DEV_QFRZN;
|
||||
|
|
@ -1460,6 +1458,7 @@ adwtimeout(void *arg)
|
|||
union ccb *ccb;
|
||||
struct adw_softc *adw;
|
||||
adw_idle_cmd_status_t status;
|
||||
int target_id;
|
||||
int s;
|
||||
|
||||
acb = (struct acb *)arg;
|
||||
|
|
@ -1478,29 +1477,21 @@ adwtimeout(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
acb->state |= ACB_RECOVERY_ACB;
|
||||
target_id = ccb->ccb_h.target_id;
|
||||
|
||||
/* Attempt a BDR first */
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
|
||||
ccb->ccb_h.target_id);
|
||||
status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
|
||||
ccb->ccb_h.target_id);
|
||||
splx(s);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status == ADW_IDLE_CMD_SUCCESS) {
|
||||
printf("%s: BDR Delivered. No longer in timeout\n",
|
||||
adw_name(adw));
|
||||
adw_handle_device_reset(adw, ccb->ccb_h.target_id);
|
||||
adw_handle_device_reset(adw, target_id);
|
||||
} else {
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
|
||||
/*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS)
|
||||
panic("%s: Bus Reset during timeout failed",
|
||||
adw_name(adw));
|
||||
DELAY(100);
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END,
|
||||
/*param*/0);
|
||||
status = adw_idle_cmd_wait(adw);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS)
|
||||
panic("%s: Bus Reset during timeout failed",
|
||||
adw_name(adw));
|
||||
adw_reset_bus(adw);
|
||||
xpt_print_path(adw->path);
|
||||
printf("Bus Reset Delivered. No longer in timeout\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -189,6 +189,32 @@ adw_reset_chip(struct adw_softc *adw)
|
|||
adw_inw(adw, ADW_SCSI_CFG1) & ~ADW_SCSI_CFG1_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the SCSI bus.
|
||||
*/
|
||||
int
|
||||
adw_reset_bus(struct adw_softc *adw)
|
||||
{
|
||||
adw_idle_cmd_status_t status;
|
||||
|
||||
status =
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START, /*param*/0);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS) {
|
||||
xpt_print_path(adw->path);
|
||||
printf("Bus Reset start attempt failed\n");
|
||||
return (1);
|
||||
}
|
||||
DELAY(ADW_BUS_RESET_HOLD_DELAY_US);
|
||||
status =
|
||||
adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0);
|
||||
if (status != ADW_IDLE_CMD_SUCCESS) {
|
||||
xpt_print_path(adw->path);
|
||||
printf("Bus Reset end attempt failed\n");
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the specified EEPROM location
|
||||
*/
|
||||
|
|
@ -818,22 +844,22 @@ adw_hshk_cfg_period_factor(u_int tinfo)
|
|||
}
|
||||
|
||||
/*
|
||||
* Send an idle command to the chip and optionally wait for completion.
|
||||
* Send an idle command to the chip and wait for completion.
|
||||
*/
|
||||
void
|
||||
adw_idle_cmd_status_t
|
||||
adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
|
||||
{
|
||||
int s;
|
||||
|
||||
adw->idle_command_cmp = 0;
|
||||
u_int timeout;
|
||||
adw_idle_cmd_status_t status;
|
||||
int s;
|
||||
|
||||
s = splcam();
|
||||
|
||||
if (adw->idle_cmd != ADW_IDLE_CMD_COMPLETED)
|
||||
printf("%s: Warning! Overlapped Idle Commands Attempted\n",
|
||||
adw_name(adw));
|
||||
adw->idle_cmd = cmd;
|
||||
adw->idle_cmd_param = parameter;
|
||||
/*
|
||||
* Clear the idle command status which is set by the microcode
|
||||
* to a non-zero value to indicate when the command is completed.
|
||||
*/
|
||||
adw_lram_write_16(adw, ADW_MC_IDLE_CMD_STATUS, 0);
|
||||
|
||||
/*
|
||||
* Write the idle command value after the idle command parameter
|
||||
|
|
@ -841,37 +867,25 @@ adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
|
|||
* followed, the microcode may process the idle command before the
|
||||
* parameters have been written to LRAM.
|
||||
*/
|
||||
adw_lram_write_16(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter);
|
||||
adw_lram_write_32(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter);
|
||||
adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd);
|
||||
|
||||
/*
|
||||
* Tickle the RISC to tell it to process the idle command.
|
||||
*/
|
||||
adw_tickle_risc(adw, ADW_TICKLE_B);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/* Wait for an idle command to complete */
|
||||
adw_idle_cmd_status_t
|
||||
adw_idle_cmd_wait(struct adw_softc *adw)
|
||||
{
|
||||
u_int timeout;
|
||||
adw_idle_cmd_status_t status;
|
||||
int s;
|
||||
|
||||
/* Wait for up to 10 seconds for the command to complete */
|
||||
timeout = 10000;
|
||||
timeout = 5000000;
|
||||
while (--timeout) {
|
||||
s = splcam();
|
||||
status = adw_lram_read_16(adw, ADW_MC_IDLE_CMD_STATUS);
|
||||
splx(s);
|
||||
if (status != 0)
|
||||
break;
|
||||
DELAY(1000);
|
||||
DELAY(20);
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
panic("%s: Idle Command Timed Out!\n", adw_name(adw));
|
||||
adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;
|
||||
splx(s);
|
||||
return (status);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -342,11 +342,18 @@ typedef enum {
|
|||
QHSTA_M_SXFR_DESELECTED = 0x22, /* Deselected */
|
||||
QHSTA_M_SXFR_XFR_PH_ERR = 0x24, /* Transfer Phase Error */
|
||||
QHSTA_M_SXFR_UNKNOWN_ERROR = 0x25, /* SXFR_STATUS Unknown Error */
|
||||
QHSTA_M_SCSI_BUS_RESET = 0x30, /* Request aborted from SBR */
|
||||
QHSTA_M_SCSI_BUS_RESET_UNSOL= 0x31, /* Request aborted from unsol. SBR*/
|
||||
QHSTA_M_BUS_DEVICE_RESET = 0x32, /* Request aborted from BDR */
|
||||
QHSTA_M_DIRECTION_ERR = 0x35, /* Data Phase mismatch */
|
||||
QHSTA_M_DIRECTION_ERR_HUNG = 0x36, /* Data Phase mismatch - bus hang */
|
||||
QHSTA_M_WTM_TIMEOUT = 0x41,
|
||||
QHSTA_M_BAD_CMPL_STATUS_IN = 0x42,
|
||||
QHSTA_M_NO_AUTO_REQ_SENSE = 0x43,
|
||||
QHSTA_M_AUTO_REQ_SENSE_FAIL = 0x44,
|
||||
QHSTA_M_INVALID_DEVICE = 0x45 /* Bad target ID */
|
||||
QHSTA_M_INVALID_DEVICE = 0x45, /* Bad target ID */
|
||||
QHSTA_M_FROZEN_TIDQ = 0x46, /* TID Queue frozen. */
|
||||
QHSTA_M_SGBACKUP_ERROR = 0x47 /* Scatter-Gather backup error */
|
||||
} host_status_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -380,6 +387,7 @@ struct adw_scsi_req_q {
|
|||
#define ADW_QSC_NO_SYNC 0x04
|
||||
#define ADW_QSC_NO_WIDE 0x08
|
||||
#define ADW_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR */
|
||||
#define ADW_QSC_SIMPLE_Q_TAG 0x00
|
||||
#define ADW_QSC_HEAD_OF_Q_TAG 0x40
|
||||
#define ADW_QSC_ORDERED_Q_TAG 0x80
|
||||
u_int8_t done_status; /* Completion status. */
|
||||
|
|
@ -405,7 +413,8 @@ struct adw_scsi_req_q {
|
|||
typedef enum {
|
||||
ACB_FREE = 0x00,
|
||||
ACB_ACTIVE = 0x01,
|
||||
ACB_RELEASE_SIMQ = 0x02
|
||||
ACB_RELEASE_SIMQ = 0x02,
|
||||
ACB_RECOVERY_ACB = 0x04
|
||||
} acb_state;
|
||||
|
||||
struct acb {
|
||||
|
|
@ -542,6 +551,8 @@ struct adw_eeprom
|
|||
#define ADW_EEP_DVC_CTL_BEGIN (offsetof(struct adw_eeprom, oem_name)/2)
|
||||
#define ADW_EEP_MAX_WORD_ADDR (sizeof(struct adw_eeprom)/2)
|
||||
|
||||
#define ADW_BUS_RESET_HOLD_DELAY_US 100
|
||||
|
||||
typedef enum {
|
||||
ADW_CHIP_NONE,
|
||||
ADW_CHIP_ASC3550, /* Ultra-Wide IC */
|
||||
|
|
@ -636,9 +647,6 @@ struct adw_softc
|
|||
char* name;
|
||||
cam_status last_reset; /* Last reset type */
|
||||
u_int16_t bios_ctrl;
|
||||
adw_idle_cmd_t idle_cmd;
|
||||
u_int idle_cmd_param;
|
||||
volatile int idle_command_cmp;
|
||||
u_int16_t user_wdtr;
|
||||
u_int16_t user_sdtr[4]; /* A nibble per-device */
|
||||
u_int16_t user_tagenb;
|
||||
|
|
@ -806,6 +814,7 @@ carrierbtov(struct adw_softc *adw, u_int32_t baddr)
|
|||
/* Intialization */
|
||||
int adw_find_signature(struct adw_softc *adw);
|
||||
void adw_reset_chip(struct adw_softc *adw);
|
||||
int adw_reset_bus(struct adw_softc *adw);
|
||||
u_int16_t adw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *buf);
|
||||
void adw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *buf);
|
||||
int adw_init_chip(struct adw_softc *adw, u_int term_scsicfg1);
|
||||
|
|
@ -819,9 +828,8 @@ u_int adw_find_period(struct adw_softc *adw, u_int mc_sdtr);
|
|||
u_int adw_hshk_cfg_period_factor(u_int tinfo);
|
||||
|
||||
/* Idle Commands */
|
||||
void adw_idle_cmd_send(struct adw_softc *adw, u_int cmd,
|
||||
adw_idle_cmd_status_t adw_idle_cmd_send(struct adw_softc *adw, u_int cmd,
|
||||
u_int parameter);
|
||||
adw_idle_cmd_status_t adw_idle_cmd_wait(struct adw_softc *adw);
|
||||
|
||||
/* SCSI Transaction Processing */
|
||||
static __inline void adw_send_acb(struct adw_softc *adw, struct acb *acb,
|
||||
|
|
|
|||
Loading…
Reference in a new issue