Newer
Older
if (p & SR_IO)
NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
else {
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_write(START_DMA_SEND_REG, 0);
}
if (!IS_A_TT()) {
/* On the Falcon, the DMA setup must be done after the last */
/* NCR access, else the DMA setup gets trashed!
*/
local_irq_save(flags);
hostdata->dma_len = (p & SR_IO) ?
NCR5380_dma_read_setup(instance, d, c) :
NCR5380_dma_write_setup(instance, d, c);
local_irq_restore(flags);
}
return 0;
}
#endif /* defined(REAL_DMA) */
/*
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
* Purpose : run through the various SCSI phases and do as the target
* directs us to. Operates on the currently connected command,
* instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
* Side effects : SCSI things happen, the disconnected queue will be
* modified if a command disconnects, *instance->connected will
* change.
*
* XXX Note : we need to watch for bus free or a reset condition here
* to recover from an unexpected bus free condition.
static void NCR5380_information_transfer(struct Scsi_Host *instance)
SETUP_HOSTDATA(instance);
unsigned long flags;
unsigned char msgout = NOP;
int sink = 0;
int len;
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
while (1) {
tmp = NCR5380_read(STATUS_REG);
/* We only have a valid SCSI phase when REQ is asserted */
if (tmp & SR_REQ) {
phase = (tmp & PHASE_MASK);
if (phase != old_phase) {
old_phase = phase;
NCR_PRINT_PHASE(NDEBUG_INFORMATION);
}
if (sink && (phase != PHASE_MSGOUT)) {
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
ICR_ASSERT_ACK);
while (NCR5380_read(STATUS_REG) & SR_REQ)
;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
ICR_ASSERT_ATN);
sink = 0;
continue;
}
switch (phase) {
case PHASE_DATAOUT:
printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
"aborted\n", HOSTNO);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
cmd->done(cmd);
return;
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
case PHASE_DATAIN:
/*
* If there is no room left in the current buffer in the
* scatter-gather list, move onto the next one.
*/
if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
/* ++roman: Try to merge some scatter-buffers if
* they are at contiguous physical addresses.
*/
merge_contiguous_buffers(cmd);
INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
HOSTNO, cmd->SCp.this_residual,
cmd->SCp.buffers_residual);
}
/*
* The preferred transfer method is going to be
* PSEUDO-DMA for systems that are strictly PIO,
* since we can let the hardware do the handshaking.
*
* For this to work, we need to know the transfersize
* ahead of time, since the pseudo-DMA code will sit
* in an unconditional loop.
*/
/* ++roman: I suggest, this should be
* #if def(REAL_DMA)
* instead of leaving REAL_DMA out.
*/
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
if (!cmd->device->borken &&
(transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
len = transfersize;
cmd->SCp.phase = phase;
if (NCR5380_transfer_dma(instance, &phase,
&len, (unsigned char **)&cmd->SCp.ptr)) {
/*
* If the watchdog timer fires, all future
* accesses to this device will use the
* polled-IO. */
printk(KERN_NOTICE "scsi%d: switching target %d "
"lun %d to slow handshake\n", HOSTNO,
cmd->device->id, cmd->device->lun);
cmd->device->borken = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
ICR_ASSERT_ATN);
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
cmd->done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
/* ++roman: When using real DMA,
* information_transfer() should return after
* starting DMA since it has nothing more to
* do.
*/
return;
#else
cmd->SCp.this_residual -= transfersize - len;
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
NCR5380_transfer_pio(instance, &phase,
(int *)&cmd->SCp.this_residual,
(unsigned char **)&cmd->SCp.ptr);
break;
case PHASE_MSGIN:
len = 1;
data = &tmp;
NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
NCR5380_transfer_pio(instance, &phase, &len, &data);
cmd->SCp.Message = tmp;
switch (tmp) {
/*
* Linking lets us reduce the time required to get the
* next command out to the device, hopefully this will
* mean we don't waste another revolution due to the delays
* required by ARBITRATION and another SELECTION.
*
* In the current implementation proposal, low level drivers
* merely have to start the next command, pointed to by
* next_link, done() is called as with unlinked commands.
*/
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
case LINKED_CMD_COMPLETE:
case LINKED_FLG_CMD_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
LNK_PRINTK("scsi%d: target %d lun %d linked command "
"complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Sanity check : A linked command should only terminate
* with one of these messages if there are more linked
* commands available.
*/
if (!cmd->next_link) {
printk(KERN_NOTICE "scsi%d: target %d lun %d "
"linked command complete, no next_link\n",
HOSTNO, cmd->device->id, cmd->device->lun);
sink = 1;
do_abort(instance);
return;
}
initialize_SCp(cmd->next_link);
/* The next command is still part of this process; copy it
* and don't free it! */
cmd->next_link->tag = cmd->tag;
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
LNK_PRINTK("scsi%d: target %d lun %d linked request "
"done, calling scsi_done().\n",
HOSTNO, cmd->device->id, cmd->device->lun);
cmd->scsi_done(cmd);
cmd = hostdata->connected;
break;
case ABORT:
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/* ++guenther: possible race with Falcon locking */
falcon_dont_release++;
hostdata->connected = NULL;
QU_PRINTK("scsi%d: command for target %d, lun %d "
"completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
cmd_free_tag(cmd);
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
/* Turn a QUEUE FULL status into BUSY, I think the
* mid level cannot handle QUEUE FULL :-( (The
* command is retried after BUSY). Also update our
* queue size to the number of currently issued
* commands now.
*/
/* ++Andreas: the mid level code knows about
QUEUE_FULL now. */
TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
TAG_PRINTK("scsi%d: target %d lun %d returned "
"QUEUE_FULL after %d commands\n",
HOSTNO, cmd->device->id, cmd->device->lun,
ta->nr_allocated);
if (ta->queue_size > ta->nr_allocated)
ta->nr_allocated = ta->queue_size;
}
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* I'm not sure what the correct thing to do here is :
*
* If the command that just executed is NOT a request
* sense, the obvious thing to do is to set the result
* code to the values of the stored parameters.
*
* If it was a REQUEST SENSE command, we need some way to
* differentiate between the failure code of the original
* and the failure code of the REQUEST sense - the obvious
* case is success, where we fall through and leave the
* result code unchanged.
*
* The non-obvious place is where the REQUEST SENSE failed
*/
if (cmd->cmnd[0] != REQUEST_SENSE)
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
else if (status_byte(cmd->SCp.Status) != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
#ifdef AUTOSENSE
if ((cmd->cmnd[0] != REQUEST_SENSE) &&
(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
cmd->cmnd[0] = REQUEST_SENSE;
cmd->cmnd[1] &= 0xe0;
cmd->cmnd[2] = 0;
cmd->cmnd[3] = 0;
cmd->cmnd[4] = sizeof(cmd->sense_buffer);
cmd->cmnd[5] = 0;
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
cmd->use_sg = 0;
/* this is initialized from initialize_SCp
cmd->SCp.buffer = NULL;
cmd->SCp.buffers_residual = 0;
*/
cmd->request_buffer = (char *) cmd->sense_buffer;
cmd->request_bufflen = sizeof(cmd->sense_buffer);
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
SET_NEXT(cmd, hostdata->issue_queue);
hostdata->issue_queue = (Scsi_Cmnd *) cmd;
local_irq_restore(flags);
QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
} else
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
cmd->scsi_done(cmd);
}
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
falcon_dont_release--;
/* ++roman: For Falcon SCSI, release the lock on the
* ST-DMA here if no other commands are waiting on the
* disconnected queue.
*/
falcon_release_lock_if_possible(hostdata);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
switch (hostdata->last_message) {
case HEAD_OF_QUEUE_TAG:
case ORDERED_QUEUE_TAG:
case SIMPLE_QUEUE_TAG:
/* The target obviously doesn't support tagged
* queuing, even though it announced this ability in
* its INQUIRY data ?!? (maybe only this LUN?) Ok,
* clear 'tagged_supported' and lock the LUN, since
* the command is treated as untagged further on.
*/
cmd->device->tagged_supported = 0;
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
cmd->tag = TAG_NONE;
TAG_PRINTK("scsi%d: target %d lun %d rejected "
"QUEUE_TAG message; tagged queuing "
"disabled\n",
HOSTNO, cmd->device->id, cmd->device->lun);
break;
}
break;
case DISCONNECT:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
local_irq_save(flags);
cmd->device->disconnect = 1;
LIST(cmd,hostdata->disconnected_queue);
SET_NEXT(cmd, hostdata->disconnected_queue);
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
hostdata->connected = NULL;
hostdata->disconnected_queue = cmd;
local_irq_restore(flags);
QU_PRINTK("scsi%d: command for target %d lun %d was "
"moved from connected to the "
"disconnected_queue\n", HOSTNO,
cmd->device->id, cmd->device->lun);
/*
* Restore phase bits to 0 so an interrupted selection,
* arbitration can resume.
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/* Wait for bus free to avoid nasty timeouts */
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
return;
/*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
* operation, in violation of the SCSI spec so we can safely
* ignore SAVE/RESTORE pointers calls.
*
* Unfortunately, some disks violate the SCSI spec and
* don't issue the required SAVE_POINTERS message before
* disconnecting, and we have to break spec to remain
* compatible.
*/
case SAVE_POINTERS:
case RESTORE_POINTERS:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/* Enable reselect interrupts */
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
break;
case EXTENDED_MESSAGE:
/*
* Extended messages are sent in the following format :
* Byte
* 0 EXTENDED_MESSAGE == 1
* 1 length (includes one byte for code, doesn't
* include first two bytes)
* 2 code
* 3..length+1 arguments
*
* Start the extended message buffer with the EXTENDED_MESSAGE
* byte, since spi_print_msg() wants the whole thing.
*/
extended_msg[0] = EXTENDED_MESSAGE;
/* Accept first byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
len = 2;
data = extended_msg + 1;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
(int)extended_msg[1], (int)extended_msg[2]);
if (!len && extended_msg[1] <=
(sizeof(extended_msg) - 1)) {
/* Accept third byte by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = extended_msg[1] - 1;
data = extended_msg + 3;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
EXT_PRINTK("scsi%d: message received, residual %d\n",
HOSTNO, len);
switch (extended_msg[2]) {
case EXTENDED_SDTR:
case EXTENDED_WDTR:
case EXTENDED_MODIFY_DATA_POINTER:
case EXTENDED_EXTENDED_IDENTIFY:
tmp = 0;
}
} else if (len) {
printk(KERN_NOTICE "scsi%d: error receiving "
"extended message\n", HOSTNO);
tmp = 0;
} else {
printk(KERN_NOTICE "scsi%d: extended message "
"code %02x length %d is too long\n",
HOSTNO, extended_msg[2], extended_msg[1]);
tmp = 0;
}
/* Fall through to reject message */
/*
* If we get something weird that we aren't expecting,
* reject it.
*/
default:
if (!tmp) {
printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"message %02x from target %d, lun %d\n",
HOSTNO, tmp, cmd->device->id, cmd->device->lun);
else
printk(KERN_DEBUG "scsi%d: rejecting unknown "
"extended message "
"code %02x, length %d from target %d, lun %d\n",
HOSTNO, extended_msg[1], extended_msg[0],
cmd->device->id, cmd->device->lun);
msgout = MESSAGE_REJECT;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
break;
} /* switch (tmp) */
break;
case PHASE_MSGOUT:
len = 1;
data = &msgout;
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
falcon_release_lock_if_possible(hostdata);
return;
}
msgout = NOP;
break;
case PHASE_CMDOUT:
len = cmd->cmd_len;
data = cmd->cmnd;
/*
* XXX for performance reasons, on machines with a
* PSEUDO-DMA architecture we should probably
* use the dma transfer function.
*/
NCR5380_transfer_pio(instance, &phase, &len, &data);
break;
case PHASE_STATIN:
len = 1;
data = &tmp;
NCR5380_transfer_pio(instance, &phase, &len, &data);
cmd->SCp.Status = tmp;
break;
default:
printk("scsi%d: unknown phase\n", HOSTNO);
NCR_PRINT(NDEBUG_ANY);
} /* switch(phase) */
} /* if (tmp * SR_REQ) */
} /* while (1) */
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
* field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
* Inputs : instance - this instance of the NCR5380.
*
*/
static void NCR5380_reselect(struct Scsi_Host *instance)
SETUP_HOSTDATA(instance);
unsigned char target_mask;
unsigned char lun, phase;
int len;
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
unsigned char msg[3];
unsigned char *data;
Scsi_Cmnd *tmp = NULL, *prev;
/* unsigned long flags; */
/*
* Disable arbitration, etc. since the host adapter obviously
* lost, and tell an interrupted NCR5380_select() to restart.
*/
NCR5380_write(MODE_REG, MR_BASE);
hostdata->restart_select = 1;
target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
/*
* At this point, we have detected that our SCSI ID is on the bus,
* SEL is true and BSY was false for at least one bus settle delay
* (400 ns).
*
* We must assert BSY ourselves, until the target drops the SEL
* signal.
*/
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
while (NCR5380_read(STATUS_REG) & SR_SEL)
;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
/*
* Wait for target to go into MSGIN.
*/
while (!(NCR5380_read(STATUS_REG) & SR_REQ))
;
len = 1;
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (!(msg[0] & 0x80)) {
printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
spi_print_msg(msg);
do_abort(instance);
return;
}
lun = (msg[0] & 0x07);
/* If the phase is still MSGIN, the target wants to send some more
* messages. In case it supports tagged queuing, this is probably a
* SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
*/
tag = TAG_NONE;
if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
/* Accept previous IDENTIFY message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = 2;
data = msg + 1;
if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
msg[1] == SIMPLE_QUEUE_TAG)
tag = msg[2];
TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
"reselection\n", HOSTNO, target_mask, lun, tag);
}
/*
* Find the command corresponding to the I_T_L or I_T_L_Q nexus we
* just reestablished, and remove it from the disconnected queue.
*/
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
tmp; prev = tmp, tmp = NEXT(tmp)) {
if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
) {
/* ++guenther: prevent race with falcon_release_lock */
falcon_dont_release++;
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
} else {
REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
hostdata->disconnected_queue = NEXT(tmp);
}
if (!tmp) {
printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
"not in disconnected_queue.\n",
HOSTNO, target_mask, lun
);
/*
* Since we have an established nexus that we can't do anything
* with, we must abort it.
*/
do_abort(instance);
return;
}
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
hostdata->connected = tmp;
RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
falcon_dont_release--;
}
/*
* Function : int NCR5380_abort (Scsi_Cmnd *cmd)
*
* Purpose : abort a command
*
* Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
* host byte of the result field to, if zero DID_ABORTED is
* used.
*
* Returns : 0 - success, -1 on failure.
*
* XXX - there is no way to abort the command that is currently
* connected, you have to wait for it to complete. If this is
* a problem, we could implement longjmp() / setjmp(), setjmp()
* called where the loop started in NCR5380_main().
struct Scsi_Host *instance = cmd->device->host;
SETUP_HOSTDATA(instance);
Scsi_Cmnd *tmp, **prev;
unsigned long flags;
printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
scsi_print_command(cmd);
NCR5380_print_status(instance);
local_irq_save(flags);
if (!IS_A_TT() && !falcon_got_lock)
printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
HOSTNO);
ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
NCR5380_read(BUS_AND_STATUS_REG),
NCR5380_read(STATUS_REG));
/*
* Case 1 : If the command is the currently executing command,
* we'll set the aborted flag and return control so that
* information transfer routine can exit cleanly.
*/
ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
/*
* We should perform BSY checking, and make sure we haven't slipped
* into BUS FREE.
*/
/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
/*
* Since we can't change phases until we've completed the current
* handshake, we have to source or sink a byte of data if the current
* phase is not MSGOUT.
*/
/*
* Return control to the executing NCR drive so we can clear the
* aborted flag and get back into our main loop.
*/
if (do_abort(instance) == 0) {
hostdata->aborted = 1;
hostdata->connected = NULL;
cmd->result = DID_ABORT << 16;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
local_irq_restore(flags);
cmd->scsi_done(cmd);
falcon_release_lock_if_possible(hostdata);
return SCSI_ABORT_SUCCESS;
} else {
/* local_irq_restore(flags); */
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return SCSI_ABORT_ERROR;
}
}
/*
* Case 2 : If the command hasn't been issued yet, we simply remove it
* from the issue queue.
*/
for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue),
tmp = (Scsi_Cmnd *)hostdata->issue_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
(*prev) = NEXT(tmp);
tmp->result = DID_ABORT << 16;
local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
* yet... */
tmp->scsi_done(tmp);
falcon_release_lock_if_possible(hostdata);
return SCSI_ABORT_SUCCESS;
}
/*
* Case 3 : If any commands are connected, we're going to fail the abort
* and let the high level SCSI driver retry at a later time or
* issue a reset.
*
* Timeouts, and therefore aborted commands, will be highly unlikely
* and handling them cleanly in this situation would make the common
* case of noresets less efficient, and would pollute our code. So,
* we fail.
*/
if (hostdata->connected) {
local_irq_restore(flags);
ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
return SCSI_ABORT_SNOOZE;
}
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
/*
* Case 4: If the command is currently disconnected from the bus, and
* there are no connected commands, we reconnect the I_T_L or
* I_T_L_Q nexus associated with it, go into message out, and send
* an abort message.
*
* This case is especially ugly. In order to reestablish the nexus, we
* need to call NCR5380_select(). The easiest way to implement this
* function was to abort if the bus was busy, and let the interrupt
* handler triggered on the SEL for reselect take care of lost arbitrations
* where necessary, meaning interrupts need to be enabled.
*
* When interrupts are enabled, the queues may change - so we
* can't remove it from the disconnected queue before selecting it
* because that could cause a failure in hashing the nexus if that
* device reselected.
*
* Since the queues may change, we can't use the pointers from when we
* first locate it.
*
* So, we must first locate the command, and if NCR5380_select()
* succeeds, then issue the abort, relocate the command and remove
* it from the disconnected queue.
*/
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp)) {
if (cmd == tmp) {
local_irq_restore(flags);
ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
if (NCR5380_select(instance, cmd, (int)cmd->tag))
return SCSI_ABORT_BUSY;
ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
do_abort(instance);
local_irq_save(flags);
for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
*prev = NEXT(tmp);
tmp->result = DID_ABORT << 16;
/* We must unlock the tag/LUN immediately here, since the
* target goes to BUS FREE and doesn't send us another
* message (COMMAND_COMPLETE or the like)
*/
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
local_irq_restore(flags);
tmp->scsi_done(tmp);
falcon_release_lock_if_possible(hostdata);
return SCSI_ABORT_SUCCESS;
}
}
/*
* Case 5 : If we reached this point, the command was not found in any of
* the queues.
*
* We probably reached this point because of an unlikely race condition
* between the command completing successfully and the abortion code,
* so we won't panic, but we will notify the user in case something really
* broke.
*/
local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
KERN_INFO " before abortion\n", HOSTNO);
/* Maybe it is sufficient just to release the ST-DMA lock... (if
* possible at all) At least, we should check if the lock could be
* released after the abort, in case it is kept due to some bug.
*/
falcon_release_lock_if_possible(hostdata);
* Purpose : reset the SCSI bus.
*
* Returns : SCSI_RESET_WAKEUP
*
static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
SETUP_HOSTDATA(cmd->device->host);
int i;
unsigned long flags;
Scsi_Cmnd *connected, *disconnected_queue;
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
if (!IS_A_TT() && !falcon_got_lock)
printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
H_NO(cmd));
NCR5380_print_status(cmd->device->host);
/* get in phase */
NCR5380_write(TARGET_COMMAND_REG,
PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
/* assert RST */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
udelay(40);
/* reset NCR registers */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
/* ++roman: reset interrupt condition! otherwise no interrupts don't get
* through anymore ... */
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
/* XXX see below XXX */
/* MSch: old-style reset: actually abort all command processing here */
/* After the reset, there are no more connected or disconnected commands
* and no busy units; to avoid problems with re-inserting the commands
* into the issue_queue (via scsi_done()), the aborted commands are
* remembered in local variables first.
*/
local_irq_save(flags);
connected = (Scsi_Cmnd *)hostdata->connected;
hostdata->connected = NULL;
disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
hostdata->disconnected_queue = NULL;
for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0;
/* In order to tell the mid-level code which commands were aborted,
* set the command status to DID_RESET and call scsi_done() !!!
* This ultimately aborts processing of these commands in the mid-level.
*/
if ((cmd = connected)) {
ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
cmd->scsi_done(cmd);
}
for (i = 0; (cmd = disconnected_queue); ++i) {
disconnected_queue = NEXT(cmd);
cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
cmd->scsi_done(cmd);
}
if (i > 0)
ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
/* The Falcon lock should be released after a reset...
*/
/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
* unlocking and enabling dma interrupt.
*/
/* falcon_release_lock_if_possible( hostdata );*/
/* since all commands have been explicitly terminated, we need to tell
* the midlevel code that the reset was SUCCESSFUL, and there is no
* need to 'wake up' the commands by a request_sense
*/
return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
/* MSch: new-style reset handling: let the mid-level do what it can */
/* ++guenther: MID-LEVEL IS STILL BROKEN.
* Mid-level is supposed to requeue all commands that were active on the
* various low-level queues. In fact it does this, but that's not enough
* because all these commands are subject to timeout. And if a timeout
* happens for any removed command, *_abort() is called but all queues
* are now empty. Abort then gives up the falcon lock, which is fatal,
* since the mid-level will queue more commands and must have the lock
* (it's all happening inside timer interrupt handler!!).
* Even worse, abort will return NOT_RUNNING for all those commands not