|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: // Copyright 1997 by Apple Computer, Inc., all rights reserved.
26: /*
27: * Copyright (c) 1995-1997 NeXT Software, Inc. All rights reserved.
28: *
29: * AtapiCnt.m - Implementation of ATAPI controller class.
30: *
31: *
32: * HISTORY
33: * 31-Aug-1994 Rakesh Dubey at NeXT
34: * Created.
35: */
36:
37: #undef DEBUG
38:
39: #import <kern/assert.h>
40: #import <driverkit/kernelDriver.h>
41: #import <driverkit/interruptMsg.h>
42: #import <mach/mach_interface.h>
43: #import <driverkit/IODevice.h>
44: #import <driverkit/ppc/IOTreeDevice.h>
45: #import <driverkit/align.h>
46: #import <machkit/NXLock.h>
47: #import "io_inline.h"
48:
49: #import "IdeCnt.h"
50: #import "AtapiCnt.h"
51: #import "AtapiCntInternal.h"
52:
53: /*
54: * opcode groups
55: */
56: #define SCSI_OPGROUP(opcode) ((opcode) & 0xe0)
57:
58: #define OPGROUP_0 0x00 /* six byte commands */
59: #define OPGROUP_1 0x20 /* ten byte commands */
60: #define OPGROUP_2 0x40 /* ten byte commands */
61: #define OPGROUP_5 0xa0 /* twelve byte commands */
62: #define OPGROUP_6 0xc0 /* six byte, vendor unique commands */
63: #define OPGROUP_7 0xe0 /* ten byte, vendor unique commands */
64:
65: /*
66: * List of SCSI commands that do not have a counterpart in ATAPI
67: * implementation. These commands will need to be mapped individually.
68: */
69: static unsigned char mapToAtapi[] = {
70: C6OP_MODESELECT,
71: C6OP_MODESENSE
72: };
73:
74: /*
75: * List of controllers that have been already probed. We need this since each
76: * Instance table lists IdeDisk as well as IdeCOntroller classes. And we need
77: * to create instances of disks attached to each controller only once.
78: */
79: static int probedControllerCount = 0;
80: static id probedControllers[MAX_IDE_CONTROLLERS];
81:
82: @implementation AtapiController
83:
84: + (BOOL)probe : deviceDescription
85: {
86:
87: int unit, i;
88: id direct;
89: id atapiCnt;
90:
91: direct = [deviceDescription directDevice];
92:
93: for (i = 0; i < probedControllerCount; i++)
94: {
95: if (probedControllers[i] == direct)
96: {
97: return YES;
98: }
99: }
100:
101: probedControllers[probedControllerCount++] = direct;
102:
103: for (unit = 0; unit < [direct numDevices]; unit++)
104: {
105: if ([direct isAtapiDevice:unit])
106: {
107: atapiCnt = [[self alloc] initFromDeviceDescription:deviceDescription];
108:
109: if (atapiCnt == nil)
110: {
111: IOLog("ATAPI: failed to probe device %d.\n", unit);
112: continue;
113: }
114:
115: if ([atapiCnt initResources:direct] == nil)
116: {
117: IOLog("ATAPI: failed to initialize device %d.\n", unit);
118: [atapiCnt free];
119: continue;
120: }
121:
122: if ([atapiCnt registerDevice] == nil)
123: {
124: IOLog("ATAPI: failed to register device %d.\n", unit);
125: [atapiCnt free];
126: continue;
127: }
128: else
129: {
130: return YES;
131: }
132: }
133: }
134: return NO;
135: }
136:
137: /*
138: * We override IOSCSIController to make ourself look like an indirect device
139: * in order to get connected to IdeController.
140: */
141: + (IODeviceStyle)deviceStyle
142: {
143: return IO_IndirectDevice;
144: }
145:
146: /*
147: * The protocol we need as an indirect device.
148: */
149: static Protocol *protocols[] = {
150: @protocol(AtapiControllerPublic),
151: nil
152: };
153:
154: + (Protocol **)requiredProtocols
155: {
156: return protocols;
157: }
158:
159:
160: - (unsigned short)scsiCmdLen:(IOSCSIRequest *) scsiReq
161: {
162: unsigned char cmdlen;
163: union cdb *cdbp = &scsiReq->cdb;
164:
165: switch (SCSI_OPGROUP(cdbp->cdb_opcode)) {
166:
167: case OPGROUP_0:
168: cmdlen = sizeof(struct cdb_6);
169: break;
170:
171: case OPGROUP_1:
172: case OPGROUP_2:
173: cmdlen = sizeof(struct cdb_10);
174: break;
175:
176: case OPGROUP_5:
177: cmdlen = sizeof(struct cdb_12);
178: break;
179:
180: case OPGROUP_6:
181: if (scsiReq->cdbLength)
182: cmdlen = scsiReq->cdbLength;
183: else
184: cmdlen = sizeof(struct cdb_6);
185: break;
186:
187: case OPGROUP_7:
188: if (scsiReq->cdbLength)
189: cmdlen = scsiReq->cdbLength;
190: else
191: cmdlen = sizeof(struct cdb_10);
192: break;
193:
194: default:
195: scsiReq->driverStatus = SR_IOST_CMDREJ;
196: return 0;
197: }
198:
199: return cmdlen;
200: }
201:
202: #define C10OP_MODESELECT 0x55 /* OPT: set device parameters */
203: #define C10OP_MODESENSE 0x5a /* OPT: get device parameters */
204: #define C10OP_READCAPACITY 0x25 /* read capacity */
205:
206: /*
207: * Do a SCSI command, as specified by an IOSCSIRequest.
208: */
209: - (sc_status_t) executeRequest : (IOSCSIRequest *)scsiReq
210: buffer : (void *)buffer
211: client : (vm_task_t)client
212: {
213: int i;
214: atapiIoReq_t atapiIoReq;
215: atapiBuf_t *atapiBuf;
216: unsigned char *scsiCmd;
217: cdb_t my_cdb;
218: sc_status_t ret;
219: IOReturn driverStatus;
220:
221: [_ataController atapiCntrlrLock];
222:
223: my_cdb = scsiReq->cdb;
224:
225: bzero(&atapiIoReq, sizeof(atapiIoReq_t));
226:
227: atapiIoReq.cmdLen = [_ataController atapiCommandPacketSize:scsiReq->target];
228:
229: atapiIoReq.read = scsiReq->read;
230: atapiIoReq.maxTransfer = scsiReq->maxTransfer;
231: atapiIoReq.drive = scsiReq->target;
232: atapiIoReq.lun = scsiReq->lun;
233:
234: scsiCmd = (unsigned char *) &(my_cdb.cdb_opcode);
235:
236: for (i = 0; i < [self scsiCmdLen:scsiReq]; i++) {
237: atapiIoReq.atapiCmd[i] = *scsiCmd;
238: scsiCmd++;
239: }
240:
241: /*
242: * Map to available ATAPI command if necessary.
243: */
244: for (i = 0; i < sizeof(mapToAtapi)/sizeof(mapToAtapi[0]); i++)
245: {
246: if (atapiIoReq.atapiCmd[0] == mapToAtapi[i])
247: {
248: if ([self maptoAtapiCmd: &atapiIoReq buffer:buffer] == NO)
249: {
250: [_ataController atapiCntrlrUnLock];
251: return SR_IOST_CMDREJ;
252: }
253: break;
254: }
255: }
256:
257: /*
258: * If emulation is successful then return quickly.
259: */
260: if ([self emulateSCSICmd: &atapiIoReq buffer:buffer] == YES)
261: {
262: [_ataController atapiCntrlrUnLock];
263: return SR_IOST_GOOD;
264: }
265:
266: /*
267: * Send the command to the ioThread.
268: */
269: atapiBuf = [self allocAtapiBuf];
270: atapiBuf->atapiIoReq = &atapiIoReq;
271: atapiBuf->buffer = buffer;
272: atapiBuf->client = client;
273: atapiBuf->command = ATAPI_CNT_IOREQ;
274: driverStatus = [self enqueueAtapiBuf:atapiBuf];
275: ret = atapiBuf->status; // SCSI status
276: [self freeAtapiBuf:atapiBuf];
277:
278: /*
279: * This is a workaround for the Mitsumi Read CD-ROM capacity bug. It
280: * reports the block size as 2352 bytes instead of 2048 bytes. It is
281: * including preamble and other info. I have seen this on MITSUMI CD-ROM
282: * !B B02. The workaround is truncate the returned value. Remove this
283: * when it is no longer needed.
284: */
285: {
286: unsigned int blockSize;
287: char *buf = (char *)buffer;
288:
289: if ((atapiIoReq.atapiCmd[0] == C10OP_READCAPACITY) && (atapiIoReq.lun == 0))
290: {
291: blockSize = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
292:
293: if ( blockSize == 2352 )
294: {
295: blockSize = 2048;
296: buf[4] = (blockSize >> 24) & 0xff;
297: buf[5] = (blockSize >> 16) & 0xff;
298: buf[6] = (blockSize >> 8) & 0xff;
299: buf[7] = blockSize & 0xff;
300: }
301: }
302: }
303:
304: scsiReq->bytesTransferred = atapiIoReq.bytesTransferred;
305: scsiReq->scsiStatus = atapiIoReq.scsiStatus;
306: scsiReq->driverStatus = driverStatus;
307:
308: [_ataController atapiCntrlrUnLock];
309:
310: return ret;
311: }
312:
313: - (BOOL) maptoAtapiCmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer
314: {
315: int i, pageLength;
316: unsigned char *data = (unsigned char *)buffer;
317:
318: if (atapiIoReq->atapiCmd[0] == C6OP_MODESENSE)
319: {
320: atapiIoReq->atapiCmd[0] = C10OP_MODESENSE;
321: atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4];
322: atapiIoReq->atapiCmd[4] = 0;
323: return YES;
324: }
325:
326: if (atapiIoReq->atapiCmd[0] == C6OP_MODESELECT)
327: {
328: atapiIoReq->atapiCmd[0] = C10OP_MODESELECT;
329: atapiIoReq->atapiCmd[8] = atapiIoReq->atapiCmd[4];
330: atapiIoReq->atapiCmd[4] = 0;
331:
332: /*
333: * This is complicated since SCSI and ATAPI have very different
334: * data layouts for mode select.
335: */
336: if ((atapiIoReq->atapiCmd[0] == C10OP_MODESELECT) &&
337: (data[3] == 0x08)) {
338: data[0] = data[1] = 0; /* mode data length is reserved */
339: data[2] = 0; /* always for CD-ROM. Tape? FIXME */
340: data[3] = 0; /* reserved for ATAPI */
341:
342: /*
343: * Move the data up by four bytes since there only four bytes of
344: * block descriptor in ATAPI while SCSI has eight.
345: */
346: pageLength = data[13] & 0x01f;
347: for (i = 8; i < pageLength+8; i++)
348: {
349: data[i] = data[i+4];
350: data[i+4] = 0;
351: }
352:
353: atapiIoReq->atapiCmd[8] = 0x14; /* 8 + 12 */
354: data[9] = 0;
355:
356: return YES;
357: }
358:
359: /*
360: * Now handle the case where block descriptor length is zero. This is
361: * more messy since we are short of memory. FIXME later..
362: */
363:
364: return YES; /* this will fail now */
365: }
366:
367: return YES;
368: }
369:
370: /*
371: * If this SCSI command is not supported by ATAPI then try to fake its
372: * execution if possible.
373: */
374: - (BOOL) emulateSCSICmd:(atapiIoReq_t *)atapiIoReq buffer:(void *)buffer
375: {
376: unsigned char *data = (unsigned char *)buffer;
377:
378: /*
379: * We need to fake mode sense page 2. Workspace sends that and this page
380: * is reserved in ATAPI. In the SCSI world this page is for
381: * disconnect-reconnect and ATAPI doesn't support that now.
382: */
383: if (atapiIoReq->atapiCmd[0] == C10OP_MODESENSE)
384: {
385: if ((atapiIoReq->atapiCmd[2] & 0x1f) == 0x02)
386: {
387: bzero(data, atapiIoReq->atapiCmd[4]);
388: data[0] = 0x02;
389: data[1] = atapiIoReq->atapiCmd[4];
390: data[2] = 1; /* our preferred size: 2048 bytes */
391: atapiIoReq->bytesTransferred = atapiIoReq->atapiCmd[4];
392: atapiIoReq->scsiStatus = STAT_GOOD;
393:
394: return YES;
395: }
396: }
397:
398: return NO; /* default */
399: }
400:
401:
402: /*
403: * Reset all ATAPI devices connected to this controller. Note that we have
404: * obtain a lock before resetting the controller.
405: */
406: - (sc_status_t)resetSCSIBus
407: {
408: int unit;
409: atapi_return_t ret;
410: sc_status_t status = SR_IOST_GOOD;
411:
412: for (unit = 0; unit < [_ataController numDevices]; unit++) {
413:
414: if ([_ataController isAtapiDevice:unit])
415: {
416: [_ataController atapiCntrlrLock];
417: ret = [_ataController atapiSoftReset:unit];
418: [_ataController atapiCntrlrUnLock];
419:
420: if (ret != IDER_SUCCESS)
421: {
422: IOLog("%s: ATAPI reset failed.\n", [self name]);
423: status = SR_IOST_HW;
424: }
425: }
426: }
427:
428: return status;
429: }
430:
431: /*
432: * Note: ATAPI requires transfer byte counts be even.
433: * The alignment fields readLength and writeLength are set 2.
434: */
435:
436: - (void)getDMAAlignment:(IODMAAlignment *)alignment
437: {
438: alignment->readStart = 1; /* XXX */
439: alignment->writeStart = 1; /* XXX */
440: alignment->readLength = 2; /* XXX */
441: alignment->writeLength = 2; /* XXX */
442: }
443:
444: /*
445: * Set maximum I/O length for SCSI framework.
446: *
447: * There are 256 DBDMA descriptors available. One is used for a DBDMA STOP command. Another is
448: * potentially used to handle odd-byte transfers. An additional one may be potentially used if
449: * the transfer address is not page-aligned, for ex: a 64KB unaligned transfer requires 17 descriptors.
450: */
451: - (unsigned) maxTransfer
452: {
453: return (MAX_IDE_DESCRIPTORS - 3) * PAGE_SIZE;
454: }
455:
456: - property_IODeviceClass:(char *)classes length:(unsigned int *)maxLen
457: {
458: strcpy( classes, IOClassATAPIController);
459: return( self);
460: }
461:
462: - property_IODeviceType:(char *)types length:(unsigned int *)maxLen
463: {
464: strcat( types, " "IOTypeATAPI);
465: return( self);
466: }
467:
468:
469: @end
470:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.