summaryrefslogtreecommitdiff
path: root/sys/dev/advansys/adwcam.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/advansys/adwcam.c')
-rw-r--r--sys/dev/advansys/adwcam.c565
1 files changed, 373 insertions, 192 deletions
diff --git a/sys/dev/advansys/adwcam.c b/sys/dev/advansys/adwcam.c
index b30f16c8e933..b64a60a94db6 100644
--- a/sys/dev/advansys/adwcam.c
+++ b/sys/dev/advansys/adwcam.c
@@ -4,9 +4,9 @@
*
* Product specific probe and attach routines can be found in:
*
- * pci/adw_pci.c ABP940UW
+ * adw_pci.c ABP[3]940UW, ABP950UW, ABP3940U2W
*
- * Copyright (c) 1998 Justin Gibbs.
+ * Copyright (c) 1998, 1999, 2000 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
- * without modification, immediately at the beginning of the file.
+ * without modification.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -50,11 +50,15 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
+#include <sys/bus.h>
#include <machine/bus_pio.h>
#include <machine/bus_memio.h>
#include <machine/bus.h>
#include <machine/clock.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@@ -74,10 +78,6 @@
u_long adw_unit;
-static __inline u_int32_t acbvtop(struct adw_softc *adw,
- struct acb *acb);
-static __inline struct acb * acbptov(struct adw_softc *adw,
- u_int32_t busaddr);
static __inline struct acb* adwgetacb(struct adw_softc *adw);
static __inline void adwfreeacb(struct adw_softc *adw,
struct acb *acb);
@@ -101,20 +101,6 @@ static void adw_handle_device_reset(struct adw_softc *adw,
static void adw_handle_bus_reset(struct adw_softc *adw,
int initiated);
-static __inline u_int32_t
-acbvtop(struct adw_softc *adw, struct acb *acb)
-{
- return (adw->acb_busbase
- + (u_int32_t)((caddr_t)acb - (caddr_t)adw->acbs));
-}
-
-static __inline struct acb *
-acbptov(struct adw_softc *adw, u_int32_t busaddr)
-{
- return (adw->acbs
- + ((struct acb *)busaddr - (struct acb *)adw->acb_busbase));
-}
-
static __inline struct acb*
adwgetacb(struct adw_softc *adw)
{
@@ -208,7 +194,6 @@ adwallocacbs(struct adw_softc *adw)
int i;
next_acb = &adw->acbs[adw->num_acbs];
-
sg_map = adwallocsgmap(adw);
if (sg_map == NULL)
@@ -220,22 +205,17 @@ adwallocacbs(struct adw_softc *adw)
newcount = (PAGE_SIZE / (ADW_SG_BLOCKCNT * sizeof(*blocks)));
for (i = 0; adw->num_acbs < adw->max_acbs && i < newcount; i++) {
int error;
- int j;
error = bus_dmamap_create(adw->buffer_dmat, /*flags*/0,
&next_acb->dmamap);
if (error != 0)
break;
- next_acb->queue.scsi_req_baddr = acbvtop(adw, next_acb);
- next_acb->queue.sense_addr =
- acbvtop(adw, next_acb) + offsetof(struct acb, sense_data);
+ next_acb->queue.scsi_req_baddr = acbvtob(adw, next_acb);
+ next_acb->queue.scsi_req_bo = acbvtobo(adw, next_acb);
+ next_acb->queue.sense_baddr =
+ acbvtob(adw, next_acb) + offsetof(struct acb, sense_data);
next_acb->sg_blocks = blocks;
next_acb->sg_busaddr = busaddr;
- /* Setup static data in the sg blocks */
- for (j = 0; j < ADW_SG_BLOCKCNT; j++) {
- next_acb->sg_blocks[j].first_entry_no =
- j * ADW_NO_OF_SG_PER_BLOCK;
- }
next_acb->state = ACB_FREE;
SLIST_INSERT_HEAD(&adw->free_acb_list, next_acb, links);
blocks += ADW_SG_BLOCKCNT;
@@ -289,19 +269,20 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
sg_index = 0;
/* Copy the segments into our SG list */
for (sg_block = acb->sg_blocks;; sg_block++) {
- u_int sg_left;
+ u_int i;
- sg_left = ADW_NO_OF_SG_PER_BLOCK;
sg = sg_block->sg_list;
- while (dm_segs < end_seg && sg_left != 0) {
+ for (i = 0; i < ADW_NO_OF_SG_PER_BLOCK; i++) {
+ if (dm_segs >= end_seg)
+ break;
+
sg->sg_addr = dm_segs->ds_addr;
sg->sg_count = dm_segs->ds_len;
sg++;
dm_segs++;
- sg_left--;
}
- sg_index += ADW_NO_OF_SG_PER_BLOCK - sg_left;
- sg_block->last_entry_no = sg_index - 1;
+ sg_block->sg_cnt = i;
+ sg_index += i;
if (dm_segs == end_seg) {
sg_block->sg_busaddr_next = 0;
break;
@@ -311,11 +292,8 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
sg_block->sg_busaddr_next = sg_busaddr;
}
}
-
- acb->queue.sg_entry_cnt = nseg;
acb->queue.sg_real_addr = acb->sg_busaddr;
} else {
- acb->queue.sg_entry_cnt = 0;
acb->queue.sg_real_addr = 0;
}
@@ -327,13 +305,10 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
bus_dmamap_sync(adw->buffer_dmat, acb->dmamap, op);
} else {
- acb->queue.sg_entry_cnt = 0;
acb->queue.data_addr = 0;
acb->queue.data_cnt = 0;
acb->queue.sg_real_addr = 0;
}
- acb->queue.free_scsiq_link = 0;
- acb->queue.ux_wk_data_cnt = 0;
s = splcam();
@@ -357,7 +332,7 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
timeout(adwtimeout, (caddr_t)acb,
(ccb->ccb_h.timeout * hz) / 1000);
- adw_send_acb(adw, acb, acbvtop(adw, acb));
+ adw_send_acb(adw, acb, acbvtob(adw, acb));
splx(s);
}
@@ -381,6 +356,7 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
csio = &ccb->csio;
ccbh = &ccb->ccb_h;
+
/* Max supported CDB length is 12 bytes */
if (csio->cdb_len > 12) {
ccb->ccb_h.status = CAM_REQ_INVALID;
@@ -400,31 +376,42 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
return;
}
- /* Link dccb and ccb so we can find one from the other */
+ /* Link acb and ccb so we can find one from the other */
acb->ccb = ccb;
ccb->ccb_h.ccb_acb_ptr = acb;
ccb->ccb_h.ccb_adw_ptr = adw;
acb->queue.cntl = 0;
+ acb->queue.target_cmd = 0;
acb->queue.target_id = ccb->ccb_h.target_id;
acb->queue.target_lun = ccb->ccb_h.target_lun;
- acb->queue.srb_ptr = 0;
- acb->queue.a_flag = 0;
+ acb->queue.mflag = 0;
acb->queue.sense_len =
MIN(csio->sense_len, sizeof(acb->sense_data));
acb->queue.cdb_len = csio->cdb_len;
+ if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
+ switch (csio->tag_action) {
+ case MSG_SIMPLE_Q_TAG:
+ acb->queue.scsi_cntl = 0;
+ break;
+ case MSG_HEAD_OF_Q_TAG:
+ acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
+ break;
+ case MSG_ORDERED_Q_TAG:
+ acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
+ break;
+ }
+ } else
+ acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
- if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
- acb->queue.tag_code = csio->tag_action;
- else
- acb->queue.tag_code = 0;
+ if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
+ acb->queue.scsi_cntl |= ADW_QSC_NO_DISC;
acb->queue.done_status = 0;
acb->queue.scsi_status = 0;
acb->queue.host_status = 0;
- acb->queue.ux_sg_ix = 0;
-
+ acb->queue.sg_wk_ix = 0;
if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
bcopy(csio->cdb_io.cdb_ptr,
@@ -541,6 +528,9 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
s = splcam();
if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
+ u_int sdtrdone;
+
+ sdtrdone = adw_lram_read_16(adw, ADW_MC_SDTR_DONE);
if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
u_int discenb;
@@ -592,58 +582,57 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
adw_lram_write_16(adw,
ADW_MC_WDTR_DONE,
wdtrdone);
+ /* Wide negotiation forces async */
+ sdtrdone &= ~target_mask;
+ adw_lram_write_16(adw,
+ ADW_MC_SDTR_DONE,
+ sdtrdone);
}
}
if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
|| ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
- u_int sdtrenb_orig;
- u_int sdtrenb;
- u_int ultraenb_orig;
- u_int ultraenb;
- u_int sdtrdone;
-
- sdtrenb_orig =
- adw_lram_read_16(adw, ADW_MC_SDTR_ABLE);
- sdtrenb = sdtrenb_orig;
-
- ultraenb_orig =
- adw_lram_read_16(adw, ADW_MC_ULTRA_ABLE);
- ultraenb = ultraenb_orig;
-
- sdtrdone = adw_lram_read_16(adw,
- ADW_MC_SDTR_DONE);
+ u_int sdtr_orig;
+ u_int sdtr;
+ u_int sdtrable_orig;
+ u_int sdtrable;
+
+ sdtr = adw_get_chip_sdtr(adw,
+ ccb->ccb_h.target_id);
+ sdtr_orig = sdtr;
+ sdtrable = adw_lram_read_16(adw,
+ ADW_MC_SDTR_ABLE);
+ sdtrable_orig = sdtrable;
if ((cts->valid
& CCB_TRANS_SYNC_RATE_VALID) != 0) {
- if (cts->sync_period == 0) {
- sdtrenb &= ~target_mask;
- } else if (cts->sync_period > 12) {
- ultraenb &= ~target_mask;
- sdtrenb |= target_mask;
- } else {
- ultraenb |= target_mask;
- sdtrenb |= target_mask;
- }
+ sdtr =
+ adw_find_sdtr(adw,
+ cts->sync_period);
}
if ((cts->valid
& CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
if (cts->sync_offset == 0)
- sdtrenb &= ~target_mask;
+ sdtr = ADW_MC_SDTR_ASYNC;
}
- if (sdtrenb != sdtrenb_orig
- || ultraenb != ultraenb_orig) {
- adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
- sdtrenb);
- adw_lram_write_16(adw,
- ADW_MC_ULTRA_ABLE,
- ultraenb);
+ if (sdtr == ADW_MC_SDTR_ASYNC)
+ sdtrable &= ~target_mask;
+ else
+ sdtrable |= target_mask;
+ if (sdtr != sdtr_orig
+ || sdtrable != sdtrable_orig) {
+ adw_set_chip_sdtr(adw,
+ ccb->ccb_h.target_id,
+ sdtr);
sdtrdone &= ~target_mask;
+ adw_lram_write_16(adw, ADW_MC_SDTR_ABLE,
+ sdtrable);
adw_lram_write_16(adw, ADW_MC_SDTR_DONE,
sdtrdone);
+
}
}
}
@@ -661,6 +650,8 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
cts = &ccb->cts;
target_mask = 0x01 << ccb->ccb_h.target_id;
if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
+ u_int mc_sdtr;
+
cts->flags = 0;
if ((adw->user_discenb & target_mask) != 0)
cts->flags |= CCB_TRANS_DISC_ENB;
@@ -673,13 +664,12 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
else
cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
- if ((adw->user_sdtr & target_mask) != 0) {
- if ((adw->user_ultra & target_mask) != 0)
- cts->sync_period = 12; /* 20MHz */
- else
- cts->sync_period = 25; /* 10MHz */
+ mc_sdtr = adw_get_user_sdtr(adw, ccb->ccb_h.target_id);
+ cts->sync_period = adw_find_period(adw, mc_sdtr);
+ if (cts->sync_period != 0)
cts->sync_offset = 15; /* XXX ??? */
- }
+ else
+ cts->sync_offset = 0;
cts->valid = CCB_TRANS_SYNC_RATE_VALID
| CCB_TRANS_SYNC_OFFSET_VALID
@@ -709,7 +699,7 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
cts->sync_period =
- ADW_HSHK_CFG_PERIOD_FACTOR(targ_tinfo);
+ adw_hshk_cfg_period_factor(targ_tinfo);
cts->sync_offset = targ_tinfo & ADW_HSHK_CFG_OFFSET;
if (cts->sync_period == 0)
@@ -760,16 +750,27 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
{
adw_idle_cmd_status_t status;
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
+ 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) {
- ccb->ccb_h.status = CAM_REQ_CMP;
- if (bootverbose) {
- xpt_print_path(adw->path);
- printf("Bus Reset Delivered\n");
- }
- } else
+ if (status != ADW_IDLE_CMD_SUCCESS) {
+ 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");
+ }
xpt_done(ccb);
break;
}
@@ -819,7 +820,7 @@ adw_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
}
struct adw_softc *
-adw_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
+adw_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id)
{
struct adw_softc *adw;
int i;
@@ -829,19 +830,23 @@ adw_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
*/
adw = malloc(sizeof(struct adw_softc), M_DEVBUF, M_NOWAIT);
if (adw == NULL) {
- printf("adw%d: cannot malloc!\n", unit);
+ printf("adw%d: cannot malloc!\n", device_get_unit(dev));
return NULL;
}
bzero(adw, sizeof(struct adw_softc));
LIST_INIT(&adw->pending_ccbs);
SLIST_INIT(&adw->sg_maps);
- adw->unit = unit;
- adw->tag = tag;
- adw->bsh = bsh;
+ adw->device = dev;
+ adw->unit = device_get_unit(dev);
+ adw->regs_res_type = regs_type;
+ adw->regs_res_id = regs_id;
+ adw->regs = regs;
+ adw->tag = rman_get_bustag(regs);
+ adw->bsh = rman_get_bushandle(regs);
i = adw->unit / 10;
adw->name = malloc(sizeof("adw") + i + 1, M_DEVBUF, M_NOWAIT);
if (adw->name == NULL) {
- printf("adw%d: cannot malloc name!\n", unit);
+ printf("adw%d: cannot malloc name!\n", adw->unit);
free(adw, M_DEVBUF);
return NULL;
}
@@ -853,7 +858,7 @@ void
adw_free(struct adw_softc *adw)
{
switch (adw->init_level) {
- case 6:
+ case 9:
{
struct sg_map_node *sg_map;
@@ -867,14 +872,22 @@ adw_free(struct adw_softc *adw)
}
bus_dma_tag_destroy(adw->sg_dmat);
}
- case 5:
+ case 8:
bus_dmamap_unload(adw->acb_dmat, adw->acb_dmamap);
- case 4:
+ case 7:
bus_dmamem_free(adw->acb_dmat, adw->acbs,
adw->acb_dmamap);
bus_dmamap_destroy(adw->acb_dmat, adw->acb_dmamap);
- case 3:
+ case 6:
bus_dma_tag_destroy(adw->acb_dmat);
+ case 5:
+ bus_dmamap_unload(adw->carrier_dmat, adw->carrier_dmamap);
+ case 4:
+ bus_dmamem_free(adw->carrier_dmat, adw->carriers,
+ adw->carrier_dmamap);
+ bus_dmamap_destroy(adw->carrier_dmat, adw->carrier_dmamap);
+ case 3:
+ bus_dma_tag_destroy(adw->carrier_dmat);
case 2:
bus_dma_tag_destroy(adw->buffer_dmat);
case 1:
@@ -890,16 +903,18 @@ int
adw_init(struct adw_softc *adw)
{
struct adw_eeprom eep_config;
+ u_int tid;
+ u_int i;
u_int16_t checksum;
u_int16_t scsicfg1;
- adw_reset_chip(adw);
checksum = adw_eeprom_read(adw, &eep_config);
bcopy(eep_config.serial_number, adw->serial_number,
sizeof(adw->serial_number));
if (checksum != eep_config.checksum) {
u_int16_t serial_number[3];
+ adw->flags |= ADW_EEPROM_FAILED;
printf("%s: EEPROM checksum failed. Restoring Defaults\n",
adw_name(adw));
@@ -909,7 +924,7 @@ adw_init(struct adw_softc *adw)
* from EEPROM is correct even if the EEPROM checksum
* failed.
*/
- bcopy(&adw_default_eeprom, &eep_config, sizeof(eep_config));
+ bcopy(adw->default_eeprom, &eep_config, sizeof(eep_config));
bcopy(adw->serial_number, eep_config.serial_number,
sizeof(serial_number));
adw_eeprom_write(adw, &eep_config);
@@ -918,8 +933,46 @@ adw_init(struct adw_softc *adw)
/* Pull eeprom information into our softc. */
adw->bios_ctrl = eep_config.bios_ctrl;
adw->user_wdtr = eep_config.wdtr_able;
- adw->user_sdtr = eep_config.sdtr_able;
- adw->user_ultra = eep_config.ultra_able;
+ for (tid = 0; tid < ADW_MAX_TID; tid++) {
+ u_int mc_sdtr;
+ u_int16_t tid_mask;
+
+ tid_mask = 0x1 << tid;
+ if ((adw->features & ADW_ULTRA) != 0) {
+ /*
+ * Ultra chips store sdtr and ultraenb
+ * bits in their seeprom, so we must
+ * construct valid mc_sdtr entries for
+ * indirectly.
+ */
+ if (eep_config.sync1.sync_enable & tid_mask) {
+ if (eep_config.sync2.ultra_enable & tid_mask)
+ mc_sdtr = ADW_MC_SDTR_20;
+ else
+ mc_sdtr = ADW_MC_SDTR_10;
+ } else
+ mc_sdtr = ADW_MC_SDTR_ASYNC;
+ } else {
+ switch (ADW_TARGET_GROUP(tid)) {
+ case 3:
+ mc_sdtr = eep_config.sync4.sdtr4;
+ break;
+ case 2:
+ mc_sdtr = eep_config.sync3.sdtr3;
+ break;
+ case 1:
+ mc_sdtr = eep_config.sync2.sdtr2;
+ break;
+ default: /* Shut up compiler */
+ case 0:
+ mc_sdtr = eep_config.sync1.sdtr1;
+ break;
+ }
+ mc_sdtr >>= ADW_TARGET_GROUP_SHIFT(tid);
+ mc_sdtr &= 0xFF;
+ }
+ adw_set_user_sdtr(adw, tid, mc_sdtr);
+ }
adw->user_tagenb = eep_config.tagqng_able;
adw->user_discenb = eep_config.disc_enable;
adw->max_acbs = eep_config.max_host_qng;
@@ -936,15 +989,36 @@ adw_init(struct adw_softc *adw)
adw->max_acbs = ADW_DEF_MAX_HOST_QNG;
else
adw->max_acbs = ADW_DEF_MIN_HOST_QNG;
-
}
scsicfg1 = 0;
- switch (eep_config.termination) {
+ if ((adw->features & ADW_ULTRA2) != 0) {
+ switch (eep_config.termination_lvd) {
+ default:
+ printf("%s: Invalid EEPROM LVD Termination Settings.\n",
+ adw_name(adw));
+ printf("%s: Reverting to Automatic LVD Termination\n",
+ adw_name(adw));
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_AUTO:
+ break;
+ case ADW_EEPROM_TERM_BOTH_ON:
+ scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_LO;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_HIGH_ON:
+ scsicfg1 |= ADW2_SCSI_CFG1_TERM_LVD_HI;
+ /* FALLTHROUGH */
+ case ADW_EEPROM_TERM_OFF:
+ scsicfg1 |= ADW2_SCSI_CFG1_DIS_TERM_DRV;
+ break;
+ }
+ }
+
+ switch (eep_config.termination_se) {
default:
- printf("%s: Invalid EEPROM Termination Settings.\n",
+ printf("%s: Invalid SE EEPROM Termination Settings.\n",
adw_name(adw));
- printf("%s: Reverting to Automatic Termination\n",
+ printf("%s: Reverting to Automatic SE Termination\n",
adw_name(adw));
/* FALLTHROUGH */
case ADW_EEPROM_TERM_AUTO:
@@ -959,29 +1033,79 @@ adw_init(struct adw_softc *adw)
scsicfg1 |= ADW_SCSI_CFG1_TERM_CTL_MANUAL;
break;
}
-
printf("%s: SCSI ID %d, ", adw_name(adw), adw->initiator_id);
- if (adw_init_chip(adw, scsicfg1) != 0)
- return (-1);
-
- printf("Queue Depth %d\n", adw->max_acbs);
-
/* DMA tag for mapping buffers into device visible space. */
if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/1, /*boundary*/0,
- /*lowaddr*/BUS_SPACE_MAXADDR,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*highaddr*/BUS_SPACE_MAXADDR,
/*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/MAXBSIZE, /*nsegments*/ADW_SGSIZE,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/BUS_DMA_ALLOCNOW,
&adw->buffer_dmat) != 0) {
- return (-1);
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* DMA tag for our ccb carrier structures */
+ if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/0x10,
+ /*boundary*/0,
+ /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+ /*highaddr*/BUS_SPACE_MAXADDR,
+ /*filter*/NULL, /*filterarg*/NULL,
+ (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
+ * sizeof(struct adw_carrier),
+ /*nsegments*/1,
+ /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+ /*flags*/0, &adw->carrier_dmat) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* Allocation for our ccb carrier structures */
+ if (bus_dmamem_alloc(adw->carrier_dmat, (void **)&adw->carriers,
+ BUS_DMA_NOWAIT, &adw->carrier_dmamap) != 0) {
+ return (ENOMEM);
+ }
+
+ adw->init_level++;
+
+ /* And permanently map them */
+ bus_dmamap_load(adw->carrier_dmat, adw->carrier_dmamap,
+ adw->carriers,
+ (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
+ * sizeof(struct adw_carrier),
+ adwmapmem, &adw->carrier_busbase, /*flags*/0);
+
+ /* Clear them out. */
+ bzero(adw->carriers, (adw->max_acbs + ADW_NUM_CARRIER_QUEUES + 1)
+ * sizeof(struct adw_carrier));
+
+ /* Setup our free carrier list */
+ adw->free_carriers = adw->carriers;
+ for (i = 0; i < adw->max_acbs + ADW_NUM_CARRIER_QUEUES; i++) {
+ adw->carriers[i].carr_offset =
+ carriervtobo(adw, &adw->carriers[i]);
+ adw->carriers[i].carr_ba =
+ carriervtob(adw, &adw->carriers[i]);
+ adw->carriers[i].areq_ba = 0;
+ adw->carriers[i].next_ba =
+ carriervtobo(adw, &adw->carriers[i+1]);
}
+ /* Terminal carrier. Never leaves the freelist */
+ adw->carriers[i].carr_offset =
+ carriervtobo(adw, &adw->carriers[i]);
+ adw->carriers[i].carr_ba =
+ carriervtob(adw, &adw->carriers[i]);
+ adw->carriers[i].areq_ba = 0;
+ adw->carriers[i].next_ba = ~0;
adw->init_level++;
- /* DMA tag for our ccb structures */
+ /* DMA tag for our acb structures */
if (bus_dma_tag_create(adw->parent_dmat, /*alignment*/1, /*boundary*/0,
/*lowaddr*/BUS_SPACE_MAXADDR,
/*highaddr*/BUS_SPACE_MAXADDR,
@@ -990,16 +1114,15 @@ adw_init(struct adw_softc *adw)
/*nsegments*/1,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/0, &adw->acb_dmat) != 0) {
- return (-1);
+ return (ENOMEM);
}
adw->init_level++;
/* Allocation for our ccbs */
if (bus_dmamem_alloc(adw->acb_dmat, (void **)&adw->acbs,
- BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0) {
- return (-1);
- }
+ BUS_DMA_NOWAIT, &adw->acb_dmamap) != 0)
+ return (ENOMEM);
adw->init_level++;
@@ -1020,14 +1143,19 @@ adw_init(struct adw_softc *adw)
PAGE_SIZE, /*nsegments*/1,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/0, &adw->sg_dmat) != 0) {
- return (-1);
+ return (ENOMEM);
}
adw->init_level++;
/* Allocate our first batch of ccbs */
if (adwallocacbs(adw) == 0)
- return (-1);
+ return (ENOMEM);
+
+ if (adw_init_chip(adw, scsicfg1) != 0)
+ return (ENXIO);
+
+ printf("Queue Depth %d\n", adw->max_acbs);
return (0);
}
@@ -1040,6 +1168,18 @@ adw_attach(struct adw_softc *adw)
{
struct ccb_setasync csa;
struct cam_devq *devq;
+ int s;
+ int error;
+
+ error = 0;
+ s = splcam();
+ /* Hook up our interrupt handler */
+ if ((error = bus_setup_intr(adw->device, adw->irq, INTR_TYPE_CAM,
+ adw_intr, adw, &adw->ih)) != 0) {
+ device_printf(adw->device, "bus_setup_intr() failed: %d\n",
+ error);
+ goto fail;
+ }
/* Start the Risc processor now that we are fully configured. */
adw_outw(adw, ADW_RISC_CSR, ADW_RISC_CSR_RUN);
@@ -1049,22 +1189,25 @@ adw_attach(struct adw_softc *adw)
*/
devq = cam_simq_alloc(adw->max_acbs);
if (devq == NULL)
- return (0);
+ return (ENOMEM);
/*
* Construct our SIM entry.
*/
adw->sim = cam_sim_alloc(adw_action, adw_poll, "adw", adw, adw->unit,
1, adw->max_acbs, devq);
- if (adw->sim == NULL)
- return (0);
+ if (adw->sim == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
/*
* Register the bus.
*/
if (xpt_bus_register(adw->sim, 0) != CAM_SUCCESS) {
cam_sim_free(adw->sim, /*free devq*/TRUE);
- return (0);
+ error = ENOMEM;
+ goto fail;
}
if (xpt_create_path(&adw->path, /*periph*/NULL, cam_sim_path(adw->sim),
@@ -1078,7 +1221,9 @@ adw_attach(struct adw_softc *adw)
xpt_action((union ccb *)&csa);
}
- return (0);
+fail:
+ splx(s);
+ return (error);
}
void
@@ -1086,9 +1231,6 @@ adw_intr(void *arg)
{
struct adw_softc *adw;
u_int int_stat;
- u_int next_doneq;
- u_int next_completeq;
- u_int doneq_start;
adw = (struct adw_softc *)arg;
if ((adw_inw(adw, ADW_CTRL_REG) & ADW_CTRL_REG_HOST_INTR) == 0)
@@ -1098,61 +1240,80 @@ adw_intr(void *arg)
int_stat = adw_inb(adw, ADW_INTR_STATUS_REG);
if ((int_stat & ADW_INTR_STATUS_INTRB) != 0) {
- /* Idle Command Complete */
- adw->idle_command_cmp = 1;
- switch (adw->idle_cmd) {
- case ADW_IDLE_CMD_DEVICE_RESET:
- adw_handle_device_reset(adw,
- /*target*/adw->idle_cmd_param);
+ u_int intrb_code;
+
+ /* Async Microcode Event */
+ intrb_code = adw_lram_read_8(adw, ADW_MC_INTRB_CODE);
+ switch (intrb_code) {
+ case ADW_ASYNC_CARRIER_READY_FAILURE:
+ /*
+ * The RISC missed our update of
+ * the commandq.
+ */
+ if (LIST_FIRST(&adw->pending_ccbs) != NULL)
+ adw_tickle_risc(adw, ADW_TICKLE_A);
break;
- case ADW_IDLE_CMD_SCSI_RESET:
- adw_handle_bus_reset(adw, /*initiated*/TRUE);
+ case ADW_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ printf("Someone Reset the Bus\n");
+ adw_handle_bus_reset(adw, /*initiated*/FALSE);
break;
- default:
+ case ADW_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the
+ * SCSI Bus and chip.
+ */
+#if XXX
+ AdvResetChipAndSB(adv_dvc_varp);
+#endif
+ break;
+
+ case ADW_ASYNC_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ adw_handle_bus_reset(adw, /*initiated*/TRUE);
+ break;
+ default:
+ printf("adw_intr: unknown async code 0x%x\n",
+ intrb_code);
break;
}
- adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;
}
- if ((int_stat & ADW_INTR_STATUS_INTRC) != 0) {
- /* SCSI Bus Reset */
- adw_handle_bus_reset(adw, /*initiated*/FALSE);
- }
-
/*
- * ADW_MC_HOST_NEXT_DONE is actually the last completed RISC
- * Queue List request. Its forward pointer (RQL_FWD) points to the
- * current completed RISC Queue List request.
+ * Run down the RequestQ.
*/
- next_doneq = adw_lram_read_8(adw, ADW_MC_HOST_NEXT_DONE);
- next_doneq = ADW_MC_RISC_Q_LIST_BASE + RQL_FWD
- + (next_doneq * ADW_MC_RISC_Q_LIST_SIZE);
-
- next_completeq = adw_lram_read_8(adw, next_doneq);
- doneq_start = ADW_MC_NULL_Q;
- /* Loop until all completed Q's are processed. */
- while (next_completeq != ADW_MC_NULL_Q) {
- u_int32_t acb_busaddr;
- struct acb *acb;
- union ccb *ccb;
-
- doneq_start = next_completeq;
-
- next_doneq = ADW_MC_RISC_Q_LIST_BASE +
- (next_completeq * ADW_MC_RISC_Q_LIST_SIZE);
-
+ while ((adw->responseq->next_ba & ADW_RQ_DONE) != 0) {
+ struct adw_carrier *free_carrier;
+ struct acb *acb;
+ union ccb *ccb;
+
+#if 0
+ printf("0x%x, 0x%x, 0x%x, 0x%x\n",
+ adw->responseq->carr_offset,
+ adw->responseq->carr_ba,
+ adw->responseq->areq_ba,
+ adw->responseq->next_ba);
+#endif
/*
- * Read the ADW_SCSI_REQ_Q physical address pointer from
- * the RISC list entry.
+ * The firmware copies the adw_scsi_req_q.acb_baddr
+ * field into the areq_ba field of the carrier.
*/
- acb_busaddr = adw_lram_read_32(adw, next_doneq + RQL_PHYADDR);
- acb = acbptov(adw, acb_busaddr);
-
- /* Change the RISC Queue List state to free. */
- adw_lram_write_8(adw, next_doneq + RQL_STATE, ADW_MC_QS_FREE);
+ acb = acbbotov(adw, adw->responseq->areq_ba);
- /* Get the RISC Queue List forward pointer. */
- next_completeq = adw_lram_read_8(adw, next_doneq + RQL_FWD);
+ /*
+ * The least significant four bits of the next_ba
+ * field are used as flags. Mask them out and then
+ * advance through the list.
+ */
+ free_carrier = adw->responseq;
+ adw->responseq =
+ carrierbotov(adw, free_carrier->next_ba & ADW_NEXT_BA_MASK);
+ free_carrier->next_ba = adw->free_carriers->carr_offset;
+ adw->free_carriers = free_carrier;
/* Process CCB */
ccb = acb->ccb;
@@ -1195,14 +1356,10 @@ adw_intr(void *arg)
}
adwfreeacb(adw, acb);
xpt_done(ccb);
-
} else {
adwprocesserror(adw, acb);
}
}
-
- if (doneq_start != ADW_MC_NULL_Q)
- adw_lram_write_8(adw, ADW_MC_HOST_NEXT_DONE, doneq_start);
}
static void
@@ -1239,11 +1396,26 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
break;
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,
+ 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));
break;
+ }
case QHSTA_M_SXFR_XFR_PH_ERR:
ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
break;
@@ -1314,8 +1486,17 @@ adwtimeout(void *arg)
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);
} else {
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET, /*param*/0);
+ 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",