Lock iir(4) and mark it MPSAFE.

- Add a per-device mutex to the softc and use it for bus_dma tags,
  CAM SIMs, callouts, and interrupt handler.
- Switch from timeout(9) to callout(9).
- Add a separate global mutex to protect the global event buffer ring.
- Return completed index from iir_intr_locked() and remove the global
  gdt_wait_* variables.
- Remove global list of gdt softcs and replace its use with
  devclass_get_device().
- Use si_drv1 to store softc pointer in the SDEV_PER_HBA case instead
  of minor numbers.
- Do math on osreldate instead of dubious char math on osrelease[]
  that didn't work on 10.0+.
- Use bus_*() instead of bus_space_*().
- Use device_printf() instead of printf() with a unit number.

Tested by:	no one
This commit is contained in:
John Baldwin 2014-11-13 22:00:18 +00:00
parent cdce6f654b
commit 7ff829cb0e
4 changed files with 252 additions and 372 deletions

View File

@ -71,9 +71,6 @@ __FBSDID("$FreeBSD$");
static MALLOC_DEFINE(M_GDTBUF, "iirbuf", "iir driver buffer");
struct gdt_softc *gdt_wait_gdt;
int gdt_wait_index;
#ifdef GDT_DEBUG
int gdt_debug = GDT_DEBUG;
#ifdef __SERIAL__
@ -135,13 +132,13 @@ int ser_printf(const char *fmt, ...)
#endif
#endif
/* The linked list of softc structures */
struct gdt_softc_list gdt_softcs = TAILQ_HEAD_INITIALIZER(gdt_softcs);
/* controller cnt. */
int gdt_cnt = 0;
/* event buffer */
static gdt_evt_str ebuffer[GDT_MAX_EVENTS];
static int elastidx, eoldidx;
static struct mtx elock;
MTX_SYSINIT(iir_elock, &elock, "iir events", MTX_DEF);
/* statistics */
gdt_statist_t gdt_stat;
@ -150,6 +147,7 @@ gdt_statist_t gdt_stat;
#define ccb_priority spriv_field1
static void iir_action(struct cam_sim *sim, union ccb *ccb);
static int iir_intr_locked(struct gdt_softc *gdt);
static void iir_poll(struct cam_sim *sim);
static void iir_shutdown(void *arg, int howto);
static void iir_timeout(void *arg);
@ -168,12 +166,12 @@ static int gdt_sync_event(struct gdt_softc *gdt, int service,
u_int8_t index, struct gdt_ccb *gccb);
static int gdt_async_event(struct gdt_softc *gdt, int service);
static struct gdt_ccb *gdt_raw_cmd(struct gdt_softc *gdt,
union ccb *ccb, int *lock);
union ccb *ccb);
static struct gdt_ccb *gdt_cache_cmd(struct gdt_softc *gdt,
union ccb *ccb, int *lock);
union ccb *ccb);
static struct gdt_ccb *gdt_ioctl_cmd(struct gdt_softc *gdt,
gdt_ucmd_t *ucmd, int *lock);
static void gdt_internal_cache_cmd(struct gdt_softc *gdt,union ccb *ccb);
gdt_ucmd_t *ucmd);
static void gdt_internal_cache_cmd(struct gdt_softc *gdt, union ccb *ccb);
static void gdtmapmem(void *arg, bus_dma_segment_t *dm_segs,
int nseg, int error);
@ -197,7 +195,6 @@ iir_init(struct gdt_softc *gdt)
SLIST_INIT(&gdt->sc_pending_gccb);
TAILQ_INIT(&gdt->sc_ccb_queue);
TAILQ_INIT(&gdt->sc_ucmd_queue);
TAILQ_INSERT_TAIL(&gdt_softcs, gdt, links);
/* DMA tag for mapping buffers into device visible space. */
if (bus_dma_tag_create(gdt->sc_parent_dmat, /*alignment*/1, /*boundary*/0,
@ -207,10 +204,11 @@ iir_init(struct gdt_softc *gdt)
/*maxsize*/MAXBSIZE, /*nsegments*/GDT_MAXSG,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/BUS_DMA_ALLOCNOW,
/*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant,
/*lockfunc*/busdma_lock_mutex,
/*lockarg*/&gdt->sc_lock,
&gdt->sc_buffer_dmat) != 0) {
printf("iir%d: bus_dma_tag_create(...,gdt->sc_buffer_dmat) failed\n",
gdt->sc_hanum);
device_printf(gdt->sc_devnode,
"bus_dma_tag_create(..., gdt->sc_buffer_dmat) failed\n");
return (1);
}
gdt->sc_init_level++;
@ -227,9 +225,10 @@ iir_init(struct gdt_softc *gdt)
/*nsegments*/1,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
/*lockarg*/&Giant, &gdt->sc_gcscratch_dmat) != 0) {
printf("iir%d: bus_dma_tag_create(...,gdt->sc_gcscratch_dmat) failed\n",
gdt->sc_hanum);
/*lockarg*/&gdt->sc_lock,
&gdt->sc_gcscratch_dmat) != 0) {
device_printf(gdt->sc_devnode,
"bus_dma_tag_create(...,gdt->sc_gcscratch_dmat) failed\n");
return (1);
}
gdt->sc_init_level++;
@ -237,8 +236,8 @@ iir_init(struct gdt_softc *gdt)
/* Allocation for our ccb scratch area */
if (bus_dmamem_alloc(gdt->sc_gcscratch_dmat, (void **)&gdt->sc_gcscratch,
BUS_DMA_NOWAIT, &gdt->sc_gcscratch_dmamap) != 0) {
printf("iir%d: bus_dmamem_alloc(...,&gdt->sc_gccbs,...) failed\n",
gdt->sc_hanum);
device_printf(gdt->sc_devnode,
"bus_dmamem_alloc(...,&gdt->sc_gccbs,...) failed\n");
return (1);
}
gdt->sc_init_level++;
@ -256,7 +255,7 @@ iir_init(struct gdt_softc *gdt)
gdt->sc_gccbs = malloc(sizeof(struct gdt_ccb) * GDT_MAXCMDS, M_GDTBUF,
M_NOWAIT | M_ZERO);
if (gdt->sc_gccbs == NULL) {
printf("iir%d: no memory for gccbs.\n", gdt->sc_hanum);
device_printf(gdt->sc_devnode, "no memory for gccbs.\n");
return (1);
}
for (i = GDT_MAXCMDS-1; i >= 0; i--) {
@ -270,28 +269,30 @@ iir_init(struct gdt_softc *gdt)
gccb->gc_map_flag = TRUE;
gccb->gc_scratch = &gdt->sc_gcscratch[GDT_SCRATCH_SZ * i];
gccb->gc_scratch_busbase = gdt->sc_gcscratch_busbase + GDT_SCRATCH_SZ * i;
callout_handle_init(&gccb->gc_timeout_ch);
callout_init_mtx(&gccb->gc_timeout, &gdt->sc_lock, 0);
SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
}
gdt->sc_init_level++;
/* create the control device */
gdt->sc_dev = gdt_make_dev(gdt->sc_hanum);
gdt->sc_dev = gdt_make_dev(gdt);
/* allocate ccb for gdt_internal_cmd() */
mtx_lock(&gdt->sc_lock);
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
printf("iir%d: No free command index found\n",
gdt->sc_hanum);
mtx_unlock(&gdt->sc_lock);
device_printf(gdt->sc_devnode, "No free command index found\n");
return (1);
}
bzero(gccb->gc_cmd, GDT_CMD_SZ);
if (!gdt_internal_cmd(gdt, gccb, GDT_SCREENSERVICE, GDT_INIT,
0, 0, 0)) {
printf("iir%d: Screen service initialization error %d\n",
gdt->sc_hanum, gdt->sc_status);
device_printf(gdt->sc_devnode,
"Screen service initialization error %d\n", gdt->sc_status);
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
@ -300,9 +301,10 @@ iir_init(struct gdt_softc *gdt)
if (!gdt_internal_cmd(gdt, gccb, GDT_CACHESERVICE, GDT_INIT,
GDT_LINUX_OS, 0, 0)) {
printf("iir%d: Cache service initialization error %d\n",
gdt->sc_hanum, gdt->sc_status);
device_printf(gdt->sc_devnode, "Cache service initialization error %d\n",
gdt->sc_status);
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
cdev_cnt = (u_int16_t)gdt->sc_info;
@ -332,9 +334,10 @@ iir_init(struct gdt_softc *gdt)
GDT_IO_CHANNEL | GDT_INVALID_CHANNEL,
GDT_GETCH_SZ)) {
if (i == 0) {
printf("iir%d: Cannot get channel count, "
"error %d\n", gdt->sc_hanum, gdt->sc_status);
device_printf(gdt->sc_devnode, "Cannot get channel count, "
"error %d\n", gdt->sc_status);
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
break;
@ -351,9 +354,10 @@ iir_init(struct gdt_softc *gdt)
if (!gdt_internal_cmd(gdt, gccb, GDT_SCSIRAWSERVICE, GDT_INIT,
0, 0, 0)) {
printf("iir%d: Raw service initialization error %d\n",
gdt->sc_hanum, gdt->sc_status);
device_printf(gdt->sc_devnode,
"Raw service initialization error %d\n", gdt->sc_status);
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
@ -365,9 +369,11 @@ iir_init(struct gdt_softc *gdt)
0, 0, 0)) {
gdt->sc_raw_feat = gdt->sc_info;
if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
panic("iir%d: Scatter/Gather Raw Service "
"required but not supported!\n", gdt->sc_hanum);
panic("%s: Scatter/Gather Raw Service "
"required but not supported!\n",
device_get_nameunit(gdt->sc_devnode));
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
}
@ -381,9 +387,11 @@ iir_init(struct gdt_softc *gdt)
0, 0, 0)) {
gdt->sc_cache_feat = gdt->sc_info;
if (!(gdt->sc_info & GDT_SCATTER_GATHER)) {
panic("iir%d: Scatter/Gather Cache Service "
"required but not supported!\n", gdt->sc_hanum);
panic("%s: Scatter/Gather Cache Service "
"required but not supported!\n",
device_get_nameunit(gdt->sc_devnode));
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
return (1);
}
}
@ -442,8 +450,9 @@ iir_init(struct gdt_softc *gdt)
gdt->sc_bus_cnt, cdev_cnt,
cdev_cnt == 1 ? "" : "s"));
gdt_free_ccb(gdt, gccb);
mtx_unlock(&gdt->sc_lock);
gdt_cnt++;
atomic_add_int(&gdt_cnt, 1);
return (0);
}
@ -459,9 +468,11 @@ iir_free(struct gdt_softc *gdt)
gdt_destroy_dev(gdt->sc_dev);
case 5:
for (i = GDT_MAXCMDS-1; i >= 0; i--)
if (gdt->sc_gccbs[i].gc_map_flag)
if (gdt->sc_gccbs[i].gc_map_flag) {
callout_drain(&gdt->sc_gccbs[i].gc_timeout);
bus_dmamap_destroy(gdt->sc_buffer_dmat,
gdt->sc_gccbs[i].gc_dmamap);
}
bus_dmamap_unload(gdt->sc_gcscratch_dmat, gdt->sc_gcscratch_dmamap);
free(gdt->sc_gccbs, M_GDTBUF);
case 4:
@ -475,7 +486,6 @@ iir_free(struct gdt_softc *gdt)
case 0:
break;
}
TAILQ_REMOVE(&gdt_softcs, gdt, links);
}
void
@ -499,11 +509,12 @@ iir_attach(struct gdt_softc *gdt)
* Construct our SIM entry
*/
gdt->sims[i] = cam_sim_alloc(iir_action, iir_poll, "iir",
gdt, gdt->sc_hanum, &Giant,
/*untagged*/1,
/*tagged*/GDT_MAXCMDS, devq);
gdt, device_get_unit(gdt->sc_devnode), &gdt->sc_lock,
/*untagged*/1, /*tagged*/GDT_MAXCMDS, devq);
mtx_lock(&gdt->sc_lock);
if (xpt_bus_register(gdt->sims[i], gdt->sc_devnode, i) != CAM_SUCCESS) {
cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
mtx_unlock(&gdt->sc_lock);
break;
}
@ -513,8 +524,10 @@ iir_attach(struct gdt_softc *gdt)
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path(gdt->sims[i]));
cam_sim_free(gdt->sims[i], /*free_devq*/i == 0);
mtx_unlock(&gdt->sc_lock);
break;
}
mtx_unlock(&gdt->sc_lock);
}
if (i > 0)
EVENTHANDLER_REGISTER(shutdown_final, iir_shutdown,
@ -556,9 +569,7 @@ gdt_wait(struct gdt_softc *gdt, struct gdt_ccb *gccb,
gdt->sc_state |= GDT_POLL_WAIT;
do {
iir_intr(gdt);
if (gdt == gdt_wait_gdt &&
gccb->gc_cmd_index == gdt_wait_index) {
if (iir_intr_locked(gdt) == gccb->gc_cmd_index) {
rv = 1;
break;
}
@ -642,11 +653,10 @@ static struct gdt_ccb *
gdt_get_ccb(struct gdt_softc *gdt)
{
struct gdt_ccb *gccb;
int lock;
GDT_DPRINTF(GDT_D_QUEUE, ("gdt_get_ccb(%p)\n", gdt));
lock = splcam();
mtx_assert(&gdt->sc_lock, MA_OWNED);
gccb = SLIST_FIRST(&gdt->sc_free_gccb);
if (gccb != NULL) {
SLIST_REMOVE_HEAD(&gdt->sc_free_gccb, sle);
@ -655,23 +665,20 @@ gdt_get_ccb(struct gdt_softc *gdt)
if (gdt_stat.cmd_index_act > gdt_stat.cmd_index_max)
gdt_stat.cmd_index_max = gdt_stat.cmd_index_act;
}
splx(lock);
return (gccb);
}
void
gdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb)
{
int lock;
GDT_DPRINTF(GDT_D_QUEUE, ("gdt_free_ccb(%p, %p)\n", gdt, gccb));
lock = splcam();
mtx_assert(&gdt->sc_lock, MA_OWNED);
gccb->gc_flags = GDT_GCF_UNUSED;
SLIST_REMOVE(&gdt->sc_pending_gccb, gccb, gdt_ccb, sle);
SLIST_INSERT_HEAD(&gdt->sc_free_gccb, gccb, sle);
--gdt_stat.cmd_index_act;
splx(lock);
if (gdt->sc_state & GDT_SHUTDOWN)
wakeup(gccb);
}
@ -679,7 +686,6 @@ gdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb)
void
gdt_next(struct gdt_softc *gdt)
{
int lock;
union ccb *ccb;
gdt_ucmd_t *ucmd;
struct cam_sim *sim;
@ -693,10 +699,9 @@ gdt_next(struct gdt_softc *gdt)
GDT_DPRINTF(GDT_D_QUEUE, ("gdt_next(%p)\n", gdt));
lock = splcam();
mtx_assert(&gdt->sc_lock, MA_OWNED);
if (gdt->sc_test_busy(gdt)) {
if (!(gdt->sc_state & GDT_POLLING)) {
splx(lock);
return;
}
while (gdt->sc_test_busy(gdt))
@ -715,7 +720,7 @@ gdt_next(struct gdt_softc *gdt)
ucmd = TAILQ_FIRST(&gdt->sc_ucmd_queue);
if (ucmd != NULL) {
TAILQ_REMOVE(&gdt->sc_ucmd_queue, ucmd, links);
if ((gccb = gdt_ioctl_cmd(gdt, ucmd, &lock)) == NULL) {
if ((gccb = gdt_ioctl_cmd(gdt, ucmd)) == NULL) {
TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
break;
}
@ -746,7 +751,7 @@ gdt_next(struct gdt_softc *gdt)
xpt_done(ccb);
} else if (bus != gdt->sc_virt_bus) {
/* raw service command */
if ((gccb = gdt_raw_cmd(gdt, ccb, &lock)) == NULL) {
if ((gccb = gdt_raw_cmd(gdt, ccb)) == NULL) {
TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
sim_links.tqe);
++gdt_stat.req_queue_act;
@ -763,7 +768,7 @@ gdt_next(struct gdt_softc *gdt)
/* cache service command */
if (cmd == READ_6 || cmd == WRITE_6 ||
cmd == READ_10 || cmd == WRITE_10) {
if ((gccb = gdt_cache_cmd(gdt, ccb, &lock)) == NULL) {
if ((gccb = gdt_cache_cmd(gdt, ccb)) == NULL) {
TAILQ_INSERT_HEAD(&gdt->sc_ccb_queue, &ccb->ccb_h,
sim_links.tqe);
++gdt_stat.req_queue_act;
@ -772,9 +777,7 @@ gdt_next(struct gdt_softc *gdt)
next_cmd = FALSE;
}
} else {
splx(lock);
gdt_internal_cache_cmd(gdt, ccb);
lock = splcam();
}
}
if ((gdt->sc_state & GDT_POLLING) || !next_cmd)
@ -783,15 +786,13 @@ gdt_next(struct gdt_softc *gdt)
if (gdt->sc_cmd_cnt > 0)
gdt->sc_release_event(gdt);
splx(lock);
if ((gdt->sc_state & GDT_POLLING) && gdt->sc_cmd_cnt > 0) {
gdt_wait(gdt, gccb, GDT_POLL_TIMEOUT);
}
}
static struct gdt_ccb *
gdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
gdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb)
{
struct gdt_ccb *gccb;
struct cam_sim *sim;
@ -802,15 +803,15 @@ gdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
if (roundup(GDT_CMD_UNION + GDT_RAW_SZ, sizeof(u_int32_t)) +
gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET >
gdt->sc_ic_all_size) {
GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_raw_cmd(): DPMEM overflow\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_raw_cmd(): DPMEM overflow\n",
device_get_nameunit(gdt->sc_devnode)));
return (NULL);
}
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
GDT_DPRINTF(GDT_D_INVALID, ("iir%d: No free command index found\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_INVALID, ("%s: No free command index found\n",
device_get_nameunit(gdt->sc_devnode)));
return (gccb);
}
bzero(gccb->gc_cmd, GDT_CMD_SZ);
@ -821,7 +822,6 @@ gdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
if (gdt->sc_cmd_cnt == 0)
gdt->sc_set_sema0(gdt);
splx(*lock);
gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
gccb->gc_cmd_index);
gdt_enc16(gccb->gc_cmd + GDT_CMD_OPCODE, GDT_WRITE);
@ -856,12 +856,11 @@ gdt_raw_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
}
*lock = splcam();
return (gccb);
}
static struct gdt_ccb *
gdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
gdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb)
{
struct gdt_ccb *gccb;
struct cam_sim *sim;
@ -875,15 +874,15 @@ gdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
if (roundup(GDT_CMD_UNION + GDT_CACHE_SZ, sizeof(u_int32_t)) +
gdt->sc_cmd_off + GDT_DPMEM_COMMAND_OFFSET >
gdt->sc_ic_all_size) {
GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_cache_cmd(): DPMEM overflow\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_cache_cmd(): DPMEM overflow\n",
device_get_nameunit(gdt->sc_devnode)));
return (NULL);
}
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_DEBUG, ("%s: No free command index found\n",
device_get_nameunit(gdt->sc_devnode)));
return (gccb);
}
bzero(gccb->gc_cmd, GDT_CMD_SZ);
@ -894,7 +893,6 @@ gdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
if (gdt->sc_cmd_cnt == 0)
gdt->sc_set_sema0(gdt);
splx(*lock);
gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
gccb->gc_cmd_index);
cmdp = ccb->csio.cdb_io.cdb_bytes;
@ -928,12 +926,11 @@ gdt_cache_cmd(struct gdt_softc *gdt, union ccb *ccb, int *lock)
xpt_freeze_simq(sim, 1);
gccb->gc_ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
}
*lock = splcam();
return (gccb);
}
static struct gdt_ccb *
gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd)
{
struct gdt_ccb *gccb;
u_int32_t cnt;
@ -942,8 +939,8 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
GDT_DPRINTF(GDT_D_DEBUG, ("iir%d: No free command index found\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_DEBUG, ("%s: No free command index found\n",
device_get_nameunit(gdt->sc_devnode)));
return (gccb);
}
bzero(gccb->gc_cmd, GDT_CMD_SZ);
@ -958,8 +955,8 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
sizeof(u_int32_t));
cnt = ucmd->u.ioctl.param_size;
if (cnt > GDT_SCRATCH_SZ) {
printf("iir%d: Scratch buffer too small (%d/%d)\n",
gdt->sc_hanum, GDT_SCRATCH_SZ, cnt);
device_printf(gdt->sc_devnode,
"Scratch buffer too small (%d/%d)\n", GDT_SCRATCH_SZ, cnt);
gdt_free_ccb(gdt, gccb);
return (NULL);
}
@ -968,8 +965,8 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
GDT_SG_SZ, sizeof(u_int32_t));
cnt = ucmd->u.cache.BlockCnt * GDT_SECTOR_SIZE;
if (cnt > GDT_SCRATCH_SZ) {
printf("iir%d: Scratch buffer too small (%d/%d)\n",
gdt->sc_hanum, GDT_SCRATCH_SZ, cnt);
device_printf(gdt->sc_devnode,
"Scratch buffer too small (%d/%d)\n", GDT_SCRATCH_SZ, cnt);
gdt_free_ccb(gdt, gccb);
return (NULL);
}
@ -979,8 +976,8 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
GDT_SG_SZ, sizeof(u_int32_t));
cnt = ucmd->u.raw.sdlen;
if (cnt + ucmd->u.raw.sense_len > GDT_SCRATCH_SZ) {
printf("iir%d: Scratch buffer too small (%d/%d)\n",
gdt->sc_hanum, GDT_SCRATCH_SZ, cnt + ucmd->u.raw.sense_len);
device_printf(gdt->sc_devnode, "Scratch buffer too small (%d/%d)\n",
GDT_SCRATCH_SZ, cnt + ucmd->u.raw.sense_len);
gdt_free_ccb(gdt, gccb);
return (NULL);
}
@ -990,15 +987,14 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
if (gdt->sc_cmd_off + gccb->gc_cmd_len + GDT_DPMEM_COMMAND_OFFSET >
gdt->sc_ic_all_size) {
GDT_DPRINTF(GDT_D_INVALID, ("iir%d: gdt_ioctl_cmd(): DPMEM overflow\n",
gdt->sc_hanum));
GDT_DPRINTF(GDT_D_INVALID, ("%s: gdt_ioctl_cmd(): DPMEM overflow\n",
device_get_nameunit(gdt->sc_devnode)));
gdt_free_ccb(gdt, gccb);
return (NULL);
}
if (gdt->sc_cmd_cnt == 0)
gdt->sc_set_sema0(gdt);
splx(*lock);
/* fill cmd structure */
gdt_enc32(gccb->gc_cmd + GDT_CMD_COMMANDINDEX,
@ -1064,7 +1060,6 @@ gdt_ioctl_cmd(struct gdt_softc *gdt, gdt_ucmd_t *ucmd, int *lock)
GDT_SG_LEN, ucmd->u.raw.sdlen);
}
*lock = splcam();
gdt_stat.sg_count_act = 1;
gdt->sc_copy_cmd(gdt, gccb);
return (gccb);
@ -1181,13 +1176,12 @@ gdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
struct gdt_ccb *gccb;
union ccb *ccb;
struct gdt_softc *gdt;
int i, lock;
lock = splcam();
int i;
gccb = (struct gdt_ccb *)arg;
ccb = gccb->gc_ccb;
gdt = cam_sim_softc((struct cam_sim *)ccb->ccb_h.ccb_sim_ptr);
mtx_assert(&gdt->sc_lock, MA_OWNED);
GDT_DPRINTF(GDT_D_CMD, ("gdtexecuteccb(%p, %p, %p, %d, %d)\n",
gdt, gccb, dm_segs, nseg, error));
@ -1240,12 +1234,10 @@ gdtexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
ccb->ccb_h.status |= CAM_SIM_QUEUED;
/* timeout handling */
gccb->gc_timeout_ch =
timeout(iir_timeout, (caddr_t)gccb,
(ccb->ccb_h.timeout * hz) / 1000);
callout_reset(&gccb->gc_timeout, (ccb->ccb_h.timeout * hz) / 1000,
iir_timeout, gccb);
gdt->sc_copy_cmd(gdt, gccb);
splx(lock);
}
@ -1253,9 +1245,10 @@ static void
iir_action( struct cam_sim *sim, union ccb *ccb )
{
struct gdt_softc *gdt;
int lock, bus, target, lun;
int bus, target, lun;
gdt = (struct gdt_softc *)cam_sim_softc( sim );
mtx_assert(&gdt->sc_lock, MA_OWNED);
ccb->ccb_h.ccb_sim_ptr = sim;
bus = cam_sim_bus(sim);
target = ccb->ccb_h.target_id;
@ -1270,12 +1263,10 @@ iir_action( struct cam_sim *sim, union ccb *ccb )
switch (ccb->ccb_h.func_code) {
case XPT_SCSI_IO:
lock = splcam();
TAILQ_INSERT_TAIL(&gdt->sc_ccb_queue, &ccb->ccb_h, sim_links.tqe);
++gdt_stat.req_queue_act;
if (gdt_stat.req_queue_act > gdt_stat.req_queue_max)
gdt_stat.req_queue_max = gdt_stat.req_queue_act;
splx(lock);
gdt_next(gdt);
break;
case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
@ -1406,7 +1397,7 @@ iir_poll( struct cam_sim *sim )
gdt = (struct gdt_softc *)cam_sim_softc( sim );
GDT_DPRINTF(GDT_D_CMD, ("iir_poll sim %p gdt %p\n", sim, gdt));
iir_intr(gdt);
iir_intr_locked(gdt);
}
static void
@ -1421,29 +1412,29 @@ iir_shutdown( void *arg, int howto )
struct gdt_softc *gdt;
struct gdt_ccb *gccb;
gdt_ucmd_t *ucmd;
int lock, i;
int i;
gdt = (struct gdt_softc *)arg;
GDT_DPRINTF(GDT_D_CMD, ("iir_shutdown(%p, %d)\n", gdt, howto));
printf("iir%d: Flushing all Host Drives. Please wait ... ",
gdt->sc_hanum);
device_printf(gdt->sc_devnode,
"Flushing all Host Drives. Please wait ... ");
/* allocate ucmd buffer */
ucmd = malloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_NOWAIT);
if (ucmd == NULL) {
printf("iir%d: iir_shutdown(): Cannot allocate resource\n",
gdt->sc_hanum);
printf("\n");
device_printf(gdt->sc_devnode,
"iir_shutdown(): Cannot allocate resource\n");
return;
}
bzero(ucmd, sizeof(gdt_ucmd_t));
/* wait for pending IOs */
lock = splcam();
mtx_lock(&gdt->sc_lock);
gdt->sc_state = GDT_SHUTDOWN;
splx(lock);
if ((gccb = SLIST_FIRST(&gdt->sc_pending_gccb)) != NULL)
(void) tsleep((void *)gccb, PCATCH | PRIBIO, "iirshw", 100 * hz);
mtx_sleep(gccb, &gdt->sc_lock, PCATCH | PRIBIO, "iirshw", 100 * hz);
/* flush */
for (i = 0; i < GDT_MAX_HDRIVES; ++i) {
@ -1451,15 +1442,15 @@ iir_shutdown( void *arg, int howto )
ucmd->service = GDT_CACHESERVICE;
ucmd->OpCode = GDT_FLUSH;
ucmd->u.cache.DeviceNo = i;
lock = splcam();
TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
ucmd->complete_flag = FALSE;
splx(lock);
gdt_next(gdt);
if (!ucmd->complete_flag)
(void) tsleep((void *)ucmd, PCATCH|PRIBIO, "iirshw", 10*hz);
mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirshw",
10 * hz);
}
}
mtx_unlock(&gdt->sc_lock);
free(ucmd, M_DEVBUF);
printf("Done.\n");
@ -1469,29 +1460,33 @@ void
iir_intr(void *arg)
{
struct gdt_softc *gdt = arg;
mtx_lock(&gdt->sc_lock);
iir_intr_locked(gdt);
mtx_unlock(&gdt->sc_lock);
}
int
iir_intr_locked(struct gdt_softc *gdt)
{
struct gdt_intr_ctx ctx;
int lock = 0;
struct gdt_ccb *gccb;
gdt_ucmd_t *ucmd;
u_int32_t cnt;
GDT_DPRINTF(GDT_D_INTR, ("gdt_intr(%p)\n", gdt));
mtx_assert(&gdt->sc_lock, MA_OWNED);
/* If polling and we were not called from gdt_wait, just return */
if ((gdt->sc_state & GDT_POLLING) &&
!(gdt->sc_state & GDT_POLL_WAIT))
return;
if (!(gdt->sc_state & GDT_POLLING))
lock = splcam();
gdt_wait_index = 0;
return (0);
ctx.istatus = gdt->sc_get_status(gdt);
if (ctx.istatus == 0x00) {
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
gdt->sc_status = GDT_S_NO_STATUS;
return;
return (ctx.istatus);
}
gdt->sc_intr(gdt, &ctx);
@ -1501,27 +1496,18 @@ iir_intr(void *arg)
gdt->sc_info = ctx.info;
gdt->sc_info2 = ctx.info2;
if (gdt->sc_state & GDT_POLL_WAIT) {
gdt_wait_gdt = gdt;
gdt_wait_index = ctx.istatus;
}
if (ctx.istatus == GDT_ASYNCINDEX) {
gdt_async_event(gdt, ctx.service);
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
return;
return (ctx.istatus);
}
if (ctx.istatus == GDT_SPEZINDEX) {
GDT_DPRINTF(GDT_D_INVALID,
("iir%d: Service unknown or not initialized!\n",
gdt->sc_hanum));
("%s: Service unknown or not initialized!\n",
device_get_nameunit(gdt->sc_devnode)));
gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
gdt_store_event(GDT_ES_DRIVER, 4, &gdt->sc_dvr);
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
return;
return (ctx.istatus);
}
gccb = &gdt->sc_gccbs[ctx.istatus - 2];
@ -1529,18 +1515,16 @@ iir_intr(void *arg)
switch (gccb->gc_flags) {
case GDT_GCF_UNUSED:
GDT_DPRINTF(GDT_D_INVALID, ("iir%d: Index (%d) to unused command!\n",
gdt->sc_hanum, ctx.istatus));
GDT_DPRINTF(GDT_D_INVALID, ("%s: Index (%d) to unused command!\n",
device_get_nameunit(gdt->sc_devnode), ctx.istatus));
gdt->sc_dvr.size = sizeof(gdt->sc_dvr.eu.driver);
gdt->sc_dvr.eu.driver.ionode = gdt->sc_hanum;
gdt->sc_dvr.eu.driver.index = ctx.istatus;
gdt_store_event(GDT_ES_DRIVER, 1, &gdt->sc_dvr);
gdt_free_ccb(gdt, gccb);
/* fallthrough */
break;
case GDT_GCF_INTERNAL:
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
break;
case GDT_GCF_IOCTL:
@ -1549,8 +1533,6 @@ iir_intr(void *arg)
GDT_DPRINTF(GDT_D_DEBUG, ("iir_intr(%p) ioctl: gccb %p busy\n",
gdt, gccb));
TAILQ_INSERT_HEAD(&gdt->sc_ucmd_queue, ucmd, links);
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
} else {
ucmd->status = gdt->sc_status;
ucmd->info = gdt->sc_info;
@ -1573,8 +1555,6 @@ iir_intr(void *arg)
bcopy(gccb->gc_scratch, ucmd->data, cnt);
}
gdt_free_ccb(gdt, gccb);
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
/* wakeup */
wakeup(ucmd);
}
@ -1584,11 +1564,11 @@ iir_intr(void *arg)
default:
gdt_free_ccb(gdt, gccb);
gdt_sync_event(gdt, ctx.service, ctx.istatus, gccb);
if (!(gdt->sc_state & GDT_POLLING))
splx(lock);
gdt_next(gdt);
break;
}
return (ctx.istatus);
}
int
@ -1604,8 +1584,7 @@ gdt_async_event(struct gdt_softc *gdt, int service)
DELAY(1);
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
printf("iir%d: No free command index found\n",
gdt->sc_hanum);
device_printf(gdt->sc_devnode, "No free command index found\n");
return (1);
}
bzero(gccb->gc_cmd, GDT_CMD_SZ);
@ -1624,8 +1603,8 @@ gdt_async_event(struct gdt_softc *gdt, int service)
sizeof(u_int32_t));
gdt->sc_cmd_cnt = 0;
gdt->sc_copy_cmd(gdt, gccb);
printf("iir%d: [PCI %d/%d] ",
gdt->sc_hanum,gdt->sc_bus,gdt->sc_slot);
device_printf(gdt->sc_devnode, "[PCI %d/%d] ", gdt->sc_bus,
gdt->sc_slot);
gdt->sc_release_event(gdt);
}
@ -1644,7 +1623,7 @@ gdt_async_event(struct gdt_softc *gdt, int service)
*(u_int32_t *)gdt->sc_dvr.eu.async.scsi_coord = gdt->sc_info2;
}
gdt_store_event(GDT_ES_ASYNC, service, &gdt->sc_dvr);
printf("iir%d: %s\n", gdt->sc_hanum, gdt->sc_dvr.event_string);
device_printf(gdt->sc_devnode, "%s\n", gdt->sc_dvr.event_string);
}
return (0);
@ -1679,8 +1658,7 @@ gdt_sync_event(struct gdt_softc *gdt, int service,
bzero(gccb->gc_cmd, GDT_CMD_SZ);
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
printf("iir%d: No free command index found\n",
gdt->sc_hanum);
device_printf(gdt->sc_devnode, "No free command index found\n");
return (1);
}
gccb->gc_service = service;
@ -1723,8 +1701,7 @@ gdt_sync_event(struct gdt_softc *gdt, int service,
bzero(gccb->gc_cmd, GDT_CMD_SZ);
gccb = gdt_get_ccb(gdt);
if (gccb == NULL) {
printf("iir%d: No free command index found\n",
gdt->sc_hanum);
device_printf(gdt->sc_devnode, "No free command index found\n");
return (1);
}
gccb->gc_service = service;
@ -1748,7 +1725,7 @@ gdt_sync_event(struct gdt_softc *gdt, int service,
printf("\n");
return (0);
} else {
untimeout(iir_timeout, gccb, gccb->gc_timeout_ch);
callout_stop(&gccb->gc_timeout);
if (gdt->sc_status == GDT_S_BSY) {
GDT_DPRINTF(GDT_D_DEBUG, ("gdt_sync_event(%p) gccb %p busy\n",
gdt, gccb));
@ -1816,7 +1793,7 @@ gdt_sync_event(struct gdt_softc *gdt, int service,
}
/* Controller event handling functions */
gdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx,
void gdt_store_event(u_int16_t source, u_int16_t idx,
gdt_evt_data *evt)
{
gdt_evt_str *e;
@ -1824,8 +1801,9 @@ gdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx,
GDT_DPRINTF(GDT_D_MISC, ("gdt_store_event(%d, %d)\n", source, idx));
if (source == 0) /* no source -> no event */
return 0;
return;
mtx_lock(&elock);
if (ebuffer[elastidx].event_source == source &&
ebuffer[elastidx].event_idx == idx &&
((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
@ -1858,16 +1836,16 @@ gdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx,
e->event_data = *evt;
e->application = 0;
}
return e;
mtx_unlock(&elock);
}
int gdt_read_event(int handle, gdt_evt_str *estr)
{
gdt_evt_str *e;
int eindex, lock;
int eindex;
GDT_DPRINTF(GDT_D_MISC, ("gdt_read_event(%d)\n", handle));
lock = splcam();
mtx_lock(&elock);
if (handle == -1)
eindex = eoldidx;
else
@ -1875,7 +1853,7 @@ int gdt_read_event(int handle, gdt_evt_str *estr)
estr->event_source = 0;
if (eindex >= GDT_MAX_EVENTS) {
splx(lock);
mtx_unlock(&elock);
return eindex;
}
e = &ebuffer[eindex];
@ -1888,7 +1866,7 @@ int gdt_read_event(int handle, gdt_evt_str *estr)
}
memcpy(estr, e, sizeof(gdt_evt_str));
}
splx(lock);
mtx_unlock(&elock);
return eindex;
}
@ -1896,10 +1874,10 @@ void gdt_readapp_event(u_int8_t application, gdt_evt_str *estr)
{
gdt_evt_str *e;
int found = FALSE;
int eindex, lock;
int eindex;
GDT_DPRINTF(GDT_D_MISC, ("gdt_readapp_event(%d)\n", application));
lock = splcam();
mtx_lock(&elock);
eindex = eoldidx;
for (;;) {
e = &ebuffer[eindex];
@ -1919,13 +1897,15 @@ void gdt_readapp_event(u_int8_t application, gdt_evt_str *estr)
memcpy(estr, e, sizeof(gdt_evt_str));
else
estr->event_source = 0;
splx(lock);
mtx_unlock(&elock);
}
void gdt_clear_events()
{
GDT_DPRINTF(GDT_D_MISC, ("gdt_clear_events\n"));
mtx_lock(&elock);
eoldidx = elastidx = 0;
ebuffer[0].event_source = 0;
mtx_unlock(&elock);
}

View File

@ -591,6 +591,7 @@ struct gdt_intr_ctx {
/* softc structure */
struct gdt_softc {
device_t sc_devnode;
struct mtx sc_lock;
int sc_hanum;
int sc_class; /* Controller class */
#define GDT_MPR 0x05
@ -608,9 +609,7 @@ struct gdt_softc {
#define GDT_SHUTDOWN 0x02
#define GDT_POLL_WAIT 0x80
struct cdev *sc_dev;
bus_space_tag_t sc_dpmemt;
bus_space_handle_t sc_dpmemh;
bus_addr_t sc_dpmembase;
struct resource *sc_dpmem;
bus_dma_tag_t sc_parent_dmat;
bus_dma_tag_t sc_buffer_dmat;
bus_dma_tag_t sc_gcscratch_dmat;
@ -684,9 +683,8 @@ struct gdt_ccb {
union ccb *gc_ccb;
gdt_ucmd_t *gc_ucmd;
bus_dmamap_t gc_dmamap;
struct callout_handle gc_timeout_ch;
struct callout gc_timeout;
int gc_map_flag;
int gc_timeout;
u_int8_t gc_service;
u_int8_t gc_cmd_index;
u_int8_t gc_flags;
@ -738,15 +736,14 @@ gdt_dec32(u_int8_t *addr)
}
#endif
extern TAILQ_HEAD(gdt_softc_list, gdt_softc) gdt_softcs;
extern u_int8_t gdt_polling;
struct cdev *gdt_make_dev(int unit);
struct cdev *gdt_make_dev(struct gdt_softc *gdt);
void gdt_destroy_dev(struct cdev *dev);
void gdt_next(struct gdt_softc *gdt);
void gdt_free_ccb(struct gdt_softc *gdt, struct gdt_ccb *gccb);
gdt_evt_str *gdt_store_event(u_int16_t source, u_int16_t idx,
void gdt_store_event(u_int16_t source, u_int16_t idx,
gdt_evt_data *evt);
int gdt_read_event(int handle, gdt_evt_str *estr);
void gdt_readapp_event(u_int8_t app, gdt_evt_str *estr);

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
@ -52,12 +53,13 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/disklabel.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <machine/bus.h>
#include <dev/iir/iir.h>
/* Entry points and other prototypes */
static struct gdt_softc *gdt_minor2softc(int minor_no);
static struct gdt_softc *gdt_minor2softc(struct cdev *dev, int minor_no);
static d_open_t iir_open;
static d_close_t iir_close;
@ -68,7 +70,6 @@ static d_ioctl_t iir_ioctl;
/* Normally, this is a static structure. But we need it in pci/iir_pci.c */
static struct cdevsw iir_cdevsw = {
.d_version = D_VERSION,
.d_flags = D_NEEDGIANT,
.d_open = iir_open,
.d_close = iir_close,
.d_read = iir_read,
@ -77,11 +78,10 @@ static struct cdevsw iir_cdevsw = {
.d_name = "iir",
};
/*
static int iir_devsw_installed = 0;
*/
#ifndef SDEV_PER_HBA
static int sdev_made = 0;
static struct sx sdev_lock;
SX_SYSINIT(iir_sdev_lock, &sdev_lock, "iir sdev");
#endif
extern int gdt_cnt;
extern gdt_statist_t gdt_stat;
@ -91,19 +91,22 @@ extern gdt_statist_t gdt_stat;
* make a special device and return the dev_t
*/
struct cdev *
gdt_make_dev(int unit)
gdt_make_dev(struct gdt_softc *gdt)
{
struct cdev *dev;
#ifdef SDEV_PER_HBA
dev = make_dev(&iir_cdevsw, hba2minor(unit), UID_ROOT, GID_OPERATOR,
dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
S_IRUSR | S_IWUSR, "iir%d", unit);
dev->si_drv1 = gdt;
#else
sx_xlock(&sdev_lock);
if (sdev_made)
return (0);
return (NULL);
dev = make_dev(&iir_cdevsw, 0, UID_ROOT, GID_OPERATOR,
S_IRUSR | S_IWUSR, "iir");
sdev_made = 1;
sx_xunlock(&sdev_lock);
#endif
return (dev);
}
@ -120,22 +123,23 @@ gdt_destroy_dev(struct cdev *dev)
* return the pointer to its softc structure
*/
static struct gdt_softc *
gdt_minor2softc(int minor_no)
gdt_minor2softc(struct cdev *dev, int minor_no)
{
struct gdt_softc *gdt;
int hanum;
#ifdef SDEV_PER_HBA
hanum = minor2hba(minor_no);
return (dev->si_drv1);
#else
hanum = minor_no;
devclass_t dc;
device_t child;
dc = devclass_find("iir");
if (dc == NULL)
return (NULL);
child = devclass_get_device(dc, minor_no);
if (child == NULL)
return (NULL);
return (device_get_softc(child));
#endif
for (gdt = TAILQ_FIRST(&gdt_softcs);
gdt != NULL && gdt->sc_hanum != hanum;
gdt = TAILQ_NEXT(gdt, links));
return (gdt);
}
static int
@ -143,16 +147,6 @@ iir_open(struct cdev *dev, int flags, int fmt, struct thread * p)
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_open()\n"));
#ifdef SDEV_PER_HBA
int minor_no;
struct gdt_softc *gdt;
minor_no = dev2unit(dev);
gdt = gdt_minor2softc(minor_no);
if (gdt == NULL)
return (ENXIO);
#endif
return (0);
}
@ -161,16 +155,6 @@ iir_close(struct cdev *dev, int flags, int fmt, struct thread * p)
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_close()\n"));
#ifdef SDEV_PER_HBA
int minor_no;
struct gdt_softc *gdt;
minor_no = dev2unit(dev);
gdt = gdt_minor2softc(minor_no);
if (gdt == NULL)
return (ENXIO);
#endif
return (0);
}
@ -179,16 +163,6 @@ iir_write(struct cdev *dev, struct uio * uio, int ioflag)
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_write()\n"));
#ifdef SDEV_PER_HBA
int minor_no;
struct gdt_softc *gdt;
minor_no = dev2unit(dev);
gdt = gdt_minor2softc(minor_no);
if (gdt == NULL)
return (ENXIO);
#endif
return (0);
}
@ -197,16 +171,6 @@ iir_read(struct cdev *dev, struct uio * uio, int ioflag)
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_read()\n"));
#ifdef SDEV_PER_HBA
int minor_no;
struct gdt_softc *gdt;
minor_no = dev2unit(dev);
gdt = gdt_minor2softc(minor_no);
if (gdt == NULL)
return (ENXIO);
#endif
return (0);
}
@ -221,15 +185,6 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_ioctl() cmd 0x%lx\n",cmd));
#ifdef SDEV_PER_HBA
int minor_no;
struct gdt_softc *gdt;
minor_no = dev2unit(dev);
gdt = gdt_minor2softc(minor_no);
if (gdt == NULL)
return (ENXIO);
#endif
++gdt_stat.io_count_act;
if (gdt_stat.io_count_act > gdt_stat.io_count_max)
gdt_stat.io_count_max = gdt_stat.io_count_act;
@ -239,19 +194,19 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
{
gdt_ucmd_t *ucmd;
struct gdt_softc *gdt;
int lock;
ucmd = (gdt_ucmd_t *)cmdarg;
gdt = gdt_minor2softc(ucmd->io_node);
gdt = gdt_minor2softc(dev, ucmd->io_node);
if (gdt == NULL)
return (ENXIO);
lock = splcam();
mtx_lock(&gdt->sc_lock);
TAILQ_INSERT_TAIL(&gdt->sc_ucmd_queue, ucmd, links);
ucmd->complete_flag = FALSE;
splx(lock);
gdt_next(gdt);
if (!ucmd->complete_flag)
(void) tsleep((void *)ucmd, PCATCH | PRIBIO, "iirucw", 0);
(void) mtx_sleep(ucmd, &gdt->sc_lock, PCATCH | PRIBIO, "iirucw",
0);
mtx_unlock(&gdt->sc_lock);
break;
}
@ -268,7 +223,7 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
struct gdt_softc *gdt;
p = (gdt_ctrt_t *)cmdarg;
gdt = gdt_minor2softc(p->io_node);
gdt = gdt_minor2softc(dev, p->io_node);
if (gdt == NULL)
return (ENXIO);
/* only RP controllers */
@ -298,15 +253,9 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
p = (gdt_osv_t *)cmdarg;
p->oscode = 10;
p->version = osrelease[0] - '0';
if (osrelease[1] == '.')
p->subversion = osrelease[2] - '0';
else
p->subversion = 0;
if (osrelease[3] == '.')
p->revision = osrelease[4] - '0';
else
p->revision = 0;
p->version = osreldate / 100000;
p->subversion = osreldate / 1000 % 100;
p->revision = 0;
strcpy(p->name, ostype);
break;
}
@ -318,7 +267,6 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
case GDT_IOCTL_EVENT:
{
gdt_event_t *p;
int lock;
p = (gdt_event_t *)cmdarg;
if (p->erase == 0xff) {
@ -330,14 +278,10 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.sync);
else
p->dvr.event_data.size = sizeof(p->dvr.event_data.eu.async);
lock = splcam();
gdt_store_event(p->dvr.event_source, p->dvr.event_idx,
&p->dvr.event_data);
splx(lock);
} else if (p->erase == 0xfe) {
lock = splcam();
gdt_clear_events();
splx(lock);
} else if (p->erase == 0) {
p->handle = gdt_read_event(p->handle, &p->dvr);
} else {
@ -362,18 +306,3 @@ iir_ioctl(struct cdev *dev, u_long cmd, caddr_t cmdarg, int flags, struct thread
--gdt_stat.io_count_act;
return (0);
}
/*
static void
iir_drvinit(void *unused)
{
GDT_DPRINTF(GDT_D_DEBUG, ("iir_drvinit()\n"));
if (!iir_devsw_installed) {
cdevsw_add(&iir_cdevsw);
iir_devsw_installed = 1;
}
}
SYSINIT(iir_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, iir_drvinit, NULL)
*/

View File

@ -183,15 +183,18 @@ static int
iir_pci_attach(device_t dev)
{
struct gdt_softc *gdt;
struct resource *io = NULL, *irq = NULL;
struct resource *irq = NULL;
int retries, rid, error = 0;
void *ih;
u_int8_t protocol;
gdt = device_get_softc(dev);
mtx_init(&gdt->sc_lock, "iir", NULL, MTX_DEF);
/* map DPMEM */
rid = PCI_DPMEM;
io = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (io == NULL) {
gdt->sc_dpmem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
if (gdt->sc_dpmem == NULL) {
device_printf(dev, "can't allocate register resources\n");
error = ENOMEM;
goto err;
@ -207,12 +210,8 @@ iir_pci_attach(device_t dev)
goto err;
}
gdt = device_get_softc(dev);
gdt->sc_devnode = dev;
gdt->sc_init_level = 0;
gdt->sc_dpmemt = rman_get_bustag(io);
gdt->sc_dpmemh = rman_get_bushandle(io);
gdt->sc_dpmembase = rman_get_start(io);
gdt->sc_hanum = device_get_unit(dev);
gdt->sc_bus = pci_get_bus(dev);
gdt->sc_slot = pci_get_slot(dev);
@ -227,85 +226,70 @@ iir_pci_attach(device_t dev)
/* initialize RP controller */
/* check and reset interface area */
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC,
htole32(GDT_MPR_MAGIC));
if (bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC) !=
htole32(GDT_MPR_MAGIC)) {
printf("cannot access DPMEM at 0x%jx (shadowed?)\n",
(uintmax_t)gdt->sc_dpmembase);
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC, htole32(GDT_MPR_MAGIC));
if (bus_read_4(gdt->sc_dpmem, GDT_MPR_IC) != htole32(GDT_MPR_MAGIC)) {
device_printf(dev, "cannot access DPMEM at 0x%lx (shadowed?)\n",
rman_get_start(gdt->sc_dpmem));
error = ENXIO;
goto err;
}
bus_space_set_region_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_I960_SZ, htole32(0),
GDT_MPR_SZ >> 2);
bus_set_region_4(gdt->sc_dpmem, GDT_I960_SZ, htole32(0), GDT_MPR_SZ >> 2);
/* Disable everything */
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_EDOOR_EN,
bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_EDOOR_EN) | 4);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_EDOOR, 0xff);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_STATUS,
0);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_CMD_INDEX,
0);
bus_write_1(gdt->sc_dpmem, GDT_EDOOR_EN,
bus_read_1(gdt->sc_dpmem, GDT_EDOOR_EN) | 4);
bus_write_1(gdt->sc_dpmem, GDT_MPR_EDOOR, 0xff);
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_STATUS, 0);
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_CMD_INDEX, 0);
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_INFO,
htole32(gdt->sc_dpmembase));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_CMD_INDX,
0xff);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_LDOOR, 1);
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_INFO,
htole32(rman_get_start(gdt->sc_dpmem)));
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_CMD_INDX, 0xff);
bus_write_1(gdt->sc_dpmem, GDT_MPR_LDOOR, 1);
DELAY(20);
retries = GDT_RETRIES;
while (bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_STATUS) != 0xff) {
while (bus_read_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_STATUS) != 0xff) {
if (--retries == 0) {
printf("DEINIT failed\n");
device_printf(dev, "DEINIT failed\n");
error = ENXIO;
goto err;
}
DELAY(1);
}
protocol = (uint8_t)le32toh(bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_INFO));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_STATUS,
0);
protocol = (uint8_t)le32toh(bus_read_4(gdt->sc_dpmem,
GDT_MPR_IC + GDT_S_INFO));
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_STATUS, 0);
if (protocol != GDT_PROTOCOL_VERSION) {
printf("unsupported protocol %d\n", protocol);
device_printf(dev, "unsupported protocol %d\n", protocol);
error = ENXIO;
goto err;
}
/* special commnd to controller BIOS */
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_INFO,
htole32(0));
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_INFO + sizeof (u_int32_t), htole32(0));
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_INFO + 2 * sizeof (u_int32_t),
htole32(1));
bus_space_write_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_INFO + 3 * sizeof (u_int32_t),
htole32(0));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_CMD_INDX,
0xfe);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_LDOOR, 1);
/* special command to controller BIOS */
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_INFO, htole32(0));
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_INFO + sizeof (u_int32_t),
htole32(0));
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_INFO + 2 * sizeof (u_int32_t),
htole32(1));
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_INFO + 3 * sizeof (u_int32_t),
htole32(0));
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_CMD_INDX, 0xfe);
bus_write_1(gdt->sc_dpmem, GDT_MPR_LDOOR, 1);
DELAY(20);
retries = GDT_RETRIES;
while (bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_S_STATUS) != 0xfe) {
while (bus_read_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_STATUS) != 0xfe) {
if (--retries == 0) {
printf("initialization error\n");
device_printf(dev, "initialization error\n");
error = ENXIO;
goto err;
}
DELAY(1);
}
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_IC + GDT_S_STATUS,
0);
bus_write_1(gdt->sc_dpmem, GDT_MPR_IC + GDT_S_STATUS, 0);
gdt->sc_ic_all_size = GDT_MPR_SZ;
@ -326,7 +310,7 @@ iir_pci_attach(device_t dev)
/*nsegments*/GDT_MAXSG,
/*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
/*lockarg*/&Giant, &gdt->sc_parent_dmat) != 0) {
/*lockarg*/&gdt->sc_lock, &gdt->sc_parent_dmat) != 0) {
error = ENXIO;
goto err;
}
@ -342,7 +326,7 @@ iir_pci_attach(device_t dev)
iir_attach(gdt);
/* associate interrupt handler */
if (bus_setup_intr( dev, irq, INTR_TYPE_CAM,
if (bus_setup_intr(dev, irq, INTR_TYPE_CAM | INTR_MPSAFE,
NULL, iir_intr, gdt, &ih )) {
device_printf(dev, "Unable to register interrupt handler\n");
error = ENXIO;
@ -355,10 +339,11 @@ iir_pci_attach(device_t dev)
err:
if (irq)
bus_release_resource( dev, SYS_RES_IRQ, 0, irq );
/*
if (io)
bus_release_resource( dev, SYS_RES_MEMORY, rid, io );
*/
if (gdt->sc_dpmem)
bus_release_resource( dev, SYS_RES_MEMORY, rid, gdt->sc_dpmem );
mtx_destroy(&gdt->sc_lock);
return (error);
}
@ -371,11 +356,9 @@ gdt_pci_enable_intr(struct gdt_softc *gdt)
switch(GDT_CLASS(gdt)) {
case GDT_MPR:
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_EDOOR, 0xff);
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_EDOOR_EN,
bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_EDOOR_EN) & ~4);
bus_write_1(gdt->sc_dpmem, GDT_MPR_EDOOR, 0xff);
bus_write_1(gdt->sc_dpmem, GDT_EDOOR_EN,
bus_read_1(gdt->sc_dpmem, GDT_EDOOR_EN) & ~4);
break;
}
}
@ -396,15 +379,14 @@ gdt_mpr_copy_cmd(struct gdt_softc *gdt, struct gdt_ccb *gccb)
gdt->sc_cmd_off += cp_count;
bus_space_write_region_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_DPR_CMD + dp_offset,
(u_int32_t *)gccb->gc_cmd, cp_count >> 2);
bus_space_write_2(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_OFFSET,
htole16(GDT_DPMEM_COMMAND_OFFSET + dp_offset));
bus_space_write_2(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_SERV_ID,
htole16(gccb->gc_service));
bus_write_region_4(gdt->sc_dpmem, GDT_MPR_IC + GDT_DPR_CMD + dp_offset,
(u_int32_t *)gccb->gc_cmd, cp_count >> 2);
bus_write_2(gdt->sc_dpmem,
GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_OFFSET,
htole16(GDT_DPMEM_COMMAND_OFFSET + dp_offset));
bus_write_2(gdt->sc_dpmem,
GDT_MPR_IC + GDT_COMM_QUEUE + cmd_no * GDT_COMM_Q_SZ + GDT_SERV_ID,
htole16(gccb->gc_service));
}
u_int8_t
@ -412,7 +394,7 @@ gdt_mpr_get_status(struct gdt_softc *gdt)
{
GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_get_status(%p) ", gdt));
return bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_EDOOR);
return bus_read_1(gdt->sc_dpmem, GDT_MPR_EDOOR);
}
void
@ -422,39 +404,32 @@ gdt_mpr_intr(struct gdt_softc *gdt, struct gdt_intr_ctx *ctx)
GDT_DPRINTF(GDT_D_INTR, ("gdt_mpr_intr(%p) ", gdt));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_EDOOR, 0xff);
bus_write_1(gdt->sc_dpmem, GDT_MPR_EDOOR, 0xff);
if (ctx->istatus & 0x80) { /* error flag */
ctx->istatus &= ~0x80;
ctx->cmd_status = bus_space_read_2(gdt->sc_dpmemt,
gdt->sc_dpmemh, GDT_MPR_STATUS);
ctx->cmd_status = bus_read_2(gdt->sc_dpmem, GDT_MPR_STATUS);
} else /* no error */
ctx->cmd_status = GDT_S_OK;
ctx->info =
bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_INFO);
ctx->service =
bus_space_read_2(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_SERVICE);
ctx->info2 =
bus_space_read_4(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_INFO + sizeof (u_int32_t));
ctx->info = bus_read_4(gdt->sc_dpmem, GDT_MPR_INFO);
ctx->service = bus_read_2(gdt->sc_dpmem, GDT_MPR_SERVICE);
ctx->info2 = bus_read_4(gdt->sc_dpmem, GDT_MPR_INFO + sizeof (u_int32_t));
/* event string */
if (ctx->istatus == GDT_ASYNCINDEX) {
if (ctx->service != GDT_SCREENSERVICE &&
(gdt->sc_fw_vers & 0xff) >= 0x1a) {
gdt->sc_dvr.severity =
bus_space_read_1(gdt->sc_dpmemt,gdt->sc_dpmemh, GDT_SEVERITY);
gdt->sc_dvr.severity = bus_read_1(gdt->sc_dpmem, GDT_SEVERITY);
for (i = 0; i < 256; ++i) {
gdt->sc_dvr.event_string[i] =
bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_EVT_BUF + i);
gdt->sc_dvr.event_string[i] = bus_read_1(gdt->sc_dpmem,
GDT_EVT_BUF + i);
if (gdt->sc_dvr.event_string[i] == 0)
break;
}
}
}
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_SEMA1, 0);
bus_write_1(gdt->sc_dpmem, GDT_MPR_SEMA1, 0);
}
void
@ -462,7 +437,7 @@ gdt_mpr_release_event(struct gdt_softc *gdt)
{
GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_release_event(%p) ", gdt));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_LDOOR, 1);
bus_write_1(gdt->sc_dpmem, GDT_MPR_LDOOR, 1);
}
void
@ -470,7 +445,7 @@ gdt_mpr_set_sema0(struct gdt_softc *gdt)
{
GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_set_sema0(%p) ", gdt));
bus_space_write_1(gdt->sc_dpmemt, gdt->sc_dpmemh, GDT_MPR_SEMA0, 1);
bus_write_1(gdt->sc_dpmem, GDT_MPR_SEMA0, 1);
}
int
@ -478,6 +453,5 @@ gdt_mpr_test_busy(struct gdt_softc *gdt)
{
GDT_DPRINTF(GDT_D_MISC, ("gdt_mpr_test_busy(%p) ", gdt));
return (bus_space_read_1(gdt->sc_dpmemt, gdt->sc_dpmemh,
GDT_MPR_SEMA0) & 1);
return (bus_read_1(gdt->sc_dpmem, GDT_MPR_SEMA0) & 1);
}