/* Test if the drive is ready */ status_t scsi_test_ready( SCSI_device_s * psDevice ) { SCSI_cmd_s sCmd; int nError; retry: nError = 0; /* Try to test the state of the unit */ scsi_init_cmd( &sCmd, psDevice ); sCmd.nCmd[0] = SCSI_TEST_UNIT_READY; if( psDevice->nSCSILevel <= SCSI_2 ) sCmd.nCmd[1] = ( psDevice->nLun << 5 ) & 0xe0; sCmd.nCmdLen = scsi_get_command_size( SCSI_TEST_UNIT_READY ); /* Send command */ nError = psDevice->psHost->queue_command( &sCmd ); if( sCmd.s.sSense.sense_key != SCSI_NO_SENSE || sCmd.nResult != 0 ) { SCSI_sense_s sSense; nError = scsi_request_sense( psDevice, &sSense ); if( nError < 0 ) { kerndbg( KERN_PANIC, "Unable to request sense data from SCSI device, aborting.\n" ); return -EIO; } nError = scsi_check_sense( psDevice, &sSense, false ); switch ( nError ) { case SENSE_OK: break; case SENSE_RETRY: goto retry; case SENSE_FATAL: { kerndbg( KERN_PANIC, "SCSI device reporting fatal error, aborting.\n" ); return -EIO; } } } kerndbg( KERN_DEBUG, "scsi_test_ready(): Device ready\n" ); return 0; }
int scsi_test_unit_ready(struct scsi_request *srb, struct scsi_transport *tr, void *priv) { int rc = VMM_EFAIL, retries = 10; unsigned char *data; unsigned long datalen; if (!srb || !tr || !tr->transport) { return VMM_EINVALID; } data = srb->data; datalen = srb->datalen; do { memset(&srb->cmd, 0, sizeof(srb->cmd)); srb->cmd[0] = SCSI_TST_U_RDY; srb->cmd[1] = srb->lun << 5; srb->data = NULL; srb->datalen = 0; srb->cmdlen = 12; rc = tr->transport(srb, tr, priv); if (rc == VMM_OK) { break; } rc = scsi_request_sense(srb, tr, priv); if (rc != VMM_OK) { return rc; } /* * Check the Key Code Qualifier, if it matches * "Not Ready - medium not present" * (the sense Key equals 0x2 and the ASC is 0x3a) * return immediately as the medium being absent won't change * unless there is a user action. */ if ((srb->sense_buf[2] == 0x02) && (srb->sense_buf[12] == 0x3a)) { rc = VMM_ENODEV; break; } vmm_mdelay(100); rc = VMM_EFAIL; } while (retries--); srb->data = data; srb->datalen = datalen; return rc; }
/* * Analyze the IE mode sense page explicitly. This is only needed if the IE log * page is not supported. */ static int analyze_ie_sense(ds_scsi_info_t *sip) { uint_t skey, asc, ascq; nvlist_t *nvl; /* * Don't bother checking if we weren't able to set our MRIE correctly. */ if (sip->si_iec_current.ie_mrie != IE_REPORT_ON_REQUEST) return (0); if (scsi_request_sense(sip, &skey, &asc, &ascq) != 0) { printf("failed to request IE page (KEY=0x%x ASC=0x%x " "ASCQ=0x%x)\n", skey, asc, ascq); return (scsi_set_errno(sip, EDS_IO)); } else if (skey == KEY_NO_SENSE) { assert(sip->si_dsp->ds_predfail == NULL); if (nvlist_alloc(&sip->si_dsp->ds_predfail, NV_UNIQUE_NAME, 0) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); nvl = sip->si_dsp->ds_predfail; if (nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASC, asc) != 0 || nvlist_add_uint8(nvl, FM_EREPORT_PAYLOAD_SCSI_ASCQ, ascq) != 0) { nvlist_free(nvl); return (scsi_set_errno(sip, EDS_NOMEM)); } if (asc != 0) sip->si_dsp->ds_faults |= DS_FAULT_PREDFAIL; } return (0); }
int scsi(int argc, char *argv[]) { char *p; int i, status; if (argc < 2) { printf("This command is required subcommand !!\n"); return ST_ERROR; } if (!strcmp(argv[1], "device")) { if (argc > 2) { i = 0; for (p = argv[2]; *p != '\0' ; p++) { i = i * 10 + *p - '0'; } if ( i < 8 && i >= 0) { scsi_device = i; } } printf("Current Device ID: %d\n", scsi_device); } else if (!strcmp(argv[1], "test_unit_rdy")) { /* CTLR SLAVE LUN */ scsi_test_unit_rdy( 0, scsi_device, 0); } else if (!strcmp(argv[1], "request_sense")) { /* CTLR SLAVE LUN */ scsi_request_sense( 0, scsi_device, 0, sensbuff, SENSBUFF); } else if (!strcmp(argv[1], "inquiry")) { if (scsi_immed_command( 0, scsi_device, 0, &inquiry, (u_char *)&inquirybuf, sizeof(inquirybuf)) == 0) { printf("Type:\t0x%x\n", inquirybuf.type); printf("Qualifier:\t0x%x\n", inquirybuf.qual); printf("Version:\t0x%x\n", inquirybuf.version); printf("RDF:\t0x%x\n", inquirybuf.rsvd); printf("Vender ID:\t"); for (i = 0; i < 8; i++) printf("%c", inquirybuf.vendor_id[i]); printf("\n"); printf("Product ID:\t"); for (i = 0; i < 16; i++) printf("%c", inquirybuf.product_id[i]); printf("\n"); printf("Revision:\t"); for (i = 0; i < 4; i++) printf("%c", inquirybuf.rev[i]); printf("\n"); } } else if (!strcmp(argv[1], "read_capacity")) { if (scsi_immed_command( 0, scsi_device, 0, &capacity, (u_char *)&capacitybuf, sizeof(capacitybuf)) == 0) { printf("Logical Block Address:\t%ld (0x%lx)\n", capacitybuf[0], capacitybuf[0]); printf("Block Length:\t\t%ld (0x%lx)\n", capacitybuf[1], capacitybuf[1]); } } else if (!strcmp(argv[1], "trace")) { for (i = 0; i < 7; i++) { printf("SCSI ID %d .... ", i); status = scsi_test_unit_rdy( 0, i, 0); if (status >= 0) printf("found.\n"); else printf("no.\n"); } } else if (!strcmp(argv[1], "format_unit")) { i = 0; while (i == 0) { printf("Do you really want to format SCSI %d device ?" " [y/n]: ", scsi_device); i = getchar(); printf("\n"); if ((i != 'y') && (i != 'Y') && (i != 'n') && (i != 'N')) i = 0; } if ((i == 'y') || (i == 'Y')) status = scsi_format_unit( 0, scsi_device, 0); } return ST_NORMAL; }
/* Read capacity of the drive */ status_t scsi_read_capacity( SCSI_device_s * psDevice, unsigned long *pnCapacity ) { int nError; struct { uint32 lba; uint32 blocklen; } sCap; SCSI_cmd_s sCmd; retry: nError = 0; scsi_init_cmd( &sCmd, psDevice ); sCmd.nDirection = SCSI_DATA_READ; sCmd.pRequestBuffer = (void*)&sCap; sCmd.nRequestSize = sizeof( sCap ); sCmd.nCmd[0] = SCSI_READ_CAPACITY; sCmd.nCmd[1] = ( psDevice->nLun << 5 ) & 0xe0; sCmd.nCmdLen = scsi_get_command_size( SCSI_READ_CAPACITY ); /* Send command */ nError = psDevice->psHost->queue_command( &sCmd ); if( sCmd.s.sSense.sense_key != SCSI_NO_SENSE || sCmd.nResult != 0 ) { SCSI_sense_s sSense; nError = scsi_request_sense( psDevice, &sSense ); if( nError < 0 ) { kerndbg( KERN_PANIC, "Unable to request sense data from SCSI device, aborting.\n" ); goto error; } nError = scsi_check_sense( psDevice, &sSense, false ); switch ( nError ) { case SENSE_OK: break; case SENSE_RETRY: goto retry; case SENSE_FATAL: { kerndbg( KERN_PANIC, "SCSI device reporting fatal error, aborting.\n" ); goto error; } } } psDevice->nSectorSize = be32_to_cpu( sCap.blocklen ); if( psDevice->nSectorSize > 2048 ) psDevice->nSectorSize = 2048; psDevice->nSectors = 1 + be32_to_cpu( sCap.lba ); psDevice->nSize = psDevice->nSectors * psDevice->nSectorSize; if( pnCapacity != NULL ) *pnCapacity = psDevice->nSize; kerndbg( KERN_DEBUG, "scsi_read_capacity(): %d bytes\n", psDevice->nSize ); return 0; error: psDevice->nSectors = 0; psDevice->nSectorSize = 0; psDevice->nSize = 0; if( pnCapacity != NULL ) *pnCapacity = psDevice->nSize; return -EIO; }
DiscDCB *DevOpen(Device *dev, DiscDevInfo * info) { DiscDCB *dcb; DriveInfo *dvi; WORD command_status; BYTE sense_data[SENSE_LENGTH]; /* Create a DiscDCB for File System Server */ if ((dcb = Malloc(sizeof(DiscDCB))) == NULL) { IOdebug("File System driver failed to allocate work space"); return(NULL); } dvi = (DriveInfo *)RTOA(info->Drives); /* Initialise controlling link to the HE1000 */ if(( dcb->Table = HE1000_init( info->Controller, dvi->DriveId , info->Mode)) < 0) { IOdebug("File System driver failed to initialise HE1000"); return(NULL); } /* Initialise DiscDCB with drive information */ dcb->DeviceId = dvi->DriveId; dcb->SectorSize = dvi->SectorSize; dcb->DCB.Device = dev; dcb->DCB.Operate = DevOperate; dcb->DCB.Close = DevClose; dcb->Link = info->Controller; dcb->BlockSize = info->Addressing; dcb->SectorsPerTrack = dvi->SectorsPerTrack; dcb->TracksPerCyl = dvi->TracksPerCyl; dcb->Cylinders = dvi->Cylinders; dcb->Mode = info->Mode; scsi_start_stop( dcb->Link, dcb->Table, dcb->DeviceId, 0, 1, /* place head on track 0 */ &command_status); /* Test disc for ready */ do { scsi_test_unit_ready( dcb->Link, dcb->Table, dcb->DeviceId, 0, &command_status); if( command_status eq CHECK_SENSE ) { scsi_request_sense( dcb->Link, dcb->Table, dcb->DeviceId, 0, SENSE_LENGTH, sense_data, &command_status); } } while ( command_status ne 0 ); /* Initialise the access locking semaphore */ InitSemaphore(&dcb->Lock, 1); /* return DiscDCB */ return(dcb); }
void DevOperate(DiscDCB *dcb, DiscReq *req) { BYTE capacity_data[CAPACITY_LENGTH]; WORD command_status,second_status; WORD block_addr, block_len; WORD done = 0; WORD size; BYTE *buf = req->Buf; INT res; BYTE sense_data[SENSE_LENGTH]; FormatReq *freq; Wait(&dcb->Lock); /* Select the appropriate command */ switch( req->DevReq.Request & FG_Mask) { case FG_Read: #ifdef DEBUG IOdebug("read pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize); #endif size = req->Size; while( done < size ) { WORD tfr = size - done; WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize); command_status = 8;/* make loop happen once*/ if ( tfr > MAX_TFR ) { tfr = MAX_TFR; } while (command_status == 8) { res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status); } if ( ( res < 0 ) || ( command_status ne 0 )) { command_status = 8; while (command_status == 8) { res = scsi_read(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status); } } done += tfr; buf += tfr; } req->DevReq.Result = command_status; if ( req->DevReq.Result eq 0 ) req->Actual = req->Size; else req->Actual = 0; break; case FG_Write: #ifdef DEBUG IOdebug("write pos = %d size = %d",req->Pos / dcb->SectorSize,req->Size / dcb->SectorSize); #endif size = req->Size; while( done < size ) { WORD tfr = size - done; WORD position = (req->Pos / dcb->SectorSize) + (done/dcb->SectorSize); command_status = 8; /* make loop happen once*/ if ( tfr > MAX_TFR ) { tfr = MAX_TFR; } while (command_status == 8) { res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status); } if ( ( res < 0 ) || ( command_status ne 0 )) { command_status = 8; while (command_status == 8) { res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,position,tfr,dcb->SectorSize,buf,&command_status); } } done += tfr; buf += tfr; } req->DevReq.Result = command_status; if ( req->DevReq.Result eq 0 ) req->Actual = req->Size; else req->Actual = 0; break; case FG_GetSize: #ifdef DEBUG IOdebug("read capacity request"); #endif command_status = 8; while (command_status == 8) { scsi_read_capacity( dcb->Link, dcb->Table, dcb->DeviceId, 0, /* lun */ 8, /* capacity length */ capacity_data, &command_status); } if ( command_status eq 0 ) { block_addr = capacity_data[0] * 0x1000000 + capacity_data[1] * 0x10000 + capacity_data[2] * 0x100 + capacity_data[3]; block_len = capacity_data[4] * 0x1000000 + capacity_data[5] * 0x10000 + capacity_data[6] * 0x100 + capacity_data[7]; req->DevReq.Result = block_addr * block_len; } break; case FG_Format: IOdebug("\rFormatting disk please wait ...."); freq = (FormatReq *)req; command_status = 8;/* so the loop happens once*/ while (command_status == 8) { scsi_mode_select( dcb->Link, dcb->Table, dcb->DeviceId, 0, 0, /* format whole disk */ dcb->SectorSize, &command_status); } command_status = 8;/* so the loop happens once*/ while (command_status == 8) { scsi_format( dcb->Link, dcb->Table, dcb->DeviceId, 0, freq->Interleave, &command_status); } /* If the disk supports the busy status we need to wait until busy goes away before giving the message that we are verifying */ command_status = 8; while (command_status == 8) { scsi_test_unit_ready( dcb->Link, dcb->Table, dcb->DeviceId, 0, &command_status); } /* some disks will queue one command so we need to wait twice to cope with this */ command_status = 8; while (command_status != 0) { IOdebug("status = %d",command_status); scsi_test_unit_ready( dcb->Link, dcb->Table, dcb->DeviceId, 0, &command_status); scsi_request_sense( dcb->Link, dcb->Table, dcb->DeviceId, 0, SENSE_LENGTH, sense_data, &command_status); IOdebug("sense =%x",sense_data[2]); } { WORD total_blocks; WORD i,j; WORD ten_cent,done = 0; BYTE *data; IOdebug("\rVerifying disk please wait ...."); data = Malloc(dcb->SectorSize); command_status = 8; /* do at least once*/ while (command_status == 8 ) { res = scsi_write(dcb->Link,dcb->Table,dcb->DeviceId,0,1,dcb->SectorSize,dcb->SectorSize,data,&command_status); } total_blocks = (dcb->SectorsPerTrack * dcb->TracksPerCyl * dcb->Cylinders); /* IOdebug("\rdisk size is %d blocks",total_blocks);*/ ten_cent = total_blocks / 10; for ( i = 1; i < total_blocks; i++) { command_status = 8; /* you know by now*/ while (command_status == 8) { res = scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status); } second_status = 8; while (second_status == 8) { res = scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status); } if (( i % ten_cent ) eq 0) { done += 10; IOdebug("\rVerified %d percent of disk\v",done); } if ((command_status ne 0) || (second_status ne 0)) { command_status = 8; while (command_status == 8 ) { scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status); } second_status = 8; while (second_status == 8) { scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status); } if (( command_status ne 0 ) || (second_status ne 0)) { IOdebug("Verifier found bad block at %d",i); for( j = 0; j < 10; j++) { command_status = 8; while (command_status == 8) { scsi_reassign_block(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status); } command_status = 8; while (command_status == 8) { scsi_write_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&command_status); } second_status = 8; while (second_status == 8) { scsi_read_quick(dcb->Link,dcb->Table,dcb->DeviceId,0,i,&second_status); } if ((command_status eq 0) && (second_status eq 0))break; } if (( command_status eq 0 ) && (second_status eq 0)) IOdebug("Block %d reassigned OK",i); else IOdebug("Failed to reassign block %d",i); } } } } IOdebug("Verification complete "); req->DevReq.Result = 0; break; default: break; } /* Unlock the driver */ Signal(&dcb->Lock); /* Client action */ (*req->DevReq.Action)(req); return; }
static int siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs) { void *xfer = adp->xfer; int timo, error; if (adp->sel_t != xs->target) { const int free_lo = __arraycount(siop_script); int i; void *scriptaddr = (void *)local_to_PCI((u_long)adp->script); if (adp->sel_t != -1) adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] = htoc32(0x800c00ff); for (i = 0; i < __arraycount(lun_switch); i++) adp->script[free_lo + i] = htoc32(lun_switch[i]); adp->script[free_lo + E_abs_lunsw_return_Used[0]] = htoc32(scriptaddr + Ent_lunsw_return); siop_add_reselsw(adp, xs->target, free_lo); adp->sel_t = xs->target; } restart: siop_setuptables(adp, xfer, xs); /* load the DMA maps */ if (xs->datalen != 0) _inv((u_long)xs->data, xs->datalen); _wbinv((u_long)xs->cmd, xs->cmdlen); _wbinv((u_long)xfer, sizeof(struct siop_xfer)); siop_start(adp, xs); adp->xs = xs; timo = 0; while (!(xs->xs_status & XS_STS_DONE)) { delay(1000); siop_intr(adp); if (timo++ > 3000) { /* XXXX: 3sec */ printf("%s: timeout\n", __func__); return ETIMEDOUT; } } if (xs->error != XS_NOERROR) { if (xs->error == XS_BUSY || xs->status == SCSI_CHECK) scsi_request_sense(adp, xs); switch (xs->error) { case XS_SENSE: case XS_SHORTSENSE: error = scsi_interpret_sense(adp, xs); break; case XS_RESOURCE_SHORTAGE: printf("adapter resource shortage\n"); /* FALLTHROUGH */ case XS_BUSY: error = EBUSY; break; case XS_REQUEUE: printf("XXXX: requeue...\n"); error = ERESTART; break; case XS_SELTIMEOUT: case XS_TIMEOUT: error = EIO; break; case XS_RESET: error = EIO; break; case XS_DRIVER_STUFFUP: printf("generic HBA error\n"); error = EIO; break; default: printf("invalid return code from adapter: %d\n", xs->error); error = EIO; break; } if (error == ERESTART) { xs->error = XS_NOERROR; xs->status = SCSI_OK; xs->xs_status &= ~XS_STS_DONE; goto restart; } return error; } return 0; }
int scsi_parse(uint8_t *block, uint8_t in_len) { /* set new operation */ if (state == USB_MS_SCSI_STATE_IDLE) { state = USB_MS_SCSI_STATE_PARSE; op = block[0]; } /* skip operation if sending reply */ if (state != USB_MS_SCSI_STATE_REPLY) { switch (op) { case SCSI_INQUIRY: scsi_inquiry(block, in_len); break; case SCSI_MODE_SENSE6: scsi_mode_sense6(block, in_len); break; case SCSI_READ10: scsi_read10(block, in_len); break; case SCSI_READ_CAPACITY10: scsi_read_capacity10(block, in_len); break; case SCSI_READ_FORMAT_CAPACITIES: scsi_read_format_capacities(block, in_len); break; case SCSI_REPORT_LUNS: scsi_report_luns(block, in_len); break; case SCSI_REQUEST_SENSE: scsi_request_sense(block, in_len); break; case SCSI_START_STOP_UNIT: scsi_start_stop_unit(block, in_len); break; case SCSI_SYNCHRONIZE_CACHE10: scsi_synchronize_cache10(block, in_len); break; case SCSI_TEST_UNIT_READY: scsi_test_unit_ready(block, in_len); break; case SCSI_WRITE10: scsi_write10(block, in_len); break; default: state = USB_MS_SCSI_STATE_REPLY; scsi_sense_code(SCSI_SENSE_ILLEGAL_REQUEST, SCSI_SENSE_CODE_INVALID_COMMAND_OPERATION_CODE); break; } } /* error during data rx/tx */ if (((state == USB_MS_SCSI_STATE_DATA_OUT) || (state == USB_MS_SCSI_STATE_DATA_IN)) && scsi_sense_data.key) { btable_ep[USB_EP_MS_TX].tx_count = 0; state = USB_MS_SCSI_STATE_REPLY; return SCSI_STATUS_CONTINUE; } /* done sending data */ if (state == USB_MS_SCSI_STATE_REPLY) { state = USB_MS_SCSI_STATE_IDLE; return scsi_sense_data.key; } /* still sending/receiving data and no error has occurred */ return SCSI_STATUS_CONTINUE; }
/* * Start/completion routine for disks */ void scdisk_start( target_info_t *tgt, boolean_t done) { register io_req_t ior = tgt->ior; #ifdef CHECKSUM register unsigned secno; #endif register io_req_t rdone = NULL; register unsigned part, secno; scsi_ret_t ret; if (ior == 0) return; if (tgt->flags & TGT_BBR_ACTIVE) { scdisk_bbr_start(tgt, done); return; } if (done) { unsigned int xferred; unsigned int max_dma_data; max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; /* see if we must retry */ if ((tgt->done == SCSI_RET_RETRY) && ((ior->io_op & IO_INTERNAL) == 0)) { if(tgt->dev_info.disk.b.retry_count++ == DISK_RETRIES) { tgt->done = SCSI_RET_DEVICE_DOWN; } else { timeout((timeout_fcn_t)wakeup, tgt, hz); await(tgt); goto start; } } /* got a bus reset ? pifff.. */ if ((tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) && ((ior->io_op & IO_INTERNAL) == 0)) { if (xferred = ior->io_residual) { /* * No special thing to do for * chained IOs, should work as well */ ior->io_data -= xferred; ior->io_count += xferred; ior->io_recnum -= xferred / tgt->block_size; ior->io_residual = 0; } goto start; } else if ((tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) && (!rzpassthru(ior->io_unit))) { /* * Quickly check for errors: if anything goes wrong * we do a request sense, see if that is what we did. */ scsi_sense_data_t *sns; unsigned int blockno; char *outcome; ior->io_op = ior->io_temporary; sns = (scsi_sense_data_t *)tgt->cmd_ptr; if (sns->addr_valid) blockno = sns->u.xtended.info0 << 24 | sns->u.xtended.info1 << 16 | sns->u.xtended.info2 << 8 | sns->u.xtended.info3; else { part = rzpartition(ior->io_unit); blockno = tgt->dev_info.disk.l.d_partitions[part].p_offset * (tgt->dev_info.disk.l.d_secsize / tgt->block_size); blockno += ior->io_recnum; } if ((blockno + btodb(ior->io_count + tgt->block_size - 1) >= tgt->dev_info.disk.l.d_secperunit)) { ior->io_error = D_INVALID_RECNUM; ior->io_op |= IO_ERROR; outcome = "Unrecoverable"; } else if (scsi_check_sense_data(tgt, sns)) { ior->io_error = 0; if ((tgt->done == SCSI_RET_RETRY) && ((ior->io_op & IO_INTERNAL) == 0)) { timeout((timeout_fcn_t)wakeup, tgt, hz); await(tgt); goto start; } outcome = "Recovered"; #if CHAINED_IOS } else if (ior->io_op & IO_CHAINED) { /* * Since multiple IOs are chained, split them * and restart prior to error handling */ simple_lock(&tgt->target_lock); split_io_reqs(ior); simple_unlock(&tgt->target_lock); ior->io_residual = 0; goto start; #endif /* CHAINED_IOS */ } else { outcome = "Unrecoverable"; ior->io_error = D_IO_ERROR; ior->io_op |= IO_ERROR; } if ((tgt->flags & TGT_OPTIONAL_CMD) == 0) { printf("%s Error, rz%d: %s%s%d\n", outcome, tgt->target_id + (tgt->masterno * 8), (ior->io_op & IO_READ) ? "Read" : ((ior->io_op & IO_INTERNAL) ? "(command)" : "Write"), " disk error, phys block no. ", blockno); scsi_print_sense_data(sns); printf("\n"); #ifndef POWERMAC /* * On fatal read/write errors try replacing the * bad block. The bbr routine will return TRUE * iff it took control over the target for all * subsequent operations. In this event, the * queue of requests is effectively frozen. */ if (ior->io_error && ((sns->error_class == SCSI_SNS_XTENDED_SENSE_DATA) && ((sns->u.xtended.sense_key == SCSI_SNS_HW_ERR) || (sns->u.xtended.sense_key == SCSI_SNS_MEDIUM_ERR))) && scdisk_bad_block_repl(tgt, blockno)) return; #endif } } else if ((tgt->done != SCSI_RET_SUCCESS) && #ifdef POWERMAC (!rzpassthru(ior->io_unit) && (ior->io_op & IO_INTERNAL) == 0)) { #else !rzpassthru(ior->io_unit)) { #endif #if CHAINED_IOS if (ior->io_op & IO_CHAINED) { /* * Since multiple IOs are chained, split them * and restart prior to error handling */ simple_lock(&tgt->target_lock); split_io_reqs(ior); simple_unlock(&tgt->target_lock); ior->io_residual = 0; goto start; } #endif /* CHAINED_IOS */ /* * See if we had errors */ if (tgt->done == SCSI_RET_NEED_SENSE) { ior->io_temporary = ior->io_op; ior->io_op = IO_INTERNAL; scsi_request_sense(tgt, ior, 0); return; } else if (tgt->done == SCSI_RET_DEVICE_DOWN) { part = rzpartition(ior->io_unit); secno = ior->io_recnum; secno += tgt->dev_info.disk.l.d_partitions[part].p_offset * (tgt->dev_info.disk.l.d_secsize / tgt->block_size); secno += btodb(ior->io_count + tgt->block_size - 1); if (secno >= tgt->dev_info.disk.l.d_secperunit) ior->io_error = D_INVALID_RECNUM; else ior->io_error = D_DEVICE_DOWN; ior->io_op |= IO_ERROR; } else { printf("%s%x\n", "?rz_disk Disk error, ret=x", tgt->done); ior->io_error = D_IO_ERROR; ior->io_op |= IO_ERROR; } } else if (ior->io_count > (xferred = max_dma_data)) { /* * No errors. * See if we requested more than the max * (We use io_residual in a flip-side way here) */ #if CHAINED_IOS if (ior->io_op & IO_CHAINED) { /* Should not happen since we checked max_data & max_segs before */ panic("chained io to large: 1"); } #endif /* CHAINED_IOS */ ior->io_residual += xferred; ior->io_count -= xferred; ior->io_data += xferred; ior->io_recnum += xferred / tgt->block_size; goto start; } else if (xferred = ior->io_residual) { #if CHAINED_IOS if (ior->io_op & IO_CHAINED) { /* Should not happen since we checked max_data & max_segs before */ panic("chained io to large: 2"); } #endif /* CHAINED_IOS */ ior->io_data -= xferred; ior->io_count += xferred; ior->io_recnum -= xferred / tgt->block_size; ior->io_residual = 0; } /* that's it */ #ifdef CHECKSUM if ((ior->io_op & IO_READ) && (ior->io_count < max_checksum_size)) { part = rzpartition(ior->io_unit); secno = ior->io_recnum + tgt->dev_info.disk.l.d_partitions[part].p_offset * (tgt->dev_info.disk.l.d_secsize / tgt->block_size); scdisk_bcheck(secno, ior->io_data, ior->io_count); } #endif /* CHECKSUM */ /* If this is a pass-through device, save the target result */ if (rzpassthru(ior->io_unit)) ior->io_error = tgt->done; /* dequeue next one */ { io_req_t next; simple_lock(&tgt->target_lock); next = ior->io_next; tgt->ior = next; simple_unlock(&tgt->target_lock); if (next == 0) { #if CHAINED_IOS if (ior->io_op & IO_CHAINED) chained_iodone(ior); else #endif /* CHAINED_IOS */ iodone(ior); return; } rdone = ior; ior = next; } #ifdef CHECKSUM if (((ior->io_op & IO_READ) == 0) && (ior->io_count < max_checksum_size)) { part = rzpartition(ior->io_unit); secno = ior->io_recnum + tgt->dev_info.disk.l.d_partitions[part].p_offset * (tgt->dev_info.disk.l.d_secsize / tgt->block_size); scdisk_checksum(secno, ior->io_data, ior->io_count); } #endif /* CHECKSUM */ }
void scsi_proc(void) { if (USBD_ep_buffer_full(BOMS_EP_DATA_OUT)) { if (sizeof(BOMSCmd) == USBD_transfer(BOMS_EP_DATA_OUT, (uint8_t *)&BOMSCmd, sizeof(BOMSCmd))) { if (BOMSCmd.dCBWSignature == BOMS_USBC) { if (BOMSCmd.CBWCB.unit_ready.op_code == BOMS_SCSI_TEST_UNIT_READY) // SCSI Test Unit Ready { scsi_test_unit_ready(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ) // SCSI Read { scsi_read(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_WRITE) // SCSI Write { scsi_write(&BOMSCmd); } else if (BOMSCmd.CBWCB.inquiry.op_code == BOMS_SCSI_INQUIRY) // SCSI Inquiry { scsi_inquiry(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_REQUEST_SENSE) // SCSI Request Sense { scsi_request_sense(&BOMSCmd); } else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_CAPACITY) // SCSI Read Capacity (10) { scsi_read_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_FORMAT_CAPACITY) // SCSI Read Format Capacity (10) { scsi_read_format_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.mode_sense.op_code == BOMS_SCSI_MODE_SENSE) // SCSI Mode Sense { scsi_mode_sense(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ_CAPACITY_16) // SCSI Read Capacity (16) { scsi_read_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_PREVENT_ALLOW_REMOVAL) // SCSI Prevent Allow Removal { scsi_prevent_allow_removal(&BOMSCmd); } else { // Send IN a zero length packet. if (BOMSCmd.dCBWDataTransferLength) { USBD_stall_endpoint(BOMS_EP_DATA_IN); } boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd); scsi_sense_illegal_request_command(); } } else { // Was not a USBC signature. boms_send_status(BOMS_STATUS_PHASE_ERROR, &BOMSCmd); scsi_sense_illegal_request_cdb(); } }else{ // Wrong command size. boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd); scsi_sense_illegal_request_parm(); } } }