📄 gscdd.c
字号:
static intgsc_ioctl(dev_t dev, int cmd, void *arg, ulong dflag){ switch (cmd) { case GSC_CMD: return (gsccmd(dev, arg, dflag)); case GSC_SETDBG: { int i; cmd = copyin(arg, (caddr_t) &i, sizeof (int)); if (cmd != 0) { return (cmd); } cmd = scudebug; scudebug = i; return (copyout((caddr_t) &cmd, arg, sizeof (int))); } default: return (ENOTTY); }}/****************************************************************************/static intgsccmd(dev_t dev, scmd_t *argcmd, ulong dflag){ gsc_softc_t *sp; scmd_t local, *l; char sbyte, albits; struct sc_buf *usc; struct buf *Ubp; int r, r2, ival, upin, unit, rqvalid, once; unit = minor(dev); Trace2(1, "%d: cmd for unit %d", __LINE__, minor(dev)); if (unit < 0 || unit >= MAX_UNITS) { setuerror(ENXIO); return (ENXIO); } sp = &softinfo[unit]; if (sp->iscfg == 0 || sp->fp == NULL) { Trace2(0, "gsccmd: bad unit %d (cfg=%d)", unit, sp->iscfg); r = ENODEV; setuerror(r); return (r); } simple_lock(&sp->dd_lock); l = &local; if (dflag & DKERNEL) { l = argcmd; } else { r = copyin((caddr_t) argcmd, (caddr_t) l, sizeof (scmd_t)); if (r != 0) { Trace2(0, "%d: copyin=%d", __LINE__, r); setuerror(r); MJ_RTN (r); } } Trace6(1, "%d: cdblen%d datalen%d snslen%d rw=%d tv=%d", __LINE__, l->cdblen, l->datalen, l->senselen, l->rw, l->timeval); sbyte = 0; rqvalid = upin = r = r2 = 0; usc = &sp->cmdbuf; Ubp = &usc->bufstruct; memset(usc, 0, sizeof (struct sc_buf)); /* * Check some parameters... */ if (l->cdblen > sizeof (struct sc_cmd)) { r = EINVAL; goto out; } /* * Setup sc_buf structure */ Ubp->b_iodone = gscdd_intr; Ubp->b_dev = sp->dev; Ubp->b_flags = B_BUSY | B_MPSAFE; Ubp->b_resid = Ubp->b_bcount = l->datalen; Ubp->b_xmemd.aspace_id = XMEM_INVAL; Ubp->b_event = EVENT_NULL; if (l->datalen) { Ubp->b_un.b_addr = l->data_buf; if (l->rw) { Ubp->b_flags |= B_READ; } if (dflag & DKERNEL) { r = pinu(l->data_buf, l->datalen, UIO_SYSSPACE); } else { r = pinu(l->data_buf, l->datalen, UIO_USERSPACE); } if (r) { Trace2(0, "%d: pinu buf %d", __LINE__, r); goto out; } upin++; if (dflag & DKERNEL) { r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, SYS_ADSPACE); } else { r = xmattach(l->data_buf, l->datalen, &Ubp->b_xmemd, USER_ADSPACE); } if (r != XMEM_SUCC) { Trace2(0, "%d: xmattach %d", __LINE__, r); r = EFAULT; goto out; } upin++; r = xmemdma(&Ubp->b_xmemd, l->data_buf, XMEM_UNHIDE); if (r == XMEM_FAIL) { Trace2(0, "%d: xmemdma %d", __LINE__, r); r = EFAULT; goto out; } r = 0; } usc->scsi_command.scsi_id = sp->tgt; usc->scsi_command.scsi_length = l->cdblen; if (dflag & DKERNEL) { bcopy(l->cdb, (caddr_t)&usc->scsi_command.scsi_cmd, l->cdblen); } else { r = copyin(l->cdb, (caddr_t) & usc->scsi_command.scsi_cmd, l->cdblen); if (r != 0) { goto out; } } /* Setting lun in SCSI CDB as well as sc_buf structure */ usc->lun = sp->lun; usc->scsi_command.scsi_cmd.lun &= 0x1F; usc->scsi_command.scsi_cmd.lun |= (sp->lun << 5) & 0xE0; albits = usc->scsi_command.scsi_cmd.lun; usc->timeout_value = l->timeval; if (sp->needresume) { usc->flags |= SC_RESUME; sp->needresume = 0; } if (scudebug > 1) { char *c = (char *) &usc->scsi_command.scsi_cmd; char cdbuf[64]; (void) sprintf(cdbuf, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x " "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11]); Trace2(0, "%d: cdb=%s", __LINE__, cdbuf); } once = 0;again: Ubp->b_flags &= ~B_DONE; r = devstrat(Ubp); if (r == 0) { ival = disable_lock(INTCLASS1, &sp->buf_lock); while ((Ubp->b_flags & B_DONE) == 0) { e_sleep_thread(&Ubp->b_event, &sp->buf_lock, LOCK_HANDLER); } unlock_enable(ival, &sp->buf_lock); } else { /* * If ENXIO, We never actually got started. */ if (r == ENXIO && once == 0) { once++; usc->flags |= SC_RESUME|SC_DELAY_CMD; goto again; } sp->needresume = 1; Trace2(1, "%d: devstrat=%d", __LINE__, r); goto out; } Trace4(1, "%d: b_flags %x b_error %d b_resid %d", __LINE__, Ubp->b_flags, Ubp->b_error, Ubp->b_resid); Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__, usc->status_validity, usc->scsi_status, usc->general_card_status, usc->adap_q_status); if (Ubp->b_flags & B_ERROR) { r = Ubp->b_error; sp->needresume = 1; } if (usc->status_validity & SC_SCSI_ERROR) { sbyte = (usc->scsi_status & SCSI_STATUS_MASK); sp->needresume = 1; if (sbyte == SC_CHECK_CONDITION && l->senselen) { struct sc_buf *usl; struct buf *Sbp; r = make_rqs(sp, albits, l->sense_buf, l->senselen, (dflag & DKERNEL) != 0); if (r) { Trace2(0, "%d: make_rqs=%d", __LINE__, r); goto out; } usl = &sp->rqsbuf; Sbp = &usl->bufstruct; r = devstrat(Sbp); if (r == 0) { ival = disable_lock(INTCLASS1, &sp->buf_lock); while ((Sbp->b_flags & B_DONE) == 0) { e_sleep_thread(&Sbp->b_event, &sp->buf_lock, LOCK_HANDLER); } unlock_enable(ival, &sp->buf_lock); } else { Trace2(0, "%d:ds=%d for rqs", __LINE__, r); goto out; } xmdetach(&Sbp->b_xmemd); if (dflag & DKERNEL) { (void) unpinu(l->sense_buf, l->senselen, UIO_SYSSPACE); } else { (void) unpinu(l->sense_buf, l->senselen, UIO_USERSPACE); } Trace4(1, "%d SENSE: b_flags %x b_error %d b_resid %d", __LINE__, Sbp->b_flags, Sbp->b_error, Sbp->b_resid); Trace5(1, "%d: sv %x st %x gc %x as %x", __LINE__, usl->status_validity, usl->scsi_status, usl->general_card_status, usl->adap_q_status); if (usl->scsi_status || usl->general_card_status) { r = EIO; } else { rqvalid = 1; } } } if (usc->status_validity & SC_ADAPTER_ERROR) { sp->needresume = 1; Trace2(0, "%d: adapter error 0x%x", __LINE__, usc->general_card_status); Ubp->b_flags |= B_ERROR; switch (usc->general_card_status) { case SC_NO_DEVICE_RESPONSE: case SC_HOST_IO_BUS_ERR: case SC_SCSI_BUS_FAULT: case SC_CMD_TIMEOUT: case SC_ADAPTER_HDW_FAILURE: case SC_ADAPTER_SFW_FAILURE: case SC_FUSE_OR_TERMINAL_PWR: case SC_SCSI_BUS_RESET: default: r = EIO; break; } } /* * Log errors through errsave function */ if (usc->status_validity & (SC_SCSI_ERROR|SC_ADAPTER_ERROR)) { struct sc_error_log_df log; memset(&log, 0, sizeof (log)); /* * All errors are 'temporary unknown driver error' */ log.error_id = ERRID_SCSI_ERR6; (void) sprintf(log.resource_name, "gsc%d", unit); memcpy(&log.scsi_command, &usc->scsi_command, sizeof (struct scsi)); log.status_validity = usc->status_validity; log.scsi_status = usc->scsi_status; log.general_card_status = usc->general_card_status; if (rqvalid) { int amt; if (l->senselen > 128) amt = 128; else amt = l->senselen; (void) copyin(l->sense_buf, log.req_sense_data, amt); } errsave(&log, sizeof (struct sc_error_log_df)); } if (dflag & DKERNEL) { *l->statusp = sbyte; } else { r2 = copyout(&sbyte, l->statusp, 1); if (r2 != 0) { if (r == 0) r = r2; goto out; } }out: if (l->datalen) { if (upin > 1) { xmdetach(&Ubp->b_xmemd); upin--; } if (upin > 0) { if (dflag & DKERNEL) { (void) unpinu(l->data_buf, l->datalen, UIO_SYSSPACE); } else { (void) unpinu(l->data_buf, l->datalen, UIO_USERSPACE); } upin--; } } Trace2(1, "%d: returning %d", __LINE__, r); if (r) setuerror(r); MJ_RTN (r);}static intmake_rqs(gsc_softc_t * sp, char albits, char *uaddr, int ulen, int isk){ struct sc_buf *usl; struct buf *Sbp; int err, upin; if (ulen > 255) ulen = 255; upin = err = 0; usl = &sp->rqsbuf; Sbp = &usl->bufstruct; memset(usl, 0, sizeof (struct sc_buf)); Sbp->b_un.b_addr = uaddr; Sbp->b_resid = Sbp->b_bcount = ulen; Sbp->b_iodone = gscdd_intr; Sbp->b_dev = sp->dev; Sbp->b_flags = B_BUSY | B_READ | B_MPSAFE; Sbp->b_event = EVENT_NULL; Sbp->b_xmemd.aspace_id = XMEM_INVAL; if (isk) err = pinu(uaddr, ulen, UIO_SYSSPACE); else err = pinu(uaddr, ulen, UIO_USERSPACE); if (err) goto out; upin++; if (isk) err = xmattach(uaddr, ulen, &Sbp->b_xmemd, SYS_ADSPACE); else err = xmattach(uaddr, ulen, &Sbp->b_xmemd, USER_ADSPACE); if (err != XMEM_SUCC) { err = EFAULT; goto out; } upin++; err = xmemdma(&Sbp->b_xmemd, Sbp->b_un.b_addr, XMEM_UNHIDE); if (err == XMEM_FAIL) { err = EFAULT; (void) xmdetach(&Sbp->b_xmemd); goto out; } err = 0; usl->lun = sp->lun; /* Setting lun in sc_buf structure */ usl->scsi_command.scsi_id = sp->tgt; usl->scsi_command.scsi_length = 6; usl->scsi_command.scsi_cmd.scsi_op_code = 0x3; usl->scsi_command.scsi_cmd.lun = albits & 0xE0; /*ONLY copy the lun bits*/ usl->scsi_command.scsi_cmd.scsi_bytes[2] = ulen; usl->timeout_value = 2; usl->flags = SC_RESUME; sp->needresume = 0; out: if (err) { if (upin > 1) { xmdetach(&Sbp->b_xmemd); upin--; } if (upin > 0) { if (isk) (void) unpinu(uaddr, ulen, UIO_SYSSPACE); else (void) unpinu(uaddr, ulen, UIO_USERSPACE); upin--; } } return (err);}voidgscdd_intr(struct buf * bp){ int lv; gsc_softc_t *sp = &softinfo[((gsc_buf_t *)bp)->index]; lv = disable_lock(INTIODONE, &sp->buf_lock); bp->b_flags |= B_DONE; unlock_enable(lv, &sp->buf_lock); e_wakeup(&bp->b_event);}/* * mode: c * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -